|
|
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.