|
|
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: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 24: * ! 25: * IOATAHDCommand.cpp - Performs ATA command processing. ! 26: * ! 27: * HISTORY ! 28: * Aug 27, 1999 jliu - Ported from AppleATADrive. ! 29: */ ! 30: ! 31: #include <IOKit/assert.h> ! 32: #include <IOKit/IOSyncer.h> ! 33: #include <IOKit/storage/ata/IOATAHDDrive.h> ! 34: ! 35: // Enable this define to generate debugging messages. ! 36: // #define DEBUG_LOG 1 ! 37: ! 38: // -------------------------------------------------------------------------- ! 39: // Set the device timings. ! 40: ! 41: bool ! 42: IOATAHDDrive::selectTimingProtocol(ATATimingProtocol protocol) ! 43: { ! 44: bool ret; ! 45: UInt8 ataReadCmd; ! 46: UInt8 ataWriteCmd; ! 47: ! 48: if (protocol >= ataMaxTimings) ! 49: { ! 50: // If protocol override is invalid, get the list of supported timing ! 51: // protocols from the device, and use the 'best' one. If the device ! 52: // cannot report the available protocols, default to PIO mode. ! 53: ! 54: ret = _ataDevice->getTimingsSupported(&protocol); ! 55: if (!ret) ! 56: { ! 57: IOLog("%s: getTimingsSupported() error\n", getName()); ! 58: protocol = ataTimingPIO; ! 59: } ! 60: } ! 61: ! 62: // IOLog("%s: timing protocols: %08x\n", getName(), protocol); ! 63: ! 64: if (protocol & (ataTimingUltraDMA66 | ataTimingUltraDMA33 | ataTimingDMA)) ! 65: { ! 66: if (protocol & ataTimingUltraDMA66) ! 67: { ! 68: IOLog("%s: Using U-DMA/66 transfers\n", getName()); ! 69: protocol = ataTimingUltraDMA66; ! 70: } ! 71: else if (protocol & ataTimingUltraDMA33) ! 72: { ! 73: IOLog("%s: Using U-DMA/33 transfers\n", getName()); ! 74: protocol = ataTimingUltraDMA33; ! 75: } ! 76: else ! 77: { ! 78: IOLog("%s: Using DMA transfers\n", getName()); ! 79: protocol = ataTimingDMA; ! 80: } ! 81: ! 82: ataReadCmd = kIOATACommandReadDMA; ! 83: ataWriteCmd = kIOATACommandWriteDMA; ! 84: selectCommandProtocol(true); ! 85: } ! 86: else ! 87: { ! 88: IOLog("%s: Using PIO transfers\n", getName()); ! 89: protocol = ataTimingPIO; ! 90: ataReadCmd = kIOATACommandReadPIO; ! 91: ataWriteCmd = kIOATACommandWritePIO; ! 92: selectCommandProtocol(false); ! 93: } ! 94: ! 95: ret = _ataDevice->selectTiming(protocol); ! 96: if (!ret) { ! 97: IOLog("%s: selectTiming() failed\n", getName()); ! 98: } ! 99: else { ! 100: _timingProtocol = protocol; ! 101: _ataReadCmd = ataReadCmd; ! 102: _ataWriteCmd = ataWriteCmd; ! 103: } ! 104: ! 105: return ret; ! 106: } ! 107: ! 108: // -------------------------------------------------------------------------- ! 109: // Returns the Command protocol to use (e.g. ataProtocolPIO, ataProtocolDMA). ! 110: ! 111: void ! 112: IOATAHDDrive::selectCommandProtocol(bool useDMA) ! 113: { ! 114: if (useDMA) ! 115: _ataProtocol = ataProtocolDMA; ! 116: else ! 117: _ataProtocol = ataProtocolPIO; ! 118: } ! 119: ! 120: // -------------------------------------------------------------------------- ! 121: // Setup an ATATaskFile from the parameters given, and write the taskfile ! 122: // to the ATATaskfile structure pointer provided. ! 123: // ! 124: // taskfile - pointer to a taskfile structure. ! 125: // protocol - An ATA transfer protocol (ataProtocolPIO, ataProtocolDMA, etc) ! 126: // command - ATA command byte. ! 127: // block - Initial transfer block. ! 128: // nblks - Number of blocks to transfer. ! 129: ! 130: void ! 131: IOATAHDDrive::setupReadWriteTaskFile(ATATaskfile * taskfile, ! 132: ATAProtocol protocol, ! 133: UInt8 command, ! 134: UInt32 block, ! 135: UInt32 nblks) ! 136: { ! 137: taskfile->protocol = protocol; ! 138: ! 139: // Mask of all taskfile registers that shall contain valid ! 140: // data and should be written to the hardware registers. ! 141: // ! 142: taskfile->regmask = ATARegtoMask(ataRegSectorNumber) | ! 143: ATARegtoMask(ataRegCylinderLow) | ! 144: ATARegtoMask(ataRegCylinderHigh) | ! 145: ATARegtoMask(ataRegDriveHead) | ! 146: ATARegtoMask(ataRegSectorCount) | ! 147: ATARegtoMask(ataRegCommand); ! 148: ! 149: taskfile->resultmask = 0; ! 150: ! 151: taskfile->ataRegs[ataRegSectorNumber] = block & 0x0ff; ! 152: taskfile->ataRegs[ataRegCylinderLow] = (block >> 8) & 0xff; ! 153: taskfile->ataRegs[ataRegCylinderHigh] = (block >> 16) & 0xff; ! 154: taskfile->ataRegs[ataRegDriveHead] = ((block >> 24) & 0x0f) | ! 155: ataModeLBA | (_unit << 4); ! 156: taskfile->ataRegs[ataRegSectorCount] = (nblks == kIOATAMaxBlocksPerXfer) ? ! 157: 0 : nblks; ! 158: taskfile->ataRegs[ataRegCommand] = command; ! 159: } ! 160: ! 161: // -------------------------------------------------------------------------- ! 162: // Allocate and return an IOATACommand that is initialized to perform ! 163: // a read/write operation. ! 164: // ! 165: // buffer - IOMemoryDescriptor object describing this transfer. ! 166: // block - Initial transfer block. ! 167: // nblks - Number of blocks to transfer. ! 168: ! 169: IOATACommand * ! 170: IOATAHDDrive::ataCommandReadWrite(IOMemoryDescriptor * buffer, ! 171: UInt32 block, ! 172: UInt32 nblks) ! 173: { ! 174: ATATaskfile taskfile; ! 175: bool isWrite; ! 176: ! 177: assert(buffer); ! 178: ! 179: IOATACommand * cmd = allocateCommand(); ! 180: if (!cmd) return 0; // error, command allocation failed. ! 181: ! 182: isWrite = (buffer->getDirection() == kIODirectionOut) ? ! 183: true : false; ! 184: ! 185: #ifdef DEBUG_LOG ! 186: IOLog("%s: ataCommandReadWrite %08x (%d) %s %d %d\n", ! 187: getName(), ! 188: buffer, ! 189: buffer->getLength(), ! 190: isWrite ? "WR" : "RD", ! 191: block, ! 192: nblks); ! 193: #endif ! 194: ! 195: #if 0 // used for testing - force PIO mode ! 196: setupReadWriteTaskFile(&taskfile, ! 197: ataProtocolPIO, ! 198: isWrite ? kIOATACommandWritePIO : ! 199: kIOATACommandReadPIO, ! 200: block, ! 201: nblks); ! 202: #else ! 203: ! 204: // Setup the taskfile structure with the size and direction of the ! 205: // transfer. This structure will be written to the actual taskfile ! 206: // registers when this command is processed. ! 207: // ! 208: setupReadWriteTaskFile(&taskfile, ! 209: _ataProtocol, ! 210: isWrite ? _ataWriteCmd : _ataReadCmd, ! 211: block, ! 212: nblks); ! 213: #endif ! 214: ! 215: // Get a pointer to the client data buffer, and record parameters ! 216: // which shall be later used by the completion routine. ! 217: // ! 218: IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); ! 219: assert(clientData); ! 220: ! 221: clientData->buffer = buffer; ! 222: ! 223: cmd->setTaskfile(&taskfile); ! 224: ! 225: cmd->setPointers(buffer, /* (IOMemoryDescriptor *) */ ! 226: buffer->getLength(), /* transferCount (bytes) */ ! 227: isWrite); /* isWrite */ ! 228: ! 229: return cmd; ! 230: } ! 231: ! 232: // -------------------------------------------------------------------------- ! 233: // Allocate and return a ATA SetFeatures command. ! 234: ! 235: IOATACommand * ! 236: IOATAHDDrive::ataCommandSetFeatures(UInt8 features, ! 237: UInt8 SectorCount, ! 238: UInt8 SectorNumber, ! 239: UInt8 CylinderLow, ! 240: UInt8 CyclinderHigh) ! 241: { ! 242: ATATaskfile taskfile; ! 243: ! 244: IOATACommand * cmd = allocateCommand(); ! 245: if (!cmd) return 0; // error, command allocation failed. ! 246: ! 247: taskfile.protocol = ataProtocolSetRegs; ! 248: ! 249: taskfile.regmask = ATARegtoMask(ataRegSectorNumber) | ! 250: ATARegtoMask(ataRegCylinderLow) | ! 251: ATARegtoMask(ataRegCylinderHigh) | ! 252: ATARegtoMask(ataRegDriveHead) | ! 253: ATARegtoMask(ataRegSectorCount) | ! 254: ATARegtoMask(ataRegCommand); ! 255: ! 256: taskfile.resultmask = ATARegtoMask(ataRegError) | ! 257: ATARegtoMask(ataRegStatus); ! 258: ! 259: taskfile.ataRegs[ataRegFeatures] = features; ! 260: taskfile.ataRegs[ataRegSectorNumber] = SectorNumber; ! 261: taskfile.ataRegs[ataRegCylinderLow] = CylinderLow; ! 262: taskfile.ataRegs[ataRegCylinderHigh] = CyclinderHigh; ! 263: taskfile.ataRegs[ataRegDriveHead] = ataModeLBA | (_unit << 4); ! 264: taskfile.ataRegs[ataRegSectorCount] = SectorCount; ! 265: taskfile.ataRegs[ataRegCommand] = kIOATACommandSetFeatures; ! 266: ! 267: cmd->setTaskfile(&taskfile); ! 268: ! 269: return cmd; ! 270: } ! 271: ! 272: // -------------------------------------------------------------------------- ! 273: // This method is responsible for calling the client's completion routine ! 274: // for an async command. ! 275: ! 276: void ! 277: IOATAHDDrive::completionCallback(IOService * target, ! 278: gdCompletionFunction action, ! 279: void * param, ! 280: UInt32 bytesTransferred, ! 281: IOReturn status) ! 282: { ! 283: (*action)(target, param, bytesTransferred, status); ! 284: } ! 285: ! 286: // -------------------------------------------------------------------------- ! 287: // This routine is called by our provider when a command processing has ! 288: // completed. We currently do not use the 'refcon' argument. ! 289: ! 290: void ! 291: IOATAHDDrive::completionHandler(IOService * device, ! 292: IOATACommand * cmd, ! 293: void * refcon) ! 294: { ! 295: assert(cmd && device); ! 296: ! 297: ATAResults results; ! 298: IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); ! 299: ! 300: assert(clientData); ! 301: ! 302: if ((cmd->getResults(&results) != ataReturnNoError) && ! 303: (clientData->maxRetries-- > 0) && ! 304: enqueueCommand(cmd)) ! 305: return; ! 306: ! 307: #if 0 ! 308: // Force command retry to test retry logic. ! 309: // Controller will reset the IOMemoryDescriptor's position, right? ! 310: // ! 311: cmd->getResults(&results); ! 312: if (clientData->maxRetries-- > 2) { ! 313: enqueueCommand(cmd); ! 314: return; ! 315: } ! 316: #endif ! 317: ! 318: #ifdef DEBUG_LOG ! 319: IOLog("%s: completionHandler %08x %08x %08x %08x %d\n", ! 320: getName(), device, cmd, refcon, getIOReturn(&results), ! 321: results.bytesTransferred); ! 322: #endif ! 323: ! 324: // Return ATAReturnCode for sync commands. ! 325: // ! 326: clientData->returnCode = results.returnCode; ! 327: ! 328: if (clientData->isSync) { ! 329: // For sync commands, unblock the client thread. ! 330: // ! 331: assert(clientData->completion.syncLock); ! 332: clientData->completion.syncLock->signal(); // unblock the client. ! 333: } ! 334: else { ! 335: // The TAP fields must be set for an async command. ! 336: // Signal the completion routine that the request has been completed. ! 337: // ! 338: assert(clientData->completion.async.action && ! 339: clientData->completion.async.target); ! 340: ! 341: completionCallback(clientData->completion.async.target, ! 342: clientData->completion.async.action, ! 343: clientData->completion.async.param, ! 344: results.bytesTransferred, ! 345: getIOReturn(&results)); ! 346: } ! 347: ! 348: // Release the IOMemoryDescriptor. ! 349: // ! 350: if (clientData->buffer) ! 351: clientData->buffer->release(); ! 352: ! 353: // Command processing is complete, release the command object. ! 354: // ! 355: cmd->release(); ! 356: } ! 357: ! 358: // -------------------------------------------------------------------------- ! 359: // Issue a synchronous ATA command. ! 360: ! 361: ATAReturnCode ! 362: IOATAHDDrive::syncExecute(IOATACommand * cmd, /* command object */ ! 363: UInt32 timeout, /* timeout in ms */ ! 364: UInt retries) /* max retries */ ! 365: { ! 366: IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); ! 367: ! 368: // Bump the retain count on the command. The completion handler ! 369: // will decrement the retain count. ! 370: // ! 371: cmd->retain(); ! 372: ! 373: // Set timeout and register the completion handler. ! 374: // ! 375: cmd->setTimeout(timeout); ! 376: cmd->setCallback(this, ! 377: (ATACallback) &IOATAHDDrive::completionHandler, ! 378: (void *) 0); ! 379: ! 380: // Increment the retain count on the IOMemoryDescriptor. ! 381: // Release when the completion routine gets called. ! 382: // ! 383: if (clientData->buffer) ! 384: clientData->buffer->retain(); ! 385: ! 386: // Set the max retry count. If retry count is 0, then the command shall ! 387: // not be retried if an error occurs. ! 388: // ! 389: clientData->maxRetries = retries; ! 390: clientData->completion.syncLock = IOSyncer::create(); ! 391: clientData->isSync = true; ! 392: ! 393: cmd->execute(); ! 394: // enqueueCommand(cmd); // queue command and kick off workloop. ! 395: ! 396: // Block client thread on lock until the completion handler ! 397: // receives an indication that the processing is complete. ! 398: // ! 399: clientData->completion.syncLock->wait(); ! 400: ! 401: return clientData->returnCode; ! 402: } ! 403: ! 404: // -------------------------------------------------------------------------- ! 405: // Issue an asynchronous ATA command. ! 406: ! 407: ATAReturnCode ! 408: IOATAHDDrive::asyncExecute(IOATACommand * cmd, /* command object */ ! 409: IOService * target, ! 410: gdCompletionFunction action, ! 411: void * param, ! 412: UInt32 timeout, /* timeout in ms */ ! 413: UInt retries) /* max retries */ ! 414: { ! 415: IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); ! 416: ! 417: // For async commands, the completion target/action must have ! 418: // not be 0. ! 419: // ! 420: if ((target && action) == 0) ! 421: return ataReturnNotSupported; ! 422: ! 423: // Bump the retain count on the command. The completion handler ! 424: // will decrement the retain count. ! 425: // ! 426: cmd->retain(); ! 427: ! 428: // Set timeout and register the completion handler. ! 429: // ! 430: cmd->setTimeout(timeout); ! 431: cmd->setCallback(this, ! 432: (ATACallback) &IOATAHDDrive::completionHandler, ! 433: (void *) 0); ! 434: ! 435: // Increment the retain count on the IOMemoryDescriptor. ! 436: // Release when the completion routine gets called. ! 437: // ! 438: if (clientData->buffer) ! 439: clientData->buffer->retain(); ! 440: ! 441: // Set the max retry count. If retry count is 0, then the command shall ! 442: // not be retried if an error occurs. ! 443: // ! 444: clientData->maxRetries = retries; ! 445: clientData->isSync = false; ! 446: ! 447: clientData->completion.async.target = target; ! 448: clientData->completion.async.action = action; ! 449: clientData->completion.async.param = param; ! 450: ! 451: return (cmd->execute() ? ataReturnNoError : ataReturnNoResource); ! 452: } ! 453: ! 454: // -------------------------------------------------------------------------- ! 455: // Add a command to the retry/sync queue. ! 456: ! 457: bool ! 458: IOATAHDDrive::enqueueCommand(IOATACommand * cmd) ! 459: { ! 460: // Add command to the queue. ! 461: // ! 462: _retryQueue->enqueueCommand(cmd); ! 463: ! 464: // wake up the workloop. ! 465: // ! 466: _evSource->interruptOccurred(0, 0, 0); ! 467: ! 468: return true; ! 469: } ! 470: ! 471: // -------------------------------------------------------------------------- ! 472: // Dequeues commands from the queue and executes them. ! 473: ! 474: void ! 475: IOATAHDDrive::dequeueCommands(IOInterruptEventSource * /*source*/, ! 476: int /*count*/) ! 477: { ! 478: _retryQueue->executeCommands(); ! 479: } ! 480: ! 481: // -------------------------------------------------------------------------- ! 482: // Allocate an IOATACommand object. ! 483: ! 484: IOATACommand * ! 485: IOATAHDDrive::allocateCommand() ! 486: { ! 487: IOATACommand * cmd; ! 488: ! 489: cmd = _ataDevice->allocCommand(sizeof(IOATAClientData)); ! 490: return cmd; ! 491: } ! 492: ! 493: // ========================================================================== ! 494: // IOATACommandQueue ! 495: // ========================================================================== ! 496: ! 497: #define super OSObject ! 498: OSDefineMetaClassAndStructors(IOATACommandQueue, OSObject) ! 499: ! 500: // -------------------------------------------------------------------------- ! 501: // Static member function which allocates and returns a queue object. ! 502: ! 503: IOATACommandQueue * IOATACommandQueue::commmandQueue() ! 504: { ! 505: IOATACommandQueue * queue = new IOATACommandQueue; ! 506: ! 507: if (queue && !queue->init()) { ! 508: queue->release(); ! 509: queue = 0; ! 510: } ! 511: ! 512: return queue; ! 513: } ! 514: ! 515: // -------------------------------------------------------------------------- ! 516: // Initializes the queue object. ! 517: ! 518: bool IOATACommandQueue::init() ! 519: { ! 520: _enabled = false; ! 521: _cmdLock = 0; ! 522: _qLock = 0; ! 523: ! 524: if (!super::init()) ! 525: return false; ! 526: ! 527: // Initialize the queue. ! 528: // ! 529: queue_init(&_queue); ! 530: ! 531: _cmdLock = IORecursiveLockAlloc(); ! 532: if (!_cmdLock) ! 533: return false; ! 534: ! 535: // Queue access is protected by a spinlock. ! 536: // ! 537: _qLock = IOSimpleLockAlloc(); ! 538: if (!_qLock) ! 539: return false; ! 540: ! 541: return true; ! 542: } ! 543: ! 544: // -------------------------------------------------------------------------- ! 545: // Frees the queue object. ! 546: ! 547: void IOATACommandQueue::free() ! 548: { ! 549: if (_qLock) { ! 550: IOSimpleLockFree(_qLock); ! 551: _qLock = 0; ! 552: } ! 553: ! 554: if (_cmdLock) { ! 555: IORecursiveLockFree(_cmdLock); ! 556: _cmdLock = 0; ! 557: } ! 558: ! 559: // ! 560: // What about IOATACommand objects in the queue? ! 561: // ! 562: ! 563: super::free(); ! 564: } ! 565: ! 566: // -------------------------------------------------------------------------- ! 567: // Dequeues and executes all IOATACommand objects in the queue. ! 568: ! 569: void IOATACommandQueue::executeCommands() ! 570: { ! 571: IOATAClientData * clientData; ! 572: IOATACommand * cmd; ! 573: ! 574: IORecursiveLockLock(_cmdLock); ! 575: ! 576: while (_enabled && !queue_empty(&_queue)) { ! 577: IOSimpleLockLock(_qLock); ! 578: queue_remove_first(&_queue, clientData, IOATAClientData *, link); ! 579: IOSimpleLockUnlock(_qLock); ! 580: ! 581: assert(clientData); ! 582: ! 583: cmd = clientData->command; ! 584: ! 585: #ifdef DEBUG_LOG ! 586: IOLog("cmd:%08x clientData:%08x ATA_CLIENT_DATA(cmd):%08x\n", ! 587: cmd, clientData, ATA_CLIENT_DATA(cmd)); ! 588: #endif ! 589: ! 590: assert(cmd && (ATA_CLIENT_DATA(cmd) == clientData)); ! 591: ! 592: cmd->execute(); ! 593: } ! 594: ! 595: IORecursiveLockUnlock(_cmdLock); ! 596: } ! 597: ! 598: // -------------------------------------------------------------------------- ! 599: // Enqueues an IOATACommand object to the queue. ! 600: // Returns true if the command specifed was enqueued. ! 601: ! 602: bool IOATACommandQueue::enqueueCommand(IOATACommand * cmd) ! 603: { ! 604: assert(cmd); ! 605: ! 606: IOATAClientData * clientData = ATA_CLIENT_DATA(cmd); ! 607: ! 608: // Make sure the clientData to IOATACommand linkage is correct. ! 609: // ! 610: clientData->command = cmd; ! 611: ! 612: #ifdef DEBUG_LOG ! 613: IOLog("enqueueCommand: %08x\n", (UInt) cmd); ! 614: #endif ! 615: ! 616: IOSimpleLockLock(_qLock); ! 617: queue_enter(&_queue, clientData, IOATAClientData *, link); ! 618: IOSimpleLockUnlock(_qLock); ! 619: ! 620: return true; ! 621: } ! 622: ! 623: // -------------------------------------------------------------------------- ! 624: // Enable/disable the queue. ! 625: ! 626: void IOATACommandQueue::setEnabled(bool enable) ! 627: { ! 628: IORecursiveLockLock(_cmdLock); ! 629: _enabled = enable; ! 630: IORecursiveLockUnlock(_cmdLock); ! 631: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.