|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.0 (the 'License'). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License." ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* ! 25: * Copyright 1997-1998 by Apple Computer, Inc., All rights reserved. ! 26: * Copyright 1994-1997 NeXT Software, Inc., All rights reserved. ! 27: * ! 28: * AtapiCnt.m - Implementation of ATAPI controller class. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 4-Jan-1998 Joe Liu at Apple ! 33: * Modified the ATAPI to SCSI translation routines. ! 34: * ! 35: * 31-Aug-1994 Rakesh Dubey at NeXT ! 36: * Created. ! 37: */ ! 38: ! 39: //#define DEBUG ! 40: //#define COMMAND_HISTORY ! 41: //#define COMMAND_PRINT ! 42: ! 43: #import "IdeCnt.h" ! 44: #import "AtapiCnt.h" ! 45: #import "AtapiCntInternal.h" ! 46: #import <kern/assert.h> ! 47: #import <driverkit/kernelDriver.h> ! 48: #import <driverkit/interruptMsg.h> ! 49: #import <mach/mach_interface.h> ! 50: #import <driverkit/IODevice.h> ! 51: #import <driverkit/align.h> ! 52: #import <machkit/NXLock.h> ! 53: #import <machdep/i386/io_inline.h> ! 54: #import <bsd/dev/scsireg.h> ! 55: ! 56: /* ! 57: * opcode groups ! 58: */ ! 59: #define SCSI_OPGROUP(opcode) ((opcode) & 0xe0) ! 60: ! 61: #define OPGROUP_0 0x00 /* six byte commands */ ! 62: #define OPGROUP_1 0x20 /* ten byte commands */ ! 63: #define OPGROUP_2 0x40 /* ten byte commands */ ! 64: #define OPGROUP_5 0xa0 /* twelve byte commands */ ! 65: #define OPGROUP_6 0xc0 /* six byte, vendor unique commands */ ! 66: #define OPGROUP_7 0xe0 /* ten byte, vendor unique commands */ ! 67: ! 68: #ifdef undef ! 69: static void testDebug(id driver); ! 70: #endif undef ! 71: ! 72: /* ! 73: * List of SCSI commands that do not have a counterpart in ATAPI ! 74: * implementation, or commands which have different command structure. ! 75: * These commands will need to be specially handled. ! 76: */ ! 77: #define C10OP_MODESELECT 0x55 ! 78: ! 79: static unsigned char mapToAtapi[] = { ! 80: C6OP_MODESELECT, ! 81: C10OP_MODESELECT, ! 82: C6OP_MODESENSE ! 83: }; ! 84: ! 85: /* ! 86: * List of controllers that have been already probed. We need this since each ! 87: * Instance table lists IdeDisk as well as IdeController classes. And we need ! 88: * to create instances of disks attached to each controller only once. ! 89: */ ! 90: static int probedControllerCount = 0; ! 91: static id probedControllers[MAX_IDE_CONTROLLERS]; ! 92: ! 93: @implementation AtapiController ! 94: ! 95: + (BOOL)probe : deviceDescription ! 96: { ! 97: ! 98: int unit, i; ! 99: id direct; ! 100: id atapiCnt; ! 101: ! 102: ! 103: direct = [deviceDescription directDevice]; ! 104: ! 105: ! 106: #ifdef undef ! 107: IOLog("AtapiController probed with direct device %x\n", direct); ! 108: #endif undef ! 109: ! 110: for (i = 0; i < probedControllerCount; i++) { ! 111: if (probedControllers[i] == direct) { ! 112: { ! 113: #ifdef undef ! 114: IOLog("AtapiController already probed for controller %x\n", ! 115: direct); ! 116: #endif undef ! 117: return YES; ! 118: } ! 119: } ! 120: } ! 121: ! 122: probedControllers[probedControllerCount++] = direct; ! 123: ! 124: for (unit = 0; unit < [direct numDevices]; unit++) { ! 125: ! 126: if ([direct isAtapiDevice:unit]) { ! 127: atapiCnt = [[self alloc] ! 128: initFromDeviceDescription:deviceDescription]; ! 129: ! 130: if (atapiCnt == nil) { ! 131: IOLog("ATAPI: failed to probe device %d.\n", unit); ! 132: continue; ! 133: } ! 134: ! 135: #ifdef undef ! 136: IOLog("ATAPI: found ATAPI device %d.\n", unit); ! 137: #endif undef ! 138: ! 139: if ([atapiCnt initResources:direct] == nil) { ! 140: IOLog("ATAPI: failed to initialize device %d.\n", unit); ! 141: [atapiCnt free]; ! 142: continue; ! 143: } ! 144: ! 145: /* ! 146: * To clear pending Unit attention. Not needed. ! 147: */ ! 148: //[direct atapiRequestSense:NULL]; ! 149: ! 150: /* ! 151: * Use this to test before we call registerDevice. ! 152: */ ! 153: //testDebug(direct); ! 154: ! 155: if ([atapiCnt registerDevice] == nil) { ! 156: IOLog("ATAPI: failed to register device %d.\n", unit); ! 157: [atapiCnt free]; ! 158: continue; ! 159: } else { ! 160: return YES; ! 161: } ! 162: } ! 163: } ! 164: ! 165: return NO; ! 166: } ! 167: ! 168: /* ! 169: * We override IOSCSIController to make ourself look like an indirect device ! 170: * in order to get connected to IdeController. ! 171: */ ! 172: + (IODeviceStyle)deviceStyle ! 173: { ! 174: return IO_IndirectDevice; ! 175: } ! 176: ! 177: /* ! 178: * The protocol we need as an indirect device. ! 179: */ ! 180: static Protocol *protocols[] = { ! 181: @protocol(AtapiControllerPublic), ! 182: nil ! 183: }; ! 184: ! 185: + (Protocol **)requiredProtocols ! 186: { ! 187: return protocols; ! 188: } ! 189: ! 190: - (unsigned short)scsiCmdLen:(IOSCSIRequest *) scsiReq ! 191: { ! 192: unsigned char cmdlen; ! 193: union cdb *cdbp = &scsiReq->cdb; ! 194: ! 195: switch (SCSI_OPGROUP(cdbp->cdb_opcode)) { ! 196: ! 197: case OPGROUP_0: ! 198: cmdlen = sizeof(struct cdb_6); ! 199: break; ! 200: ! 201: case OPGROUP_1: ! 202: case OPGROUP_2: ! 203: cmdlen = sizeof(struct cdb_10); ! 204: break; ! 205: ! 206: case OPGROUP_5: ! 207: cmdlen = sizeof(struct cdb_12); ! 208: break; ! 209: ! 210: case OPGROUP_6: ! 211: if (scsiReq->cdbLength) ! 212: cmdlen = scsiReq->cdbLength; ! 213: else ! 214: cmdlen = sizeof(struct cdb_6); ! 215: break; ! 216: ! 217: case OPGROUP_7: ! 218: if (scsiReq->cdbLength) ! 219: cmdlen = scsiReq->cdbLength; ! 220: else ! 221: cmdlen = sizeof(struct cdb_10); ! 222: break; ! 223: ! 224: default: ! 225: scsiReq->driverStatus = SR_IOST_CMDREJ; ! 226: return 0; ! 227: } ! 228: ! 229: return cmdlen; ! 230: } ! 231: ! 232: #define C10OP_MODESELECT 0x55 /* OPT: set device parameters */ ! 233: #define C10OP_MODESENSE 0x5a /* OPT: get device parameters */ ! 234: #define C10OP_READCAPACITY 0x25 /* read capacity */ ! 235: ! 236: /* ! 237: * This will enable us to print last 32 commands in case of an error. The ! 238: * command that caused the error is printed last. ! 239: */ ! 240: #ifdef COMMAND_HISTORY ! 241: #define MAXCMDS 32 ! 242: static atapiIoReq_t cmdBuf[MAXCMDS]; ! 243: static unsigned int cmdPos = 0; ! 244: static unsigned int cmdsInBuf = 0; ! 245: #endif COMMAND_HISTORY ! 246: ! 247: /* ! 248: * Do a SCSI command, as specified by an IOSCSIRequest. ! 249: */ ! 250: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq ! 251: buffer : (void *)buffer ! 252: client : (vm_task_t)client ! 253: { ! 254: int i; ! 255: atapiIoReq_t atapiIoReq; ! 256: atapiBuf_t *atapiBuf; ! 257: unsigned char *scsiCmd; ! 258: cdb_t my_cdb; ! 259: sc_status_t ret; ! 260: IOReturn driverStatus; ! 261: BOOL cmdMapped = NO; ! 262: ! 263: [_ataController atapiCntrlrLock]; ! 264: ! 265: my_cdb = scsiReq->cdb; ! 266: ! 267: #ifdef DEBUG ! 268: if ((scsiReq->lun == 0) && (scsiReq->target < 2)) { ! 269: IOLog("%s: executeRequest %x target %x lun %x Read %d\n", ! 270: [self name], my_cdb.cdb_opcode, scsiReq->target, scsiReq->lun, ! 271: scsiReq->read); ! 272: } ! 273: #endif DEBUG ! 274: ! 275: bzero(&atapiIoReq, sizeof(atapiIoReq_t)); ! 276: ! 277: atapiIoReq.cmdLen = [_ataController ! 278: atapiCommandPacketSize:scsiReq->target]; ! 279: ! 280: atapiIoReq.read = scsiReq->read; ! 281: atapiIoReq.maxTransfer = scsiReq->maxTransfer; ! 282: atapiIoReq.drive = scsiReq->target; ! 283: atapiIoReq.lun = scsiReq->lun; ! 284: atapiIoReq.timeout = scsiReq->timeoutLength * 1000; // sec to ms ! 285: ! 286: // IOLog("max: %d\n", atapiIoReq.maxTransfer); ! 287: ! 288: scsiCmd = (unsigned char *) &(my_cdb.cdb_opcode); ! 289: atapiIoReq.scsiCmd = *scsiCmd; ! 290: ! 291: for (i = 0; i < [self scsiCmdLen:scsiReq]; i++) { ! 292: atapiIoReq.atapiCmd[i] = *scsiCmd; ! 293: scsiCmd++; ! 294: } ! 295: ! 296: /* ! 297: * Use this to print SCSI commands being sent to ATA object. ! 298: */ ! 299: ! 300: #ifdef COMMAND_PRINT ! 301: if ((atapiIoReq.atapiCmd[0] == 0x28) && (atapiIoReq.lun == 0)) { ! 302: IOLog("%s: Command 0x28.\n", [self name]); ! 303: for (i = 0; i < [self scsiCmdLen:scsiReq]; i+=2) { ! 304: IOLog("%s: %02x %02x\n", [self name], ! 305: atapiIoReq.atapiCmd[i], atapiIoReq.atapiCmd[i+1]); ! 306: } ! 307: ! 308: } ! 309: if ((atapiIoReq.atapiCmd[0] == 0x15) && (atapiIoReq.lun == 0)) { ! 310: unsigned char *tmp = (unsigned char *)buffer; ! 311: IOLog("%s: Command 0x15 data.\n", [self name]); ! 312: for (i = 0; i < 0x1c; i+=2) { ! 313: IOLog("%s: %02x %02x\n", [self name], ! 314: tmp[i], tmp[i+1]); ! 315: } ! 316: } ! 317: #endif COMMAND_PRINT ! 318: ! 319: #ifdef COMMAND_HISTORY ! 320: /* Keep history */ ! 321: cmdBuf[cmdPos++] = atapiIoReq; ! 322: if (cmdsInBuf < MAXCMDS) ! 323: cmdsInBuf += 1; ! 324: if (cmdPos == MAXCMDS) ! 325: cmdPos = 0; ! 326: #endif COMMAND_HISTORY ! 327: ! 328: /* ! 329: * Map to available ATAPI command if necessary. ! 330: */ ! 331: for (i = 0; i < sizeof(mapToAtapi)/sizeof(mapToAtapi[0]); i++) { ! 332: if (atapiIoReq.atapiCmd[0] == mapToAtapi[i]) { ! 333: //IOLog("%s: Mapping to SCSI command\n", [self name]); ! 334: bzero((void *)&modeData, sizeof(modeData)); ! 335: if ([self maptoAtapiCmd: &atapiIoReq buffer:buffer ! 336: newBuffer:&modeData] == NO) { ! 337: [_ataController atapiCntrlrUnLock]; ! 338: return SR_IOST_CMDREJ; ! 339: } ! 340: cmdMapped = YES; ! 341: break; ! 342: } ! 343: } ! 344: ! 345: /* ! 346: * If emulation is successful then return quickly. ! 347: */ ! 348: if ([self emulateSCSICmd: &atapiIoReq buffer:buffer] == YES) { ! 349: [_ataController atapiCntrlrUnLock]; ! 350: return SR_IOST_GOOD; ! 351: } ! 352: ! 353: /* ! 354: * Send the command to the ioThread. ! 355: */ ! 356: atapiBuf = [self allocAtapiBuf]; ! 357: atapiBuf->atapiIoReq = &atapiIoReq; ! 358: if (cmdMapped) { ! 359: atapiBuf->buffer = (void *)&modeData; ! 360: atapiBuf->client = IOVmTaskSelf(); ! 361: } ! 362: else { ! 363: atapiBuf->buffer = buffer; ! 364: atapiBuf->client = client; ! 365: } ! 366: atapiBuf->command = ATAPI_CNT_IOREQ; ! 367: driverStatus = [self enqueueAtapiBuf:atapiBuf]; ! 368: ret = atapiBuf->status; // SCSI status ! 369: ! 370: /* ! 371: * Re-map to SCSI command if necessary. ! 372: */ ! 373: if (driverStatus == SR_IOST_GOOD) { ! 374: for (i = 0; i < sizeof(mapToAtapi)/sizeof(mapToAtapi[0]); i++) { ! 375: if (atapiIoReq.scsiCmd == mapToAtapi[i]) { ! 376: if ([self maptoSCSICmd: &atapiIoReq buffer:buffer ! 377: newBuffer:&modeData] == NO) { ! 378: [_ataController atapiCntrlrUnLock]; ! 379: return SR_IOST_CMDREJ; ! 380: } ! 381: break; ! 382: } ! 383: } ! 384: } ! 385: ! 386: [self freeAtapiBuf:atapiBuf]; ! 387: ! 388: /* ! 389: * Use this to filter and print data returned from the device. ! 390: */ ! 391: #ifdef DEBUG ! 392: { ! 393: unsigned char *buf = (unsigned char *)buffer; ! 394: if ((atapiIoReq.atapiCmd[0] == 0x25) && (atapiIoReq.lun == 0)) { ! 395: IOLog("%s: Returned data.\n", [self name]); ! 396: for (i = 0; i < atapiIoReq.bytesTransferred; i+=4) { ! 397: IOLog("%s: %02x %02x %02x %02x\n", [self name], buf[i], ! 398: buf[i+1], buf[i+2], buf[i+3]); ! 399: } ! 400: IOLog("%s: total bytes transferred = %d\n", [self name], ! 401: atapiIoReq.bytesTransferred); ! 402: IOLog("%s: scsi status: %x driver status: %x\n", [self name], ! 403: atapiIoReq.scsiStatus, ret); ! 404: } ! 405: ! 406: } ! 407: #endif DEBUG ! 408: ! 409: /* ! 410: * This is a workaround for the Mitsumi Read CD-ROM capacity bug. It ! 411: * reports the block size as 2352 bytes instead of 2048 bytes. It is ! 412: * including preamble and other info. I have seen this on MITSUMI CD-ROM ! 413: * !B B02. The workaround is truncate the returned value. Remove this ! 414: * when it is no longer needed. ! 415: */ ! 416: { ! 417: unsigned int blockSize, value; ! 418: char *buf = (char *)buffer; ! 419: if ((atapiIoReq.atapiCmd[0] == C10OP_READCAPACITY) && ! 420: (atapiIoReq.lun == 0)) { ! 421: blockSize = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | ! 422: buf[7]; ! 423: if (blockSize == 0) /* self defense */ ! 424: blockSize = 2048; ! 425: for (value = 16; value < blockSize; value *= 2) ! 426: ; ! 427: if (value > blockSize) { ! 428: //IOLog("%s: block size set to %d from %d\n", [self name], value/2, blockSize); ! 429: blockSize = value / 2; ! 430: buf[4] = (blockSize >> 24) & 0xff; ! 431: buf[5] = (blockSize >> 16) & 0xff; ! 432: buf[6] = (blockSize >> 8) & 0xff; ! 433: buf[7] = blockSize & 0xff; ! 434: } ! 435: } ! 436: } ! 437: ! 438: #ifdef COMMAND_HISTORY ! 439: { ! 440: int j, k; ! 441: ! 442: /* Print history in case of error. */ ! 443: if ((ret != SR_IOST_GOOD) && (atapiIoReq.atapiCmd[0] != 0x00) ! 444: && (atapiIoReq.atapiCmd[0] != 0x12)) { ! 445: IOLog("%s: Command %02x failed. Backtrace..\n", [self name], ! 446: atapiIoReq.atapiCmd[0]); ! 447: i = (cmdPos - cmdsInBuf) % MAXCMDS; ! 448: k = (int) cmdsInBuf; ! 449: while (--k >= 0) { ! 450: IOLog("%s: ", [self name]); ! 451: for (j = 0; j < 12; j++) { ! 452: IOLog("%02x ", cmdBuf[i].atapiCmd[j]); ! 453: } ! 454: IOLog("\n"); ! 455: if (i == MAXCMDS) ! 456: i = 0; ! 457: else ! 458: i += 1; ! 459: } ! 460: cmdsInBuf = 0; ! 461: } ! 462: } ! 463: #endif COMMAND_HISTORY ! 464: ! 465: scsiReq->bytesTransferred = atapiIoReq.bytesTransferred; ! 466: scsiReq->scsiStatus = atapiIoReq.scsiStatus; ! 467: scsiReq->driverStatus = driverStatus; ! 468: ! 469: [_ataController atapiCntrlrUnLock]; ! 470: ! 471: return ret; ! 472: } ! 473: ! 474: #define MPH_SCSI_6_SIZE sizeof(mode_sel_hdr_t) ! 475: #define MPH_SCSI_10_SIZE 8 ! 476: #define MPH_ATAPI_SIZE sizeof(atapiMPH_t) ! 477: #define MPH_DELTA (MPH_ATAPI_SIZE - MPH_SCSI_6_SIZE) ! 478: ! 479: /* ! 480: * Map SCSI commands into ATAPI commands. ! 481: * We use this to modify the SCSI Mode Sense/Select commands to fit ! 482: * the ATAPI protocol. ! 483: * ! 484: * FIXME - We do not handle multiple mode pages. Only the first page is ! 485: * translated. ! 486: */ ! 487: - (BOOL) maptoAtapiCmd:(atapiIoReq_t *)atapiIoReq ! 488: buffer:(void *)buffer ! 489: newBuffer:(atapiMPL_t *)mode ! 490: { ! 491: int i, pageLength, bd_len, page_start, hdr_size, maxTransfer; ! 492: unsigned char *data = (unsigned char *)buffer; ! 493: ! 494: /* ! 495: * Modify the SCSI mode sense (6) command. ! 496: * ! 497: * SCSI mode sense (10) should be fine for ATAPI since it matches ! 498: * the ATAPI spec very closely. ! 499: */ ! 500: if (atapiIoReq->scsiCmd == C6OP_MODESENSE) { ! 501: ! 502: /* ! 503: * Our ATAPI buffer must be MPH_DELTA bytes larger than the size ! 504: * of the SCSI buffer passed in. ! 505: */ ! 506: if ((atapiIoReq->atapiCmd[4] + MPH_DELTA) > sizeof(atapiMPL_t)) ! 507: return NO; ! 508: ! 509: /* ! 510: * Transform the SCSI mode sense (6) command into a SCSI ! 511: * mode sense (10) command. ! 512: */ ! 513: atapiIoReq->atapiCmd[0] = C10OP_MODESENSE; ! 514: atapiIoReq->atapiCmd[8] = atapiIoReq->atapiCmd[4] + MPH_DELTA; ! 515: atapiIoReq->atapiCmd[4] = 0; ! 516: atapiIoReq->atapiCmd[5] = 0; ! 517: ! 518: /* Increase the maxTransfer by 4 bytes, since in SCSI Mode ! 519: * Sense(6), the Mode Parameter Header is only 4 bytes long, ! 520: * while in ATAPI, it is always 8-bytes. Therefore, we may ! 521: * need to transfer 4 additional bytes over the set SCSI limit. ! 522: * We also know that we have enough storage since we did the ! 523: * check earlier. ! 524: */ ! 525: atapiIoReq->maxTransfer += MPH_DELTA; ! 526: ! 527: return YES; ! 528: } ! 529: ! 530: /* ! 531: * Modify the SCSI mode select commands. ! 532: */ ! 533: if ((atapiIoReq->scsiCmd == C6OP_MODESELECT) || ! 534: (atapiIoReq->scsiCmd == C10OP_MODESELECT)) { ! 535: ! 536: if (atapiIoReq->scsiCmd == C6OP_MODESELECT) { ! 537: atapiIoReq->atapiCmd[0] = C10OP_MODESELECT; ! 538: atapiIoReq->atapiCmd[4] = 0; ! 539: atapiIoReq->atapiCmd[5] = 0; /* reset control field */ ! 540: ! 541: bd_len = data[3]; /* block descriptor length */ ! 542: hdr_size = MPH_SCSI_6_SIZE; /* mode parameter hdr size */ ! 543: } ! 544: else { // C10OP_MODESELECT ! 545: atapiIoReq->atapiCmd[9] = 0; /* reset control field */ ! 546: bd_len = (data[6] << 8) | data[7]; /* block descriptor length */ ! 547: hdr_size = MPH_SCSI_10_SIZE; /* mode parameter hdr size */ ! 548: } ! 549: ! 550: page_start = hdr_size + bd_len; /* start of mode page */ ! 551: pageLength = data[page_start + 1] + 2; /* total size of mode page */ ! 552: if (pageLength > MODSEL_DATA_LEN) /* page too large */ ! 553: return NO; ! 554: ! 555: /* copy the mode page to our own buffer space */ ! 556: for (i = 0; i < pageLength; i++) { ! 557: mode->pageData[i] = data[page_start + i]; ! 558: } ! 559: ! 560: /* Update allocation length in the mode select command. ! 561: * length = page size + ATAPI header size ! 562: */ ! 563: maxTransfer = pageLength + MPH_ATAPI_SIZE; ! 564: atapiIoReq->atapiCmd[8] = maxTransfer & 0xff; /* LSB */ ! 565: atapiIoReq->atapiCmd[7] = (maxTransfer >> 8) & 0xff; /* MSB */ ! 566: ! 567: /* ! 568: * Update the maxTransfer count. ! 569: */ ! 570: atapiIoReq->maxTransfer = maxTransfer; ! 571: return YES; ! 572: } ! 573: ! 574: return YES; ! 575: } ! 576: ! 577: /* ! 578: * Map the result of ATAPI commands into their SCSI counterparts. ! 579: * ! 580: * FIXME - We do not handle multiple mode pages. Only the first page is ! 581: * translated. ! 582: */ ! 583: - (BOOL) maptoSCSICmd:(atapiIoReq_t *)atapiIoReq ! 584: buffer:(void *)buffer ! 585: newBuffer:(atapiMPL_t *)mode ! 586: { ! 587: int i, pageLength; ! 588: unsigned char *data = (unsigned char *)buffer; ! 589: ! 590: /* ! 591: * If the executed command was originally a SCSI Mode Sense(6) ! 592: * command, we need to modify the result since the returned ! 593: * Page Parameter Header size is now 8-bytes instead of the ! 594: * expected 4-bytes. ! 595: */ ! 596: if ((atapiIoReq->scsiCmd == C6OP_MODESENSE) && ! 597: (atapiIoReq->bytesTransferred >= 10)) { ! 598: ! 599: // bytesTransferred must be greater than 10 or otherwise the ! 600: // PageLength field in the page (byte 1) would not be valid. ! 601: ! 602: pageLength = mode->pageData[1] + 2; ! 603: ! 604: /* Mode Page + Mode Header must fit in the SCSI buffer. ! 605: * Remember that the value in atapiCmd[8] was ! 606: * artificially increased by 4 bytes, so we need to ! 607: * take that into account. ! 608: */ ! 609: if ((pageLength + MPH_SCSI_6_SIZE) > ! 610: (atapiIoReq->atapiCmd[8] - MPH_DELTA)) { ! 611: /* SCSI buffer is too small */ ! 612: #ifdef DEBUG ! 613: IOLog("maptoSCSICmd: Mode Select buffer too small\n"); ! 614: #endif DEBUG ! 615: return NO; ! 616: } ! 617: ! 618: data[0] = mode->mph.mdl0; // mode data length ! 619: data[1] = mode->mph.mt; // medium type ! 620: data[2] = 0; // device-specific parameter ! 621: data[3] = 0; // block descriptor length ! 622: ! 623: for (i = 0; i < pageLength; i++) { ! 624: data[4 + i] = mode->pageData[i]; ! 625: } ! 626: ! 627: /* ! 628: * Modify bytesTransferred count to make it appear that ! 629: * we transferred 4 less bytes. ! 630: */ ! 631: atapiIoReq->bytesTransferred -= MPH_DELTA; ! 632: return YES; ! 633: } ! 634: ! 635: return YES; ! 636: } ! 637: ! 638: /* ! 639: * If this SCSI command is not supported by ATAPI then try to fake its ! 640: * execution if possible. ! 641: */ ! 642: - (BOOL) emulateSCSICmd:(atapiIoReq_t *)atapiIoReq buffer:(void *)buffer ! 643: { ! 644: unsigned char *data = (unsigned char *)buffer; ! 645: ! 646: /* ! 647: * We need to fake mode sense page 2. Workspace sends that and this page ! 648: * is reserved in ATAPI. In the SCSI world this page is for ! 649: * disconnect-reconnect and ATAPI doesn't support that now. ! 650: */ ! 651: if (atapiIoReq->atapiCmd[0] == C10OP_MODESENSE) { ! 652: if ((atapiIoReq->atapiCmd[2] & 0x1f) == 0x02) { ! 653: bzero(data, atapiIoReq->atapiCmd[4]); ! 654: data[0] = 0x02; ! 655: data[1] = atapiIoReq->atapiCmd[4]; ! 656: data[2] = 1; /* our preferred size: 2048 bytes */ ! 657: atapiIoReq->bytesTransferred = atapiIoReq->atapiCmd[4]; ! 658: atapiIoReq->scsiStatus = STAT_GOOD; ! 659: ! 660: return YES; ! 661: } ! 662: } ! 663: ! 664: return NO; /* default */ ! 665: } ! 666: ! 667: ! 668: /* ! 669: * Reset all ATAPI devices connected to this controller. Note that we have ! 670: * obtain a lock before resetting the controller. ! 671: */ ! 672: - (sc_status_t)resetSCSIBus ! 673: { ! 674: int unit; ! 675: atapi_return_t ret; ! 676: sc_status_t status = SR_IOST_GOOD; ! 677: ! 678: for (unit = 0; unit < [_ataController numDevices]; unit++) { ! 679: ! 680: if ([_ataController isAtapiDevice:unit]) { ! 681: ! 682: [_ataController atapiCntrlrLock]; ! 683: ret = [_ataController atapiSoftReset:unit]; ! 684: [_ataController atapiCntrlrUnLock]; ! 685: ! 686: if (ret != IDER_SUCCESS) { ! 687: IOLog("%s: ATAPI reset failed.\n", [self name]); ! 688: status = SR_IOST_HW; ! 689: } ! 690: } ! 691: } ! 692: ! 693: return status; ! 694: } ! 695: ! 696: #ifdef undef ! 697: /* For testing individual commands. */ ! 698: static void testDebug(id driver) ! 699: { ! 700: void *buffer; ! 701: atapiIoReq_t atapiIoReq; ! 702: ! 703: buffer = IOMalloc(2048); ! 704: bzero(&atapiIoReq, sizeof(atapiIoReq_t)); ! 705: ! 706: atapiIoReq.cmdLen = 12; ! 707: atapiIoReq.read = 1; ! 708: atapiIoReq.drive = 0; ! 709: atapiIoReq.lun = 0; ! 710: ! 711: atapiIoReq.atapiCmd[0] = 0x28; ! 712: atapiIoReq.atapiCmd[2] = 0; ! 713: atapiIoReq.atapiCmd[3] = 0; ! 714: atapiIoReq.atapiCmd[4] = 0; ! 715: atapiIoReq.atapiCmd[5] = 5; ! 716: atapiIoReq.atapiCmd[7] = 0; ! 717: atapiIoReq.atapiCmd[8] = 1; ! 718: ! 719: [driver atapiExecuteCmd:&atapiIoReq ! 720: buffer:buffer client:IOVmTaskSelf()]; ! 721: ! 722: } ! 723: #endif undef ! 724: ! 725: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen ! 726: { ! 727: strcpy( classes, IOClassATAPIController); ! 728: return( self); ! 729: } ! 730: ! 731: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen ! 732: { ! 733: strcat( types, " "IOTypeATAPI); ! 734: return( self); ! 735: } ! 736: ! 737: @end ! 738:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.