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