|
|
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: #include <IOKit/IOLib.h> ! 24: #include <IOKit/IOReturn.h> ! 25: #include <IOKit/scsi/IOSCSIDeviceInterface.h> ! 26: #include <IOKit/storage/scsi/IOSCSIHDDrive.h> ! 27: #include <IOKit/storage/scsi/IOSCSIHDDriveNub.h> ! 28: ! 29: ! 30: /* Device types that we intend to handle. */ ! 31: ! 32: const UInt8 DT_DIRACCESS = 0x00; /* direct access disk */ ! 33: ! 34: #define super IOBasicSCSI ! 35: OSDefineMetaClassAndStructors(IOSCSIHDDrive,IOBasicSCSI) ! 36: ! 37: IOReturn ! 38: IOSCSIHDDrive::allocateFormatBuffer(UInt8 **buf,UInt32 *len) ! 39: { ! 40: /* The default implementation uses no buffer. */ ! 41: ! 42: *buf = 0; ! 43: *len = 0; ! 44: return(kIOReturnSuccess); ! 45: } ! 46: ! 47: UInt8 ! 48: IOSCSIHDDrive::composeFormatBuffer(UInt8 * /* buf */,UInt32 /* buflen */) ! 49: { ! 50: return(0); /* default: no fmtdata buffer to transfer */ ! 51: } ! 52: ! 53: OSDictionary * ! 54: IOSCSIHDDrive::constructDeviceProperties(void) ! 55: { ! 56: OSDictionary *propTable; ! 57: OSData *prop; ! 58: char *typeString; ! 59: ! 60: propTable = OSDictionary::withCapacity(6); ! 61: ! 62: if (propTable) { ! 63: ! 64: prop = OSData::withBytes((void *)(&_vendor),strlen(_vendor)); ! 65: if (prop) { ! 66: propTable->setObject("vendor", prop); ! 67: } ! 68: ! 69: prop = OSData::withBytes((void *)(&_product),strlen(_product)); ! 70: if (prop) { ! 71: propTable->setObject("product", prop); ! 72: } ! 73: ! 74: prop = OSData::withBytes((void *)(&_rev),strlen(_rev)); ! 75: if (prop) { ! 76: propTable->setObject("revision", prop); ! 77: } ! 78: ! 79: typeString = (char *)getDeviceTypeName(); ! 80: prop = OSData::withBytes((void *)(typeString),strlen(typeString)); ! 81: if (prop) { ! 82: propTable->setObject("device-type", prop); ! 83: } ! 84: ! 85: #ifdef xxx ! 86: prop = OSData::withBytes((void *)(&_removable),sizeof(bool)); ! 87: if (prop) { ! 88: propTable->setObject("removable", prop); ! 89: } ! 90: ! 91: prop = OSData::withBytes((void *)(&_ejectable),sizeof(bool)); ! 92: if (prop) { ! 93: propTable->setObject("ejectable", prop); ! 94: } ! 95: #endif //xxx ! 96: ! 97: } ! 98: ! 99: return(propTable); ! 100: } ! 101: ! 102: UInt32 ! 103: IOSCSIHDDrive::createFormatCdb(UInt64 /* byteCapacity */, ! 104: UInt8 *cdb,UInt32 *cdbLength, ! 105: UInt8 buf[],UInt32 bufLen, ! 106: UInt32 *maxAutoSenseLength,UInt32 *timeoutSeconds) ! 107: { ! 108: struct IOFormatcdb *c; ! 109: UInt8 formatControls; /* CmpLst & Defect List Format bits */ ! 110: ! 111: c = (struct IOFormatcdb *)cdb; ! 112: ! 113: c->opcode = SOP_FORMAT; ! 114: c->lunbits = 0; ! 115: c->vendor = 0; ! 116: c->interleave_msb = 0; ! 117: c->interleave_lsb = 0; ! 118: c->ctlbyte = 0; ! 119: ! 120: *cdbLength = 6; ! 121: ! 122: /* If we are to use a format buffer, set it up: */ ! 123: ! 124: if (buf != NULL) { ! 125: formatControls = composeFormatBuffer(buf,bufLen); ! 126: c->lunbits |= (formatControls | 0x10); /* data transfer will occur */ ! 127: } ! 128: ! 129: *maxAutoSenseLength = sizeof(SCSISenseData); /* do the sense */ ! 130: *timeoutSeconds = 15 * 60; /* a nice long time */ ! 131: ! 132: return(0); ! 133: } ! 134: ! 135: IOService * ! 136: IOSCSIHDDrive::createNub(void) ! 137: { ! 138: IOService *nub; ! 139: ! 140: // IOLog("%s[IOSCSIHDDrive]::createNub\n",getName()); ! 141: ! 142: /* Instantiate a nub so a generic driver can match above us. */ ! 143: ! 144: nub = instantiateNub(); ! 145: if (nub == NULL) { ! 146: IOLog("%s[IOSCSIHDDrive]::createNub; nub didn't instantiate\n",getName()); ! 147: return(NULL); ! 148: } ! 149: ! 150: nub->init(); ! 151: ! 152: if (!nub->attach(this)) { ! 153: IOPanic("IOSCSIHDDrive::createNub; couldn't attach IOSCSIHDDriveNub"); ! 154: } ! 155: ! 156: nub->registerService(); ! 157: ! 158: return(nub); ! 159: } ! 160: ! 161: void ! 162: IOSCSIHDDrive::deleteFormatBuffer(UInt8 * /* buf */, UInt32 /* buflen */) ! 163: { ! 164: /* The default implementation has no buffer to free. */ ! 165: } ! 166: ! 167: bool ! 168: IOSCSIHDDrive::deviceTypeMatches(UInt8 inqBuf[],UInt32 inqLen) ! 169: { ! 170: if ((_inqBuf[0] & 0x1f) == DT_DIRACCESS) { ! 171: return(true); ! 172: } else { ! 173: return(false); /* we don't handle other devices */ ! 174: } ! 175: } ! 176: ! 177: IOReturn ! 178: IOSCSIHDDrive::doAsyncReadWrite(IOMemoryDescriptor *buffer, ! 179: UInt32 block,UInt32 nblks, ! 180: gdCompletionFunction action, ! 181: IOService *target,void *param) ! 182: { ! 183: /** ! 184: IOLog("IOSCSIHDDrive::doAsyncReadWrite: target=%08x,action=%08x,param=%08x\n", ! 185: (int)target,(int)action,(int)param); ! 186: **/ ! 187: return(standardAsyncReadWrite(buffer,block,nblks,action,target,param)); ! 188: } ! 189: ! 190: IOReturn ! 191: IOSCSIHDDrive::doEjectMedia(void) ! 192: { ! 193: /* Spin down, eject, and leave power alone: */ ! 194: ! 195: return(doStartStop(false,true,IOStartStopcdb::P_NOCHANGE)); ! 196: } ! 197: ! 198: IOReturn ! 199: IOSCSIHDDrive::doFormatMedia(UInt64 byteCapacity) ! 200: { ! 201: struct context *cx; ! 202: UInt8 *fmtbuf; ! 203: IOReturn result; ! 204: IOSCSICommand *req; ! 205: SCSICDBInfo scsiCDB; ! 206: UInt32 transferLength; ! 207: UInt32 senseLength; ! 208: UInt32 timeoutSeconds; ! 209: ! 210: cx = allocateContext(); ! 211: if (cx == NULL) { ! 212: return(kIOReturnNoMemory); ! 213: } ! 214: ! 215: req = cx->scsireq; ! 216: ! 217: /* Allow a subclass to construct the cdb and return an optional ! 218: * memory buffer address for defect lists, etc. ! 219: */ ! 220: ! 221: result = allocateFormatBuffer(&fmtbuf,&transferLength); ! 222: if (result != kIOReturnSuccess) { ! 223: return(result); ! 224: } ! 225: ! 226: bzero( &scsiCDB, sizeof(scsiCDB) ); ! 227: ! 228: scsiCDB.cdbFlags |= createFormatCdb(byteCapacity,(UInt8 *)&scsiCDB.cdb,&scsiCDB.cdbLength, ! 229: fmtbuf,transferLength, ! 230: &senseLength, ! 231: &timeoutSeconds); ! 232: ! 233: req->setCDB( &scsiCDB ); ! 234: req->setPointers( cx->senseDataDesc, senseLength, false, true ); ! 235: req->setTimeout( timeoutSeconds * 1000 ); ! 236: ! 237: /* If we have a buffer to transfer, create a Memory Descriptor for it: */ ! 238: ! 239: if ((fmtbuf != NULL) && (transferLength != 0)) { ! 240: cx->memory = IOMemoryDescriptor::withAddress((void *)fmtbuf, ! 241: transferLength, ! 242: kIODirectionOut); ! 243: } ! 244: ! 245: req->setPointers( cx->memory, transferLength, true ); ! 246: queueCommand(cx,kSync,getFormatMediaPowerState()); /* queue the operation, sleep awaiting power */ ! 247: ! 248: result = simpleSynchIO(cx); /* issue a simple command */ ! 249: ! 250: /* Free the format buffer, if any: */ ! 251: ! 252: deleteFormatBuffer(fmtbuf,transferLength); ! 253: ! 254: deleteContext(cx); ! 255: ! 256: return(result); ! 257: } ! 258: ! 259: UInt32 ! 260: IOSCSIHDDrive::doGetFormatCapacities(UInt64 * capacities, ! 261: UInt32 capacitiesMaxCount) const ! 262: { ! 263: if ((capacities != NULL) && (capacitiesMaxCount > 0)) { ! 264: *capacities = _blockSize * (_maxBlock + 1); ! 265: return(1); ! 266: } else { ! 267: return(0); ! 268: } ! 269: } ! 270: ! 271: /* We issue a simple Prevent/Allow command to lock or unlock the media: */ ! 272: IOReturn ! 273: IOSCSIHDDrive::doLockUnlockMedia(bool doLock) ! 274: { ! 275: struct context *cx; ! 276: struct IOPrevAllowcdb *c; ! 277: IOSCSICommand *req; ! 278: SCSICDBInfo scsiCDB; ! 279: IOReturn result; ! 280: ! 281: cx = allocateContext(); ! 282: if (cx == NULL) { ! 283: return(kIOReturnNoMemory); ! 284: } ! 285: ! 286: req = cx->scsireq; ! 287: ! 288: bzero( &scsiCDB, sizeof(scsiCDB) ); ! 289: ! 290: c = (struct IOPrevAllowcdb *)&scsiCDB.cdb; ! 291: ! 292: c->opcode = SOP_PREVALLOW; ! 293: c->lunbits = 0; ! 294: c->reserved1 = 0; ! 295: c->reserved2 = 0; ! 296: ! 297: if (doLock) { ! 298: c->prevent = 0x01; /* prevent removal from device */ ! 299: } else { ! 300: c->prevent = 0x00; /* allow removal from device */ ! 301: } ! 302: ! 303: c->ctlbyte = 0; ! 304: ! 305: scsiCDB.cdbLength = 6; ! 306: ! 307: req->setCDB( &scsiCDB ); ! 308: ! 309: cx->memory = 0; ! 310: ! 311: req->setPointers( cx->memory, 0, false ); ! 312: ! 313: queueCommand(cx,kSync,getLockUnlockMediaPowerState()); /* queue the operation, sleep awaiting power */ ! 314: ! 315: result = simpleSynchIO(cx); ! 316: ! 317: deleteContext(cx); ! 318: ! 319: return(result); ! 320: } ! 321: ! 322: IOReturn ! 323: IOSCSIHDDrive::doStart(void) ! 324: { ! 325: return(doStartStop(true,false,IOStartStopcdb::P_ACTIVE)); ! 326: } ! 327: ! 328: IOReturn ! 329: IOSCSIHDDrive::doStop(void) ! 330: { ! 331: return(doStartStop(false,false,IOStartStopcdb::P_NOCHANGE)); ! 332: } ! 333: ! 334: IOReturn ! 335: IOSCSIHDDrive::doStartStop(bool start,bool loadEject,UInt8 powerCondition) ! 336: { ! 337: struct context *cx; ! 338: struct IOStartStopcdb *c; ! 339: IOSCSICommand *req; ! 340: SCSICDBInfo scsiCDB; ! 341: IOReturn result; ! 342: UInt32 powerLevel; /* what power level we need to be in */ ! 343: ! 344: /* Issue a Start/Stop Unit command. */ ! 345: ! 346: cx = allocateContext(); ! 347: if (cx == NULL) { ! 348: return(kIOReturnNoMemory); ! 349: } ! 350: ! 351: powerLevel = getStopPowerState(); /* assume we're spinning down */ ! 352: req = cx->scsireq; ! 353: ! 354: bzero( &scsiCDB, sizeof(SCSICDBInfo) ); ! 355: ! 356: c = (struct IOStartStopcdb *)&scsiCDB.cdb; ! 357: c->opcode = SOP_STARTSTOP; ! 358: c->lunImmed = 0; ! 359: c->reserved1 = 0; ! 360: c->reserved2 = 0; ! 361: c->controls = powerCondition; ! 362: c->controls = 0; /* xxx powerCondition is a SCSI-3 thing */ ! 363: if (loadEject) { ! 364: c->controls |= IOStartStopcdb::C_LOEJ; ! 365: powerLevel = getEjectPowerState(); /* let subclass decide what we need */ ! 366: }; ! 367: if (start) { ! 368: c->controls |= IOStartStopcdb::C_SPINUP; ! 369: powerLevel = getStartPowerState(); ! 370: } ! 371: c->ctlbyte = 0; ! 372: ! 373: scsiCDB.cdbLength = 6; ! 374: ! 375: req->setCDB( &scsiCDB ); ! 376: req->setTimeout( 10000 ); ! 377: ! 378: cx->memory = 0; ! 379: ! 380: req->setPointers( cx->memory, 0, false ); ! 381: ! 382: queueCommand(cx,kSync,powerLevel); /* queue the operation, sleep awaiting power */ ! 383: ! 384: result = simpleSynchIO(cx); ! 385: ! 386: deleteContext(cx); ! 387: return(result); ! 388: } ! 389: ! 390: IOReturn ! 391: IOSCSIHDDrive::doSynchronizeCache(void) ! 392: { ! 393: struct context *cx; ! 394: struct IOSyncCachecdb *c; ! 395: IOSCSICommand *req; ! 396: SCSICDBInfo scsiCDB; ! 397: IOReturn result; ! 398: ! 399: cx = allocateContext(); ! 400: if (cx == NULL) { ! 401: return(kIOReturnNoMemory); ! 402: } ! 403: ! 404: req = cx->scsireq; ! 405: bzero( &scsiCDB, sizeof(scsiCDB) ); ! 406: ! 407: c = (struct IOSyncCachecdb *)&scsiCDB.cdb; ! 408: ! 409: c->opcode = SOP_SYNCCACHE; ! 410: c->lunbits = 0; ! 411: c->lba_3 = 0; /* if zero, start at block zero */ ! 412: c->lba_2 = 0; ! 413: c->lba_1 = 0; ! 414: c->lba_0 = 0; ! 415: c->reserved = 0; ! 416: c->nblks_msb = 0; /* if zero, do all blocks */ ! 417: c->nblks_lsb = 0; ! 418: c->ctlbyte = 0; ! 419: ! 420: scsiCDB.cdbLength = 10; ! 421: ! 422: req->setCDB( &scsiCDB ); ! 423: ! 424: cx->memory = 0; ! 425: ! 426: req->setPointers( cx->memory, 0, false ); ! 427: ! 428: /* We assume there will be some data in the drive's cache, so we force the ! 429: * drive to be running before we issue this command. ! 430: */ ! 431: ! 432: queueCommand(cx,kSync,getSynchronizeCachePowerState()); /* queue the operation, sleep awaiting power */ ! 433: ! 434: result = simpleSynchIO(cx); ! 435: ! 436: deleteContext(cx); ! 437: ! 438: return(result); ! 439: } ! 440: ! 441: IOReturn ! 442: IOSCSIHDDrive::doSyncReadWrite(IOMemoryDescriptor *buffer,UInt32 block,UInt32 nblks) ! 443: { ! 444: return(standardSyncReadWrite(buffer,block,nblks)); ! 445: } ! 446: ! 447: const char * ! 448: IOSCSIHDDrive::getDeviceTypeName(void) ! 449: { ! 450: return(kDeviceTypeHardDisk); ! 451: } ! 452: ! 453: UInt32 ! 454: IOSCSIHDDrive::getEjectPowerState(void) ! 455: { ! 456: return(kElectronicsOn); ! 457: } ! 458: ! 459: UInt32 ! 460: IOSCSIHDDrive::getExecuteCDBPowerState(void) ! 461: { ! 462: return(kAllOn); ! 463: } ! 464: ! 465: UInt32 ! 466: IOSCSIHDDrive::getFormatMediaPowerState(void) ! 467: { ! 468: return(kAllOn); ! 469: } ! 470: ! 471: UInt32 ! 472: IOSCSIHDDrive::getInitialPowerState(void) ! 473: { ! 474: return(kAllOn); ! 475: } ! 476: ! 477: UInt32 ! 478: IOSCSIHDDrive::getInquiryPowerState(void) ! 479: { ! 480: return(kElectronicsOn); ! 481: } ! 482: ! 483: UInt32 ! 484: IOSCSIHDDrive::getLockUnlockMediaPowerState(void) ! 485: { ! 486: return(kElectronicsOn); ! 487: } ! 488: ! 489: UInt32 ! 490: IOSCSIHDDrive::getReadCapacityPowerState(void) ! 491: { ! 492: return(kElectronicsOn); ! 493: } ! 494: ! 495: UInt32 ! 496: IOSCSIHDDrive::getReadWritePowerState(void) ! 497: { ! 498: return(kAllOn); ! 499: } ! 500: ! 501: UInt32 ! 502: IOSCSIHDDrive::getReportWriteProtectionPowerState(void) ! 503: { ! 504: return(kElectronicsOn); ! 505: } ! 506: ! 507: UInt32 ! 508: IOSCSIHDDrive::getStartPowerState(void) ! 509: { ! 510: return(kElectronicsOn); ! 511: } ! 512: ! 513: UInt32 ! 514: IOSCSIHDDrive::getStopPowerState(void) ! 515: { ! 516: return(kElectronicsOn); /* we don't have to be spinning to spin down */ ! 517: } ! 518: ! 519: UInt32 ! 520: IOSCSIHDDrive::getSynchronizeCachePowerState(void) ! 521: { ! 522: return(kAllOn); ! 523: } ! 524: ! 525: UInt32 ! 526: IOSCSIHDDrive::getTestUnitReadyPowerState(void) ! 527: { ! 528: return(kElectronicsOn); ! 529: } ! 530: ! 531: bool ! 532: IOSCSIHDDrive::init(OSDictionary * properties) ! 533: { ! 534: _mediaPresent = false; ! 535: _startStopDisabled = false; ! 536: ! 537: return(super::init(properties)); ! 538: } ! 539: ! 540: IOService * ! 541: IOSCSIHDDrive::instantiateNub(void) ! 542: { ! 543: IOService *nub; ! 544: ! 545: /* Instantiate a nub so a generic driver can match above us. */ ! 546: ! 547: nub = new IOSCSIHDDriveNub; ! 548: return(nub); ! 549: } ! 550: ! 551: bool ! 552: IOSCSIHDDrive::powerTickle(UInt32 desiredState) ! 553: { ! 554: return(activityTickle(kIOPMSuperclassPolicy1,desiredState)); ! 555: } ! 556: ! 557: IOReturn ! 558: IOSCSIHDDrive::reportMediaState(bool *mediaPresent,bool *changed) ! 559: { ! 560: struct context *cx; ! 561: struct IOTURcdb *c; ! 562: IOSCSICommand *req; ! 563: SCSICDBInfo scsiCDB; ! 564: SCSIResults scsiResults; ! 565: IOReturn result; ! 566: UInt8 status; ! 567: UInt8 senseKey; ! 568: ! 569: cx = allocateContext(); ! 570: if (cx == NULL) { ! 571: return(kIOReturnNoMemory); ! 572: } ! 573: ! 574: req = cx->scsireq; ! 575: ! 576: bzero( &scsiCDB, sizeof(scsiCDB) ); ! 577: ! 578: c = (struct IOTURcdb *)&scsiCDB.cdb; ! 579: c->opcode = SOP_TUR; ! 580: c->lunbits = 0; ! 581: c->reserved1 = 0; ! 582: c->reserved2 = 0; ! 583: c->reserved3 = 0; ! 584: c->ctlbyte = 0; ! 585: ! 586: scsiCDB.cdbLength = 6; ! 587: ! 588: req->setCDB( &scsiCDB ); ! 589: req->setPointers( cx->senseDataDesc, 255, false, true ); ! 590: ! 591: req->setTimeout( 2000 ); ! 592: ! 593: cx->memory = 0; ! 594: ! 595: req->setPointers( cx->memory, 0, false ); ! 596: ! 597: /** ! 598: IOLog("IOSCSIHDDrive::reportMediaState: mp=%08x,ch=%08x\n", ! 599: (int)mediaPresent,(int)changed); ! 600: IOLog("IOSCSIHDDrive::reportMediaState: doing TUR\n"); ! 601: **/ ! 602: ! 603: queueCommand(cx,kSync,getTestUnitReadyPowerState()); ! 604: result = simpleSynchIO(cx); ! 605: ! 606: req->getResults( &scsiResults ); ! 607: ! 608: status = scsiResults.scsiStatus; ! 609: ! 610: /** ! 611: IOLog("%s[IOSCSIHDDrive]::reportMediaState; result=%s, status=%02x,sense=%02x\n", ! 612: getName(),stringFromReturn(result),status,cx->senseData->senseKey ! 613: ); ! 614: **/ ! 615: ! 616: if (result == kIOReturnSuccess) { /* TUR succeeded; device is ready */ ! 617: ! 618: *mediaPresent = true; ! 619: *changed = (*mediaPresent != _mediaPresent); /* report if it's changed */ ! 620: _mediaPresent = true; /* remember current state */ ! 621: result = kIOReturnSuccess; ! 622: ! 623: } else { /* TUR failed; check sense key */ ! 624: ! 625: if ( scsiResults.requestSenseDone == true ) { ! 626: senseKey = cx->senseData->senseKey; ! 627: ! 628: if (senseKey == 0x02) { /* device says "not ready" */ ! 629: *mediaPresent = false; ! 630: *changed = (*mediaPresent != _mediaPresent); /* report if it's changed */ ! 631: _mediaPresent = false; /* remember current state */ ! 632: result = kIOReturnSuccess; ! 633: ! 634: } else { /* funky sense key? forget it. */ ! 635: ! 636: *mediaPresent = false; ! 637: *changed = (*mediaPresent != _mediaPresent); /* report if it's changed */ ! 638: _mediaPresent = false; /* remember current state */ ! 639: result = kIOReturnIOError; ! 640: } ! 641: } ! 642: } ! 643: ! 644: deleteContext(cx); ! 645: ! 646: #ifndef DISKPM ! 647: if (*changed && *mediaPresent) ! 648: doStart(); ! 649: #endif ! 650: ! 651: return(result); ! 652: } ! 653: ! 654: IOReturn ! 655: IOSCSIHDDrive::restoreElectronicsState(void) ! 656: { ! 657: return(kIOReturnSuccess); ! 658: } ! 659: ! 660: /* The standard completion for a doAsyncReadWrite operation. We fire it ! 661: * up to our target, the generic driver. ! 662: */ ! 663: void ! 664: IOSCSIHDDrive::RWCompletion(struct context *cx) ! 665: { ! 666: SCSIResults scsiResults; ! 667: ! 668: /** IOLog("IOSCSIHDDrive::RWCompletion: cx=%08x,target=%08x,action=%08x,param=%08x\n", ! 669: (int)cx,(int)cx->completion.target,(int)cx->completion.action,(int)cx->completion.param); ! 670: **/ ! 671: cx->scsireq->getResults( &scsiResults ); ! 672: (*cx->completion.action)(cx->completion.target,cx->completion.param, ! 673: scsiResults.bytesTransferred, ! 674: scsiResults.returnCode); ! 675: ! 676: ! 677: /* Attempt to dequeue and execute any waiting commands: */ ! 678: ! 679: dequeueCommands(); ! 680: } ! 681: ! 682: IOReturn ! 683: IOSCSIHDDrive::saveElectronicsState(void) ! 684: { ! 685: return(kIOReturnSuccess); ! 686: } ! 687: ! 688: static IOPMPowerState ourPowerStates[kNumberOfPowerStates] = { ! 689: {1,IOPMNotAttainable,0,0,0,0,0,0,0,0,0,0}, /* state 00 kAllOff */ ! 690: {1,0,0,IOPMPowerOn,0,0,0,0,0,0,0,0}, /* state 01 kElectronicsOn */ ! 691: {1,0,0,IOPMPowerOn,0,0,0,0,0,0,0,0} /* state 02 kAllOn */ ! 692: }; ! 693: ! 694: ! 695: bool ! 696: IOSCSIHDDrive::start(IOService *provider) ! 697: { ! 698: IOService *nub; ! 699: ! 700: if (!super::start(provider)) { ! 701: return(false); ! 702: } ! 703: ! 704: // IOLog("%s[IOSCSIHDDrive]::start\n",getName()); ! 705: ! 706: /* Initialize and set up to perform Power Management: */ ! 707: ! 708: PMinit(); ! 709: _restoreState = false; ! 710: #ifdef notyet // don't register for PM yet till we handle queuing requests! ! 711: IOPMRegisterDevice(pm_vars->ourName,this); // join the power management tree ! 712: #endif ! 713: registerControllingDriver(this,ourPowerStates,kNumberOfPowerStates); // export power states ! 714: ! 715: nub = createNub(); ! 716: if (nub == NULL) { ! 717: return(false); ! 718: } else { ! 719: return(true); ! 720: } ! 721: } ! 722: ! 723: // ********************************************************************************** ! 724: // maxCapabilityForDomainState ! 725: // ! 726: // This simple device needs only power. If the power domain is supplying ! 727: // power, the disk can go to its highest state. If there is no power ! 728: // it can only be in its lowest state, which is off. ! 729: // ********************************************************************************** ! 730: ! 731: unsigned long ! 732: IOSCSIHDDrive::maxCapabilityForDomainState(IOPMPowerFlags domainState) ! 733: { ! 734: if (domainState & IOPMPowerOn) { ! 735: return(kAllOn); ! 736: } else { ! 737: return(kAllOff); ! 738: } ! 739: } ! 740: ! 741: // ********************************************************************************** ! 742: // powerStateForDomainState ! 743: // ! 744: // The power domain may be changing state. If power is ON in its new ! 745: // state, we will be on, too. If domain power is OFF, we are off. ! 746: // ********************************************************************************** ! 747: unsigned long ! 748: IOSCSIHDDrive::powerStateForDomainState(IOPMPowerFlags domainState) ! 749: { ! 750: if (domainState & IOPMPowerOn) { ! 751: return(kAllOn); /* xxx might be kElectronicsOn if drive not spun up */ ! 752: } else { ! 753: return(kAllOff); ! 754: } ! 755: } ! 756: ! 757: // ********************************************************************************** ! 758: // initialPowerStateForDomainState ! 759: // ! 760: // Our parent wants to know what our initial power state is. If power is ON in the ! 761: // domain, we are in state kElectronicsOn or kAllOn. If domain power is OFF, we are off. ! 762: // ********************************************************************************** ! 763: unsigned long ! 764: IOSCSIHDDrive::initialPowerStateForDomainState(IOPMPowerFlags domainState) ! 765: { ! 766: if (domainState & IOPMPowerOn) { ! 767: return(getInitialPowerState()); /* report whether it's spinning on startup */ ! 768: } else { ! 769: return(kAllOff); ! 770: } ! 771: } ! 772: ! 773: // ********************************************************************************** ! 774: // setPowerState ! 775: // ! 776: // Someone has decided to change the disk state. We perform the change here. ! 777: // ********************************************************************************** ! 778: IOReturn ! 779: IOSCSIHDDrive::setPowerState(unsigned long powerStateOrdinal,IOService *) ! 780: { ! 781: IOReturn result; ! 782: ! 783: result = kIOReturnSuccess; ! 784: ! 785: /* All we do in the default implementation is spin up and down. If the drive reports an ! 786: * error to a start/stop command, we don't bother attempting to issue those commands again. ! 787: * ! 788: * xxx Question: What should we return? Success? or an error meaning "we didn't do it!" ! 789: */ ! 790: switch (powerStateOrdinal) { ! 791: ! 792: case kElectronicsOn : /* spin down if necessary */ ! 793: if (pm_vars->myCurrentState == kAllOn) { ! 794: if (!_startStopDisabled) { ! 795: result = doStop(); ! 796: if (result != kIOReturnSuccess) { ! 797: _startStopDisabled = true; ! 798: result = kIOReturnSuccess; ! 799: } ! 800: } ! 801: } ! 802: break; ! 803: ! 804: case kAllOn : /* spin up if necessary */ ! 805: if (pm_vars->myCurrentState == kElectronicsOn) { ! 806: if (!_startStopDisabled) { ! 807: result = doStart(); ! 808: if (result != kIOReturnSuccess) { ! 809: _startStopDisabled = true; ! 810: result = kIOReturnSuccess; ! 811: } ! 812: } ! 813: } ! 814: break; ! 815: ! 816: default: /* we don't do other states */ ! 817: result = kIOReturnSuccess; ! 818: break; ! 819: ! 820: } ! 821: ! 822: return(result); ! 823: } ! 824: ! 825: // ********************************************************************************** ! 826: /* We get called here as an advisory that the power state will change. If we are coming up ! 827: * from the all-off state, remember to restore the electronics state when we later power up. ! 828: * If we are powering-down the electronics, save any required state now. ! 829: */ ! 830: IOReturn ! 831: IOSCSIHDDrive::powerStateWillChangeTo(unsigned long,unsigned long stateOrdinal,IOService *) ! 832: { ! 833: if ((pm_vars->myCurrentState == kAllOff) && ! 834: (stateOrdinal > kAllOff)) { /* we're powering up from all-off */ ! 835: _restoreState = true; ! 836: } ! 837: ! 838: if ((stateOrdinal == kAllOff) && ! 839: (pm_vars->myCurrentState > kAllOff)) { /* we're powering down to all-off */ ! 840: saveElectronicsState(); ! 841: } ! 842: ! 843: return(IOPMAckImplied); ! 844: } ! 845: ! 846: // ********************************************************************************** ! 847: /* We get called here when power has successfully changed state. */ ! 848: IOReturn ! 849: IOSCSIHDDrive::powerStateDidChangeTo(unsigned long,unsigned long stateOrdinal,IOService*) ! 850: { ! 851: IOReturn result; ! 852: ! 853: /* If we must restore the electronics state, do it now. */ ! 854: ! 855: if (_restoreState) { ! 856: result = restoreElectronicsState(); ! 857: _restoreState = false; ! 858: } ! 859: ! 860: /* If we have powered up into a state that can execute commands, release any queued ! 861: * requests that were awaiting the power change. ! 862: */ ! 863: ! 864: if (stateOrdinal > kAllOff) { ! 865: dequeueCommands(); ! 866: } ! 867: ! 868: return IOPMAckImplied; ! 869: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.