|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * ! 24: * IOATADevice.cpp ! 25: * ! 26: */ ! 27: ! 28: #include <IOKit/IOSyncer.h> ! 29: #include <IOKit/ata/IOATA.h> ! 30: #include <IOKit/ata/IOATAController.h> ! 31: #include "ATAPrivate.h" ! 32: ! 33: #undef super ! 34: #define super IOService ! 35: ! 36: OSDefineMetaClassAndStructors( IOATADevice, IOService ); ! 37: ! 38: extern EndianTable AppleIdentifyEndianTable[]; ! 39: ! 40: extern UInt32 AppleNumPIOModes; ! 41: extern ATAModeTable ApplePIOModes[]; ! 42: extern UInt32 AppleNumDMAModes; ! 43: extern ATAModeTable AppleDMAModes[]; ! 44: extern UInt32 AppleNumUltraModes; ! 45: extern ATAModeTable AppleUltraModes[]; ! 46: ! 47: /* ! 48: * ! 49: * ! 50: */ ! 51: bool IOATADevice::probeDevice() ! 52: { ! 53: OSDictionary *propTable = 0; ! 54: ! 55: if ( open( this ) != true ) ! 56: { ! 57: goto probeDevice_error; ! 58: } ! 59: ! 60: if ( doIdentify( (void **)&identifyData ) != ataReturnNoError ) ! 61: { ! 62: goto probeDevice_error; ! 63: } ! 64: ! 65: if ( deviceType == ataDeviceATA ) ! 66: { ! 67: doSpinUp(); ! 68: } ! 69: ! 70: else if ( deviceType == ataDeviceATAPI ) ! 71: { ! 72: atapiPktInt = ((identifyData->generalConfiguration & atapiPktProtocolIntDRQ) != 0); ! 73: ! 74: if ( doInquiry( (void **)&inquiryData ) != ataReturnNoError ) ! 75: { ! 76: goto probeDevice_error; ! 77: } ! 78: ! 79: reqSenseCmd = allocCommand(); ! 80: } ! 81: ! 82: if ( getATATimings() != true ) ! 83: { ! 84: goto probeDevice_error; ! 85: } ! 86: ! 87: propTable = createProperties(); ! 88: if ( !propTable ) ! 89: { ! 90: goto probeDevice_error; ! 91: } ! 92: ! 93: setPropertyTable( propTable ); ! 94: ! 95: propTable->release(); ! 96: ! 97: close( this ); ! 98: ! 99: return true; ! 100: ! 101: probeDevice_error: ; ! 102: close( this ); ! 103: return false; ! 104: } ! 105: ! 106: /* ! 107: * ! 108: * ! 109: * ! 110: */ ! 111: ATADeviceType IOATADevice::probeDeviceType() ! 112: { ! 113: ATATaskfile taskfile; ! 114: ATAResults results; ! 115: ! 116: bzero( (void *)&taskfile, sizeof(taskfile) ); ! 117: ! 118: taskfile.protocol = ataProtocolSetRegs; ! 119: taskfile.regmask = ATARegtoMask(ataRegDriveHead); ! 120: ! 121: taskfile.resultmask = ATARegtoMask(ataRegSectorCount) ! 122: | ATARegtoMask(ataRegSectorNumber) ! 123: | ATARegtoMask(ataRegCylinderLow) ! 124: | ATARegtoMask(ataRegCylinderHigh) ! 125: | ATARegtoMask(ataRegStatus); ! 126: ! 127: taskfile.ataRegs[ataRegDriveHead] = ataModeLBA | (getUnit() << 4); ! 128: ! 129: utilCmd->setTaskfile( &taskfile ); ! 130: utilCmd->execute(); ! 131: ! 132: if ( utilCmd->getResults( &results ) != ataReturnNoError ) ! 133: { ! 134: return (deviceType = ataDeviceNone); ! 135: } ! 136: ! 137: if ( results.ataRegs[ataRegSectorCount] == ataSignatureSectorCount ! 138: && results.ataRegs[ataRegSectorNumber] == ataSignatureSectorNumber ! 139: && results.ataRegs[ataRegCylinderLow] == ataSignatureCylinderLow ! 140: && results.ataRegs[ataRegCylinderHigh] == ataSignatureCylinderHigh ) ! 141: { ! 142: if ( !(results.ataRegs[ataRegStatus] & ataStatusBSY) ! 143: && (results.ataRegs[ataRegStatus] & ataStatusDRDY) ) ! 144: { ! 145: return (deviceType = ataDeviceATA); ! 146: } ! 147: } ! 148: ! 149: if ( results.ataRegs[ataRegCylinderLow] == atapiSignatureCylinderLow ! 150: && results.ataRegs[ataRegCylinderHigh] == atapiSignatureCylinderHigh ) ! 151: { ! 152: return (deviceType = ataDeviceATAPI); ! 153: } ! 154: ! 155: return (deviceType = ataDeviceNone); ! 156: } ! 157: ! 158: ! 159: /* ! 160: * ! 161: * ! 162: * ! 163: */ ! 164: ATAReturnCode IOATADevice::doSpinUp() ! 165: { ! 166: void *buffer = NULL; ! 167: ATAReturnCode rc; ! 168: ! 169: rc = doSectorCommand( ataCommandReadSector, 0, 1, &buffer ); ! 170: ! 171: if ( rc != ataReturnNoError ) ! 172: { ! 173: return rc; ! 174: } ! 175: ! 176: IOFree( buffer, 512 ); ! 177: ! 178: return rc ; ! 179: } ! 180: ! 181: /* ! 182: * ! 183: * ! 184: * ! 185: */ ! 186: ATAReturnCode IOATADevice::doIdentify( void **dataPtr ) ! 187: { ! 188: ATACommand ataCmd; ! 189: ATAReturnCode rc; ! 190: ! 191: ataCmd = (deviceType == ataDeviceATA) ? ataCommandIdentify : atapiCommandIdentify; ! 192: ! 193: rc = doSectorCommand( ataCmd, 0, 1, dataPtr ); ! 194: ! 195: if ( rc != ataReturnNoError ) ! 196: { ! 197: return rc; ! 198: } ! 199: ! 200: endianConvertData( *dataPtr, AppleIdentifyEndianTable ); ! 201: ! 202: return rc; ! 203: } ! 204: ! 205: ! 206: ! 207: /* ! 208: * ! 209: * ! 210: * ! 211: */ ! 212: ATAReturnCode IOATADevice::doSectorCommand( ATACommand ataCmd, UInt32 ataLBA, UInt32 ataCount, void **dataPtr ) ! 213: { ! 214: ATATaskfile taskfile; ! 215: ATAResults result; ! 216: IOMemoryDescriptor *desc; ! 217: UInt32 size; ! 218: void *data; ! 219: UInt32 i; ! 220: ATAReturnCode rc; ! 221: ! 222: *dataPtr = NULL; ! 223: ! 224: size = ataCount * 512; ! 225: ! 226: if ( !(data = (void *)IOMalloc(size)) ) ! 227: { ! 228: return ataReturnNoResource; ! 229: } ! 230: ! 231: bzero( &taskfile, sizeof(taskfile) ); ! 232: ! 233: desc = IOMemoryDescriptor::withAddress( data, size, kIODirectionIn ); ! 234: if ( desc == NULL ) ! 235: { ! 236: rc = ataReturnNoResource; ! 237: goto doSectorCommand_error; ! 238: } ! 239: ! 240: ! 241: taskfile.protocol = ataProtocolPIO; ! 242: taskfile.regmask = ATARegtoMask(ataRegDriveHead) ! 243: | ATARegtoMask(ataRegSectorCount) ! 244: | ATARegtoMask(ataRegSectorNumber) ! 245: | ATARegtoMask(ataRegCylinderLow) ! 246: | ATARegtoMask(ataRegCylinderHigh) ! 247: | ATARegtoMask(ataRegFeatures) ! 248: | ATARegtoMask(ataRegCommand); ! 249: ! 250: ! 251: taskfile.resultmask = ATARegtoMask(ataRegError) ! 252: | ATARegtoMask(ataRegStatus); ! 253: ! 254: taskfile.ataRegs[ataRegSectorCount] = ataCount; ! 255: taskfile.ataRegs[ataRegSectorNumber] = ataLBA & 0xff; ! 256: taskfile.ataRegs[ataRegCylinderLow] = (ataLBA >> 8) & 0xff; ! 257: taskfile.ataRegs[ataRegCylinderHigh] = (ataLBA >> 16) & 0xff; ! 258: taskfile.ataRegs[ataRegDriveHead] = (ataLBA >> 24) & 0x0f; ! 259: ! 260: taskfile.ataRegs[ataRegDriveHead] |= ataModeLBA | (getUnit() << 4); ! 261: taskfile.ataRegs[ataRegCommand] = ataCmd; ! 262: ! 263: for ( i = 0; i < 2; i++ ) ! 264: { ! 265: utilCmd->setTimeout( 25000 ); ! 266: utilCmd->setTaskfile( &taskfile ); ! 267: utilCmd->setPointers( desc, size, false ); ! 268: submitCommand( utilCmd ); ! 269: ! 270: rc = utilCmd->getResults( &result ); ! 271: if ( rc == ataReturnNoError ) ! 272: { ! 273: break; ! 274: } ! 275: } ! 276: ! 277: ! 278: doSectorCommand_error: ; ! 279: ! 280: desc->release(); ! 281: ! 282: if ( rc != ataReturnNoError ) ! 283: { ! 284: IOFree( data, size ); ! 285: return result.returnCode; ! 286: } ! 287: ! 288: *dataPtr = data; ! 289: ! 290: return ataReturnNoError; ! 291: } ! 292: ! 293: ! 294: /* ! 295: * ! 296: * ! 297: */ ! 298: ATAReturnCode IOATADevice::doInquiry( void **dataPtr ) ! 299: { ! 300: ATATaskfile taskfile; ! 301: ATAPICmd atapiCmd; ! 302: ATAResults result; ! 303: void *data; ! 304: IOMemoryDescriptor *desc; ! 305: UInt32 size = sizeof(ATAPIInquiry); ! 306: ! 307: *dataPtr = 0; ! 308: ! 309: if ( !(data = (void *)IOMalloc(size)) ) ! 310: { ! 311: return ataReturnNoResource;; ! 312: } ! 313: ! 314: bzero( &taskfile, sizeof(taskfile) ); ! 315: bzero( &atapiCmd, sizeof(atapiCmd) ); ! 316: ! 317: desc = IOMemoryDescriptor::withAddress( data, size, kIODirectionIn ); ! 318: ! 319: taskfile.protocol = atapiProtocolPIO; ! 320: taskfile.regmask = ATARegtoMask(atapiRegDeviceSelect) ! 321: | ATARegtoMask(atapiRegCommand) ! 322: | ATARegtoMask(atapiRegByteCountLow) ! 323: | ATARegtoMask(atapiRegByteCountHigh) ! 324: | ATARegtoMask(atapiRegFeatures); ! 325: taskfile.ataRegs[atapiRegDeviceSelect] = ataModeLBA | (getUnit() << 4); ! 326: taskfile.ataRegs[atapiRegCommand] = atapiCommandPacket; ! 327: taskfile.ataRegs[atapiRegFeatures] = 0; ! 328: taskfile.ataRegs[atapiRegByteCountLow] = 0xfe; ! 329: taskfile.ataRegs[atapiRegByteCountHigh] = 0xff; ! 330: ! 331: atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? ! 332: atapiCmd.cdb[0] = 0x12; ! 333: atapiCmd.cdb[4] = size; ! 334: ! 335: utilCmd->setATAPICmd( &atapiCmd, 0, 0 ); ! 336: utilCmd->setTaskfile( &taskfile ); ! 337: utilCmd->setPointers( desc, size, false ); ! 338: utilCmd->setTimeout( 5000 ); ! 339: submitCommand( utilCmd ); ! 340: ! 341: if ( utilCmd->getResults(&result) == ataReturnNoError ) ! 342: { ! 343: *dataPtr = data; ! 344: } ! 345: else ! 346: { ! 347: IOFree( data, size ); ! 348: } ! 349: ! 350: desc->release(); ! 351: ! 352: return result.returnCode; ! 353: } ! 354: ! 355: /* ! 356: * ! 357: * ! 358: */ ! 359: bool IOATADevice::getDeviceCapacity( UInt32 *blockMax, UInt32 *blockSize ) ! 360: { ! 361: UInt32 i; ! 362: UInt32 data[2]; ! 363: ! 364: if ( deviceType == ataDeviceATA ) ! 365: { ! 366: if ( identifyData != NULL ) ! 367: { ! 368: *blockMax = *(UInt32 *)identifyData->userAddressableSectors - 1; ! 369: *blockSize = 512; ! 370: return true; ! 371: } ! 372: } ! 373: ! 374: if ( deviceType == ataDeviceATAPI ) ! 375: { ! 376: for ( i=0; i < 8; i++ ) ! 377: { ! 378: if ( doTestUnitReady() == ataReturnNoError ) ! 379: { ! 380: break; ! 381: } ! 382: } ! 383: ! 384: if ( doReadCapacity( data ) == ataReturnNoError ) ! 385: { ! 386: *blockMax = OSSwapBigToHostInt32( data[0] ); ! 387: *blockSize = OSSwapBigToHostInt32( data[1] ); ! 388: return true; ! 389: } ! 390: } ! 391: ! 392: return false; ! 393: } ! 394: ! 395: ! 396: ATAReturnCode IOATADevice::doTestUnitReady() ! 397: { ! 398: ATATaskfile taskfile; ! 399: ATAPICmd atapiCmd; ! 400: ATAResults result; ! 401: ! 402: bzero( &taskfile, sizeof(taskfile) ); ! 403: bzero( &atapiCmd, sizeof(atapiCmd) ); ! 404: ! 405: taskfile.protocol = atapiProtocolPIO; ! 406: ! 407: taskfile.regmask = ATARegtoMask(atapiRegDeviceSelect) ! 408: | ATARegtoMask(atapiRegCommand) ! 409: | ATARegtoMask(atapiRegByteCountLow) ! 410: | ATARegtoMask(atapiRegByteCountHigh) ! 411: | ATARegtoMask(atapiRegFeatures); ! 412: ! 413: taskfile.ataRegs[atapiRegDeviceSelect] = ataModeLBA | (getUnit() << 4); ! 414: taskfile.ataRegs[atapiRegCommand] = atapiCommandPacket; ! 415: taskfile.ataRegs[atapiRegFeatures] = 0; ! 416: taskfile.ataRegs[atapiRegByteCountLow] = 0xfe; ! 417: taskfile.ataRegs[atapiRegByteCountHigh] = 0xff; ! 418: ! 419: atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? ! 420: atapiCmd.cdb[0] = 0x00; ! 421: ! 422: utilCmd->setATAPICmd( &atapiCmd ); ! 423: utilCmd->setTaskfile( &taskfile ); ! 424: utilCmd->setPointers( (IOMemoryDescriptor *)NULL, 0, false ); ! 425: utilCmd->setTimeout( 5000 ); ! 426: submitCommand( utilCmd ); ! 427: utilCmd->getResults(&result); ! 428: ! 429: return result.returnCode; ! 430: } ! 431: ! 432: ! 433: /* ! 434: * ! 435: * ! 436: */ ! 437: ATAReturnCode IOATADevice::doReadCapacity( void *data ) ! 438: { ! 439: ATATaskfile taskfile; ! 440: ATAPICmd atapiCmd; ! 441: ATAResults result; ! 442: IOMemoryDescriptor *dataDesc; ! 443: UInt32 size = 8; ! 444: ! 445: ! 446: bzero( &taskfile, sizeof(taskfile) ); ! 447: bzero( &atapiCmd, sizeof(atapiCmd) ); ! 448: ! 449: dataDesc = IOMemoryDescriptor::withAddress( data, size, kIODirectionIn ); ! 450: if ( dataDesc == NULL ) ! 451: { ! 452: return ataReturnNoResource; ! 453: } ! 454: ! 455: taskfile.protocol = atapiProtocolPIO; ! 456: taskfile.regmask = ATARegtoMask(atapiRegDeviceSelect) ! 457: | ATARegtoMask(atapiRegCommand) ! 458: | ATARegtoMask(atapiRegByteCountLow) ! 459: | ATARegtoMask(atapiRegByteCountHigh) ! 460: | ATARegtoMask(atapiRegFeatures); ! 461: taskfile.ataRegs[atapiRegDeviceSelect] = ataModeLBA | (getUnit() << 4); ! 462: taskfile.ataRegs[atapiRegCommand] = atapiCommandPacket; ! 463: taskfile.ataRegs[atapiRegFeatures] = 0; ! 464: taskfile.ataRegs[atapiRegByteCountLow] = 0xfe; ! 465: taskfile.ataRegs[atapiRegByteCountHigh] = 0xff; ! 466: ! 467: atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? ! 468: atapiCmd.cdb[0] = 0x25; ! 469: ! 470: utilCmd->setATAPICmd( &atapiCmd ); ! 471: utilCmd->setTaskfile( &taskfile ); ! 472: utilCmd->setPointers( dataDesc, size, false ); ! 473: utilCmd->setTimeout( 5000 ); ! 474: submitCommand( utilCmd ); ! 475: ! 476: utilCmd->getResults(&result); ! 477: ! 478: dataDesc->release(); ! 479: ! 480: return result.returnCode; ! 481: } ! 482: ! 483: ! 484: /* ! 485: * ! 486: * ! 487: */ ! 488: IOATACommand *IOATADevice::makeRequestSense( IOATACommand *origCmd ) ! 489: { ! 490: ATATaskfile taskfile; ! 491: ATAPICmd atapiCmd; ! 492: ! 493: if ( reqSenseCmd == NULL ) ! 494: { ! 495: return NULL; ! 496: } ! 497: ! 498: bzero( &taskfile, sizeof(taskfile) ); ! 499: bzero( &atapiCmd, sizeof(atapiCmd) ); ! 500: ! 501: taskfile.protocol = atapiProtocolPIO; ! 502: ! 503: taskfile.regmask = ATARegtoMask(atapiRegDeviceSelect) ! 504: | ATARegtoMask(atapiRegCommand) ! 505: | ATARegtoMask(atapiRegByteCountLow) ! 506: | ATARegtoMask(atapiRegByteCountHigh) ! 507: | ATARegtoMask(atapiRegFeatures); ! 508: ! 509: taskfile.ataRegs[atapiRegDeviceSelect] = ataModeLBA | (getUnit() << 4); ! 510: taskfile.ataRegs[atapiRegCommand] = atapiCommandPacket; ! 511: taskfile.ataRegs[atapiRegFeatures] = 0; ! 512: taskfile.ataRegs[atapiRegByteCountLow] = origCmd->senseLength & 0xff; ! 513: taskfile.ataRegs[atapiRegByteCountHigh] = 0; ! 514: ! 515: atapiCmd.cdbLength = 12; // Fix 16 byte cmdpkts?? ! 516: atapiCmd.cdb[0] = 0x03; ! 517: atapiCmd.cdb[4] = origCmd->senseLength; ! 518: ! 519: reqSenseCmd->setATAPICmd( &atapiCmd, 0, 0 ); ! 520: reqSenseCmd->setTaskfile( &taskfile ); ! 521: reqSenseCmd->setPointers( origCmd->senseData, origCmd->senseLength, false ); ! 522: ! 523: return reqSenseCmd; ! 524: } ! 525: ! 526: /* ! 527: * ! 528: * ! 529: */ ! 530: bool IOATADevice::completeRequestSense( IOATACommand *origCmd, IOATACommand *reqSense ) ! 531: { ! 532: ATAResults result; ! 533: ! 534: if ( reqSense->getResults(&result) != ataReturnNoError ) ! 535: { ! 536: return false; ! 537: } ! 538: ! 539: origCmd->results.senseLength = result.bytesTransferred; ! 540: return true; ! 541: } ! 542: ! 543: ! 544: /* ! 545: * ! 546: * ! 547: */ ! 548: bool IOATADevice::getTimingsSupported( ATATimingProtocol *timingsSupported ) ! 549: { ! 550: UInt32 i; ! 551: ! 552: *(UInt32 *)timingsSupported = 0; ! 553: ! 554: for ( i=0; i < numTimings; i++ ) ! 555: { ! 556: *(UInt32 *) timingsSupported |= (UInt32)ataTimings[i].timingProtocol; ! 557: } ! 558: ! 559: return true; ! 560: } ! 561: ! 562: /* ! 563: * ! 564: * ! 565: */ ! 566: bool IOATADevice::getTiming( ATATimingProtocol *timingProtocol, ATATiming *timing ) ! 567: { ! 568: UInt32 i; ! 569: ! 570: for ( i=0; i < numTimings; i++ ) ! 571: { ! 572: if ( ataTimings[i].timingProtocol == *timingProtocol ) ! 573: { ! 574: bcopy( &ataTimings[i], timing, sizeof(ATATiming) ); ! 575: return true; ! 576: } ! 577: } ! 578: ! 579: return false; ! 580: } ! 581: ! 582: ! 583: /* ! 584: * ! 585: * ! 586: */ ! 587: bool IOATADevice::selectTiming( ATATimingProtocol timingProtocol ) ! 588: { ! 589: ATATaskfile taskfile; ! 590: ATAResults result; ! 591: bool rc = false; ! 592: UInt32 i; ! 593: ! 594: for ( i=0; i < numTimings; i++ ) ! 595: { ! 596: if ( ataTimings[i].timingProtocol == timingProtocol ) ! 597: { ! 598: rc = true; ! 599: break; ! 600: } ! 601: } ! 602: ! 603: if ( rc == false ) return rc; ! 604: ! 605: if ( controller->selectTiming( getUnit(), timingProtocol ) == false ) ! 606: { ! 607: return false; ! 608: } ! 609: ! 610: bzero( &taskfile, sizeof(taskfile) ); ! 611: bzero( &result, sizeof(result) ); ! 612: ! 613: taskfile.protocol = ataProtocolPIO; ! 614: taskfile.regmask = ATARegtoMask(ataRegFeatures) ! 615: | ATARegtoMask(ataRegSectorCount) ! 616: | ATARegtoMask(ataRegDriveHead) ! 617: | ATARegtoMask(ataRegCommand); ! 618: ! 619: taskfile.ataRegs[ataRegSectorCount] = ataTimings[i].featureSetting; ! 620: taskfile.ataRegs[ataRegFeatures] = ataFeatureTransferMode; ! 621: taskfile.ataRegs[ataRegDriveHead] = ataModeLBA | (getUnit() << 4); ! 622: taskfile.ataRegs[ataRegCommand] = ataCommandSetFeatures; ! 623: ! 624: utilCmd->setTaskfile( &taskfile ); ! 625: utilCmd->setPointers( (IOMemoryDescriptor *)NULL, 0, false ); ! 626: utilCmd->setTimeout( 5000 ); ! 627: utilCmd->setCallback(); ! 628: submitCommand( utilCmd ); ! 629: ! 630: if ( utilCmd->getResults( &result ) != ataReturnNoError ) ! 631: { ! 632: rc = false; ! 633: } ! 634: return rc; ! 635: } ! 636: ! 637: ! 638: /* ! 639: * ! 640: * ! 641: */ ! 642: bool IOATADevice::getATATimings() ! 643: { ! 644: int i, n; ! 645: UInt32 mode = 0; ! 646: UInt32 cycleTime = 0; ! 647: ! 648: ATATiming *pTimings; ! 649: ! 650: pTimings = ataTimings; ! 651: ! 652: /* ! 653: * PIO Cycle timing...... ! 654: * ! 655: * 1. Try to match Word 51 (pioCycleTime) with cycle timings ! 656: * in our pioModes table to get mode/CycleTime. (Valid for Modes 0-2) ! 657: * 2. If Words 64-68 are supported and Mode 3 or 4 supported check, ! 658: * update CycleTime with Word 68 (CycleTimeWithIORDY). ! 659: */ ! 660: ! 661: cycleTime = identifyData->pioMode; ! 662: ! 663: if ( cycleTime > 2 ) ! 664: { ! 665: for ( i=AppleNumPIOModes-1; i != -1; i-- ) ! 666: { ! 667: if ( cycleTime <= ApplePIOModes[i].minDataCycle ) ! 668: { ! 669: mode = i; ! 670: break; ! 671: } ! 672: } ! 673: ! 674: if ( i == -1 ) ! 675: { ! 676: cycleTime = ApplePIOModes[mode].minDataCycle; ! 677: } ! 678: } ! 679: else ! 680: { ! 681: mode = cycleTime; ! 682: cycleTime = ApplePIOModes[mode].minDataCycle; ! 683: } ! 684: ! 685: ! 686: if ( identifyData->validFields & identifyWords_64to70_Valid ) ! 687: { ! 688: if (identifyData->advancedPIOModes & advPIOModes_Mode4_Supported) ! 689: mode = 4; ! 690: else if (identifyData->advancedPIOModes & advPIOModes_Mode3_Supported) ! 691: mode = 3; ! 692: ! 693: if ( (mode >= 3) && identifyData->minPIOCyclcTimeIORDY ) ! 694: { ! 695: cycleTime = identifyData->minPIOCyclcTimeIORDY; ! 696: } ! 697: } ! 698: ! 699: pTimings->timingProtocol = ataTimingPIO; ! 700: pTimings->mode = mode; ! 701: pTimings->featureSetting = mode | ataTransferModePIOwFC; ! 702: pTimings->minDataCycle = cycleTime; ! 703: pTimings->minDataAccess = ApplePIOModes[mode].minDataAccess; ! 704: ! 705: if ( controller->calculateTiming( getUnit(), pTimings ) == false ) ! 706: { ! 707: IOLog("IOATADevice::%s() - Controller driver must support PIO timings\n\r", __FUNCTION__); ! 708: return false; ! 709: } ! 710: ! 711: pTimings++; ! 712: numTimings++; ! 713: ! 714: /* ! 715: * Multiword DMA timing..... ! 716: * ! 717: * 1. Check Word 63(7:0) (Multiword DMA Modes Supported). Lookup ! 718: * CycleTime for highest mode we support. ! 719: * 2. If Words 64-68 supported, update CycleTime from Word 66 ! 720: * (RecommendedMultiWordCycleTime) if specified. ! 721: */ ! 722: ! 723: n = identifyData->dmaModes & dmaModes_Supported; ! 724: if ( n ) ! 725: { ! 726: for ( i=0; n; i++, n>>=1 ) ! 727: ; ! 728: ! 729: mode = i - 1; ! 730: if ( mode > AppleNumDMAModes-1 ) ! 731: { ! 732: mode = AppleNumDMAModes-1; ! 733: } ! 734: cycleTime = AppleDMAModes[mode].minDataCycle; ! 735: ! 736: if (identifyData->validFields & identifyWords_64to70_Valid) ! 737: { ! 738: if ( identifyData->recDMACycleTime ) ! 739: { ! 740: cycleTime = identifyData->recDMACycleTime; ! 741: } ! 742: } ! 743: pTimings->timingProtocol = ataTimingDMA; ! 744: pTimings->mode = mode; ! 745: pTimings->featureSetting = mode | ataTransferModeDMA; ! 746: pTimings->minDataCycle = cycleTime; ! 747: pTimings->minDataAccess = AppleDMAModes[mode].minDataAccess; ! 748: ! 749: if ( controller->calculateTiming( getUnit(), pTimings ) == true ) ! 750: { ! 751: pTimings++; ! 752: numTimings++; ! 753: } ! 754: } ! 755: ! 756: /* ! 757: * Ultra DMA timing..... ! 758: * ! 759: */ ! 760: if ( identifyData->validFields & identifyWords_88to88_Valid ) ! 761: { ! 762: n = identifyData->ultraDMAModes & ultraDMAModes_Supported; ! 763: if ( n ) ! 764: { ! 765: for ( i=0; n; i++, n>>=1 ) ! 766: ; ! 767: ! 768: mode = i - 1; ! 769: if ( mode > AppleNumUltraModes-1 ) ! 770: { ! 771: mode = AppleNumUltraModes-1; ! 772: } ! 773: ! 774: /* ! 775: * Build a separate timing entry for Ultra DMA/33 (mode <= 2) and Ultra DMA/66 ! 776: */ ! 777: while ( 1 ) ! 778: { ! 779: cycleTime = AppleUltraModes[mode].minDataCycle; ! 780: ! 781: pTimings->timingProtocol = (mode > 2) ? ataTimingUltraDMA66 : ataTimingUltraDMA33; ! 782: pTimings->mode = mode; ! 783: pTimings->featureSetting = mode | ataTransferModeUltraDMA33; ! 784: pTimings->minDataCycle = cycleTime; ! 785: pTimings->minDataAccess = AppleUltraModes[mode].minDataAccess; ! 786: ! 787: if ( controller->calculateTiming( getUnit(), pTimings ) == true ) ! 788: { ! 789: pTimings++; ! 790: numTimings++; ! 791: } ! 792: ! 793: if ( mode < 3 ) break; ! 794: ! 795: mode = 2; ! 796: } ! 797: } ! 798: } ! 799: ! 800: return true; ! 801: } ! 802: ! 803: /* ! 804: * ! 805: * ! 806: */ ! 807: void IOATADevice::submitCommand( IOATACommand *cmd ) ! 808: { ! 809: cmd->execute(); ! 810: IOWriteLock( resetSem ); ! 811: IORWUnlock( resetSem ); ! 812: } ! 813: ! 814: /* ! 815: * ! 816: * ! 817: */ ! 818: bool IOATADevice::executeCommand( IOATACommand *cmd ) ! 819: { ! 820: bool isSync; ! 821: ! 822: isSync = !(cmd->flags & IOATACommand::atacmdCallbackValid); ! 823: ! 824: if ( isSync ) ! 825: { ! 826: cmd->completionInfo.sync.syncer = IOSyncer::create(); ! 827: } ! 828: ! 829: cmd->deviceQueue = deviceQueue; ! 830: ! 831: controller->executeCommand( cmd ); ! 832: ! 833: if ( isSync ) ! 834: { ! 835: cmd->completionInfo.sync.syncer->wait(); ! 836: } ! 837: ! 838: return true; ! 839: } ! 840: ! 841: /* ! 842: * ! 843: * ! 844: */ ! 845: void IOATADevice::completeCommand( IOATACommand *cmd ) ! 846: { ! 847: ATATaskfile tf; ! 848: ATAResults res; ! 849: UInt32 i; ! 850: ! 851: cmd->getTaskfile(&tf); ! 852: cmd->getResults(&res); ! 853: ! 854: #if 0 ! 855: IOLog("ATA command = %02x, RegMask = %04x ResultMask = %04x ReturnCode = %04x\n\r", ! 856: tf.protocol, (int)tf.regmask, (int)tf.resultmask, (int)res.returnCode ); ! 857: ! 858: IOLog("ATA command regs: "); ! 859: ! 860: for (i=0; i < MAX_ATA_REGS; i++ ) ! 861: { ! 862: IOLog("%04x ", tf.ataRegs[i]); ! 863: } ! 864: ! 865: IOLog("\n\rATA result regs: "); ! 866: ! 867: for (i=0; i < MAX_ATA_REGS; i++ ) ! 868: { ! 869: IOLog("%04x ", res.ataRegs[i]); ! 870: } ! 871: IOLog("\n\r"); ! 872: #endif ! 873: ! 874: if ( cmd->flags & IOATACommand::atacmdCallbackValid ) ! 875: { ! 876: (*cmd->completionInfo.async.ataDoneFn)( cmd->completionInfo.async.target, ! 877: (IOService *)this, ! 878: cmd, ! 879: cmd->completionInfo.async.refcon ); ! 880: } ! 881: else ! 882: { ! 883: cmd->completionInfo.sync.syncer->signal(); ! 884: } ! 885: } ! 886: ! 887: /* ! 888: * ! 889: * ! 890: */ ! 891: IOReturn IOATADevice::message( UInt32 p0, IOService *p1, void *p2 ) ! 892: { ! 893: UInt32 msgId; ! 894: IOATADevice *ataDev; ! 895: ! 896: msgId = (UInt32) p0; ! 897: ataDev = (IOATADevice *)p1; ! 898: ! 899: switch ( msgId ) ! 900: { ! 901: case ataMessageResetStarted: ! 902: lock_init( resetSem, true, NULL, NULL ); ! 903: IORWLockWrite( resetSem ); ! 904: break; ! 905: ! 906: case ataMessageResetComplete: ! 907: IORWLockUnlock( resetSem ); ! 908: break; ! 909: ! 910: default: ! 911: ; ! 912: } ! 913: ! 914: return kIOReturnSuccess; ! 915: } ! 916: ! 917: /* ! 918: * ! 919: * ! 920: */ ! 921: UInt32 IOATADevice::getUnit() ! 922: { ! 923: return unit; ! 924: } ! 925: ! 926: /* ! 927: * ! 928: * ! 929: */ ! 930: IOCommandQueue *IOATADevice::getDeviceQueue() ! 931: { ! 932: return deviceQueue; ! 933: } ! 934: ! 935: ! 936: /* ! 937: * ! 938: * ! 939: */ ! 940: ATADeviceType IOATADevice::getDeviceType() ! 941: { ! 942: return deviceType; ! 943: } ! 944: ! 945: /* ! 946: * ! 947: * ! 948: */ ! 949: bool IOATADevice::getATAPIPktInt() ! 950: { ! 951: return atapiPktInt; ! 952: } ! 953: ! 954: /* ! 955: * ! 956: * ! 957: */ ! 958: bool IOATADevice::getIdentifyData( ATAIdentify *identifyBuffer ) ! 959: { ! 960: if ( identifyData == NULL ) ! 961: { ! 962: bzero( identifyBuffer, sizeof(ATAIdentify) ); ! 963: return false; ! 964: } ! 965: ! 966: bcopy( identifyData, identifyBuffer, sizeof(ATAIdentify) ); ! 967: return true; ! 968: } ! 969: ! 970: /* ! 971: * ! 972: * ! 973: */ ! 974: bool IOATADevice::getInquiryData( UInt32 inquiryBufLength, ATAPIInquiry *inquiryBuffer ) ! 975: { ! 976: bzero( inquiryBuffer, inquiryBufLength ); ! 977: ! 978: if ( inquiryData == NULL ) ! 979: { ! 980: return false; ! 981: } ! 982: ! 983: bcopy( inquiryData, inquiryBuffer, inquiryBufLength ); ! 984: ! 985: return true; ! 986: } ! 987: ! 988: /* ! 989: * ! 990: * ! 991: */ ! 992: bool IOATADevice::init( UInt32 unitNum, IOATAController *ctlr ) ! 993: { ! 994: controller = ctlr; ! 995: unit = unitNum; ! 996: ! 997: if ( super::init() != true ) ! 998: { ! 999: return false; ! 1000: } ! 1001: ! 1002: deviceQueue = controller->createDeviceQueue( this ); ! 1003: if ( deviceQueue == NULL ) ! 1004: { ! 1005: return false; ! 1006: } ! 1007: ! 1008: utilCmd = allocCommand(); ! 1009: if ( utilCmd == NULL ) ! 1010: { ! 1011: return false; ! 1012: } ! 1013: ! 1014: resetSem = IORWLockAlloc(); ! 1015: if ( resetSem == NULL ) ! 1016: { ! 1017: return false; ! 1018: } ! 1019: ! 1020: return true; ! 1021: } ! 1022: ! 1023: ! 1024: /* ! 1025: * ! 1026: * ! 1027: */ ! 1028: OSDictionary *IOATADevice::createProperties() ! 1029: { ! 1030: OSDictionary *propTable = 0; ! 1031: OSObject *regObj; ! 1032: char tmpbuf[81]; ! 1033: char *s, *d; ! 1034: ! 1035: ! 1036: propTable = OSDictionary::withCapacity(ATAMaxProperties); ! 1037: if ( propTable == NULL ) ! 1038: { ! 1039: return NULL; ! 1040: } ! 1041: ! 1042: s = (deviceType == ataDeviceATA) ? ATAPropertyProtocolATA : ATAPropertyProtocolATAPI; ! 1043: regObj = (OSObject *)OSString::withCString( s ); ! 1044: if ( addToRegistry( propTable, regObj, ATAPropertyProtocol ) != true ) ! 1045: { ! 1046: goto createprop_error; ! 1047: } ! 1048: ! 1049: regObj = (OSObject *)OSNumber::withNumber(unit,32); ! 1050: if ( addToRegistry( propTable, regObj, ATAPropertyDeviceNumber ) != true ) ! 1051: { ! 1052: goto createprop_error; ! 1053: } ! 1054: ! 1055: regObj = (OSObject *)OSNumber::withNumber(unit,32); ! 1056: if ( addToRegistry( propTable, regObj, ATAPropertyLocation ) != true ) ! 1057: { ! 1058: goto createprop_error; ! 1059: } ! 1060: ! 1061: d = tmpbuf; ! 1062: stripBlanks( d, identifyData->modelNumber, sizeof(identifyData->modelNumber)); ! 1063: regObj = (OSObject *)OSString::withCString( d ); ! 1064: if ( addToRegistry( propTable, regObj, ATAPropertyModelNumber ) != true ) ! 1065: { ! 1066: goto createprop_error; ! 1067: } ! 1068: ! 1069: d = tmpbuf; ! 1070: stripBlanks( d, identifyData->firmwareRevision, sizeof(identifyData->firmwareRevision)); ! 1071: regObj = (OSObject *)OSString::withCString( d ); ! 1072: if ( addToRegistry( propTable, regObj, ATAPropertyFirmwareRev ) != true ) ! 1073: { ! 1074: goto createprop_error; ! 1075: } ! 1076: ! 1077: if ( inquiryData ) ! 1078: { ! 1079: stripBlanks( d, inquiryData->vendorName, sizeof(inquiryData->vendorName) ); ! 1080: regObj = (OSObject *)OSString::withCString( d ); ! 1081: if ( addToRegistry( propTable, regObj, ATAPropertyVendorName ) != true ) ! 1082: { ! 1083: goto createprop_error; ! 1084: } ! 1085: ! 1086: stripBlanks( d, inquiryData->productName, sizeof(inquiryData->productName) ); ! 1087: regObj = (OSObject *)OSString::withCString( d ); ! 1088: if ( addToRegistry( propTable, regObj, ATAPropertyProductName ) != true ) ! 1089: { ! 1090: goto createprop_error; ! 1091: } ! 1092: ! 1093: stripBlanks( d, inquiryData->productRevision, sizeof(inquiryData->productRevision) ); ! 1094: regObj = (OSObject *)OSString::withCString( d ); ! 1095: if ( addToRegistry( propTable, regObj, ATAPropertyProductRevision ) != true ) ! 1096: { ! 1097: goto createprop_error; ! 1098: } ! 1099: } ! 1100: return propTable; ! 1101: ! 1102: createprop_error: ; ! 1103: propTable->release(); ! 1104: return NULL; ! 1105: } ! 1106: ! 1107: /* ! 1108: * ! 1109: * ! 1110: */ ! 1111: ! 1112: bool IOATADevice::matchPropertyTable( OSDictionary * table ) ! 1113: { ! 1114: return( controller->matchNubWithPropertyTable( this, table )); ! 1115: } ! 1116: ! 1117: IOService *IOATADevice::matchLocation( IOService * ) ! 1118: { ! 1119: // IOLog( "IOATADevice::%s - called\n\r", __FUNCTION__ ); ! 1120: ! 1121: return this; ! 1122: } ! 1123: ! 1124: /* ! 1125: * ! 1126: * ! 1127: */ ! 1128: bool IOATADevice::open( IOService *customer ) ! 1129: { ! 1130: bool rc; ! 1131: ! 1132: rc = super::open( customer ); ! 1133: ! 1134: if ( rc == true ) ! 1135: { ! 1136: client = customer; ! 1137: } ! 1138: ! 1139: return rc; ! 1140: } ! 1141: ! 1142: ! 1143: /* ! 1144: * ! 1145: * ! 1146: */ ! 1147: void IOATADevice::close( IOService *customer ) ! 1148: { ! 1149: super::close( customer ); ! 1150: client = NULL; ! 1151: } ! 1152: ! 1153: ! 1154: /* ! 1155: * ! 1156: * ! 1157: */ ! 1158: void IOATADevice::free() ! 1159: { ! 1160: if ( identifyData ) IOFree( identifyData, sizeof(*identifyData) ); ! 1161: if ( inquiryData ) IOFree( inquiryData, sizeof(*inquiryData) ); ! 1162: if ( utilCmd ) utilCmd->release(); ! 1163: if ( reqSenseCmd ) reqSenseCmd->release(); ! 1164: if ( deviceQueue ) deviceQueue->release(); ! 1165: if ( resetSem ) IORWLockFree( resetSem ); ! 1166: ! 1167: super::free(); ! 1168: } ! 1169: ! 1170: /* ! 1171: * ! 1172: * ! 1173: */ ! 1174: IOService *IOATADevice::getClient() ! 1175: { ! 1176: return client; ! 1177: } ! 1178: ! 1179: ! 1180: /* ! 1181: * ! 1182: * ! 1183: */ ! 1184: IOATACommand *IOATADevice::allocCommand( UInt32 clientDataSize ) ! 1185: { ! 1186: IOATACommand *cmd; ! 1187: ! 1188: if ( (cmd = controller->allocCommand( clientDataSize )) ) ! 1189: { ! 1190: cmd->setDevice( this ); ! 1191: } ! 1192: return cmd; ! 1193: } ! 1194: ! 1195: /* ! 1196: * ! 1197: * ! 1198: */ ! 1199: bool IOATADevice::addToRegistry( OSDictionary *propTable, OSObject *regObj, char *key ) ! 1200: { ! 1201: bool ret; ! 1202: ! 1203: if ( regObj == NULL ) ! 1204: { ! 1205: return false; ! 1206: } ! 1207: ! 1208: ret = propTable->setObject( key, regObj ); ! 1209: ! 1210: regObj->release(); ! 1211: ! 1212: return ret; ! 1213: } ! 1214: ! 1215: /* ! 1216: * ! 1217: * ! 1218: */ ! 1219: void IOATADevice::stripBlanks( char *d, char *s, UInt32 l ) ! 1220: { ! 1221: char *p, c; ! 1222: ! 1223: for ( p = d, c = *s; l && c ; l--) ! 1224: { ! 1225: c = (*d++ = *s++); ! 1226: if ( c != ' ' ) ! 1227: { ! 1228: p = d; ! 1229: } ! 1230: } ! 1231: *p = 0; ! 1232: } ! 1233: ! 1234: ! 1235: /* ! 1236: * ! 1237: * ! 1238: */ ! 1239: void IOATADevice::endianConvertData( void *data, void *endianTable ) ! 1240: { ! 1241: EndianTable *t; ! 1242: ! 1243: union EndianPtr ! 1244: { ! 1245: void *voidPtr; ! 1246: UInt8 *bytePtr; ! 1247: UInt16 *shortPtr; ! 1248: UInt32 *longPtr; ! 1249: UInt64 *longlongPtr; ! 1250: } p; ! 1251: ! 1252: UInt32 i,j; ! 1253: ! 1254: p.voidPtr = data; ! 1255: ! 1256: t = (EndianTable *)endianTable; ! 1257: ! 1258: for ( ; t->type; t++ ) ! 1259: { ! 1260: i = t->size/t->type; ! 1261: ! 1262: switch ( t->type ) ! 1263: { ! 1264: ! 1265: /* Note: ! 1266: * ! 1267: * The ATA standard defines identify strings as arrays of short ints, ! 1268: * with the left-most character of the string as the most significant ! 1269: * byte of the short int. Strings are not normally affected by the host ! 1270: * endianess. However, the way ATA defines strings would cause strings ! 1271: * to appear byte reversed. We do a manditory short int byte-swap here, ! 1272: * although strictly speaking this is not an endian issue. ! 1273: * ! 1274: */ ! 1275: case sizeof(UInt8): ! 1276: for ( j = 0; j < i/2; j++ ) ! 1277: { ! 1278: *p.shortPtr++ = OSSwapInt16(*p.shortPtr); ! 1279: } ! 1280: ! 1281: break; ! 1282: ! 1283: case sizeof(UInt16): ! 1284: for ( j = 0; j < i; j++ ) ! 1285: { ! 1286: *p.shortPtr++ = OSSwapLittleToHostInt16(*p.shortPtr); ! 1287: } ! 1288: break; ! 1289: ! 1290: case sizeof(UInt32): ! 1291: for ( j = 0; j < i; j++ ) ! 1292: { ! 1293: *p.longPtr++ = OSSwapLittleToHostInt32(*p.longPtr); ! 1294: } ! 1295: break; ! 1296: ! 1297: case sizeof(UInt64): ! 1298: for ( j = 0; j < i; j++ ) ! 1299: { ! 1300: *p.longlongPtr++ = OSSwapLittleToHostInt64(*p.longlongPtr); ! 1301: } ! 1302: break; ! 1303: ! 1304: default: ! 1305: ; ! 1306: } ! 1307: } ! 1308: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.