|
|
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: * IdeCntCmds.m - Implementation of Commands category for IDE Controller ! 29: * device. ! 30: * ! 31: * It contains implementation of the ATA command set. ! 32: * ! 33: * ! 34: * HISTORY ! 35: * ! 36: * 23-Feb-1998 Joe Liu at Apple ! 37: * startUpAttachedDevices method is called immediately after acquiring ! 38: * the lock. ! 39: * ! 40: * 1-Feb-1998 Joe Liu at Apple ! 41: * ideSetDriveFeature method changed to support all EIDE transfer modes. ! 42: * Added support for Bus Master DMA. ! 43: * ideExecuteCmd now sets _driveNum within the retry loop. ! 44: * ! 45: * 1-Aug-1995 Rakesh Dubey at NeXT ! 46: * Reduced the timeout in IDE_IDENTIFY_DRIVE method. ! 47: * ! 48: * 17-July-1994 Rakesh Dubey at NeXT ! 49: * Created. ! 50: */ ! 51: ! 52: //#define DEBUG ! 53: ! 54: #import "IdeCnt.h" ! 55: #import "IdeCntInit.h" ! 56: #import "IdePIIX.h" ! 57: #import <kern/assert.h> ! 58: #import <driverkit/kernelDriver.h> ! 59: #import <driverkit/interruptMsg.h> ! 60: #import <mach/mach_interface.h> ! 61: #import <driverkit/IODevice.h> ! 62: #import <driverkit/align.h> ! 63: #import <machkit/NXLock.h> ! 64: #import <machdep/i386/io_inline.h> ! 65: #import "IdeDDM.h" ! 66: ! 67: /* ! 68: * All methods in this file implement one or more of the IDE commands. These ! 69: * commands get invoked by IdeDisk objects. ! 70: */ ! 71: ! 72: @implementation IdeController(Commands) ! 73: ! 74: /* ! 75: * Returns a struct containing IDE registers values for a given sector ! 76: * address and size. Depending upon whether the drive supports LBA or CHS we ! 77: * fill in different values. The calling routine must make sure that these ! 78: * values are not overwritten. The only thing that they need to fill in is ! 79: * the drive number. ! 80: */ ! 81: - (ideRegsVal_t)logToPhys:(unsigned)block numOfBlocks:(unsigned)nblk ! 82: { ! 83: ideRegsVal_t rv; ! 84: unsigned int cyl, nheads; ! 85: unsigned int track, spt; ! 86: ! 87: if (_drives[_driveNum].addressMode == ADDRESS_MODE_CHS) { ! 88: nheads = _drives[_driveNum].ideInfo.heads; ! 89: spt = _drives[_driveNum].ideInfo.sectors_per_trk; ! 90: ! 91: track = (block / spt); ! 92: cyl = track / nheads; ! 93: rv.sectNum = block % spt + 1; ! 94: ! 95: rv.drHead = track % nheads; ! 96: rv.cylLow = (cyl & 0xff); ! 97: rv.cylHigh = ((cyl & 0xff00) >> 8); ! 98: } else { ! 99: rv.sectNum = block & 0x0ff; ! 100: rv.cylLow = (block >> 8) & 0xff; ! 101: rv.cylHigh = (block >> 16) & 0xff; ! 102: rv.drHead = (block >> 24) & 0x0f; ! 103: } ! 104: ! 105: rv.sectCnt = (nblk == MAX_BLOCKS_PER_XFER) ? 0 : nblk; ! 106: ! 107: rv.drHead |= _drives[_driveNum].addressMode; ! 108: rv.drHead |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 109: ! 110: return rv; ! 111: } ! 112: ! 113: /* ! 114: * Commands to the IDE controller. ! 115: */ ! 116: ! 117: ! 118: - (ide_return_t)ideDiagnose:(unsigned *)diagError ! 119: { ! 120: ide_return_t rtn; ! 121: unsigned char status; ! 122: ! 123: rtn = [self waitForDeviceReady]; ! 124: if (rtn != IDER_SUCCESS) ! 125: return IDER_CMD_ERROR; ! 126: ! 127: [self enableInterrupts]; ! 128: outb(_ideRegsAddrs.command, IDE_DIAGNOSE); ! 129: ! 130: rtn = [self ideWaitForInterrupt:IDE_DIAGNOSE ideStatus:&status]; ! 131: if (rtn != IDER_SUCCESS) { ! 132: [self getIdeRegisters:NULL Print:"Diagnose"]; ! 133: return IDER_CMD_ERROR; ! 134: } ! 135: ! 136: rtn = [self waitForDeviceReady]; ! 137: if (rtn != IDER_SUCCESS) ! 138: return IDER_CMD_ERROR; ! 139: ! 140: *diagError = inb(_ideRegsAddrs.error); ! 141: ! 142: if (*diagError == 0x01) { ! 143: /* FIXME: do we need to soft reset ATAPI devices? */ ! 144: return IDER_SUCCESS; ! 145: } ! 146: ! 147: /* ! 148: * At least one of the drives is bad. ! 149: */ ! 150: if (*diagError & 0x080) { ! 151: IOLog("%s: Drive 1 has failed diagnostics.\n", [self name]); ! 152: _drives[1].ideInfo.type = 0; ! 153: ! 154: if ((*diagError & 0x07f) != 1) { ! 155: IOLog("%s: Drive 0 has failed diagnostics, error %d\n", ! 156: [self name], (*diagError & 0x07f)); ! 157: return IDER_CMD_ERROR; ! 158: } ! 159: } else { ! 160: _drives[0].ideInfo.type = 0; ! 161: IOLog("%s: Drive 0 has failed diagnostics, error %d\n", ! 162: [self name], (*diagError & 0x07f)); ! 163: } ! 164: ! 165: return IDER_CMD_ERROR; ! 166: } ! 167: ! 168: - (ide_return_t)ideSetParams:(unsigned)sectCnt numHeads:(unsigned)nHeads ! 169: ForDrive:(unsigned)drive ! 170: { ! 171: unsigned char dh = _drives[drive].addressMode; ! 172: ide_return_t rtn; ! 173: ! 174: rtn = [self waitForDeviceReady]; ! 175: if (rtn != IDER_SUCCESS) ! 176: return rtn; ! 177: ! 178: dh |= ((drive ? SEL_DRIVE1 : SEL_DRIVE0) | ((nHeads - 1) & 0x0f)); ! 179: outb(_ideRegsAddrs.drHead, dh); ! 180: outb(_ideRegsAddrs.sectCnt, (sectCnt & 0xff)); ! 181: ! 182: [self enableInterrupts]; ! 183: outb(_ideRegsAddrs.command, IDE_SET_PARAMS); ! 184: ! 185: rtn = [self ideWaitForInterrupt:IDE_SET_PARAMS ideStatus:NULL]; ! 186: if (rtn != IDER_SUCCESS) { ! 187: [self getIdeRegisters:NULL Print:"SetParams"]; ! 188: return rtn; ! 189: } ! 190: ! 191: return rtn; ! 192: } ! 193: ! 194: - (ide_return_t)ideSetDriveFeature:(unsigned char)feature ! 195: value:(unsigned char)val ! 196: transferType:(ideTransferType_t)type ! 197: { ! 198: unsigned char dh = _drives[_driveNum].addressMode; ! 199: unsigned char status; ! 200: ide_return_t rtn; ! 201: // unsigned char tmp; ! 202: ! 203: #ifdef DEBUG ! 204: IOLog("Setting drive feature %x to %x\n", feature, val); ! 205: #endif DEBUG ! 206: ! 207: /* ! 208: * We are not going to do anything if EIDE support is disabled. ! 209: * ! 210: * Currently, this is useful only for setting the transfer mode. ! 211: */ ! 212: if ((_EIDESupport == NO) || (feature != FEATURE_SET_TRANSFER_MODE) || ! 213: (val == ATA_MODE_NONE)) ! 214: return IDER_SUCCESS; ! 215: ! 216: val = ata_mode_to_num(val); ! 217: // IOLog("Mode num: %d\n", val); ! 218: ! 219: rtn = [self waitForDeviceReady]; ! 220: if (rtn != IDER_SUCCESS) ! 221: return rtn; ! 222: ! 223: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 224: outb(_ideRegsAddrs.drHead, dh); ! 225: ! 226: val &= 0x07; ! 227: switch (type) { ! 228: case IDE_TRANSFER_PIO: ! 229: val |= (1 << 3); ! 230: break; ! 231: case IDE_TRANSFER_SW_DMA: ! 232: val |= (1 << 4); ! 233: break; ! 234: case IDE_TRANSFER_MW_DMA: ! 235: val |= (1 << 5); ! 236: break; ! 237: case IDE_TRANSFER_ULTRA_DMA: ! 238: val |= (1 << 6); ! 239: break; ! 240: default: ! 241: val = 0; ! 242: } ! 243: outb(_ideRegsAddrs.sectCnt, val); ! 244: outb(_ideRegsAddrs.features, feature); ! 245: ! 246: [self enableInterrupts]; ! 247: outb(_ideRegsAddrs.command, IDE_SET_FEATURES); ! 248: ! 249: rtn = [self ideWaitForInterrupt:IDE_SET_FEATURES ideStatus:&status]; ! 250: if (rtn != IDER_SUCCESS) { ! 251: [self getIdeRegisters:NULL Print:"SetFeatures"]; ! 252: return rtn; ! 253: } ! 254: ! 255: if (status & ERROR) ! 256: return IDER_ERROR; ! 257: ! 258: return rtn; ! 259: } ! 260: ! 261: - (ide_return_t)ideRestore:(ideRegsVal_t *)ideRegs ! 262: { ! 263: ide_return_t rtn; ! 264: unsigned char status; ! 265: unsigned char dh = _drives[_driveNum].addressMode; ! 266: ! 267: rtn = [self waitForDeviceReady]; ! 268: if (rtn != IDER_SUCCESS) { ! 269: return rtn; ! 270: } ! 271: ! 272: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 273: outb(_ideRegsAddrs.drHead, dh); ! 274: ! 275: [self enableInterrupts]; ! 276: outb(_ideRegsAddrs.command, IDE_RESTORE); ! 277: ! 278: rtn = [self ideWaitForInterrupt:IDE_RESTORE ideStatus: &status]; ! 279: if (rtn != IDER_SUCCESS) { ! 280: [self getIdeRegisters:NULL Print:"Restore"]; ! 281: return rtn; ! 282: } ! 283: ! 284: rtn = [self waitForDeviceReady]; ! 285: if (rtn == IDER_SUCCESS) { ! 286: if (status & ERROR) { ! 287: [self getIdeRegisters:ideRegs Print:"Restore"]; ! 288: rtn = IDER_CMD_ERROR; ! 289: } ! 290: } ! 291: ! 292: return (rtn); ! 293: } ! 294: ! 295: - (ide_return_t)ideReadGetInfoCommon:(ideRegsVal_t *)ideRegs ! 296: client:(struct vm_map *)client ! 297: addr:(caddr_t)xferAddr ! 298: command:(unsigned int)cmd ! 299: { ! 300: ide_return_t rtn; ! 301: unsigned int sec_cnt = ideRegs->sectCnt; ! 302: int i; ! 303: unsigned char *taddr; ! 304: unsigned char status; ! 305: unsigned char dh = _drives[_driveNum].addressMode; ! 306: ! 307: if (sec_cnt == 0) ! 308: sec_cnt = MAX_BLOCKS_PER_XFER; ! 309: ! 310: taddr = xferAddr; ! 311: ! 312: /* ! 313: * We have to define this for the IDE_IDENTIFY_DRIVE command. ! 314: */ ! 315: if (cmd == IDE_IDENTIFY_DRIVE) { ! 316: ideRegs->sectCnt = 1; ! 317: sec_cnt = 1; ! 318: } ! 319: ! 320: /* ! 321: * Select the drive first. This routine is invoked by the initialization ! 322: * code as well (-resetAndInit) so it is necessary to do this here. ! 323: */ ! 324: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 325: outb(_ideRegsAddrs.drHead, dh); ! 326: ! 327: ! 328: rtn = [self waitForDeviceReady]; ! 329: if (rtn != IDER_SUCCESS) { ! 330: if (_ide_debug) { ! 331: IOLog("ideReadGetInfoCommon: waitForDeviceReady\n"); ! 332: [self getIdeRegisters:ideRegs Print:NULL]; ! 333: } ! 334: return (rtn); ! 335: } ! 336: ! 337: if (cmd == IDE_READ) { ! 338: outb(_ideRegsAddrs.drHead, ideRegs->drHead); ! 339: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum); ! 340: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt); ! 341: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow); ! 342: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh); ! 343: } else { ! 344: /* probably unnecessary */ ! 345: outb(_ideRegsAddrs.drHead, dh); ! 346: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt); ! 347: } ! 348: ! 349: [self enableInterrupts]; ! 350: outb(_ideRegsAddrs.command, cmd); ! 351: ! 352: for (i = 0; i < sec_cnt; i++) { ! 353: ! 354: rtn = [self ideWaitForInterrupt:cmd ideStatus:&status]; ! 355: if (rtn != IDER_SUCCESS) { ! 356: if (_ide_debug) { ! 357: IOLog("ideReadGetInfoCommon: ideWaitForInterrupt\n"); ! 358: [self getIdeRegisters:ideRegs Print:NULL]; ! 359: } ! 360: return rtn; ! 361: } else { ! 362: /* ! 363: if (status & ERROR_CORRECTED) { ! 364: IOLog("%s: Corrected error during read.\n", [self name]); ! 365: } ! 366: */ ! 367: } ! 368: ! 369: /* ! 370: * Same as waitForDataReady but with a quick timeout. ! 371: */ ! 372: rtn = [self ataIdeReadGetInfoCommonWaitForDataReady]; ! 373: if (rtn != IDER_SUCCESS) { ! 374: if (_ide_debug) { ! 375: IOLog("ideReadGetInfoCommon: " ! 376: "ataIdeReadGetInfoCommonWaitForDataReady\n"); ! 377: [self getIdeRegisters:ideRegs Print:NULL]; ! 378: } ! 379: return (rtn); ! 380: } ! 381: ! 382: [self xferData:taddr read:YES client:client length:IDE_SECTOR_SIZE]; ! 383: taddr += IDE_SECTOR_SIZE; ! 384: } ! 385: ! 386: return rtn; ! 387: } ! 388: ! 389: - (ide_return_t)ideWrite:(ideRegsVal_t *)ideRegs ! 390: client:(struct vm_map *)client ! 391: addr:(caddr_t)xferAddr ! 392: { ! 393: ide_return_t rtn; ! 394: unsigned int sec_cnt = ideRegs->sectCnt; ! 395: int i; ! 396: unsigned char *taddr; ! 397: unsigned char status; ! 398: ! 399: if (sec_cnt == 0) ! 400: sec_cnt = MAX_BLOCKS_PER_XFER; ! 401: ! 402: taddr = xferAddr; ! 403: ! 404: rtn = [self waitForDeviceReady]; ! 405: if (rtn != IDER_SUCCESS) { ! 406: return (rtn); ! 407: } ! 408: ! 409: outb(_ideRegsAddrs.drHead, ideRegs->drHead); ! 410: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum); ! 411: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt); ! 412: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow); ! 413: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh); ! 414: ! 415: [self enableInterrupts]; ! 416: outb(_ideRegsAddrs.command, IDE_WRITE); ! 417: ! 418: for (i = 0; i < sec_cnt; i++) { ! 419: ! 420: rtn = [self waitForDataReady]; ! 421: if (rtn != IDER_SUCCESS) { ! 422: return (rtn); ! 423: } ! 424: ! 425: [self xferData:taddr read:NO client:client length:IDE_SECTOR_SIZE]; ! 426: taddr += IDE_SECTOR_SIZE; ! 427: ! 428: rtn = [self ideWaitForInterrupt:IDE_WRITE ideStatus:&status]; ! 429: ! 430: if (rtn != IDER_SUCCESS) { ! 431: [self getIdeRegisters:ideRegs Print:"Write"]; ! 432: return (rtn); ! 433: } else { ! 434: /* ! 435: if (status & ERROR_CORRECTED) { ! 436: IOLog("%s: Corrected error during write.\n", [self name]); ! 437: } ! 438: */ ! 439: } ! 440: } ! 441: ! 442: return (rtn); ! 443: } ! 444: ! 445: - (ide_return_t)ideReadVerifySeekCommon:(ideRegsVal_t *)ideRegs ! 446: command:(unsigned int)cmd ! 447: { ! 448: ide_return_t rtn; ! 449: unsigned char status; ! 450: ! 451: rtn = [self waitForDeviceReady]; ! 452: if (rtn != IDER_SUCCESS) { ! 453: return (rtn); ! 454: } ! 455: ! 456: outb(_ideRegsAddrs.drHead, ideRegs->drHead); ! 457: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum); ! 458: if (cmd == IDE_READ_VERIFY) ! 459: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt); ! 460: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow); ! 461: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh); ! 462: ! 463: [self enableInterrupts]; ! 464: outb(_ideRegsAddrs.command, cmd); ! 465: ! 466: rtn = [self ideWaitForInterrupt:cmd ideStatus: &status]; ! 467: if (rtn != IDER_SUCCESS) { ! 468: [self getIdeRegisters:NULL Print:"ReadVerify/Seek"]; ! 469: return (rtn); ! 470: } ! 471: ! 472: if (status & (ERROR | WRITE_FAULT)) { ! 473: rtn = IDER_CMD_ERROR; ! 474: } else { ! 475: if ((cmd == IDE_SEEK) && (!(status & SEEK_COMPLETE))) ! 476: rtn = IDER_CMD_ERROR; ! 477: } ! 478: ! 479: return (rtn); ! 480: } ! 481: ! 482: - (ide_return_t)ideSetMultiSectorMode:(ideRegsVal_t *)ideRegs ! 483: numSectors:(unsigned char)nSectors ! 484: { ! 485: ide_return_t rtn; ! 486: unsigned char status; ! 487: unsigned char dh = _drives[_driveNum].addressMode; ! 488: ! 489: rtn = [self waitForDeviceReady]; ! 490: if (rtn != IDER_SUCCESS) { ! 491: return (rtn); ! 492: } ! 493: ! 494: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 495: outb(_ideRegsAddrs.drHead, dh); ! 496: outb(_ideRegsAddrs.sectCnt, nSectors); ! 497: ! 498: [self enableInterrupts]; ! 499: outb(_ideRegsAddrs.command, IDE_SET_MULTIPLE); ! 500: ! 501: rtn = [self ideWaitForInterrupt:IDE_SET_MULTIPLE ideStatus:&status]; ! 502: if (rtn != IDER_SUCCESS) { ! 503: return (rtn); ! 504: } ! 505: ! 506: rtn = [self waitForDeviceReady]; ! 507: if (rtn == IDER_SUCCESS) { ! 508: if (status & ERROR) { ! 509: rtn = IDER_CMD_ERROR; ! 510: [self getIdeRegisters:ideRegs Print:NULL]; ! 511: } else ! 512: rtn = IDER_SUCCESS; ! 513: } ! 514: ! 515: return (rtn); ! 516: } ! 517: ! 518: /* ! 519: * Note: Never read the status register at the end of data transfer, you may ! 520: * clobber the next interrupt from the drive. If it is necessary to get ! 521: * status use the alternate status register. ! 522: */ ! 523: - (ide_return_t)ideReadMultiple:(ideRegsVal_t *)ideRegs ! 524: client:(struct vm_map *)client ! 525: addr:(caddr_t)xferAddr ! 526: { ! 527: ide_return_t rtn; ! 528: unsigned char status; ! 529: unsigned sec_cnt = ideRegs->sectCnt; ! 530: unsigned int nSectors; ! 531: unsigned char *taddr; ! 532: unsigned int length; ! 533: ! 534: if (sec_cnt == 0) ! 535: sec_cnt = MAX_BLOCKS_PER_XFER; ! 536: ! 537: taddr = xferAddr; ! 538: ! 539: rtn = [self waitForDeviceReady]; ! 540: if (rtn != IDER_SUCCESS) { ! 541: return (rtn); ! 542: } ! 543: ! 544: outb(_ideRegsAddrs.drHead, ideRegs->drHead); ! 545: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum); ! 546: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt); ! 547: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow); ! 548: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh); ! 549: ! 550: [self enableInterrupts]; ! 551: outb(_ideRegsAddrs.command, IDE_READ_MULTIPLE); ! 552: ! 553: ddm_ide_cmd("ideReadMultiple: sec_cnt %d sectors\n", sec_cnt, 2,3,4,5); ! 554: ! 555: while (sec_cnt > 0) { ! 556: ! 557: ddm_ide_cmd("ideReadMultiple: waiting for interrupt\n",1,2,3,4,5); ! 558: rtn = [self ideWaitForInterrupt:IDE_READ_MULTIPLE ! 559: ideStatus: &status]; ! 560: ddm_ide_cmd("ideReadMultiple: received interrupt\n",1,2,3,4,5); ! 561: ! 562: if (rtn != IDER_SUCCESS) { ! 563: [self getIdeRegisters:ideRegs Print:"Read Multiple"]; ! 564: return (rtn); ! 565: } ! 566: ! 567: #if 1 ! 568: rtn = [self waitForDataReady]; ! 569: if (rtn != IDER_SUCCESS) { ! 570: return (rtn); ! 571: } ! 572: #endif 1 ! 573: ! 574: if (status & (ERROR | WRITE_FAULT)) { ! 575: [self getIdeRegisters:ideRegs Print:"Read Multiple"]; ! 576: return IDER_CMD_ERROR; ! 577: } ! 578: ! 579: /* ! 580: * Any drive formatted with 63 sector/track (which most over 400 MB ! 581: * are) reporting this status (ERROR_CORRECTED) will cause an ! 582: * fallacious error (possibly uncorrectable) due to a long-standing ! 583: * bug in DOS. This status bit should be made vendor specific, like ! 584: * IDX. It has outlived its usefulness. ! 585: * -- [email protected] ! 586: */ ! 587: ! 588: /* ! 589: if (status & ERROR_CORRECTED) { ! 590: IOLog("%s: Corrected error during read.\n", [self name]); ! 591: } ! 592: */ ! 593: ! 594: /* ! 595: * All is well. Read in the data. ! 596: */ ! 597: if (sec_cnt > _drives[_driveNum].multiSector) ! 598: nSectors = _drives[_driveNum].multiSector; ! 599: else ! 600: nSectors = sec_cnt; ! 601: ! 602: sec_cnt -= nSectors; ! 603: ! 604: ddm_ide_cmd("ideReadMultiple: starting data transfer\n",1,2,3,4,5); ! 605: ! 606: while (nSectors) { ! 607: if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE) { ! 608: length = PAGE_SIZE; ! 609: nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE); ! 610: } else { ! 611: length = nSectors * IDE_SECTOR_SIZE; ! 612: nSectors = 0; ! 613: } ! 614: ! 615: [self xferData:taddr read:YES client:client length:length]; ! 616: taddr += length; ! 617: } ! 618: ! 619: ddm_ide_cmd("ideReadMultiple: data transfer done\n",1,2,3,4,5); ! 620: } ! 621: ! 622: ddm_ide_cmd("ideReadMultiple: completed\n",1,2,3,4,5); ! 623: ! 624: return (rtn); ! 625: } ! 626: ! 627: - (ide_return_t)ideWriteMultiple:(ideRegsVal_t *)ideRegs ! 628: client:(struct vm_map *)client ! 629: addr:(caddr_t)xferAddr ! 630: { ! 631: ide_return_t rtn; ! 632: unsigned char status; ! 633: unsigned sec_cnt = ideRegs->sectCnt; ! 634: unsigned int nSectors; ! 635: unsigned char *taddr; ! 636: unsigned int length; ! 637: ! 638: if (sec_cnt == 0) ! 639: sec_cnt = MAX_BLOCKS_PER_XFER; ! 640: ! 641: taddr = xferAddr; ! 642: ! 643: rtn = [self waitForDeviceReady]; ! 644: if (rtn != IDER_SUCCESS) { ! 645: return (rtn); ! 646: } ! 647: ! 648: outb(_ideRegsAddrs.drHead, ideRegs->drHead); ! 649: outb(_ideRegsAddrs.sectNum, ideRegs->sectNum); ! 650: outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt); ! 651: outb(_ideRegsAddrs.cylLow, ideRegs->cylLow); ! 652: outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh); ! 653: ! 654: [self enableInterrupts]; ! 655: outb(_ideRegsAddrs.command, IDE_WRITE_MULTIPLE); ! 656: ! 657: ddm_ide_cmd("ideWriteMultiple: sec_cnt %d sectors\n", sec_cnt, 2,3,4,5); ! 658: ! 659: while (sec_cnt > 0) { ! 660: ! 661: rtn = [self waitForDataReady]; ! 662: if (rtn != IDER_SUCCESS) { ! 663: return (rtn); ! 664: } ! 665: ! 666: if (sec_cnt > _drives[_driveNum].multiSector) ! 667: nSectors = _drives[_driveNum].multiSector; ! 668: else ! 669: nSectors = sec_cnt; ! 670: ! 671: sec_cnt -= nSectors; ! 672: ! 673: ddm_ide_cmd("ideWriteMultiple: starting data transfer\n",1,2,3,4,5); ! 674: ! 675: while (nSectors) { ! 676: if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE) { ! 677: length = PAGE_SIZE; ! 678: nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE); ! 679: } else { ! 680: length = nSectors * IDE_SECTOR_SIZE; ! 681: nSectors = 0; ! 682: } ! 683: ! 684: [self xferData:taddr read:NO client:client length:length]; ! 685: taddr += length; ! 686: } ! 687: ddm_ide_cmd("ideWriteMultiple: data transfer done\n",1,2,3,4,5); ! 688: ! 689: ddm_ide_cmd("ideWriteMultiple: waiting for interrupt\n",1,2,3,4,5); ! 690: rtn = [self ideWaitForInterrupt:IDE_WRITE_MULTIPLE ! 691: ideStatus:&status]; ! 692: ddm_ide_cmd("ideWriteMultiple: received interrupt\n",1,2,3,4,5); ! 693: ! 694: if (rtn != IDER_SUCCESS) { ! 695: [self getIdeRegisters:ideRegs Print:"Write Multiple"]; ! 696: return (rtn); ! 697: } ! 698: ! 699: if (status & (ERROR | WRITE_FAULT)) { ! 700: [self getIdeRegisters:ideRegs Print:"Write Multiple"]; ! 701: return IDER_CMD_ERROR; ! 702: } ! 703: ! 704: /* ! 705: if (status & ERROR_CORRECTED) { ! 706: IOLog("%s: Corrected error during write.\n", [self name]); ! 707: } ! 708: */ ! 709: ! 710: } ! 711: ! 712: ddm_ide_cmd("ideWriteMultiple: completed\n",1,2,3,4,5); ! 713: ! 714: return (rtn); ! 715: } ! 716: ! 717: /* ! 718: * Method: performDMATestOnDrive:(unsigned char)drive ! 719: * ! 720: * Purpose: ! 721: * Read a few sectors and make sure DMA really "seems" to works. ! 722: * ! 723: * NOTE: _driveNum must be set prior to calling this method. ! 724: */ ! 725: - (ide_return_t)performDMATest ! 726: { ! 727: ideIoReq_t ideIoReq; ! 728: ide_return_t status; ! 729: vm_offset_t tempDmaBuf; ! 730: vm_offset_t alignBuf; ! 731: unsigned int currentTimeout; ! 732: unsigned char dh; ! 733: ! 734: /* ! 735: * The hardware claims to supports DMA. Verify by reading a ! 736: * few sectors. Allocate memory for dummy buffer. ! 737: */ ! 738: tempDmaBuf = (vm_offset_t)IOMalloc(PAGE_SIZE); ! 739: if (tempDmaBuf == NULL) { ! 740: IOLog("%s: memory allocation failed\n", [self name]); ! 741: return IDER_REJECT; ! 742: } ! 743: ! 744: /* ! 745: * Advance the pointer and make the buffer 4 byte aligned. ! 746: */ ! 747: alignBuf = (tempDmaBuf + 3) & ~3; ! 748: ! 749: bzero((unsigned char *)&ideIoReq, sizeof(ideIoReq_t)); ! 750: ideIoReq.cmd = IDE_READ_DMA; ! 751: ideIoReq.block = 0; ! 752: ideIoReq.blkcnt = (PAGE_SIZE - 4)/IDE_SECTOR_SIZE; ! 753: ideIoReq.addr = (caddr_t)alignBuf; ! 754: ideIoReq.timeout = 5000; ! 755: ideIoReq.map = (struct vm_map *)IOVmTaskSelf(); ! 756: ! 757: /* ! 758: * Select the drive first. ! 759: */ ! 760: if ([self waitForDeviceIdle] != IDER_SUCCESS) { ! 761: IOLog("%s: Drive %d DMA test FAILED\n", [self name], _driveNum); ! 762: return IDER_TIMEOUT; ! 763: } ! 764: dh = _drives[_driveNum].addressMode; ! 765: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 766: outb(_ideRegsAddrs.drHead, dh); ! 767: ! 768: /* ! 769: * Wait 400ns before reading the status register and make sure the ! 770: * currently selected drive is ready to accept a command. ! 771: */ ! 772: IODelay(1); ! 773: if ([self waitForDeviceIdle] != IDER_SUCCESS) { ! 774: IOLog("%s: Drive %d DMA test FAILED\n", [self name], _driveNum); ! 775: return IDER_TIMEOUT; ! 776: } ! 777: ! 778: /* ! 779: * Clear any unwanted interrupts which may have accumulated. ! 780: */ ! 781: [self enableInterrupts]; ! 782: IOSleep(100); ! 783: ! 784: /* ! 785: * Set a smaller (3 sec) timeout for this test. ! 786: */ ! 787: currentTimeout = [self interruptTimeOut]; ! 788: [self setInterruptTimeOut:3000]; ! 789: [self clearInterrupts]; ! 790: ! 791: /* ! 792: * Perform test. ! 793: */ ! 794: if (([self performDMA:(ideIoReq_t *)&ideIoReq]) == IDER_SUCCESS) { ! 795: status = IDER_SUCCESS; ! 796: // IOLog("%s: Drive %d: DMA test PASSED\n", [self name], _driveNum); ! 797: } ! 798: else { ! 799: status = IDER_REJECT; ! 800: IOLog("%s: Drive %d: DMA test FAILED\n", [self name], _driveNum); ! 801: } ! 802: ! 803: /* ! 804: * Revert the original timeout value and free allocated memory. ! 805: */ ! 806: [self setInterruptTimeOut:currentTimeout]; ! 807: IOFree((void *)tempDmaBuf, PAGE_SIZE); ! 808: return status; ! 809: } ! 810: ! 811: /* ! 812: * All I/O to to controller object is done through this method. We first ! 813: * acquire a lock before executing any IDE commands since the IDE controller ! 814: * can do only one thing at a time (both drivers can not be active ! 815: * simultaneously except for reset and disgnostics). ! 816: * ! 817: * If it necessary to call any of the IDE command methods (which are invoked by ! 818: * the switch() below, like ideReadGetInfoCommon:client:addr:command) it is ! 819: * necessary to acquire the lock. The IDE command methods should not be ! 820: * invoked directly by the Disk object. ! 821: * ! 822: * This method will in turn call one of several methods which deal with ! 823: * hardware. ! 824: */ ! 825: ! 826: static unsigned char unaligned_warnings; ! 827: #define UNALIGNED_WARNINGS_MAX 20 ! 828: ! 829: #define MAX_COMMAND_RETRY 3 ! 830: ! 831: - (IOReturn) ideExecuteCmd:(ideIoReq_t *)ideIoReq ToDrive:(unsigned char)drive ! 832: { ! 833: int retry; ! 834: ideRegsVal_t irv; ! 835: unsigned block, cnt; ! 836: unsigned error; ! 837: unsigned int maxSectors; ! 838: unsigned char dh; ! 839: ! 840: ddm_ide_cmd("ideExecuteCmd: executing %x\n", ideIoReq->cmd,2,3,4,5); ! 841: ! 842: /* ! 843: * If the controller wishes to put the drive to sleep, it sets this flag ! 844: * to YES and tries to acquire the lock. This method should not try to ! 845: * get the lock (and execute any more commands) if the flag is set. This ! 846: * is needed in order to enter sleep mode as soon as the current command ! 847: * is finished. If we do not do this there is contention for lock between ! 848: * the controller (which wants to put the drive to sleep) and this method ! 849: * (which wants to service more requests). Note that this does not do ! 850: * away with the need for a lock, it only gives the controller a little ! 851: * head-start. ! 852: */ ! 853: ! 854: while (_driveSleepRequest) { ! 855: IOSleep(100); ! 856: } ! 857: ! 858: ddm_ide_lock("ideExecuteCmd: acquiring lock\n",1,2,3,4,5); ! 859: [self ideCntrlrLock]; ! 860: ddm_ide_lock("ideExecuteCmd: acquired lock\n",1,2,3,4,5); ! 861: ! 862: /* ! 863: * Check if we need to do a media access to get the drive respinning ! 864: * after a suspend operation. ! 865: */ ! 866: if ([self drivePowerState] != IDE_PM_ACTIVE) { ! 867: [self startUpAttachedDevices]; ! 868: } ! 869: ! 870: _driveNum = drive; /* used by IDE command methods. */ ! 871: ! 872: for (retry = 0; retry < MAX_COMMAND_RETRY; retry++) { ! 873: ! 874: /* ! 875: * Select the drive first. We don't know the head number at this time so ! 876: * this register will be rewritten by the specific routine later. ! 877: * ! 878: * The Device Selection protocol is defined as follows: ! 879: * HOST: Read Status or AltStatus register ! 880: * HOST: Continue reading until BSY = 0, and DRQ = 0 ! 881: * HOST: Write Device/Head register with appropriate DEV bit value ! 882: * HOST: Wait 400ns ! 883: * HOST: Read Status or AltStatus register ! 884: * HOST: Continue reading until BSY = 0, and DRQ = 0 ! 885: * ! 886: */ ! 887: // [self waitForDeviceIdle]; // Devices should be already in an idle state ! 888: dh = _drives[_driveNum].addressMode; ! 889: dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0); ! 890: outb(_ideRegsAddrs.drHead, dh); ! 891: IODelay(1); ! 892: // [self waitForDeviceIdle]; // Each method below will do their own wait ! 893: ! 894: ideIoReq->status = IDER_CMD_ERROR; ! 895: ideIoReq->blocks_xfered = 0; ! 896: ! 897: [self clearInterrupts]; ! 898: ! 899: switch (ideIoReq->cmd) { ! 900: ! 901: case IDE_READ_DMA: ! 902: if (((vm_offset_t)ideIoReq->addr & 0x03) == 0) { ! 903: block = ideIoReq->block; ! 904: cnt = ideIoReq->blkcnt; ! 905: ddm_ide_log("IDE_READ_DMA: %d\n", cnt, 2, 3, 4, 5); ! 906: if (cnt > MAX_BLOCKS_PER_XFER) { ! 907: ideIoReq->status = IDER_REJECT; ! 908: break; ! 909: } ! 910: ! 911: ideIoReq->status = [self performDMA:ideIoReq]; ! 912: if (ideIoReq->status == IDER_SUCCESS) ! 913: ideIoReq->blocks_xfered = ideIoReq->blkcnt; ! 914: break; ! 915: } ! 916: ! 917: /* ! 918: * If we reached here, it means that the buffer is not 4-byte ! 919: * aligned. This should not happen. ! 920: */ ! 921: if (unaligned_warnings < UNALIGNED_WARNINGS_MAX) { ! 922: IOLog("%s: READ DMA: buffer not 4-byte aligned\n", [self name]); ! 923: unaligned_warnings++; ! 924: } ! 925: ! 926: case IDE_READ: ! 927: case IDE_READ_MULTIPLE: ! 928: ! 929: block = ideIoReq->block; ! 930: cnt = ideIoReq->blkcnt; ! 931: ddm_ide_log("IDE_READ: %d\n", cnt, 2, 3, 4, 5); ! 932: if (cnt > MAX_BLOCKS_PER_XFER) { ! 933: ideIoReq->status = IDER_REJECT; ! 934: break; ! 935: } ! 936: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt]; ! 937: if (ideIoReq->cmd == IDE_READ) ! 938: ideIoReq->status = ! 939: [self ideReadGetInfoCommon:&(ideIoReq->regValues) ! 940: client:(ideIoReq->map) ! 941: addr:(ideIoReq->addr) command:IDE_READ]; ! 942: else ! 943: ideIoReq->status = ! 944: [self ideReadMultiple:&(ideIoReq->regValues) ! 945: client:(ideIoReq->map) addr:(ideIoReq->addr)]; ! 946: ! 947: if (ideIoReq->status == IDER_SUCCESS) ! 948: ideIoReq->blocks_xfered = ideIoReq->blkcnt; ! 949: break; ! 950: ! 951: case IDE_WRITE_DMA: ! 952: if (((vm_offset_t)ideIoReq->addr & 0x03) == 0) { ! 953: block = ideIoReq->block; ! 954: cnt = ideIoReq->blkcnt; ! 955: ddm_ide_log("IDE_WRITE_DMA: %d\n", cnt, 2, 3, 4, 5); ! 956: if (cnt > MAX_BLOCKS_PER_XFER) { ! 957: ideIoReq->status = IDER_REJECT; ! 958: break; ! 959: } ! 960: ! 961: ideIoReq->status = [self performDMA:ideIoReq]; ! 962: if (ideIoReq->status == IDER_SUCCESS) ! 963: ideIoReq->blocks_xfered = ideIoReq->blkcnt; ! 964: break; ! 965: } ! 966: ! 967: /* ! 968: * If we reached here, it means that the buffer is not 4-byte ! 969: * aligned. This should not happen. ! 970: */ ! 971: if (unaligned_warnings < UNALIGNED_WARNINGS_MAX) { ! 972: IOLog("%s: WRITE DMA: buffer not 4-byte aligned\n", [self name]); ! 973: unaligned_warnings++; ! 974: } ! 975: ! 976: case IDE_WRITE: ! 977: case IDE_WRITE_MULTIPLE: ! 978: ! 979: block = ideIoReq->block; ! 980: cnt = ideIoReq->blkcnt; ! 981: ddm_ide_log("IDE_WRITE: %d\n", cnt, 2, 3, 4, 5); ! 982: if (cnt > MAX_BLOCKS_PER_XFER) { ! 983: ideIoReq->status = IDER_REJECT; ! 984: break; ! 985: } ! 986: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt]; ! 987: if (ideIoReq->cmd == IDE_WRITE) ! 988: ideIoReq->status = [self ideWrite:&(ideIoReq->regValues) ! 989: client:(ideIoReq->map) ! 990: addr:(ideIoReq->addr)]; ! 991: else ! 992: ideIoReq->status = ! 993: [self ideWriteMultiple:&(ideIoReq->regValues) ! 994: client:(ideIoReq->map) addr:(ideIoReq->addr)]; ! 995: ! 996: if (ideIoReq->status == IDER_SUCCESS) ! 997: ideIoReq->blocks_xfered = ideIoReq->blkcnt; ! 998: break; ! 999: ! 1000: case IDE_SEEK: ! 1001: block = ideIoReq->block; ! 1002: cnt = 1; ! 1003: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt]; ! 1004: ideIoReq->status = ! 1005: [self ideReadVerifySeekCommon:&(ideIoReq->regValues) ! 1006: command:IDE_SEEK]; ! 1007: break; ! 1008: ! 1009: case IDE_RESTORE: ! 1010: ideIoReq->status = [self ideRestore:&(ideIoReq->regValues)]; ! 1011: break; ! 1012: ! 1013: case IDE_READ_VERIFY: ! 1014: block = ideIoReq->block; ! 1015: cnt = ideIoReq->blkcnt; ! 1016: ddm_ide_log("IDE_READ_VERIFY: %d\n", cnt, 2, 3, 4, 5); ! 1017: if (cnt > MAX_BLOCKS_PER_XFER) { ! 1018: ideIoReq->status = IDER_REJECT; ! 1019: break; ! 1020: } ! 1021: ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt]; ! 1022: ideIoReq->status = ! 1023: [self ideReadVerifySeekCommon:&(ideIoReq->regValues) ! 1024: command:IDE_READ_VERIFY]; ! 1025: break; ! 1026: ! 1027: case IDE_DIAGNOSE: ! 1028: [self ideDiagnose:&error]; ! 1029: ideIoReq->diagResult = error; ! 1030: ideIoReq->status = IDER_SUCCESS; ! 1031: break; ! 1032: ! 1033: case IDE_SET_PARAMS: ! 1034: ideIoReq->status = ! 1035: [self ideSetParams:_drives[_driveNum].ideInfo.sectors_per_trk ! 1036: numHeads:_drives[_driveNum].ideInfo.heads ForDrive:_driveNum]; ! 1037: break; ! 1038: ! 1039: case IDE_IDENTIFY_DRIVE: ! 1040: ideIoReq->status = ! 1041: [self ideReadGetInfoCommon:&(ideIoReq->regValues) ! 1042: client :(ideIoReq->map) addr :(ideIoReq->addr) ! 1043: command:IDE_IDENTIFY_DRIVE]; ! 1044: ! 1045: if (ideIoReq->status == IDER_SUCCESS) ! 1046: ideIoReq->blocks_xfered = 1; ! 1047: break; ! 1048: ! 1049: case IDE_SET_MULTIPLE: ! 1050: maxSectors = (_drives[_driveNum].ideIdentifyInfo->multipleSectors) ! 1051: & IDE_MULTI_SECTOR_MASK; ! 1052: if (ideIoReq->maxSectorsPerIntr > maxSectors) { ! 1053: ideIoReq->status = IDER_REJECT; ! 1054: } else { ! 1055: ideIoReq->status = [self ideSetMultiSectorMode: ! 1056: &(ideIoReq->regValues) ! 1057: numSectors:ideIoReq->maxSectorsPerIntr]; ! 1058: if (ideIoReq->status == IDER_SUCCESS) ! 1059: _drives[_driveNum].multiSector = ideIoReq->maxSectorsPerIntr; ! 1060: else ! 1061: _drives[_driveNum].multiSector = 0; ! 1062: } ! 1063: break; ! 1064: ! 1065: default: ! 1066: ideIoReq->status = IDER_REJECT; ! 1067: ddm_ide_lock("ideExecuteCmd: releasing lock, bad cmd\n",1,2,3,4,5); ! 1068: [self ideCntrlrUnLock]; ! 1069: return (IDER_REJECT); ! 1070: } ! 1071: ! 1072: /* ! 1073: * Return if command has been executed successfully or summarily ! 1074: * rejected. ! 1075: */ ! 1076: if (ideIoReq->status == IDER_SUCCESS) { ! 1077: [self ideCntrlrUnLock]; ! 1078: ddm_ide_lock("ideExecuteCmd: releasing lock, success\n",1,2,3,4,5); ! 1079: return IDER_SUCCESS; ! 1080: } ! 1081: ! 1082: if (ideIoReq->status == IDER_REJECT) { ! 1083: [self ideCntrlrUnLock]; ! 1084: ddm_ide_lock("ideExecuteCmd: releasing lock, reject\n",1,2,3,4,5); ! 1085: return IDER_REJECT; ! 1086: } ! 1087: ! 1088: /* ! 1089: * The command failed to exceute properly but was accepted by the ! 1090: * drive. Reset the drives and try again. ! 1091: */ ! 1092: IOLog("%s: ATA command %x failed. Retrying...\n", [self name], ! 1093: ideIoReq->cmd); ! 1094: [self getIdeRegisters:NULL Print:"ATA Command"]; ! 1095: [self resetAndInit]; ! 1096: ! 1097: /* ! 1098: * resetAndInit will change the value of _driveNum. ! 1099: * Revert _driveNum to the original value before retrying the ! 1100: * command. ! 1101: */ ! 1102: _driveNum = drive; ! 1103: (void) [self ideRestore:&irv]; ! 1104: } ! 1105: ! 1106: /* ! 1107: * If we get here then this is a catastrophic failure. ! 1108: */ ! 1109: ddm_ide_lock("ideExecuteCmd: releasing lock, failed\n",1,2,3,4,5); ! 1110: [self ideCntrlrUnLock]; ! 1111: return ideIoReq->status; ! 1112: } ! 1113: ! 1114: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.