2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * IOATAHDPower.cpp - Power management support.
29 #include <IOKit/storage/ata/IOATAHDDrive.h>
30 #include <IOKit/IOBufferMemoryDescriptor.h>
31 #define super IOService
33 //---------------------------------------------------------------------------
34 // Inform the policy-maker that an ATA hard-drive is capable of two power
35 // states (a simplification). The ourPowerStates[] array encodes information
38 #define kIOATAPowerStates 2
40 static IOPMPowerState ourPowerStates
[kIOATAPowerStates
] =
42 {1,0,0,0,0,0,0,0,0,0,0,0},
43 {1, IOPMDeviceUsable
, IOPMPowerOn
, IOPMPowerOn
, 0,0,0,0,0,0,0,0}
46 static const char * ataPowerStateNames
[] =
54 //---------------------------------------------------------------------------
55 // Maps the power state ordinal, used by our policy maker,
56 // to an ATA power states.
59 IOATAHDDrive::getATAPowerStateForStateOrdinal(UInt32 stateOrdinal
)
61 IOATAPowerState stateOrdinalToATAPowerState
[kIOATAPowerStates
] =
63 kIOATAPowerStateStandby
, /* state 0 */
64 kIOATAPowerStateActive
, /* state 1 */
67 if (stateOrdinal
> (kIOATAPowerStates
- 1))
68 stateOrdinal
= (kIOATAPowerStates
- 1);
70 return stateOrdinalToATAPowerState
[stateOrdinal
];
73 //---------------------------------------------------------------------------
74 // Register the driver with our policy-maker (also in the same class).
77 IOATAHDDrive::initForPM()
79 registerPowerDriver(this, ourPowerStates
, kIOATAPowerStates
);
83 //---------------------------------------------------------------------------
84 // Policy-maker code which intercepts kPMMinutesToSpinDown settings
85 // and then call setIdleTimerPeriod() to adjust the idle timer.
88 IOATAHDDrive::setAggressiveness(UInt32 type
, UInt32 minutes
)
90 if (type
== kPMMinutesToSpinDown
)
92 // IOLog("IOATAHDDrive: setting idle timer to %ld min\n", minutes);
93 setIdleTimerPeriod(minutes
* 60); // argument is in seconds
95 return super::setAggressiveness(type
, minutes
);
98 //---------------------------------------------------------------------------
99 // Policy-maker calls this function to find find out what power state
100 // the device is in, given the current power domain state.
102 // We respond to this message in the following fashion:
103 // If domain power is off, drive must be off.
104 // If domain power is on, return _currentATAPowerState.
107 IOATAHDDrive::initialPowerStateForDomainState(IOPMPowerFlags domainState
)
111 _cmdGate
->runAction((IOCommandGate::Action
)
112 &IOATAHDDrive::sHandleInitialPowerStateForDomainState
,
113 (void *) domainState
,
119 //---------------------------------------------------------------------------
120 // Static member function called by the IOCommandGate to translate
121 // initialPowerStateForDomainState() calls to the synchronized
122 // handleInitialPowerStateForDomainState() call.
125 IOATAHDDrive::sHandleInitialPowerStateForDomainState(IOATAHDDrive
* self
,
126 IOPMPowerFlags domainState
,
129 *state
= self
->handleInitialPowerStateForDomainState(domainState
);
132 //---------------------------------------------------------------------------
133 // The synchronized form of initialPowerStateForDomainState().
136 IOATAHDDrive::handleInitialPowerStateForDomainState(IOPMPowerFlags domainState
)
138 if (domainState
& IOPMPowerOn
)
139 return ((_currentATAPowerState
== kIOATAPowerStateActive
) ? 1 : 0);
144 //---------------------------------------------------------------------------
145 // Set/Change the power state of the ATA hard-drive.
148 IOATAHDDrive::setPowerState(UInt32 powerStateOrdinal
,
149 IOService
* whatDevice
)
153 // Power state transitions are synchronized by our IOCommandGate object,
154 // (attached to the ATA controller's workloop).
156 _cmdGate
->runAction((IOCommandGate::Action
)
157 &IOATAHDDrive::sHandleSetPowerState
,
158 (void *) powerStateOrdinal
,
162 kprintf("%s::%s(0x%08lx, 0x%08lx) returns 0x%08lx\n",getName(), __FUNCTION__
,powerStateOrdinal
, whatDevice
, ret
);
166 //---------------------------------------------------------------------------
167 // Static member function called by the IOCommandGate to translate
168 // setPowerState() calls to the synchronized handleSetPowerState() call.
171 IOATAHDDrive::sHandleSetPowerState(IOATAHDDrive
* self
,
172 UInt32 powerStateOrdinal
,
173 IOService
* whatDevice
,
174 IOReturn
* handlerReturn
)
176 *handlerReturn
= self
->handleSetPowerState(powerStateOrdinal
, whatDevice
);
179 //---------------------------------------------------------------------------
180 // A static member function that calls handleStandbyStateTransition().
181 // This function can be registered as the completion handler for an
185 IOATAHDDrive::sHandleStandbyStateTransition(IOATAHDDrive
* self
,
188 UInt64 bytesTransferred
)
190 self
->handleStandbyStateTransition((UInt32
) stage
, status
);
193 //---------------------------------------------------------------------------
194 // A static member function that calls handleActiveStateTransition().
195 // This function can be registered as the completion handler for an
199 IOATAHDDrive::sHandleActiveStateTransition(IOATAHDDrive
* self
,
202 UInt64 bytesTransferred
)
204 self
->handleActiveStateTransition((UInt32
) stage
, status
);
207 //---------------------------------------------------------------------------
208 // A static member function that calls handleIdleStateTransition().
209 // This function can be registered as the completion handler for an
213 IOATAHDDrive::sHandleIdleStateTransition(IOATAHDDrive
* self
,
216 UInt64 bytesTransferred
)
218 self
->handleIdleStateTransition((UInt32
) stage
, status
);
221 //---------------------------------------------------------------------------
222 // A static member function that calls handleSleepStateTransition().
223 // This function can be registered as the completion handler for an
227 IOATAHDDrive::sHandleSleepStateTransition(IOATAHDDrive
* self
,
230 UInt64 bytesTransferred
)
232 self
->handleSleepStateTransition((UInt32
) stage
, status
);
235 //---------------------------------------------------------------------------
236 // IOATAHDDrive provide a default implementation for handleSetPowerState().
237 // This (IOCommandGate synchronized) function is called by our policy-maker.
240 IOATAHDDrive::handleSetPowerState(UInt32 powerStateOrdinal
,
241 IOService
* whatDevice
)
243 IOATAPowerState ataPowerState
=
244 getATAPowerStateForStateOrdinal(powerStateOrdinal
);
247 kprintf("%s::%s %d (%d) %lx\n", getName(), __FUNCTION__
, ataPowerState
,
248 _currentATAPowerState
, (UInt32
) whatDevice
);
251 // We cannot change power state while we are still transitioning
252 // the power state from a previous state change request.
254 if (_powerStateChanging
) {
255 kprintf("%s::%s overlap detected\n",getName(), __FUNCTION__
);
256 IOLog("%s::%s overlap detected\n",getName(), __FUNCTION__
);
257 return IOPMAckImplied
; // FIXME - should return something else
260 // If we are already in the desired power state, return success.
262 if (ataPowerState
== _currentATAPowerState
) {
263 kprintf("%s::%s already in the given sate\n",getName(), __FUNCTION__
);
264 return IOPMAckImplied
;
267 _powerStateChanging
= true;
268 _setPowerAckPending
= true;
270 startATAPowerStateTransition(ataPowerState
);
272 // Return the number of microseconds it may take for the drive to
273 // complete the power state transition. Report 100 seconds max.
275 return (100 * 1000 * 1000);
278 //---------------------------------------------------------------------------
279 // Start transitioning into the specified ATA power state.
282 IOATAHDDrive::startATAPowerStateTransition(IOATAPowerState ataPowerState
)
284 _proposedATAPowerState
= ataPowerState
;
286 switch (ataPowerState
)
288 case kIOATAPowerStateStandby
:
290 // Register sHandleStandbyStateTransition to be called when the
291 // IOATADevice becomes idle. Or, if the device is already idle,
292 // the function will be called immediately.
294 _ataDevice
->notifyIdle(this,
295 (CallbackFn
) &IOATAHDDrive::sHandleStandbyStateTransition
,
296 (void *) kIOATAStandbyStage0
);
299 case kIOATAPowerStateActive
:
301 // Call sHandleActiveStateTransition and begin processing
304 sHandleActiveStateTransition(this,
305 (void *) kIOATAActiveStage0
,
311 IOPanic("IOATAHDDrive::startATAPowerStateTransition\n");
315 //---------------------------------------------------------------------------
316 // Abort the current state transition and retore the current state.
319 IOATAHDDrive::abortATAPowerStateTransition()
321 // Do not ack the setPowerState request if the power state
322 // transition is aborted.
324 _setPowerAckPending
= false;
326 // Transition to the previous state. However, if we are unable
327 // to transition to the previous state, then give up.
329 if (_proposedATAPowerState
!= _currentATAPowerState
)
331 startATAPowerStateTransition(_currentATAPowerState
);
335 IOLog("%s::%s Unable to revert to previous state\n",
336 getName(), __FUNCTION__
);
338 endATAPowerStateTransition(_currentATAPowerState
);
342 //---------------------------------------------------------------------------
343 // Complete the ATA power state transition.
346 IOATAHDDrive::endATAPowerStateTransition(IOATAPowerState ataPowerState
)
348 _currentATAPowerState
= ataPowerState
;
350 // In the future, a NACK response may be sent to indicate state change
353 if (_setPowerAckPending
) {
354 thread_call_func(acknowledgeATAPowerStateTransition
, this, 1);
355 //acknowledgeATAPowerStateTransition(this, NULL);
358 //kprintf("%s::%s %s \n", getName(), __FUNCTION__, ataPowerStateNames[_currentATAPowerState]);
361 //---------------------------------------------------------------------------
362 // To avoid deadlocks between the PM and the IOATAHDDrive workloop the
363 // actual acknolegment wuns on a different thread.
366 IOATAHDDrive::acknowledgeATAPowerStateTransition(void *castMeToIOATAHDDrive
, void*)
368 IOATAHDDrive
*myThis
= OSDynamicCast(IOATAHDDrive
, (OSObject
*)castMeToIOATAHDDrive
);
371 myThis
->_powerStateChanging
= false;
372 myThis
->acknowledgeSetPowerState();
376 //---------------------------------------------------------------------------
377 // A function called by startATAPowerStateTransition() to transition the
378 // drive into the STANDBY state. It may also be called by the IOATACommand
379 // completion handler to advance to the next stage of the state transition.
381 // stage: The current stage in the state transition.
382 // status: The status from the previous stage.
385 IOATAHDDrive::handleStandbyStateTransition(UInt32 stage
, IOReturn status
)
387 bool doAbort
= false;
388 IOATACommand
* cmd
= 0;
389 IOStorageCompletion completion
;
391 // IOLog("IOATAHDDrive::handleStandbyStateTransition %ld %x\n", stage, status);
395 case kIOATAStandbyStage0
:
396 // Device is idle. Hold the normal queue.
397 _ataDevice
->holdQueue(kATAQTypeNormalQ
);
398 status
= kIOReturnSuccess
;
400 case kIOATAStandbyStage1
:
402 if ( reportATADeviceType() == kATADeviceATA
)
404 // Issue a flush cache command.
406 if ((cmd
= ataCommandFlushCache()) == 0)
408 doAbort
= true; break;
410 cmd
->setQueueInfo(kATAQTypeBypassQ
);
412 // Must issue an async command here, otherwise the thread will
415 completion
.target
= this;
416 completion
.action
= sHandleStandbyStateTransition
;
417 completion
.parameter
= (void *) kIOATAStandbyStage2
;
421 60000, /* 1 min timeout */
422 0); /* no retry for flush cache command */
426 case kIOATAStandbyStage2
:
428 if ( reportATADeviceType() == kATADeviceATA
)
430 // Issue an ATA STANDBY IMMEDIATE command. We ignore the
431 // status from the flush cache command since not all drives
434 if ((cmd
= ataCommandStandby()) == 0)
436 doAbort
= true; break;
438 cmd
->setQueueInfo(kATAQTypeBypassQ
);
440 // Must issue an async command here, otherwise the thread will
443 completion
.target
= this;
444 completion
.action
= sHandleStandbyStateTransition
;
445 completion
.parameter
= (void *) kIOATAStandbyStage3
;
449 30000, /* 30 sec timeout */
450 0); /* no retry for STANDBY command */
454 case kIOATAStandbyStage3
:
455 // Final stage in the STANDBY state transition.
457 if (status
!= kIOReturnSuccess
) {
458 // STANDBY command failed, abort the state transition.
459 doAbort
= true; break;
462 endATAPowerStateTransition(kIOATAPowerStateStandby
);
468 IOLog("%s::%s unknown stage %ld\n", getName(), __FUNCTION__
, stage
);
471 if (cmd
) cmd
->release();
474 abortATAPowerStateTransition();
477 //---------------------------------------------------------------------------
478 // Called by startATAPowerStateTransition() to transition the drive into
479 // the ACTIVE state. It may also be called by the IOATACommand completion
480 // handler to advance to the next stage of the state transition.
482 // stage: The current stage in the state transition.
483 // status: The status from the previous stage.
486 IOATAHDDrive::handleActiveStateTransition(UInt32 stage
, IOReturn status
)
488 IOStorageCompletion completion
;
491 IOLog("IOATAHDDrive::handleActiveStateTransition %p %ld %x\n",
492 this, stage
, status
);
497 case kIOATAActiveStage0
:
498 kprintf("kIOATAActiveStage0 current power state is sleep %d\n", _currentATAPowerState
== kIOATAPowerStateSleep
);
500 #if 0 // This des not work.
501 // Issue a software reset. Only necessary if the current
502 // state is kATAPowerStateSleep.
504 // if (_currentATAPowerState == kIOATAPowerStateSleep) // Marco: Commenting because it looks that the power state is wrong
506 kprintf("Attempting to reset on kIOATAActiveStage0\n");
511 case kIOATAActiveStage1
:
512 kprintf("kIOATAActiveStage1\n");
514 if ( reportATADeviceType() == kATADeviceATA
)
516 // Spin up the drive before releasing the queue. A media
517 // access command is issued with an extra long timeout.
519 completion
.target
= this;
520 completion
.action
= sHandleActiveStateTransition
,
521 completion
.parameter
= (void *) kIOATAActiveStage2
;
523 readSector(completion
);
527 case kIOATAActiveStage2
:
528 kprintf("kIOATAActiveStage2\n");
529 // Release the normal queue.
530 _ataDevice
->releaseQueue(kATAQTypeNormalQ
);
532 case kIOATAActiveStage3
:
533 kprintf("kIOATAActiveStage3\n");
534 // Finalize ACTIVE state transition.
535 endATAPowerStateTransition(kIOATAPowerStateActive
);
539 IOLog("%s::%s unknown stage %ld\n", getName(), __FUNCTION__
, stage
);
543 //---------------------------------------------------------------------------
544 // Unimplemented state transition handlers.
547 IOATAHDDrive::handleIdleStateTransition(UInt32 stage
, IOReturn status
)
549 IOLog("%s::%s unimplemented!\n", getName(), __FUNCTION__
);
553 IOATAHDDrive::handleSleepStateTransition(UInt32 stage
, IOReturn status
)
555 IOLog("%s::%s unimplemented!\n", getName(), __FUNCTION__
);
558 //---------------------------------------------------------------------------
559 // Read a single sector from the disk. The data read is discarded.
561 IOReturn
IOATAHDDrive::readSector(IOStorageCompletion completion
,
564 IOBufferMemoryDescriptor
* desc
;
568 desc
= IOBufferMemoryDescriptor::withCapacity(kIOATASectorSize
,
571 return kIOReturnNoMemory
;
573 desc
->setLength(desc
->getCapacity());
575 cmd
= ataCommandReadWrite(desc
, sector
, 1);
577 return kIOReturnNoMemory
;
579 cmd
->setQueueInfo(kATAQTypeBypassQ
);
581 ret
= asyncExecute(cmd
, completion
, 60000);
583 // Don't worry, asyncExecute has retained both the command
584 // and the memory descriptor object.
589 return kIOReturnSuccess
;