]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOATAHDDrive/IOATAHDPower.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Families / IOATAHDDrive / IOATAHDPower.cpp
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 * IOATAHDPower.cpp - Power management support.
24 *
25 * HISTORY
26 *
27 */
28
29 #include <IOKit/storage/ata/IOATAHDDrive.h>
30 #include <IOKit/IOBufferMemoryDescriptor.h>
31 #define super IOService
32
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
36 // about each state.
37
38 #define kIOATAPowerStates 2
39
40 static IOPMPowerState ourPowerStates[kIOATAPowerStates] =
41 {
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}
44 };
45
46 static const char * ataPowerStateNames[] =
47 {
48 "Sleep",
49 "Standby",
50 "Idle",
51 "Active"
52 };
53
54 //---------------------------------------------------------------------------
55 // Maps the power state ordinal, used by our policy maker,
56 // to an ATA power states.
57
58 IOATAPowerState
59 IOATAHDDrive::getATAPowerStateForStateOrdinal(UInt32 stateOrdinal)
60 {
61 IOATAPowerState stateOrdinalToATAPowerState[kIOATAPowerStates] =
62 {
63 kIOATAPowerStateStandby, /* state 0 */
64 kIOATAPowerStateActive, /* state 1 */
65 };
66
67 if (stateOrdinal > (kIOATAPowerStates - 1))
68 stateOrdinal = (kIOATAPowerStates - 1);
69
70 return stateOrdinalToATAPowerState[stateOrdinal];
71 }
72
73 //---------------------------------------------------------------------------
74 // Register the driver with our policy-maker (also in the same class).
75
76 void
77 IOATAHDDrive::initForPM()
78 {
79 registerPowerDriver(this, ourPowerStates, kIOATAPowerStates);
80 _pmReady = true;
81 }
82
83 //---------------------------------------------------------------------------
84 // Policy-maker code which intercepts kPMMinutesToSpinDown settings
85 // and then call setIdleTimerPeriod() to adjust the idle timer.
86
87 IOReturn
88 IOATAHDDrive::setAggressiveness(UInt32 type, UInt32 minutes)
89 {
90 if (type == kPMMinutesToSpinDown)
91 {
92 // IOLog("IOATAHDDrive: setting idle timer to %ld min\n", minutes);
93 setIdleTimerPeriod(minutes * 60); // argument is in seconds
94 }
95 return super::setAggressiveness(type, minutes);
96 }
97
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.
101 //
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.
105
106 UInt32
107 IOATAHDDrive::initialPowerStateForDomainState(IOPMPowerFlags domainState)
108 {
109 UInt32 ret;
110
111 _cmdGate->runAction((IOCommandGate::Action)
112 &IOATAHDDrive::sHandleInitialPowerStateForDomainState,
113 (void *) domainState,
114 (void *) &ret);
115
116 return ret;
117 }
118
119 //---------------------------------------------------------------------------
120 // Static member function called by the IOCommandGate to translate
121 // initialPowerStateForDomainState() calls to the synchronized
122 // handleInitialPowerStateForDomainState() call.
123
124 void
125 IOATAHDDrive::sHandleInitialPowerStateForDomainState(IOATAHDDrive * self,
126 IOPMPowerFlags domainState,
127 UInt32 * state)
128 {
129 *state = self->handleInitialPowerStateForDomainState(domainState);
130 }
131
132 //---------------------------------------------------------------------------
133 // The synchronized form of initialPowerStateForDomainState().
134
135 UInt32
136 IOATAHDDrive::handleInitialPowerStateForDomainState(IOPMPowerFlags domainState)
137 {
138 if (domainState & IOPMPowerOn)
139 return ((_currentATAPowerState == kIOATAPowerStateActive) ? 1 : 0);
140 else
141 return 0;
142 }
143
144 //---------------------------------------------------------------------------
145 // Set/Change the power state of the ATA hard-drive.
146
147 IOReturn
148 IOATAHDDrive::setPowerState(UInt32 powerStateOrdinal,
149 IOService * whatDevice)
150 {
151 IOReturn ret;
152
153 // Power state transitions are synchronized by our IOCommandGate object,
154 // (attached to the ATA controller's workloop).
155
156 _cmdGate->runAction((IOCommandGate::Action)
157 &IOATAHDDrive::sHandleSetPowerState,
158 (void *) powerStateOrdinal,
159 (void *) whatDevice,
160 (void *) &ret);
161
162 kprintf("%s::%s(0x%08lx, 0x%08lx) returns 0x%08lx\n",getName(), __FUNCTION__,powerStateOrdinal, whatDevice, ret);
163 return ret;
164 }
165
166 //---------------------------------------------------------------------------
167 // Static member function called by the IOCommandGate to translate
168 // setPowerState() calls to the synchronized handleSetPowerState() call.
169
170 void
171 IOATAHDDrive::sHandleSetPowerState(IOATAHDDrive * self,
172 UInt32 powerStateOrdinal,
173 IOService * whatDevice,
174 IOReturn * handlerReturn)
175 {
176 *handlerReturn = self->handleSetPowerState(powerStateOrdinal, whatDevice);
177 }
178
179 //---------------------------------------------------------------------------
180 // A static member function that calls handleStandbyStateTransition().
181 // This function can be registered as the completion handler for an
182 // IOATACommand.
183
184 void
185 IOATAHDDrive::sHandleStandbyStateTransition(IOATAHDDrive * self,
186 void * stage,
187 IOReturn status,
188 UInt64 bytesTransferred)
189 {
190 self->handleStandbyStateTransition((UInt32) stage, status);
191 }
192
193 //---------------------------------------------------------------------------
194 // A static member function that calls handleActiveStateTransition().
195 // This function can be registered as the completion handler for an
196 // IOATACommand.
197
198 void
199 IOATAHDDrive::sHandleActiveStateTransition(IOATAHDDrive * self,
200 void * stage,
201 IOReturn status,
202 UInt64 bytesTransferred)
203 {
204 self->handleActiveStateTransition((UInt32) stage, status);
205 }
206
207 //---------------------------------------------------------------------------
208 // A static member function that calls handleIdleStateTransition().
209 // This function can be registered as the completion handler for an
210 // IOATACommand.
211
212 void
213 IOATAHDDrive::sHandleIdleStateTransition(IOATAHDDrive * self,
214 void * stage,
215 IOReturn status,
216 UInt64 bytesTransferred)
217 {
218 self->handleIdleStateTransition((UInt32) stage, status);
219 }
220
221 //---------------------------------------------------------------------------
222 // A static member function that calls handleSleepStateTransition().
223 // This function can be registered as the completion handler for an
224 // IOATACommand.
225
226 void
227 IOATAHDDrive::sHandleSleepStateTransition(IOATAHDDrive * self,
228 void * stage,
229 IOReturn status,
230 UInt64 bytesTransferred)
231 {
232 self->handleSleepStateTransition((UInt32) stage, status);
233 }
234
235 //---------------------------------------------------------------------------
236 // IOATAHDDrive provide a default implementation for handleSetPowerState().
237 // This (IOCommandGate synchronized) function is called by our policy-maker.
238
239 IOReturn
240 IOATAHDDrive::handleSetPowerState(UInt32 powerStateOrdinal,
241 IOService * whatDevice)
242 {
243 IOATAPowerState ataPowerState =
244 getATAPowerStateForStateOrdinal(powerStateOrdinal);
245
246 #if 1
247 kprintf("%s::%s %d (%d) %lx\n", getName(), __FUNCTION__, ataPowerState,
248 _currentATAPowerState, (UInt32) whatDevice);
249 #endif
250
251 // We cannot change power state while we are still transitioning
252 // the power state from a previous state change request.
253
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
258 }
259
260 // If we are already in the desired power state, return success.
261
262 if (ataPowerState == _currentATAPowerState) {
263 kprintf("%s::%s already in the given sate\n",getName(), __FUNCTION__);
264 return IOPMAckImplied;
265 }
266
267 _powerStateChanging = true;
268 _setPowerAckPending = true;
269
270 startATAPowerStateTransition(ataPowerState);
271
272 // Return the number of microseconds it may take for the drive to
273 // complete the power state transition. Report 100 seconds max.
274
275 return (100 * 1000 * 1000);
276 }
277
278 //---------------------------------------------------------------------------
279 // Start transitioning into the specified ATA power state.
280
281 void
282 IOATAHDDrive::startATAPowerStateTransition(IOATAPowerState ataPowerState)
283 {
284 _proposedATAPowerState = ataPowerState;
285
286 switch (ataPowerState)
287 {
288 case kIOATAPowerStateStandby:
289
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.
293
294 _ataDevice->notifyIdle(this,
295 (CallbackFn) &IOATAHDDrive::sHandleStandbyStateTransition,
296 (void *) kIOATAStandbyStage0);
297 break;
298
299 case kIOATAPowerStateActive:
300
301 // Call sHandleActiveStateTransition and begin processing
302 // at stage 0.
303
304 sHandleActiveStateTransition(this,
305 (void *) kIOATAActiveStage0,
306 kIOReturnSuccess,
307 0);
308 break;
309
310 default:
311 IOPanic("IOATAHDDrive::startATAPowerStateTransition\n");
312 }
313 }
314
315 //---------------------------------------------------------------------------
316 // Abort the current state transition and retore the current state.
317
318 void
319 IOATAHDDrive::abortATAPowerStateTransition()
320 {
321 // Do not ack the setPowerState request if the power state
322 // transition is aborted.
323
324 _setPowerAckPending = false;
325
326 // Transition to the previous state. However, if we are unable
327 // to transition to the previous state, then give up.
328
329 if (_proposedATAPowerState != _currentATAPowerState)
330 {
331 startATAPowerStateTransition(_currentATAPowerState);
332 }
333 else
334 {
335 IOLog("%s::%s Unable to revert to previous state\n",
336 getName(), __FUNCTION__);
337
338 endATAPowerStateTransition(_currentATAPowerState);
339 }
340 }
341
342 //---------------------------------------------------------------------------
343 // Complete the ATA power state transition.
344
345 void
346 IOATAHDDrive::endATAPowerStateTransition(IOATAPowerState ataPowerState)
347 {
348 _currentATAPowerState = ataPowerState;
349
350 // In the future, a NACK response may be sent to indicate state change
351 // failure.
352
353 if (_setPowerAckPending) {
354 thread_call_func(acknowledgeATAPowerStateTransition, this, 1);
355 //acknowledgeATAPowerStateTransition(this, NULL);
356 }
357
358 //kprintf("%s::%s %s \n", getName(), __FUNCTION__, ataPowerStateNames[_currentATAPowerState]);
359 }
360
361 //---------------------------------------------------------------------------
362 // To avoid deadlocks between the PM and the IOATAHDDrive workloop the
363 // actual acknolegment wuns on a different thread.
364
365 /* static */ void
366 IOATAHDDrive::acknowledgeATAPowerStateTransition(void *castMeToIOATAHDDrive, void*)
367 {
368 IOATAHDDrive *myThis = OSDynamicCast(IOATAHDDrive, (OSObject*)castMeToIOATAHDDrive);
369
370 if (myThis !=NULL) {
371 myThis->_powerStateChanging = false;
372 myThis->acknowledgeSetPowerState();
373 }
374 }
375
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.
380 //
381 // stage: The current stage in the state transition.
382 // status: The status from the previous stage.
383
384 void
385 IOATAHDDrive::handleStandbyStateTransition(UInt32 stage, IOReturn status)
386 {
387 bool doAbort = false;
388 IOATACommand * cmd = 0;
389 IOStorageCompletion completion;
390
391 // IOLog("IOATAHDDrive::handleStandbyStateTransition %ld %x\n", stage, status);
392
393 switch (stage)
394 {
395 case kIOATAStandbyStage0:
396 // Device is idle. Hold the normal queue.
397 _ataDevice->holdQueue(kATAQTypeNormalQ);
398 status = kIOReturnSuccess;
399
400 case kIOATAStandbyStage1:
401
402 if ( reportATADeviceType() == kATADeviceATA )
403 {
404 // Issue a flush cache command.
405
406 if ((cmd = ataCommandFlushCache()) == 0)
407 {
408 doAbort = true; break;
409 }
410 cmd->setQueueInfo(kATAQTypeBypassQ);
411
412 // Must issue an async command here, otherwise the thread will
413 // deadlock.
414
415 completion.target = this;
416 completion.action = sHandleStandbyStateTransition;
417 completion.parameter = (void *) kIOATAStandbyStage2;
418
419 asyncExecute(cmd,
420 completion,
421 60000, /* 1 min timeout */
422 0); /* no retry for flush cache command */
423 break;
424 }
425
426 case kIOATAStandbyStage2:
427
428 if ( reportATADeviceType() == kATADeviceATA )
429 {
430 // Issue an ATA STANDBY IMMEDIATE command. We ignore the
431 // status from the flush cache command since not all drives
432 // implement this.
433
434 if ((cmd = ataCommandStandby()) == 0)
435 {
436 doAbort = true; break;
437 }
438 cmd->setQueueInfo(kATAQTypeBypassQ);
439
440 // Must issue an async command here, otherwise the thread will
441 // deadlock.
442
443 completion.target = this;
444 completion.action = sHandleStandbyStateTransition;
445 completion.parameter = (void *) kIOATAStandbyStage3;
446
447 asyncExecute(cmd,
448 completion,
449 30000, /* 30 sec timeout */
450 0); /* no retry for STANDBY command */
451 break;
452 }
453
454 case kIOATAStandbyStage3:
455 // Final stage in the STANDBY state transition.
456
457 if (status != kIOReturnSuccess) {
458 // STANDBY command failed, abort the state transition.
459 doAbort = true; break;
460 }
461 else {
462 endATAPowerStateTransition(kIOATAPowerStateStandby);
463 }
464
465 break;
466
467 default:
468 IOLog("%s::%s unknown stage %ld\n", getName(), __FUNCTION__, stage);
469 }
470
471 if (cmd) cmd->release();
472
473 if (doAbort)
474 abortATAPowerStateTransition();
475 }
476
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.
481 //
482 // stage: The current stage in the state transition.
483 // status: The status from the previous stage.
484
485 void
486 IOATAHDDrive::handleActiveStateTransition(UInt32 stage, IOReturn status)
487 {
488 IOStorageCompletion completion;
489
490 #if 0
491 IOLog("IOATAHDDrive::handleActiveStateTransition %p %ld %x\n",
492 this, stage, status);
493 #endif
494
495 switch (stage)
496 {
497 case kIOATAActiveStage0:
498 kprintf("kIOATAActiveStage0 current power state is sleep %d\n", _currentATAPowerState == kIOATAPowerStateSleep);
499
500 #if 0 // This des not work.
501 // Issue a software reset. Only necessary if the current
502 // state is kATAPowerStateSleep.
503
504 // if (_currentATAPowerState == kIOATAPowerStateSleep) // Marco: Commenting because it looks that the power state is wrong
505 {
506 kprintf("Attempting to reset on kIOATAActiveStage0\n");
507 _ataDevice->reset();
508 }
509 #endif
510
511 case kIOATAActiveStage1:
512 kprintf("kIOATAActiveStage1\n");
513
514 if ( reportATADeviceType() == kATADeviceATA )
515 {
516 // Spin up the drive before releasing the queue. A media
517 // access command is issued with an extra long timeout.
518
519 completion.target = this;
520 completion.action = sHandleActiveStateTransition,
521 completion.parameter = (void *) kIOATAActiveStage2;
522
523 readSector(completion);
524 break;
525 }
526
527 case kIOATAActiveStage2:
528 kprintf("kIOATAActiveStage2\n");
529 // Release the normal queue.
530 _ataDevice->releaseQueue(kATAQTypeNormalQ);
531
532 case kIOATAActiveStage3:
533 kprintf("kIOATAActiveStage3\n");
534 // Finalize ACTIVE state transition.
535 endATAPowerStateTransition(kIOATAPowerStateActive);
536 break;
537
538 default:
539 IOLog("%s::%s unknown stage %ld\n", getName(), __FUNCTION__, stage);
540 }
541 }
542
543 //---------------------------------------------------------------------------
544 // Unimplemented state transition handlers.
545
546 void
547 IOATAHDDrive::handleIdleStateTransition(UInt32 stage, IOReturn status)
548 {
549 IOLog("%s::%s unimplemented!\n", getName(), __FUNCTION__);
550 }
551
552 void
553 IOATAHDDrive::handleSleepStateTransition(UInt32 stage, IOReturn status)
554 {
555 IOLog("%s::%s unimplemented!\n", getName(), __FUNCTION__);
556 }
557
558 //---------------------------------------------------------------------------
559 // Read a single sector from the disk. The data read is discarded.
560
561 IOReturn IOATAHDDrive::readSector(IOStorageCompletion completion,
562 UInt32 sector = 0)
563 {
564 IOBufferMemoryDescriptor * desc;
565 IOATACommand * cmd;
566 IOReturn ret;
567
568 desc = IOBufferMemoryDescriptor::withCapacity(kIOATASectorSize,
569 kIODirectionIn);
570 if (!desc)
571 return kIOReturnNoMemory;
572
573 desc->setLength(desc->getCapacity());
574
575 cmd = ataCommandReadWrite(desc, sector, 1);
576 if (!cmd)
577 return kIOReturnNoMemory;
578
579 cmd->setQueueInfo(kATAQTypeBypassQ);
580
581 ret = asyncExecute(cmd, completion, 60000);
582
583 // Don't worry, asyncExecute has retained both the command
584 // and the memory descriptor object.
585
586 desc->release();
587 cmd->release();
588
589 return kIOReturnSuccess;
590 }