|
|
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.1 (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 by Apple Computer, Inc., all rights reserved. ! 26: /* ! 27: * Copyright (c) 1994-1997 NeXT Software, Inc. All rights reserved. ! 28: * ! 29: * AtapiCntCmds.m - ATAPI command implementation for ATA interface. ! 30: * ! 31: * HISTORY ! 32: * ! 33: */ ! 34: ! 35: #import "AtapiCntCmds.h" ! 36: #import "IdeCntInit.h" ! 37: #import "IdeCntCmds.h" ! 38: #import "IdeCntDma.h" ! 39: ! 40: @implementation IdeController(ATAPI) ! 41: ! 42: #define ATAPI_MAX_WAIT_FOR_NOTBUSY (5 * 1000) ! 43: ! 44: /* ! 45: * We could use the ATA version instead of rolling our own here. ! 46: */ ! 47: - (atapi_return_t)atapiWaitForNotBusy ! 48: { ! 49: int i; ! 50: unsigned char status; ! 51: ! 52: for (i = 0; i < ATAPI_MAX_WAIT_FOR_NOTBUSY; i++) ! 53: { ! 54: status = inb(_ideRegsAddrs.status); ! 55: ! 56: if (!(status & BUSY)) ! 57: { ! 58: return IDER_SUCCESS; ! 59: } ! 60: IOSleep(1); ! 61: } ! 62: return IDER_TIMEOUT; ! 63: } ! 64: ! 65: /* ! 66: * Before sending a packet to ATAPI device, we test if BSY == 0 and DRQ == 0. ! 67: */ ! 68: #define ATAPI_MAX_WAIT_READY_FOR_PACKET (5 * 1000) ! 69: ! 70: - (atapi_return_t)atapiWaitReadyForPacket ! 71: { ! 72: int i; ! 73: unsigned char status; ! 74: ! 75: for (i = 0; i < ATAPI_MAX_WAIT_READY_FOR_PACKET; i++) ! 76: { ! 77: status = inb(_ideRegsAddrs.status); ! 78: ! 79: if (!(status & BUSY) && !(status & DREQUEST)) ! 80: { ! 81: return IDER_SUCCESS; ! 82: } ! 83: IOSleep(1); ! 84: } ! 85: ! 86: return IDER_DEV_NOT_READY; ! 87: } ! 88: ! 89: -(void)printAtapiInfo:(ideIdentifyInfo_t *)ideIdentifyInfo ! 90: Device:(unsigned char)unit ! 91: { ! 92: int i; ! 93: char name[50]; ! 94: char firmware[9]; ! 95: atapiGenConfig_t *atapiGenConfig; ! 96: char *protocolTypeStr, *deviceTypeStr, *cmdDrqTypeStr; ! 97: char *removableStr, *cmdPacketSizeStr; ! 98: ! 99: /* ! 100: * Print drive name with firmware revision number after doing byte swaps. ! 101: */ ! 102: for (i = 0; i < 20; i++) ! 103: { ! 104: name[2*i] = ideIdentifyInfo->modelNumber[2*i+1]; ! 105: name[2*i+1] = ideIdentifyInfo->modelNumber[2*i]; ! 106: } ! 107: name[40] = '\0'; ! 108: ! 109: for (i = 0; i < 4; i++) ! 110: { ! 111: firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1]; ! 112: firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i]; ! 113: } ! 114: firmware[8] = '\0'; ! 115: ! 116: for (i = 38; i >= 0; i--) { ! 117: if (name[i] != ' ') ! 118: break; ! 119: } ! 120: strcpy(name+i+2, firmware); ! 121: ! 122: /* ! 123: * This information should be printed since it is not duplicated ! 124: * elsewhere. ! 125: */ ! 126: atapiGenConfig = (atapiGenConfig_t *) &ideIdentifyInfo->genConfig; ! 127: ! 128: if (atapiGenConfig->protocolType == 0 || atapiGenConfig->protocolType == 1) ! 129: protocolTypeStr = "ATA"; ! 130: else if (atapiGenConfig->protocolType == 2) ! 131: protocolTypeStr = "ATAPI"; ! 132: else ! 133: protocolTypeStr = "UNKNOWN PROTOCOL"; ! 134: ! 135: if (atapiGenConfig->deviceType == 0) ! 136: deviceTypeStr = "DIRECT ACCESS"; ! 137: else if (atapiGenConfig->deviceType == 5) ! 138: deviceTypeStr = "CD-ROM"; ! 139: else if (atapiGenConfig->deviceType == 7) ! 140: deviceTypeStr = "OPTICAL"; ! 141: else if (atapiGenConfig->deviceType == 1) ! 142: deviceTypeStr = "TAPE"; ! 143: else ! 144: deviceTypeStr = "UNKNOWN DEVICE TYPE"; ! 145: ! 146: if (atapiGenConfig->cmdDrqType == 0) ! 147: cmdDrqTypeStr = "SLOW DRQ"; ! 148: else if (atapiGenConfig->cmdDrqType == 1) ! 149: cmdDrqTypeStr = "INTR DRQ"; ! 150: else if (atapiGenConfig->cmdDrqType == 2) ! 151: cmdDrqTypeStr = "FAST DRQ"; ! 152: else ! 153: cmdDrqTypeStr = "UNKNOWN DRQ TYPE"; ! 154: ! 155: if (atapiGenConfig->removable == 0) ! 156: removableStr = "NOT REMOVABLE"; ! 157: else if (atapiGenConfig->removable == 1) ! 158: removableStr = "REMOVABLE"; ! 159: ! 160: if (atapiGenConfig->cmdPacketSize == 0) ! 161: cmdPacketSizeStr = "CMD PKT LEN=12"; ! 162: else if (atapiGenConfig->cmdPacketSize == 1) ! 163: cmdPacketSizeStr = "CMD PKT LEN=16"; ! 164: else ! 165: cmdPacketSizeStr = "CMD PKT LEN=UNKNOWN"; ! 166: } ! 167: ! 168: /* ! 169: * This is a private version for ATAPI Identify command below. It has a short ! 170: * delay time. ! 171: */ ! 172: - (ide_return_t)atapiIdentifyDeviceWaitForDataReady ! 173: { ! 174: int delay = (100 * 1000); ! 175: unsigned char status; ! 176: ! 177: delay -= 2; ! 178: while (delay > 0) ! 179: { ! 180: status = inb(_ideRegsAddrs.altStatus); ! 181: if ((!(status & BUSY)) && (status & DREQUEST)) ! 182: return (IDER_SUCCESS); ! 183: if (delay % 1000) ! 184: { ! 185: IODelay(2); ! 186: delay -= 2; ! 187: } ! 188: else ! 189: { ! 190: IOSleep(1); ! 191: delay -= 1000; ! 192: } ! 193: } ! 194: ! 195: return IDER_DEV_NOT_READY; ! 196: } ! 197: ! 198: /* ! 199: * There are lots of ATAPI CD-ROMs that shadow the task file register and ! 200: * hence show up as two devices. They also might issue a valid interrupt when ! 201: * ATAPI Identify Device command is sent so we need to really make sure ! 202: * whether the device has data for us. ! 203: */ ! 204: -(atapi_return_t)_atapiIdentifyDevice:(struct vm_map *)client ! 205: addr:(caddr_t)xferAddr ! 206: { ! 207: unsigned int cmd = ATAPI_IDENTIFY_DRIVE; ! 208: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */ ! 209: unsigned char status; ! 210: atapi_return_t rtn; ! 211: ! 212: unsigned int oldTimeout; ! 213: ! 214: rtn = [self atapiWaitForNotBusy]; ! 215: if (rtn != IDER_SUCCESS) ! 216: { ! 217: return (rtn); ! 218: } ! 219: ! 220: [self setTransferRate: _driveNum UseDMA:NO]; ! 221: ! 222: dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0; ! 223: outb(_ideRegsAddrs.driveSelect, dh); ! 224: ! 225: bzero(xferAddr, IDE_SECTOR_SIZE); ! 226: ! 227: [self enableInterrupts]; ! 228: ! 229: outb(_ideRegsAddrs.command, ATAPI_IDENTIFY_DRIVE); ! 230: ! 231: oldTimeout = [self interruptTimeOut]; ! 232: [self setInterruptTimeOut:4000]; // four seconds ! 233: ! 234: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status]; ! 235: ! 236: if (rtn != IDER_SUCCESS) { ! 237: [self getIdeRegisters:NULL Print:"Atapi Identify"]; ! 238: [self setInterruptTimeOut:oldTimeout]; ! 239: return rtn; ! 240: } ! 241: ! 242: /* ! 243: * Let's see if it really has data for us. ! 244: */ ! 245: rtn = [self atapiIdentifyDeviceWaitForDataReady]; ! 246: if (rtn != IDER_SUCCESS) ! 247: { ! 248: [self setInterruptTimeOut:oldTimeout]; ! 249: return (rtn); ! 250: } ! 251: ! 252: /* ! 253: * FIXME: We need to do some sanity check on this data to be really sure ! 254: * that there is an ATAPI device out here. ! 255: */ ! 256: [self xferData:xferAddr read:YES client:client length:IDE_SECTOR_SIZE]; ! 257: ! 258: [self setInterruptTimeOut:oldTimeout]; ! 259: ! 260: return IDER_SUCCESS; ! 261: } ! 262: ! 263: /* ! 264: * Some CD-ROMS (like SONY CDU-55D) fail the first request so we reset the ! 265: * device and retry. ! 266: */ ! 267: #define ATAPI_IDENTIFY_DEVICE_RETRIES 5 ! 268: ! 269: -(atapi_return_t)atapiIdentifyDevice:(struct vm_map *)client ! 270: addr:(caddr_t)xferAddr ! 271: unit:(unsigned char)unit ! 272: { ! 273: int i; ! 274: atapi_return_t ret; ! 275: ! 276: for (i = 0; i < ATAPI_IDENTIFY_DEVICE_RETRIES; i++) ! 277: { ! 278: ret = [self _atapiIdentifyDevice:client addr:xferAddr]; ! 279: if (ret == IDER_SUCCESS) ! 280: break; ! 281: ! 282: /* Reset hardware and try again */ ! 283: [self atapiSoftReset:unit]; ! 284: IOSleep(500); ! 285: } ! 286: ! 287: if (i == ATAPI_IDENTIFY_DEVICE_RETRIES) { ! 288: IOLog("%s: FATAL: Device %d: ATAPI Identify Device.\n", ! 289: [self name], unit); ! 290: } ! 291: ! 292: return ret; ! 293: } ! 294: ! 295: -(void)atapiInitParameters:(ideIdentifyInfo_t *)infoPtr ! 296: Device:(unsigned char)unit ! 297: { ! 298: atapiGenConfig_t *atapiGenConfig = ! 299: (atapiGenConfig_t *) &infoPtr->genConfig; ! 300: ! 301: if (atapiGenConfig->cmdPacketSize == 0x01) ! 302: _atapiCmdLen[unit] = 16; ! 303: else ! 304: _atapiCmdLen[unit] = 12; ! 305: ! 306: /* ! 307: * The command len is 12. However some devices think it is 16 which is ! 308: * actually reserved for SAM compatibility. See page 58, SFF 8020, rev ! 309: * 1.2. This is a workaround. ! 310: */ ! 311: if (_atapiCmdLen[unit] != 12) ! 312: { ! 313: IOLog("%s: ATAPI: command len changed to 12 from %d.\n", ! 314: [self name], _atapiCmdLen[unit]); ! 315: _atapiCmdLen[unit] = 12; ! 316: } ! 317: ! 318: _atapiCmdDrqType[unit] = atapiGenConfig->cmdDrqType; ! 319: ! 320: if (infoPtr->capabilities & IDE_CAP_DMA_SUPPORTED) ! 321: { ! 322: if ( [self allocDmaMemory] == IDER_SUCCESS ) ! 323: { ! 324: _dmaSupported[unit] = YES; ! 325: } ! 326: } ! 327: ! 328: [self getTransferModes:infoPtr Unit:unit]; ! 329: ! 330: /* ! 331: * Set the Disk/CDROM transfer mode (Set Features SC=3) ! 332: */ ! 333: [self setTransferMode: unit]; ! 334: } ! 335: ! 336: /* ! 337: * Identify ATAPI device must have been executed first before callling this ! 338: * method. ! 339: */ ! 340: -(unsigned char)atapiCommandPacketSize:(unsigned char)unit ! 341: { ! 342: if (unit < MAX_IDE_DRIVES) ! 343: return _atapiCmdLen[unit]; ! 344: else ! 345: return 0; ! 346: } ! 347: ! 348: ! 349: /* ! 350: * The amount of time in milliseconds it takes for an ATAPI device to post ! 351: * its signature after a reset. Some CD-ROMs take a long time to respond. Do ! 352: * not decrease it without testing with various makes of ATAPI devices. ! 353: */ ! 354: #define ATAPI_RESET_DELAY 2500 ! 355: ! 356: -(atapi_return_t)atapiSoftReset:(unsigned char)unit ! 357: { ! 358: int delay; ! 359: unsigned char status; ! 360: atapi_return_t rtn; ! 361: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */ ! 362: ! 363: _driveReset[unit] = YES; ! 364: ! 365: dh |= unit ? SEL_DRIVE1 : SEL_DRIVE0; ! 366: ! 367: outb(_ideRegsAddrs.driveSelect, dh); ! 368: outb(_ideRegsAddrs.command, ATAPI_SOFT_RESET); ! 369: ! 370: delay = ATAPI_RESET_DELAY; ! 371: ! 372: IOSleep(50); /* Enough time to assert busy */ ! 373: ! 374: rtn = IDER_ERROR; ! 375: ! 376: while (delay > 0) ! 377: { ! 378: status = inb(_ideRegsAddrs.status); ! 379: if (!(status & BUSY)) ! 380: { ! 381: rtn = IDER_SUCCESS; ! 382: break; ! 383: } ! 384: ! 385: IOSleep(10); ! 386: delay -= 10; ! 387: } ! 388: ! 389: return rtn; ! 390: } ! 391: ! 392: ! 393: #define MAX_DRQ_WAIT (1000 * 2) // milliseconds ! 394: ! 395: -(atapi_return_t)atapiPacketCommand ! 396: { ! 397: int i; ! 398: atapi_return_t rtn; ! 399: unsigned char interruptReason; ! 400: unsigned char status; ! 401: ! 402: outb(_ideRegsAddrs.command, ATAPI_PACKET); ! 403: ! 404: /* ! 405: * Some devices might have interrupted so we should take care of that ! 406: * first. ! 407: */ ! 408: if (_atapiCmdDrqType[_driveNum] == ATAPI_CMD_DRQ_INT) ! 409: { ! 410: rtn = [self ideWaitForInterrupt:ATAPI_PACKET ideStatus:&status]; ! 411: } ! 412: ! 413: /* ! 414: * Wait till we get okay from the device. ! 415: */ ! 416: for (i = 0; i < MAX_DRQ_WAIT; i++) ! 417: { ! 418: interruptReason = inb(_ideRegsAddrs.interruptReason); ! 419: if ((interruptReason & CMD_OR_DATA) && !(interruptReason & IO_DIRECTION)) ! 420: break; ! 421: IOSleep(1); ! 422: } ! 423: ! 424: if (i == MAX_DRQ_WAIT) ! 425: { ! 426: IOLog("%s: ATAPI Device %d: Invalid Interrupt Reason: %x.\n", ! 427: [self name], _driveNum, interruptReason); ! 428: return IDER_ERROR; ! 429: } ! 430: ! 431: /* ! 432: * Now DRQ should be set. ! 433: */ ! 434: status = inb(_ideRegsAddrs.status); ! 435: if (status & DREQUEST) ! 436: { ! 437: return IDER_SUCCESS; ! 438: } ! 439: ! 440: IOLog("%s: ATAPI Device %d: No Data Request: %x.\n", ! 441: [self name], _driveNum, status); ! 442: ! 443: return IDER_ERROR; ! 444: } ! 445: ! 446: /* ! 447: * Note that the command is sent out as words in little endian format. ! 448: */ ! 449: - (void) sendAtapiCommand:(unsigned char *)atapiCmd ! 450: cmdLen:(unsigned char)len ! 451: { ! 452: int i; ! 453: ! 454: for (i = 0; i < len/2; i++) ! 455: { ! 456: outw(_ideRegsAddrs.data, (atapiCmd[2*i] << 8) | atapiCmd[2*i+1]); ! 457: } ! 458: } ! 459: ! 460: /* ! 461: * Prints command and result in case of error. ! 462: */ ! 463: - (void)dumpStatus:(atapiIoReq_t *)atapiIoReq ! 464: { ! 465: int i; ! 466: ! 467: IOLog("%s: Failed command: drive: %d lun: %d len: %d read: %d\n", ! 468: [self name], ! 469: atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen, ! 470: atapiIoReq->read); ! 471: IOLog("%s: Failed command: ", [self name]); ! 472: for (i = 0; i < atapiIoReq->cmdLen; i++) ! 473: IOLog("%x ", atapiIoReq->atapiCmd[i]); ! 474: IOLog("\n"); ! 475: ! 476: [self getIdeRegisters:NULL Print:"dumpStatus"]; ! 477: } ! 478: ! 479: ! 480: #define C10OP_MODESELECT 0x55 /* OPT: set device parameters */ ! 481: #define C10OP_MODESENSE 0x5a /* OPT: get device parameters */ ! 482: ! 483: #define MAX_SENDPACKET_RETRIES 3 ! 484: ! 485: #define MAX_BUSY_WAIT (1000*100) ! 486: ! 487: - (sc_status_t) atapiExecuteCmd:(atapiIoReq_t *)atapiIoReq ! 488: buffer : (void *)buffer ! 489: client : (struct vm_map *)client ! 490: { ! 491: int i; ! 492: atapi_return_t rtn; ! 493: unsigned int offset; ! 494: unsigned char dh = ADDRESS_MODE_LBA; /* ALWAYS */ ! 495: unsigned char xferType; ! 496: BOOL dmaAllowed; ! 497: ! 498: /* ! 499: * Reject command if there are no ATAPI devices detected. ! 500: */ ! 501: if ((atapiIoReq->drive >= MAX_IDE_DRIVES) || (atapiIoReq->lun != 0)) ! 502: { ! 503: return SR_IOST_SELTO; ! 504: } ! 505: ! 506: if ([self isAtapiDevice:atapiIoReq->drive] == NO) ! 507: { ! 508: return SR_IOST_SELTO; ! 509: } ! 510: ! 511: [self clearInterrupts]; ! 512: ! 513: _driveNum = atapiIoReq->drive; ! 514: ! 515: dmaAllowed = [self atapiDmaAllowed: buffer]; ! 516: ! 517: if ( atapiIoReq->maxTransfer != 0 ) ! 518: { ! 519: [self setTransferRate: _driveNum UseDMA:dmaAllowed]; ! 520: } ! 521: ! 522: if ( _driveReset[_driveNum] == YES ) ! 523: { ! 524: [self setTransferMode: _driveNum]; ! 525: _driveReset[_driveNum] = NO; ! 526: } ! 527: ! 528: /* Now execute the SCSI command. */ ! 529: ! 530: for (i = 0; i < MAX_SENDPACKET_RETRIES; i++) ! 531: { ! 532: rtn = [self atapiWaitReadyForPacket]; ! 533: if (rtn != IDER_SUCCESS) ! 534: { ! 535: IOLog("%s: ATAPI Device %d: Not Ready For Packet command.\n", ! 536: [self name], _driveNum); ! 537: [self atapiSoftReset:_driveNum]; ! 538: continue; ! 539: } ! 540: ! 541: /* ! 542: * Select the drive first. ! 543: */ ! 544: dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0; ! 545: outb(_ideRegsAddrs.driveSelect, dh); ! 546: ! 547: /* ! 548: * Send our preferred data transfer size (2048 bytes). ! 549: */ ! 550: outb(_ideRegsAddrs.byteCountLow, 0x00); ! 551: outb(_ideRegsAddrs.byteCountHigh, 0x08); ! 552: ! 553: /* ! 554: * Set data transfer mode PIO = 0x00 / DMA = 0x01 ! 555: */ ! 556: xferType = (dmaAllowed == YES) ? 0x01 : 0x00; ! 557: outb(_ideRegsAddrs.features, xferType); ! 558: ! 559: /* ! 560: * First tell the ATAPI device that we are going to send it a packet ! 561: * command. If this command fails the ATAPI device needs to be reset. ! 562: */ ! 563: if ([self atapiPacketCommand] == IDER_SUCCESS) ! 564: { ! 565: break; ! 566: } ! 567: ! 568: IOLog("%s: ATAPI Device %d: Packet command failed. Retrying...\n", ! 569: [self name], _driveNum); ! 570: [self atapiSoftReset:_driveNum]; ! 571: } ! 572: ! 573: /* ! 574: * Are we hosed? ! 575: */ ! 576: if (i == MAX_SENDPACKET_RETRIES) ! 577: { ! 578: atapiIoReq->scsiStatus = STAT_CHECK; ! 579: IOLog("%s: ATAPI Device %d: FATAL: Packet command.\n", ! 580: [self name], _driveNum); ! 581: return SR_IOST_CMDREJ; ! 582: } ! 583: ! 584: /* ! 585: * Send the actual command to the device. ! 586: */ ! 587: [self sendAtapiCommand:atapiIoReq->atapiCmd cmdLen:atapiIoReq->cmdLen]; ! 588: ! 589: atapiIoReq->bytesTransferred = 0; ! 590: offset = 0; ! 591: ! 592: [self enableInterrupts]; ! 593: ! 594: if ( dmaAllowed == YES ) ! 595: { ! 596: rtn = [self atapiXferDMA:(atapiIoReq_t *)atapiIoReq buffer: (void *)buffer client: (struct vm_map *)client]; ! 597: } ! 598: else ! 599: { ! 600: rtn =[self atapiXferPIO:(atapiIoReq_t *)atapiIoReq buffer: (void *)buffer client: (struct vm_map *)client]; ! 601: } ! 602: ! 603: #if 0 ! 604: kprintf("Disk(ATAPI): Cmd = %02x Length = %08x Addr=%08x:%08x Status = %d\n\r", ! 605: atapiIoReq->atapiCmd[0], (int)atapiIoReq->maxTransfer, (int)buffer, (int)client, ! 606: rtn); ! 607: #endif ! 608: ! 609: return rtn; ! 610: } ! 611: ! 612: - (sc_status_t) atapiXferPIO:(atapiIoReq_t *)atapiIoReq ! 613: buffer : (void *)buffer ! 614: client : (struct vm_map *)client ! 615: { ! 616: int i; ! 617: atapi_return_t rtn; ! 618: unsigned char status; ! 619: unsigned int bytes; ! 620: unsigned int offset = 0; ! 621: unsigned char cmd = atapiIoReq->atapiCmd[0]; ! 622: ! 623: for (;;) ! 624: { ! 625: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status]; ! 626: ! 627: if (rtn != IDER_SUCCESS) ! 628: { ! 629: IOLog("%s: FATAL: ATAPI Device: %d Command %x failed.\n", ! 630: [self name], _driveNum, atapiIoReq->atapiCmd[0]); ! 631: [self getIdeRegisters:NULL Print:"ATAPI Command"]; ! 632: [self atapiSoftReset:_driveNum]; ! 633: atapiIoReq->scsiStatus = STAT_CHECK; ! 634: return SR_IOST_CHKSNV; ! 635: } ! 636: ! 637: for (i = 0; i < MAX_BUSY_WAIT; i++) ! 638: { ! 639: if (status & BUSY) ! 640: { ! 641: IODelay(10); ! 642: } ! 643: else ! 644: { ! 645: break; ! 646: } ! 647: status = inb(_ideRegsAddrs.status); ! 648: } ! 649: ! 650: /* ! 651: * If DRQ == 0 then host has terminated the command. ! 652: */ ! 653: if (!(status & DREQUEST)) ! 654: { ! 655: /* ! 656: * Check for command completion status. ! 657: */ ! 658: if (status & ERROR) ! 659: { ! 660: atapiIoReq->scsiStatus = STAT_CHECK; ! 661: return SR_IOST_CHKSNV; ! 662: } ! 663: else ! 664: { ! 665: atapiIoReq->scsiStatus = STAT_GOOD; ! 666: return SR_IOST_GOOD; ! 667: } ! 668: } ! 669: ! 670: /* ! 671: * Command is not completed. We need to transfer data as requested by ! 672: * the device. ! 673: */ ! 674: bytes = inb(_ideRegsAddrs.byteCountHigh) << 8 | ! 675: inb(_ideRegsAddrs.byteCountLow); ! 676: ! 677: /* ! 678: * If the device requests more data to be transferred than required ! 679: * by the command protocol, then we should transfer null data. ! 680: */ ! 681: ! 682: ! 683: if (atapiIoReq->bytesTransferred + bytes > atapiIoReq->maxTransfer) ! 684: { ! 685: IOLog("%s: ATAPI Device %d: " ! 686: "ERROR: Transfer limit (%x bytes) exceeded\n", ! 687: [self name], _driveNum, atapiIoReq->maxTransfer); ! 688: ! 689: IOLog("%s: Bytes already transfered: %x, next request: %x\n", ! 690: [self name], atapiIoReq->bytesTransferred, bytes); ! 691: ! 692: [self dumpStatus: atapiIoReq]; ! 693: ! 694: /* ! 695: * This thing is probably hosed but let's do the best we can. ! 696: */ ! 697: { ! 698: int diff = atapiIoReq->maxTransfer-atapiIoReq->bytesTransferred; ! 699: IOLog("%s: Transferring %x bytes instead of %x\n", ! 700: [self name], diff, bytes); ! 701: [self xferData:buffer+offset read:atapiIoReq->read ! 702: client:client length:diff]; ! 703: atapiIoReq->bytesTransferred += diff; ! 704: offset += diff; ! 705: [self atapiSoftReset:_driveNum]; // reset hardware as well ! 706: } ! 707: ! 708: atapiIoReq->scsiStatus = STAT_GOOD; ! 709: return SR_IOST_GOOD; ! 710: } ! 711: ! 712: /* ! 713: * Now transfer data from device to memory. ! 714: */ ! 715: [self xferData:buffer+offset read:atapiIoReq->read client:client ! 716: length:bytes]; ! 717: ! 718: atapiIoReq->bytesTransferred += bytes; ! 719: offset += bytes; ! 720: } ! 721: ! 722: /* ! 723: * Will never get here. ! 724: */ ! 725: atapiIoReq->scsiStatus = STAT_GOOD; ! 726: return SR_IOST_GOOD; ! 727: } ! 728: ! 729: ! 730: - (sc_status_t) atapiXferDMA:(atapiIoReq_t *)atapiIoReq ! 731: buffer : (void *)buffer ! 732: client : (struct vm_map *)client ! 733: { ! 734: int i; ! 735: atapi_return_t rtn; ! 736: unsigned char status; ! 737: unsigned char cmd = atapiIoReq->atapiCmd[0]; ! 738: unsigned long cfgReg; ! 739: ! 740: [self setupDMA:(vm_offset_t) buffer client:(vm_task_t) client length:(int)atapiIoReq->maxTransfer fRead:(BOOL)atapiIoReq->read]; ! 741: if ( _controllerType != kControllerTypeCmd646X ) ! 742: { ! 743: IODBDMAContinue( _ideDMARegs ); ! 744: } ! 745: else ! 746: { ! 747: [[self deviceDescription] configReadLong:0x70 value: &cfgReg]; ! 748: cfgReg &= ~0x08; ! 749: cfgReg |= 0x01 | ((atapiIoReq->read) ? 0x08 : 0x00); ! 750: [[self deviceDescription] configWriteLong:0x70 value: cfgReg]; ! 751: } ! 752: ! 753: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status]; ! 754: ! 755: if (rtn != IDER_SUCCESS) ! 756: { ! 757: IOLog("%s: FATAL: ATAPI Device: %d Command %x failed.\n", [self name], _driveNum, atapiIoReq->atapiCmd[0]); ! 758: [self getIdeRegisters:NULL Print:"ATAPI Command"]; ! 759: [self atapiSoftReset:_driveNum]; ! 760: atapiIoReq->scsiStatus = STAT_CHECK; ! 761: return SR_IOST_CHKSNV; ! 762: } ! 763: ! 764: for (i = 0; i < MAX_BUSY_WAIT; i++) ! 765: { ! 766: if (status & BUSY) ! 767: { ! 768: IODelay(10); ! 769: } ! 770: else ! 771: { ! 772: break; ! 773: } ! 774: status = inb(_ideRegsAddrs.status); ! 775: } ! 776: ! 777: if ( _controllerType != kControllerTypeCmd646X ) ! 778: { ! 779: atapiIoReq->bytesTransferred = [self stopDBDMA]; ! 780: } ! 781: else ! 782: { ! 783: [[self deviceDescription] configReadLong: 0x70 value: &cfgReg]; ! 784: cfgReg &= ~0x01; ! 785: [[self deviceDescription] configWriteLong:0x70 value: cfgReg]; ! 786: ! 787: atapiIoReq->bytesTransferred = atapiIoReq->maxTransfer; ! 788: } ! 789: ! 790: /* ! 791: * The DMA has handled all the data movement. ! 792: * Must have final command status at this point. ! 793: */ ! 794: if ( status & (ERROR) ) ! 795: { ! 796: atapiIoReq->scsiStatus = STAT_CHECK; ! 797: return SR_IOST_CHKSNV; ! 798: } ! 799: else ! 800: { ! 801: atapiIoReq->scsiStatus = STAT_GOOD; ! 802: return SR_IOST_GOOD; ! 803: } ! 804: } ! 805: ! 806: - (BOOL) atapiDmaAllowed: (void *)buffer ! 807: { ! 808: if ( _dmaSupported[_driveNum] == NO ) ! 809: { ! 810: return NO; ! 811: } ! 812: ! 813: if ( (_controllerType == kControllerTypeCmd646X) && ((u_int)buffer & 1) ) ! 814: { ! 815: return NO; ! 816: } ! 817: ! 818: return YES; ! 819: } ! 820: ! 821: ! 822: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.