1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 2010
4
5 Module Name:
6
7 power.c
8
9 Abstract:
10
11 SCSI class driver routines
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #ifndef __REACTOS__
25 #include "stddef.h"
26 #include "ntddk.h"
27 #include "scsi.h"
28 #endif
29 #include "classp.h"
30
31 // #include <stdarg.h> __REACTOS__
32
33 #ifdef DEBUG_USE_WPP
34 #include "power.tmh"
35 #endif
36
37 #define CLASS_TAG_POWER 'WLcS'
38
39 // constants for power transition process. (UNIT: seconds)
40 #define DEFAULT_POWER_IRP_TIMEOUT_VALUE 10*60
41 #define TIME_LEFT_FOR_LOWER_DRIVERS 30
42 #define TIME_LEFT_FOR_UPPER_DRIVERS 5
43 #define DEFAULT_IO_TIMEOUT_VALUE 10
44 #define MINIMUM_STOP_UNIT_TIMEOUT_VALUE 2
45
46 //
47 // MINIMAL value is one that has some slack and is the value to use
48 // if there is a shortened POWER IRP timeout value. If time remaining
49 // is less than MINIMAL, we will use the MINIMUM value. Both values
50 // are in the same unit as above (seconds).
51 //
52 #define MINIMAL_START_UNIT_TIMEOUT_VALUE 60
53 #define MINIMUM_START_UNIT_TIMEOUT_VALUE 30
54
55 // PoQueryWatchdogTime was introduced in Windows 7.
56 // Returns TRUE if a watchdog-enabled power IRP is found, otherwise FALSE.
57 #if (NTDDI_VERSION < NTDDI_WIN7)
58 #define PoQueryWatchdogTime(A, B) FALSE
59 #endif
60
61 IO_COMPLETION_ROUTINE ClasspPowerDownCompletion;
62
63 IO_COMPLETION_ROUTINE ClasspPowerUpCompletion;
64
65 IO_COMPLETION_ROUTINE ClasspStartNextPowerIrpCompletion;
66 IO_COMPLETION_ROUTINE ClasspDeviceLockFailurePowerIrpCompletion;
67
68 NTSTATUS
69 ClasspPowerHandler(
70 IN PDEVICE_OBJECT DeviceObject,
71 IN PIRP Irp,
72 IN CLASS_POWER_OPTIONS Options
73 );
74
75 VOID
76 RetryPowerRequest(
77 PDEVICE_OBJECT DeviceObject,
78 PIRP Irp,
79 PCLASS_POWER_CONTEXT Context
80 );
81
82 #ifdef ALLOC_PRAGMA
83 #pragma alloc_text(PAGE, ClasspPowerSettingCallback)
84 #endif
85
86 /*++////////////////////////////////////////////////////////////////////////////
87
88 ClassDispatchPower()
89
90 Routine Description:
91
92 This routine acquires the removelock for the irp and then calls the
93 appropriate power callback.
94
95 Arguments:
96
97 DeviceObject -
98 Irp -
99
100 Return Value:
101
102 --*/
103 NTSTATUS
104 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClassDispatchPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)105 ClassDispatchPower(
106 IN PDEVICE_OBJECT DeviceObject,
107 IN PIRP Irp
108 )
109 {
110 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
111 ULONG isRemoved;
112
113 //
114 // NOTE: This code may be called at PASSIVE or DISPATCH, depending
115 // upon the device object it is being called for.
116 // don't do anything that would break under either circumstance.
117 //
118
119 //
120 // If device is added but not yet started, we need to send the Power
121 // request down the stack. If device is started and then stopped,
122 // we have enough state to process the power request.
123 //
124
125 if (!commonExtension->IsInitialized) {
126
127 PoStartNextPowerIrp(Irp);
128 IoSkipCurrentIrpStackLocation(Irp);
129 return PoCallDriver(commonExtension->LowerDeviceObject, Irp);
130 }
131
132 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
133
134 if (isRemoved) {
135 ClassReleaseRemoveLock(DeviceObject, Irp);
136 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
137 PoStartNextPowerIrp(Irp);
138 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
139 return STATUS_DEVICE_DOES_NOT_EXIST;
140 }
141
142 return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
143 } // end ClassDispatchPower()
144
145 /*++////////////////////////////////////////////////////////////////////////////
146
147 ClasspPowerUpCompletion()
148
149 Routine Description:
150
151 This routine is used for intermediate completion of a power up request.
152 PowerUp requires four requests to be sent to the lower driver in sequence.
153
154 * The queue is "power locked" to ensure that the class driver power-up
155 work can be done before request processing resumes.
156
157 * The power irp is sent down the stack for any filter drivers and the
158 port driver to return power and resume command processing for the
159 device. Since the queue is locked, no queued irps will be sent
160 immediately.
161
162 * A start unit command is issued to the device with appropriate flags
163 to override the "power locked" queue.
164
165 * The queue is "power unlocked" to start processing requests again.
166
167 This routine uses the function in the srb which just completed to determine
168 which state it is in.
169
170 Arguments:
171
172 DeviceObject - the device object being powered up
173
174 Irp - Context->Irp: original power irp; fdoExtension->PrivateFdoData->PowerProcessIrp: power process irp
175
176 Context - Class power context used to perform port/class operations.
177
178 Return Value:
179
180 STATUS_MORE_PROCESSING_REQUIRED or
181 STATUS_SUCCESS
182
183 --*/
184 NTSTATUS
185 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClasspPowerUpCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)186 ClasspPowerUpCompletion(
187 IN PDEVICE_OBJECT DeviceObject,
188 IN PIRP Irp,
189 IN PVOID Context
190 )
191 {
192 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context;
193 PCOMMON_DEVICE_EXTENSION commonExtension;
194 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
195 PIRP OriginalIrp;
196 PIO_STACK_LOCATION currentStack;
197 PIO_STACK_LOCATION nextStack;
198
199 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
200 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader;
201 ULONG srbFlags;
202 BOOLEAN FailurePredictionEnabled = FALSE;
203
204 UNREFERENCED_PARAMETER(DeviceObject);
205
206 if (PowerContext == NULL) {
207 NT_ASSERT(PowerContext != NULL);
208 return STATUS_INVALID_PARAMETER;
209 }
210
211 commonExtension = PowerContext->DeviceObject->DeviceExtension;
212 fdoExtension = PowerContext->DeviceObject->DeviceExtension;
213 OriginalIrp = PowerContext->Irp;
214
215 // currentStack - from original power irp
216 // nextStack - from power process irp
217 currentStack = IoGetCurrentIrpStackLocation(OriginalIrp);
218 nextStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp);
219
220 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerUpCompletion: Device Object %p, Irp %p, "
221 "Context %p\n",
222 PowerContext->DeviceObject, Irp, Context));
223
224 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
225 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx);
226
227 //
228 // Check if reverted to using legacy SRB.
229 //
230 if (PowerContext->Srb.Length == sizeof(SCSI_REQUEST_BLOCK)) {
231 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
232 }
233 } else {
234 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
235 }
236
237 srbFlags = SrbGetSrbFlags(srbHeader);
238 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
239 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
240 NT_ASSERT(PowerContext->Options.PowerDown == FALSE);
241 NT_ASSERT(PowerContext->Options.HandleSpinUp);
242
243 if ((Irp == OriginalIrp) && (Irp->PendingReturned)) {
244 // only for original power irp
245 IoMarkIrpPending(Irp);
246 }
247
248 PowerContext->PowerChangeState.PowerUp++;
249
250 switch (PowerContext->PowerChangeState.PowerUp) {
251
252 case PowerUpDeviceLocked: {
253
254 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent power lock\n", Irp));
255
256 //
257 // Lock Queue operation has been sent.
258 // Now, send the original power irp down to get lower driver and device ready.
259 //
260
261 IoCopyCurrentIrpStackLocationToNext(OriginalIrp);
262
263 if ((PowerContext->Options.LockQueue == TRUE) &&
264 (!NT_SUCCESS(Irp->IoStatus.Status))) {
265
266 //
267 // Lock was not successful:
268 // Issue the original power request to the lower driver and next power irp will be started in completion routine.
269 //
270
271
272 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIrp status was %lx\n",
273 Irp, Irp->IoStatus.Status));
274 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSrb status was %lx\n",
275 Irp, srbHeader->SrbStatus));
276
277 IoSetCompletionRoutine(OriginalIrp,
278 ClasspDeviceLockFailurePowerIrpCompletion,
279 PowerContext,
280 TRUE,
281 TRUE,
282 TRUE);
283
284 PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
285
286 return STATUS_MORE_PROCESSING_REQUIRED;
287
288 } else {
289 PowerContext->QueueLocked = (UCHAR)PowerContext->Options.LockQueue;
290 }
291
292 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
293
294 PowerContext->PowerChangeState.PowerUp = PowerUpDeviceLocked;
295
296 IoSetCompletionRoutine(OriginalIrp,
297 ClasspPowerUpCompletion,
298 PowerContext,
299 TRUE,
300 TRUE,
301 TRUE);
302
303 status = PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
304
305 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", OriginalIrp, status));
306 break;
307 }
308
309 case PowerUpDeviceOn: {
310
311 //
312 // Original power irp has been completed by lower driver.
313 //
314
315 if (NT_SUCCESS(Irp->IoStatus.Status)) {
316 //
317 // If power irp succeeded, START UNIT command will be sent.
318 //
319 PCDB cdb;
320 ULONG secondsRemaining = 0;
321 ULONG timeoutValue = 0;
322 ULONG startUnitTimeout;
323
324 if (PoQueryWatchdogTime(fdoExtension->LowerPdo, &secondsRemaining)) {
325
326 // do not exceed DEFAULT_POWER_IRP_TIMEOUT_VALUE.
327 secondsRemaining = min(secondsRemaining, DEFAULT_POWER_IRP_TIMEOUT_VALUE);
328
329 //
330 // It's possible for POWER IRP timeout value to be smaller than default of
331 // START_UNIT_TIMEOUT. If this is the case, use a smaller timeout value.
332 //
333 if (secondsRemaining >= START_UNIT_TIMEOUT) {
334 startUnitTimeout = START_UNIT_TIMEOUT;
335 } else {
336 startUnitTimeout = MINIMAL_START_UNIT_TIMEOUT_VALUE;
337 }
338
339 // plan to leave (TIME_LEFT_FOR_UPPER_DRIVERS) seconds to upper level drivers
340 // for processing original power irp.
341 if (secondsRemaining >= (TIME_LEFT_FOR_UPPER_DRIVERS + startUnitTimeout)) {
342 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount =
343 (secondsRemaining - TIME_LEFT_FOR_UPPER_DRIVERS) / startUnitTimeout;
344
345 // * No 'short' timeouts
346 //
347 //
348 // timeoutValue = (secondsRemaining - TIME_LEFT_FOR_UPPER_DRIVERS) %
349 // startUnitTimeout;
350 //
351
352 if (--fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount)
353 {
354 timeoutValue = startUnitTimeout;
355 } else {
356 timeoutValue = secondsRemaining - TIME_LEFT_FOR_UPPER_DRIVERS;
357 }
358 } else {
359 // issue the command with minimum timeout value and do not retry on it.
360 // case of (secondsRemaining < DEFAULT_IO_TIMEOUT_VALUE) is ignored as it should not happen.
361 NT_ASSERT(secondsRemaining >= DEFAULT_IO_TIMEOUT_VALUE);
362
363 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 0;
364 timeoutValue = MINIMUM_START_UNIT_TIMEOUT_VALUE; // use the minimum value for this corner case.
365 }
366
367 } else {
368 // don't know how long left, do not exceed DEFAULT_POWER_IRP_TIMEOUT_VALUE.
369 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount =
370 DEFAULT_POWER_IRP_TIMEOUT_VALUE / START_UNIT_TIMEOUT - 1;
371 timeoutValue = START_UNIT_TIMEOUT;
372 }
373
374
375 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSending start unit to device\n", Irp));
376
377 //
378 // Issue the start unit command to the device.
379 //
380
381 PowerContext->RetryCount = fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount;
382
383 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
384 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
385 STORAGE_ADDRESS_TYPE_BTL8,
386 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE,
387 1,
388 SrbExDataTypeScsiCdb16);
389 if (NT_SUCCESS(status)) {
390 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
391
392 //
393 // Set length field in Power Context SRB so we know legacy SRB is not being used.
394 //
395 PowerContext->Srb.Length = 0;
396
397 } else {
398 //
399 // Should not happen. Revert to legacy SRB.
400 //
401 NT_ASSERT(FALSE);
402 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
403 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
404 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
405 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI;
406 }
407
408 } else {
409 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
410 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
411 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI;
412 }
413
414 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
415 SrbSetSenseInfoBuffer(srbHeader, commonExtension->PartitionZeroExtension->SenseData);
416 SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(commonExtension->PartitionZeroExtension));
417
418 SrbSetTimeOutValue(srbHeader, timeoutValue);
419 SrbAssignSrbFlags(srbHeader,
420 (SRB_FLAGS_NO_DATA_TRANSFER |
421 SRB_FLAGS_DISABLE_AUTOSENSE |
422 SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
423 SRB_FLAGS_NO_QUEUE_FREEZE));
424
425 if (PowerContext->Options.LockQueue) {
426 SrbSetSrbFlags(srbHeader, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
427 }
428
429 SrbSetCdbLength(srbHeader, 6);
430
431 cdb = SrbGetCdb(srbHeader);
432 RtlZeroMemory(cdb, sizeof(CDB));
433
434 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
435 cdb->START_STOP.Start = 1;
436
437 PowerContext->PowerChangeState.PowerUp = PowerUpDeviceOn;
438
439 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
440 ClasspPowerUpCompletion,
441 PowerContext,
442 TRUE,
443 TRUE,
444 TRUE);
445
446 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
447 nextStack->MajorFunction = IRP_MJ_SCSI;
448
449 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp);
450
451 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status));
452
453 } else {
454
455 //
456 // power irp is failed by lower driver. we're done.
457 //
458
459 PowerContext->FinalStatus = Irp->IoStatus.Status;
460 goto ClasspPowerUpCompletionFailure;
461 }
462
463 break;
464 }
465
466 case PowerUpDeviceStarted: { // 3
467
468 //
469 // First deal with an error if one occurred.
470 //
471
472 if (SRB_STATUS(srbHeader->SrbStatus) != SRB_STATUS_SUCCESS) {
473
474 BOOLEAN retry;
475 LONGLONG delta100nsUnits = 0;
476 ULONG secondsRemaining = 0;
477 ULONG startUnitTimeout = START_UNIT_TIMEOUT;
478
479 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "%p\tError occured when issuing START_UNIT "
480 "command to device. Srb %p, Status %x\n",
481 Irp,
482 srbHeader,
483 srbHeader->SrbStatus));
484
485 NT_ASSERT(!(TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_QUEUE_FROZEN)));
486 NT_ASSERT((srbHeader->Function == SRB_FUNCTION_EXECUTE_SCSI) ||
487 (((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI));
488
489 PowerContext->RetryInterval = 0;
490 retry = InterpretSenseInfoWithoutHistory(
491 fdoExtension->DeviceObject,
492 Irp,
493 (PSCSI_REQUEST_BLOCK)srbHeader,
494 IRP_MJ_SCSI,
495 IRP_MJ_POWER,
496 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount - PowerContext->RetryCount,
497 &status,
498 &delta100nsUnits);
499
500 // NOTE: Power context is a public structure, and thus cannot be
501 // updated to use 100ns units. Therefore, must store the
502 // one-second equivalent. Round up to ensure minimum delay
503 // requirements have been met.
504 delta100nsUnits += (10*1000*1000) - 1;
505 delta100nsUnits /= (10*1000*1000);
506 // guaranteed not to have high bits set per SAL annotations
507 PowerContext->RetryInterval = (ULONG)(delta100nsUnits);
508
509
510 if ((retry == TRUE) && (PowerContext->RetryCount-- != 0)) {
511
512 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tRetrying failed request\n", Irp));
513
514 //
515 // Decrement the state so we come back through here the
516 // next time.
517 //
518
519 PowerContext->PowerChangeState.PowerUp--;
520
521 //
522 // Adjust start unit timeout based on remaining time if needed.
523 //
524 if (PoQueryWatchdogTime(fdoExtension->LowerPdo, &secondsRemaining)) {
525
526 if (secondsRemaining >= TIME_LEFT_FOR_UPPER_DRIVERS) {
527 secondsRemaining -= TIME_LEFT_FOR_UPPER_DRIVERS;
528 }
529
530 if (secondsRemaining < MINIMAL_START_UNIT_TIMEOUT_VALUE) {
531 startUnitTimeout = MINIMUM_START_UNIT_TIMEOUT_VALUE;
532 } else if (secondsRemaining < START_UNIT_TIMEOUT) {
533 startUnitTimeout = MINIMAL_START_UNIT_TIMEOUT_VALUE;
534 }
535 }
536
537 SrbSetTimeOutValue(srbHeader, startUnitTimeout);
538
539 RetryPowerRequest(commonExtension->DeviceObject,
540 Irp,
541 PowerContext);
542
543 break;
544
545 }
546
547 // reset retry count for UNLOCK command.
548 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
549 PowerContext->RetryCount = MAXIMUM_RETRIES;
550 }
551
552 ClasspPowerUpCompletionFailure:
553
554 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously spun device up\n", Irp));
555
556 if (PowerContext->QueueLocked) {
557 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tUnlocking queue\n", Irp));
558
559 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
560 //
561 // Will reuse SRB for a non-SCSI SRB.
562 //
563 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
564 STORAGE_ADDRESS_TYPE_BTL8,
565 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE,
566 0);
567 if (NT_SUCCESS(status)) {
568 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_UNLOCK_QUEUE;
569
570 //
571 // Set length field in Power Context SRB so we know legacy SRB is not being used.
572 //
573 PowerContext->Srb.Length = 0;
574
575 } else {
576 //
577 // Should not occur. Revert to legacy SRB.
578 NT_ASSERT(FALSE);
579 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
580 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
581 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
582 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE;
583 }
584 } else {
585 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
586 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
587 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE;
588 }
589 SrbAssignSrbFlags(srbHeader, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
590 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
591
592 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
593 nextStack->MajorFunction = IRP_MJ_SCSI;
594
595 PowerContext->PowerChangeState.PowerUp = PowerUpDeviceStarted;
596
597 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
598 ClasspPowerUpCompletion,
599 PowerContext,
600 TRUE,
601 TRUE,
602 TRUE);
603
604 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp);
605 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n",
606 fdoExtension->PrivateFdoData->PowerProcessIrp, status));
607 break;
608 }
609
610 // Fall-through to next case...
611
612 }
613
614 case PowerUpDeviceUnlocked: {
615
616 //
617 // This is the end of the dance.
618 // We're ignoring possible intermediate error conditions ....
619 //
620
621 if (PowerContext->QueueLocked) {
622 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously unlocked queue\n", OriginalIrp));
623
624 //
625 // If the lower device is being removed, the IRP's status may be STATUS_DELETE_PENDING or
626 // STATUS_DEVICE_DOES_NOT_EXIST.
627 //
628 if((NT_SUCCESS(Irp->IoStatus.Status) == FALSE) &&
629 (Irp->IoStatus.Status != STATUS_DELETE_PENDING) &&
630 (Irp->IoStatus.Status != STATUS_DEVICE_DOES_NOT_EXIST)) {
631
632
633 NT_ASSERT(FALSE);
634 }
635
636 } else {
637 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFall-through (queue not locked)\n", OriginalIrp));
638 }
639
640 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFreeing srb and completing\n", OriginalIrp));
641
642 status = PowerContext->FinalStatus;
643 OriginalIrp->IoStatus.Status = status;
644
645 //
646 // Set the new power state
647 //
648
649 if (NT_SUCCESS(status)) {
650 fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState;
651 }
652
653 //
654 // Check whether failure detection is enabled
655 //
656
657 if ((fdoExtension->FailurePredictionInfo != NULL) &&
658 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)) {
659 FailurePredictionEnabled = TRUE;
660 }
661
662 //
663 // Enable tick timer at end of D0 processing if it was previously enabled.
664 //
665
666 if ((commonExtension->DriverExtension->InitData.ClassTick != NULL) ||
667 ((fdoExtension->MediaChangeDetectionInfo != NULL) &&
668 (fdoExtension->FunctionSupportInfo != NULL) &&
669 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) ||
670 (FailurePredictionEnabled)) {
671
672
673 //
674 // If failure prediction is turned on and we've been powered
675 // off longer than the failure prediction query period then
676 // force the query on the next timer tick.
677 //
678
679 if ((FailurePredictionEnabled) && (ClasspFailurePredictionPeriodMissed(fdoExtension))) {
680 fdoExtension->FailurePredictionInfo->CountDown = 1;
681 }
682
683 //
684 // Finally, enable the timer.
685 //
686
687 ClasspEnableTimer(fdoExtension);
688 }
689
690 //
691 // Indicate to Po that we've been successfully powered up so
692 // it can do it's notification stuff.
693 //
694
695 PoSetPowerState(PowerContext->DeviceObject,
696 currentStack->Parameters.Power.Type,
697 currentStack->Parameters.Power.State);
698
699 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", OriginalIrp));
700
701 ClassReleaseRemoveLock(PowerContext->DeviceObject, OriginalIrp);
702
703 PowerContext->InUse = FALSE;
704
705 PoStartNextPowerIrp(OriginalIrp);
706
707 // prevent from completing the irp allocated by ourselves
708 if ((fdoExtension->PrivateFdoData) && (Irp == fdoExtension->PrivateFdoData->PowerProcessIrp)) {
709 // complete original irp if we are processing powerprocess irp,
710 // otherwise, by returning status other than STATUS_MORE_PROCESSING_REQUIRED, IO manager will complete it.
711 ClassCompleteRequest(commonExtension->DeviceObject, OriginalIrp, IO_NO_INCREMENT);
712 status = STATUS_MORE_PROCESSING_REQUIRED;
713 }
714
715 return status;
716 }
717 }
718
719 return STATUS_MORE_PROCESSING_REQUIRED;
720 } // end ClasspPowerUpCompletion()
721
722 /*++////////////////////////////////////////////////////////////////////////////
723
724 ClasspPowerDownCompletion()
725
726 Routine Description:
727
728 This routine is used for intermediate completion of a power down request.
729 PowerDown performs the following sequence to power down the device.
730
731 1. The queue(s) in the lower stack is/are "power locked" to ensure new
732 requests are held until the power-down process is complete.
733
734 2. A request to the lower layers to wait for all outstanding IO to
735 complete ("quiescence") is sent. This ensures we don't power down
736 the device while it's in the middle of handling IO.
737
738 3. A request to flush the device's cache is sent. The device may lose
739 power when we forward the D-IRP so any data in volatile storage must
740 be committed to non-volatile storage first.
741
742 4. A "stop unit" request is sent to the device to notify it that it
743 is about to be powered down.
744
745 5. The D-IRP is forwarded down the stack. If D3Cold is supported and
746 enabled via ACPI, the ACPI filter driver may power off the device.
747
748 6. Once the D-IRP is completed by the lower stack, we will "power
749 unlock" the queue(s). (It is the lower stack's responsibility to
750 continue to queue any IO that requires hardware access until the
751 device is powered up again.)
752
753 Arguments:
754
755 DeviceObject - the device object being powered down
756
757 Irp - the IO_REQUEST_PACKET containing the power request
758
759 Context - the class power context used to perform port/class operations.
760
761 Return Value:
762
763 STATUS_MORE_PROCESSING_REQUIRED or
764 STATUS_SUCCESS
765
766 --*/
767 NTSTATUS
768 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClasspPowerDownCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)769 ClasspPowerDownCompletion(
770 IN PDEVICE_OBJECT DeviceObject,
771 IN PIRP Irp,
772 IN PVOID Context
773 )
774 {
775 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context;
776 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = PowerContext->DeviceObject->DeviceExtension;
777 PCOMMON_DEVICE_EXTENSION commonExtension = PowerContext->DeviceObject->DeviceExtension;
778 PIRP OriginalIrp = PowerContext->Irp;
779
780 // currentStack is for original power irp
781 // nextStack is for power process irp
782 PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(OriginalIrp);
783 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp);
784
785 NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
786 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader;
787 ULONG srbFlags;
788
789 UNREFERENCED_PARAMETER(DeviceObject);
790
791 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerDownCompletion: Device Object %p, "
792 "Irp %p, Context %p\n",
793 PowerContext->DeviceObject, Irp, Context));
794
795 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
796 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx);
797
798 //
799 // Check if reverted to using legacy SRB.
800 //
801 if (PowerContext->Srb.Length == sizeof(SCSI_REQUEST_BLOCK)) {
802 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
803 }
804 } else {
805 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
806 }
807
808 srbFlags = SrbGetSrbFlags(srbHeader);
809 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
810 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
811 NT_ASSERT(PowerContext->Options.PowerDown == TRUE);
812 NT_ASSERT(PowerContext->Options.HandleSpinDown);
813
814 if ((Irp == OriginalIrp) && (Irp->PendingReturned)) {
815 // only for original power irp
816 IoMarkIrpPending(Irp);
817 }
818
819 PowerContext->PowerChangeState.PowerDown3++;
820
821 switch(PowerContext->PowerChangeState.PowerDown3) {
822
823 case PowerDownDeviceLocked3: {
824
825 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent power lock\n", Irp));
826
827 if ((PowerContext->Options.LockQueue == TRUE) &&
828 (!NT_SUCCESS(Irp->IoStatus.Status))) {
829
830 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIrp status was %lx\n",
831 Irp,
832 Irp->IoStatus.Status));
833 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSrb status was %lx\n",
834 Irp,
835 srbHeader->SrbStatus));
836
837
838
839 //
840 // Lock was not successful - throw down the power IRP
841 // by itself and don't try to spin down the drive or unlock
842 // the queue.
843 //
844
845 //
846 // Set the new power state
847 //
848
849 fdoExtension->DevicePowerState =
850 currentStack->Parameters.Power.State.DeviceState;
851
852 //
853 // Indicate to Po that we've been successfully powered down
854 // so it can do it's notification stuff.
855 //
856
857 IoCopyCurrentIrpStackLocationToNext(OriginalIrp);
858 IoSetCompletionRoutine(OriginalIrp,
859 ClasspStartNextPowerIrpCompletion,
860 PowerContext,
861 TRUE,
862 TRUE,
863 TRUE);
864
865 PoSetPowerState(PowerContext->DeviceObject,
866 currentStack->Parameters.Power.Type,
867 currentStack->Parameters.Power.State);
868
869 fdoExtension->PowerDownInProgress = FALSE;
870
871 ClassReleaseRemoveLock(commonExtension->DeviceObject,
872 OriginalIrp);
873
874 PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
875
876 return STATUS_MORE_PROCESSING_REQUIRED;
877
878 } else {
879 //
880 // Lock the device queue succeeded. Now wait for all outstanding IO to complete.
881 // To do this, Srb with SRB_FUNCTION_QUIESCE_DEVICE will be sent down with default timeout value.
882 // We need to tolerant failure of this request, no retry will be made.
883 //
884 PowerContext->QueueLocked = (UCHAR) PowerContext->Options.LockQueue;
885
886 //
887 // No retry on device quiescence reqeust
888 //
889 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 0;
890 PowerContext->RetryCount = 0;
891
892 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
893 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx);
894
895 //
896 // Initialize extended SRB for a SRB_FUNCTION_LOCK_QUEUE
897 //
898 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
899 STORAGE_ADDRESS_TYPE_BTL8,
900 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE,
901 0);
902 if (NT_SUCCESS(status)) {
903 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_QUIESCE_DEVICE;
904 } else {
905 //
906 // Should not happen. Revert to legacy SRB.
907 //
908 NT_ASSERT(FALSE);
909 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
910 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
911 srbHeader->Function = SRB_FUNCTION_QUIESCE_DEVICE;
912 }
913 } else {
914 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
915 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
916 srbHeader->Function = SRB_FUNCTION_QUIESCE_DEVICE;
917 }
918
919 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
920 SrbSetTimeOutValue(srbHeader, fdoExtension->TimeOutValue);
921
922 SrbAssignSrbFlags(srbHeader,
923 (SRB_FLAGS_NO_DATA_TRANSFER |
924 SRB_FLAGS_DISABLE_AUTOSENSE |
925 SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
926 SRB_FLAGS_NO_QUEUE_FREEZE |
927 SRB_FLAGS_BYPASS_LOCKED_QUEUE |
928 SRB_FLAGS_D3_PROCESSING));
929
930 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
931 ClasspPowerDownCompletion,
932 PowerContext,
933 TRUE,
934 TRUE,
935 TRUE);
936
937 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
938 nextStack->MajorFunction = IRP_MJ_SCSI;
939
940 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp);
941
942 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status));
943 break;
944 }
945
946 }
947
948 case PowerDownDeviceQuiesced3: {
949
950 PCDB cdb;
951
952 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent device quiesce\n", Irp));
953
954 //
955 // don't care the result of device quiesce, we've made the effort.
956 // continue on sending other SCSI commands anyway.
957 //
958
959
960 if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags,
961 FDO_HACK_NO_SYNC_CACHE)) {
962
963 //
964 // send SCSIOP_SYNCHRONIZE_CACHE
965 //
966
967 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
968 PowerContext->RetryCount = MAXIMUM_RETRIES;
969
970 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
971 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
972 STORAGE_ADDRESS_TYPE_BTL8,
973 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE,
974 1,
975 SrbExDataTypeScsiCdb16);
976 if (NT_SUCCESS(status)) {
977 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
978
979 //
980 // Set length field in Power Context SRB so we know legacy SRB is not being used.
981 //
982 PowerContext->Srb.Length = 0;
983
984 } else {
985 //
986 // Should not occur. Revert to legacy SRB.
987 NT_ASSERT(FALSE);
988 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
989 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
990 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
991 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI;
992 }
993
994 } else {
995 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
996 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
997 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI;
998 }
999
1000
1001 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
1002 SrbSetSenseInfoBuffer(srbHeader, commonExtension->PartitionZeroExtension->SenseData);
1003 SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(commonExtension->PartitionZeroExtension));
1004 SrbSetTimeOutValue(srbHeader, fdoExtension->TimeOutValue);
1005
1006 SrbAssignSrbFlags(srbHeader,
1007 (SRB_FLAGS_NO_DATA_TRANSFER |
1008 SRB_FLAGS_DISABLE_AUTOSENSE |
1009 SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
1010 SRB_FLAGS_NO_QUEUE_FREEZE |
1011 SRB_FLAGS_BYPASS_LOCKED_QUEUE |
1012 SRB_FLAGS_D3_PROCESSING));
1013
1014 SrbSetCdbLength(srbHeader, 10);
1015
1016 cdb = SrbGetCdb(srbHeader);
1017
1018 RtlZeroMemory(cdb, sizeof(CDB));
1019 cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
1020
1021 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
1022 ClasspPowerDownCompletion,
1023 PowerContext,
1024 TRUE,
1025 TRUE,
1026 TRUE);
1027
1028 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
1029 nextStack->MajorFunction = IRP_MJ_SCSI;
1030
1031 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp);
1032
1033 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status));
1034 break;
1035
1036 } else {
1037
1038 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_POWER, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
1039 PowerContext->DeviceObject));
1040 PowerContext->PowerChangeState.PowerDown3++;
1041 srbHeader->SrbStatus = SRB_STATUS_SUCCESS;
1042 // and fall through....
1043 }
1044 // no break in case the device doesn't like synch_cache commands
1045
1046 }
1047
1048 case PowerDownDeviceFlushed3: {
1049
1050 PCDB cdb;
1051
1052 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
1053 Irp));
1054
1055 //
1056 // SCSIOP_SYNCHRONIZE_CACHE was sent
1057 //
1058
1059 if (SRB_STATUS(srbHeader->SrbStatus) != SRB_STATUS_SUCCESS) {
1060
1061 BOOLEAN retry;
1062 LONGLONG delta100nsUnits = 0;
1063
1064 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "(%p)\tError occured when issuing "
1065 "SYNCHRONIZE_CACHE command to device. "
1066 "Srb %p, Status %lx\n",
1067 Irp,
1068 srbHeader,
1069 srbHeader->SrbStatus));
1070
1071 NT_ASSERT(!(TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_QUEUE_FROZEN)));
1072 NT_ASSERT((srbHeader->Function == SRB_FUNCTION_EXECUTE_SCSI) ||
1073 (((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI));
1074
1075 PowerContext->RetryInterval = 0;
1076 retry = InterpretSenseInfoWithoutHistory(
1077 fdoExtension->DeviceObject,
1078 Irp,
1079 (PSCSI_REQUEST_BLOCK)srbHeader,
1080 IRP_MJ_SCSI,
1081 IRP_MJ_POWER,
1082 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount - PowerContext->RetryCount,
1083 &status,
1084 &delta100nsUnits);
1085
1086 // NOTE: Power context is a public structure, and thus cannot be
1087 // updated to use 100ns units. Therefore, must store the
1088 // one-second equivalent. Round up to ensure minimum delay
1089 // requirements have been met.
1090 delta100nsUnits += (10*1000*1000) - 1;
1091 delta100nsUnits /= (10*1000*1000);
1092 // guaranteed not to have high bits set per SAL annotations
1093 PowerContext->RetryInterval = (ULONG)(delta100nsUnits);
1094
1095
1096 if ((retry == TRUE) && (PowerContext->RetryCount-- != 0)) {
1097
1098 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tRetrying failed request\n", Irp));
1099
1100 //
1101 // decrement the state so we come back through here
1102 // the next time.
1103 //
1104
1105 PowerContext->PowerChangeState.PowerDown3--;
1106 RetryPowerRequest(commonExtension->DeviceObject,
1107 Irp,
1108 PowerContext);
1109 break;
1110 }
1111
1112 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp));
1113 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
1114 PowerContext->RetryCount = MAXIMUM_RETRIES;
1115 } // end !SRB_STATUS_SUCCESS
1116
1117 //
1118 // note: we are purposefully ignoring any errors. if the drive
1119 // doesn't support a synch_cache, then we're up a creek
1120 // anyways.
1121 //
1122
1123 if ((currentStack->Parameters.Power.State.DeviceState == PowerDeviceD3) &&
1124 (currentStack->Parameters.Power.ShutdownType == PowerActionHibernate) &&
1125 (commonExtension->HibernationPathCount != 0)) {
1126
1127 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPower Down: not sending SPIN DOWN due to hibernation path\n",
1128 PowerContext->DeviceObject));
1129
1130 PowerContext->PowerChangeState.PowerDown3++;
1131 srbHeader->SrbStatus = SRB_STATUS_SUCCESS;
1132 status = STATUS_SUCCESS;
1133
1134 // Fall through to next case...
1135
1136 } else {
1137 // Send STOP UNIT command. As "Imme" bit is set to '1', this command should be completed in short time.
1138 // This command is at low importance, failure of this command has very small impact.
1139
1140 ULONG secondsRemaining;
1141 ULONG timeoutValue;
1142
1143 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSending stop unit to device\n", Irp));
1144
1145 if (PoQueryWatchdogTime(fdoExtension->LowerPdo, &secondsRemaining)) {
1146 // plan to leave some time (TIME_LEFT_FOR_LOWER_DRIVERS) to lower level drivers
1147 // for processing the original power irp.
1148 if (secondsRemaining >= (TIME_LEFT_FOR_LOWER_DRIVERS + DEFAULT_IO_TIMEOUT_VALUE)) {
1149 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount =
1150 (secondsRemaining - TIME_LEFT_FOR_LOWER_DRIVERS) / DEFAULT_IO_TIMEOUT_VALUE;
1151
1152 // * No 'short' timeouts
1153 //
1154 // timeoutValue = (secondsRemaining - TIME_LEFT_FOR_LOWER_DRIVERS) %
1155 // DEFAULT_IO_TIMEOUT_VALUE;
1156 // if (timeoutValue < MINIMUM_STOP_UNIT_TIMEOUT_VALUE)
1157 // {
1158 if (--fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount)
1159 {
1160 timeoutValue = DEFAULT_IO_TIMEOUT_VALUE;
1161 } else {
1162 timeoutValue = secondsRemaining - TIME_LEFT_FOR_LOWER_DRIVERS;
1163 }
1164 // }
1165
1166 // Limit to maximum retry count.
1167 if (fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount > MAXIMUM_RETRIES) {
1168 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
1169 }
1170 } else {
1171 // issue the command with minimum timeout value and do not retry on it.
1172 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = 0;
1173
1174 // minimum as MINIMUM_STOP_UNIT_TIMEOUT_VALUE.
1175 if (secondsRemaining > 2 * MINIMUM_STOP_UNIT_TIMEOUT_VALUE) {
1176 timeoutValue = secondsRemaining - MINIMUM_STOP_UNIT_TIMEOUT_VALUE;
1177 } else {
1178 timeoutValue = MINIMUM_STOP_UNIT_TIMEOUT_VALUE;
1179 }
1180
1181 }
1182
1183 } else {
1184 // do not know how long, use default values.
1185 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
1186 timeoutValue = DEFAULT_IO_TIMEOUT_VALUE;
1187 }
1188
1189 //
1190 // Issue STOP UNIT command to the device.
1191 //
1192
1193 PowerContext->RetryCount = fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount;
1194
1195 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1196 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
1197 STORAGE_ADDRESS_TYPE_BTL8,
1198 CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE,
1199 1,
1200 SrbExDataTypeScsiCdb16);
1201 if (NT_SUCCESS(status)) {
1202 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1203
1204 //
1205 // Set length field in Power Context SRB so we know legacy SRB is not being used.
1206 //
1207 PowerContext->Srb.Length = 0;
1208
1209 } else {
1210 //
1211 // Should not occur. Revert to legacy SRB.
1212 //
1213 NT_ASSERT(FALSE);
1214 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
1215 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
1216 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
1217 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI;
1218 }
1219
1220 } else {
1221 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
1222 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
1223 srbHeader->Function = SRB_FUNCTION_EXECUTE_SCSI;
1224 }
1225
1226 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
1227 SrbSetSenseInfoBuffer(srbHeader, commonExtension->PartitionZeroExtension->SenseData);
1228 SrbSetSenseInfoBufferLength(srbHeader, GET_FDO_EXTENSON_SENSE_DATA_LENGTH(commonExtension->PartitionZeroExtension));
1229 SrbSetTimeOutValue(srbHeader, timeoutValue);
1230
1231
1232 SrbAssignSrbFlags(srbHeader,
1233 (SRB_FLAGS_NO_DATA_TRANSFER |
1234 SRB_FLAGS_DISABLE_AUTOSENSE |
1235 SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
1236 SRB_FLAGS_NO_QUEUE_FREEZE |
1237 SRB_FLAGS_BYPASS_LOCKED_QUEUE |
1238 SRB_FLAGS_D3_PROCESSING));
1239
1240 SrbSetCdbLength(srbHeader, 6);
1241
1242 cdb = SrbGetCdb(srbHeader);
1243 RtlZeroMemory(cdb, sizeof(CDB));
1244
1245 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1246 cdb->START_STOP.Start = 0;
1247 cdb->START_STOP.Immediate = 1;
1248
1249 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
1250 ClasspPowerDownCompletion,
1251 PowerContext,
1252 TRUE,
1253 TRUE,
1254 TRUE);
1255
1256 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
1257 nextStack->MajorFunction = IRP_MJ_SCSI;
1258
1259 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp);
1260
1261 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n", fdoExtension->PrivateFdoData->PowerProcessIrp, status));
1262 break;
1263 }
1264 }
1265
1266 case PowerDownDeviceStopped3: {
1267
1268 BOOLEAN ignoreError = TRUE;
1269
1270 //
1271 // stop was sent
1272 //
1273
1274 if (SRB_STATUS(srbHeader->SrbStatus) != SRB_STATUS_SUCCESS) {
1275
1276 BOOLEAN retry;
1277 LONGLONG delta100nsUnits = 0;
1278
1279 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "(%p)\tError occured when issueing STOP_UNIT "
1280 "command to device. Srb %p, Status %lx\n",
1281 Irp,
1282 srbHeader,
1283 srbHeader->SrbStatus));
1284
1285 NT_ASSERT(!(TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_QUEUE_FROZEN)));
1286 NT_ASSERT((srbHeader->Function == SRB_FUNCTION_EXECUTE_SCSI) ||
1287 (((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI));
1288
1289 PowerContext->RetryInterval = 0;
1290 retry = InterpretSenseInfoWithoutHistory(
1291 fdoExtension->DeviceObject,
1292 Irp,
1293 (PSCSI_REQUEST_BLOCK)srbHeader,
1294 IRP_MJ_SCSI,
1295 IRP_MJ_POWER,
1296 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount - PowerContext->RetryCount,
1297 &status,
1298 &delta100nsUnits);
1299
1300 // NOTE: Power context is a public structure, and thus cannot be
1301 // updated to use 100ns units. Therefore, must store the
1302 // one-second equivalent. Round up to ensure minimum delay
1303 // requirements have been met.
1304 delta100nsUnits += (10*1000*1000) - 1;
1305 delta100nsUnits /= (10*1000*1000);
1306 // guaranteed not to have high bits set per SAL annotations
1307 PowerContext->RetryInterval = (ULONG)(delta100nsUnits);
1308
1309
1310 if ((retry == TRUE) && (PowerContext->RetryCount-- != 0)) {
1311
1312 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tRetrying failed request\n", Irp));
1313
1314 //
1315 // decrement the state so we come back through here
1316 // the next time.
1317 //
1318
1319 PowerContext->PowerChangeState.PowerDown3--;
1320
1321 SrbSetTimeOutValue(srbHeader, DEFAULT_IO_TIMEOUT_VALUE);
1322
1323 RetryPowerRequest(commonExtension->DeviceObject,
1324 Irp,
1325 PowerContext);
1326 break;
1327 }
1328
1329 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSTOP_UNIT not retried\n", Irp));
1330 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
1331 PowerContext->RetryCount = MAXIMUM_RETRIES;
1332
1333 } // end !SRB_STATUS_SUCCESS
1334
1335
1336 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent stop unit\n", Irp));
1337
1338 //
1339 // some operations, such as a physical format in progress,
1340 // should not be ignored and should fail the power operation.
1341 //
1342
1343 if (!NT_SUCCESS(status)) {
1344
1345 PVOID senseBuffer = SrbGetSenseInfoBuffer(srbHeader);
1346
1347 if (TEST_FLAG(srbHeader->SrbStatus, SRB_STATUS_AUTOSENSE_VALID) &&
1348 (senseBuffer != NULL)) {
1349
1350 BOOLEAN validSense = FALSE;
1351 UCHAR senseKey = 0;
1352 UCHAR additionalSenseCode = 0;
1353 UCHAR additionalSenseCodeQualifier = 0;
1354
1355 validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
1356 SrbGetSenseInfoBufferLength(srbHeader),
1357 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
1358 &senseKey,
1359 &additionalSenseCode,
1360 &additionalSenseCodeQualifier);
1361
1362 if (validSense) {
1363 if ((senseKey == SCSI_SENSE_NOT_READY) &&
1364 (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
1365 (additionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) {
1366
1367 ignoreError = FALSE;
1368 PowerContext->FinalStatus = STATUS_DEVICE_BUSY;
1369 status = PowerContext->FinalStatus;
1370 }
1371 }
1372 }
1373 }
1374
1375 if (NT_SUCCESS(status) || ignoreError) {
1376
1377 //
1378 // Issue the original power request to the lower driver.
1379 //
1380
1381 IoCopyCurrentIrpStackLocationToNext(OriginalIrp);
1382
1383 IoSetCompletionRoutine(OriginalIrp,
1384 ClasspPowerDownCompletion,
1385 PowerContext,
1386 TRUE,
1387 TRUE,
1388 TRUE);
1389
1390 status = PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
1391
1392 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPoCallDriver returned %lx\n", OriginalIrp, status));
1393 break;
1394 }
1395
1396 // else fall through w/o sending the power irp, since the device
1397 // is reporting an error that would be "really bad" to power down
1398 // during.
1399
1400 }
1401
1402 case PowerDownDeviceOff3: {
1403
1404 //
1405 // SpinDown request completed ... whether it succeeded or not is
1406 // another matter entirely.
1407 //
1408
1409 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously sent power irp\n", OriginalIrp));
1410
1411 if (PowerContext->QueueLocked) {
1412
1413 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tUnlocking queue\n", OriginalIrp));
1414
1415 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1416 //
1417 // Will reuse SRB for a non-SCSI SRB.
1418 //
1419 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
1420 STORAGE_ADDRESS_TYPE_BTL8,
1421 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE,
1422 0);
1423 if (NT_SUCCESS(status)) {
1424 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_UNLOCK_QUEUE;
1425
1426 //
1427 // Set length field in Power Context SRB so we know legacy SRB is not being used.
1428 //
1429 PowerContext->Srb.Length = 0;
1430
1431 } else {
1432 //
1433 // Should not occur. Revert to legacy SRB.
1434 //
1435 NT_ASSERT(FALSE);
1436 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(PowerContext->Srb);
1437 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
1438 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
1439 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE;
1440 }
1441 } else {
1442 RtlZeroMemory(srbHeader, sizeof(SCSI_REQUEST_BLOCK));
1443 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
1444 srbHeader->Function = SRB_FUNCTION_UNLOCK_QUEUE;
1445 }
1446
1447 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
1448 SrbAssignSrbFlags(srbHeader, (SRB_FLAGS_BYPASS_LOCKED_QUEUE |
1449 SRB_FLAGS_D3_PROCESSING));
1450
1451 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
1452 nextStack->MajorFunction = IRP_MJ_SCSI;
1453
1454 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
1455 ClasspPowerDownCompletion,
1456 PowerContext,
1457 TRUE,
1458 TRUE,
1459 TRUE);
1460
1461 status = IoCallDriver(commonExtension->LowerDeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp);
1462 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIoCallDriver returned %lx\n",
1463 fdoExtension->PrivateFdoData->PowerProcessIrp,
1464 status));
1465 break;
1466 }
1467
1468 }
1469
1470 case PowerDownDeviceUnlocked3: {
1471
1472 //
1473 // This is the end of the dance.
1474 // We're ignoring possible intermediate error conditions ....
1475 //
1476
1477 if (PowerContext->QueueLocked == FALSE) {
1478 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFall through (queue not locked)\n", OriginalIrp));
1479 } else {
1480 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPreviously unlocked queue\n", OriginalIrp));
1481 NT_ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
1482 NT_ASSERT(srbHeader->SrbStatus == SRB_STATUS_SUCCESS);
1483
1484 if (NT_SUCCESS(Irp->IoStatus.Status)) {
1485 PowerContext->QueueLocked = FALSE;
1486 }
1487 }
1488
1489 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tFreeing srb and completing\n", OriginalIrp));
1490 status = PowerContext->FinalStatus; // allow failure to propogate
1491
1492 OriginalIrp->IoStatus.Status = status;
1493 OriginalIrp->IoStatus.Information = 0;
1494
1495 if (NT_SUCCESS(status)) {
1496
1497 //
1498 // Set the new power state
1499 //
1500
1501 fdoExtension->DevicePowerState =
1502 currentStack->Parameters.Power.State.DeviceState;
1503
1504 }
1505
1506 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", OriginalIrp));
1507
1508 ClassReleaseRemoveLock(PowerContext->DeviceObject, OriginalIrp);
1509
1510 PowerContext->InUse = FALSE;
1511
1512 PoStartNextPowerIrp(OriginalIrp);
1513
1514 fdoExtension->PowerDownInProgress = FALSE;
1515
1516 // prevent from completing the irp allocated by ourselves
1517 if (Irp == fdoExtension->PrivateFdoData->PowerProcessIrp) {
1518 // complete original irp if we are processing powerprocess irp,
1519 // otherwise, by returning status other than STATUS_MORE_PROCESSING_REQUIRED, IO manager will complete it.
1520 ClassCompleteRequest(commonExtension->DeviceObject, OriginalIrp, IO_NO_INCREMENT);
1521 status = STATUS_MORE_PROCESSING_REQUIRED;
1522 }
1523
1524 return status;
1525 }
1526 }
1527
1528 return STATUS_MORE_PROCESSING_REQUIRED;
1529 } // end ClasspPowerDownCompletion()
1530
1531 /*++////////////////////////////////////////////////////////////////////////////
1532
1533 ClasspPowerHandler()
1534
1535 Routine Description:
1536
1537 This routine reduces the number of useless spinups and spindown requests
1538 sent to a given device by ignoring transitions to power states we are
1539 currently in.
1540
1541 ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
1542 allowing the drive
1543
1544 Arguments:
1545
1546 DeviceObject - the device object which is transitioning power states
1547 Irp - the power irp
1548 Options - a set of flags indicating what the device handles
1549
1550 Return Value:
1551
1552 --*/
1553 NTSTATUS
ClasspPowerHandler(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN CLASS_POWER_OPTIONS Options)1554 ClasspPowerHandler(
1555 IN PDEVICE_OBJECT DeviceObject,
1556 IN PIRP Irp,
1557 IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
1558 )
1559 {
1560 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1561 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
1562 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1563 PIO_STACK_LOCATION nextIrpStack;
1564 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1565 PCLASS_POWER_CONTEXT context;
1566 PSTORAGE_REQUEST_BLOCK_HEADER srbHeader;
1567 ULONG srbFlags;
1568 NTSTATUS status;
1569
1570 _Analysis_assume_(fdoExtension);
1571 _Analysis_assume_(fdoExtension->PrivateFdoData);
1572
1573 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerHandler: Power irp %p to %s %p\n",
1574 Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject));
1575
1576 if (!commonExtension->IsFdo) {
1577
1578 //
1579 // certain assumptions are made here,
1580 // particularly: having the fdoExtension
1581 //
1582
1583 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "ClasspPowerHandler: Called for PDO %p???\n",
1584 DeviceObject));
1585 NT_ASSERT(!"PDO using ClasspPowerHandler");
1586
1587 ClassReleaseRemoveLock(DeviceObject, Irp);
1588 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1589 PoStartNextPowerIrp(Irp);
1590 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1591 return STATUS_NOT_SUPPORTED;
1592 }
1593
1594 switch (irpStack->MinorFunction) {
1595
1596 case IRP_MN_SET_POWER: {
1597 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
1598
1599 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIRP_MN_SET_POWER\n", Irp));
1600
1601 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSetting %s state to %d\n",
1602 Irp,
1603 (irpStack->Parameters.Power.Type == SystemPowerState ?
1604 "System" : "Device"),
1605 irpStack->Parameters.Power.State.SystemState));
1606
1607 switch (irpStack->Parameters.Power.ShutdownType){
1608
1609 case PowerActionNone:
1610
1611 //
1612 // Skip if device doesn't need volume verification during idle power
1613 // transitions.
1614 //
1615 if ((fdoExtension->FunctionSupportInfo) &&
1616 (fdoExtension->FunctionSupportInfo->IdlePower.NoVerifyDuringIdlePower)) {
1617 break;
1618 }
1619
1620 case PowerActionSleep:
1621 case PowerActionHibernate:
1622 if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug) {
1623 /*
1624 * We are suspending device and this drive is either hot-pluggable
1625 * or contains removeable media.
1626 * Set the media dirty bit, since the media may change while
1627 * we are suspended.
1628 */
1629 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
1630
1631 //
1632 // Bumping the media change count will force the
1633 // file system to verify the volume when we resume
1634 //
1635
1636 InterlockedIncrement((volatile LONG *)&fdoExtension->MediaChangeCount);
1637 }
1638
1639 break;
1640 }
1641
1642 break;
1643 }
1644
1645 default: {
1646
1647 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tIrp minor code = %#x\n",
1648 Irp, irpStack->MinorFunction));
1649 break;
1650 }
1651 }
1652
1653 if (irpStack->Parameters.Power.Type != DevicePowerState ||
1654 irpStack->MinorFunction != IRP_MN_SET_POWER) {
1655
1656 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tSending to lower device\n", Irp));
1657
1658 goto ClasspPowerHandlerCleanup;
1659
1660 }
1661
1662 //
1663 // already in exact same state, don't work to transition to it.
1664 //
1665
1666 if (irpStack->Parameters.Power.State.DeviceState ==
1667 fdoExtension->DevicePowerState) {
1668
1669 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tAlready in device state %x\n",
1670 Irp, fdoExtension->DevicePowerState));
1671 goto ClasspPowerHandlerCleanup;
1672
1673 }
1674
1675 //
1676 // or powering down from non-d0 state (device already stopped)
1677 // NOTE -- we're not sure whether this case can exist or not (the
1678 // power system may never send this sort of request) but it's trivial
1679 // to deal with.
1680 //
1681
1682 if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) &&
1683 (fdoExtension->DevicePowerState != PowerDeviceD0)) {
1684 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tAlready powered down to %x???\n",
1685 Irp, fdoExtension->DevicePowerState));
1686 fdoExtension->DevicePowerState =
1687 irpStack->Parameters.Power.State.DeviceState;
1688 goto ClasspPowerHandlerCleanup;
1689 }
1690
1691 //
1692 // or when not handling powering up and are powering up
1693 //
1694
1695 if ((!Options.HandleSpinUp) &&
1696 (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) {
1697
1698 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tNot handling spinup to state %x\n",
1699 Irp, fdoExtension->DevicePowerState));
1700 fdoExtension->DevicePowerState =
1701 irpStack->Parameters.Power.State.DeviceState;
1702 goto ClasspPowerHandlerCleanup;
1703
1704 }
1705
1706 //
1707 // or when not handling powering down and are powering down
1708 //
1709
1710 if ((!Options.HandleSpinDown) &&
1711 (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) {
1712
1713 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tNot handling spindown to state %x\n",
1714 Irp, fdoExtension->DevicePowerState));
1715 fdoExtension->DevicePowerState =
1716 irpStack->Parameters.Power.State.DeviceState;
1717 goto ClasspPowerHandlerCleanup;
1718
1719 }
1720
1721 //
1722 // validation completed, start the real work.
1723 //
1724
1725 IoReuseIrp(fdoExtension->PrivateFdoData->PowerProcessIrp, STATUS_SUCCESS);
1726 IoSetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp);
1727 nextIrpStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp);
1728
1729 context = &(fdoExtension->PowerContext);
1730
1731 NT_ASSERT(context->InUse == FALSE);
1732
1733 RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT));
1734 context->InUse = TRUE;
1735
1736 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1737 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx);
1738
1739 //
1740 // Initialize extended SRB for a SRB_FUNCTION_LOCK_QUEUE
1741 //
1742 status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srbHeader,
1743 STORAGE_ADDRESS_TYPE_BTL8,
1744 CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE,
1745 0);
1746 if (NT_SUCCESS(status)) {
1747 ((PSTORAGE_REQUEST_BLOCK)srbHeader)->SrbFunction = SRB_FUNCTION_LOCK_QUEUE;
1748 } else {
1749 //
1750 // Should not happen. Revert to legacy SRB.
1751 //
1752 NT_ASSERT(FALSE);
1753 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(context->Srb);
1754 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
1755 srbHeader->Function = SRB_FUNCTION_LOCK_QUEUE;
1756 }
1757 } else {
1758 srbHeader = (PSTORAGE_REQUEST_BLOCK_HEADER)&(context->Srb);
1759 srbHeader->Length = sizeof(SCSI_REQUEST_BLOCK);
1760 srbHeader->Function = SRB_FUNCTION_LOCK_QUEUE;
1761 }
1762 nextIrpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
1763 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1764
1765 context->FinalStatus = STATUS_SUCCESS;
1766
1767 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
1768 SrbSetSrbFlags(srbHeader, (SRB_FLAGS_BYPASS_LOCKED_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE));
1769
1770 fdoExtension->PrivateFdoData->MaxPowerOperationRetryCount = MAXIMUM_RETRIES;
1771 context->RetryCount = MAXIMUM_RETRIES;
1772
1773 context->Options = Options;
1774 context->DeviceObject = DeviceObject;
1775 context->Irp = Irp;
1776
1777 if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
1778
1779 NT_ASSERT(Options.HandleSpinUp);
1780
1781 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tpower up - locking queue\n", Irp));
1782
1783 //
1784 // We need to issue a queue lock request so that we
1785 // can spin the drive back up after the power is restored
1786 // but before any requests are processed.
1787 //
1788
1789 context->Options.PowerDown = FALSE;
1790 context->PowerChangeState.PowerUp = PowerUpDeviceInitial;
1791 context->CompletionRoutine = ClasspPowerUpCompletion;
1792
1793 } else {
1794
1795 NT_ASSERT(Options.HandleSpinDown);
1796
1797 fdoExtension->PowerDownInProgress = TRUE;
1798
1799 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tPowering down - locking queue\n", Irp));
1800
1801 //
1802 // Disable tick timer at beginning of D3 processing if running.
1803 //
1804 if ((fdoExtension->PrivateFdoData->TickTimerEnabled)) {
1805 ClasspDisableTimer(fdoExtension);
1806 }
1807
1808 PoSetPowerState(DeviceObject,
1809 irpStack->Parameters.Power.Type,
1810 irpStack->Parameters.Power.State);
1811
1812 context->Options.PowerDown = TRUE;
1813 context->PowerChangeState.PowerDown3 = PowerDownDeviceInitial3;
1814 context->CompletionRoutine = ClasspPowerDownCompletion;
1815
1816 }
1817
1818 //
1819 // we are not dealing with port-allocated sense in these routines.
1820 //
1821
1822 srbFlags = SrbGetSrbFlags(srbHeader);
1823 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
1824 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
1825
1826 //
1827 // Mark the original power irp pending.
1828 //
1829
1830 IoMarkIrpPending(Irp);
1831
1832 if (Options.LockQueue) {
1833
1834 //
1835 // Send the lock irp down.
1836 //
1837
1838 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
1839 context->CompletionRoutine,
1840 context,
1841 TRUE,
1842 TRUE,
1843 TRUE);
1844
1845 IoCallDriver(lowerDevice, fdoExtension->PrivateFdoData->PowerProcessIrp);
1846
1847 } else {
1848
1849 //
1850 // Call the completion routine directly. It won't care what the
1851 // status of the "lock" was - it will just go and do the next
1852 // step of the operation.
1853 //
1854
1855 context->CompletionRoutine(DeviceObject, fdoExtension->PrivateFdoData->PowerProcessIrp, context);
1856 }
1857
1858 return STATUS_PENDING;
1859
1860 ClasspPowerHandlerCleanup:
1861
1862 //
1863 // Send the original power irp down, we will start the next power irp in completion routine.
1864 //
1865 ClassReleaseRemoveLock(DeviceObject, Irp);
1866
1867 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", Irp));
1868 IoCopyCurrentIrpStackLocationToNext(Irp);
1869 IoSetCompletionRoutine(Irp,
1870 ClasspStartNextPowerIrpCompletion,
1871 NULL,
1872 TRUE,
1873 TRUE,
1874 TRUE);
1875 return PoCallDriver(lowerDevice, Irp);
1876 } // end ClasspPowerHandler()
1877
1878 /*++////////////////////////////////////////////////////////////////////////////
1879
1880 ClassMinimalPowerHandler()
1881
1882 Routine Description:
1883
1884 This routine is the minimum power handler for a storage driver. It does
1885 the least amount of work possible.
1886
1887 --*/
1888 NTSTATUS
1889 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClassMinimalPowerHandler(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1890 ClassMinimalPowerHandler(
1891 IN PDEVICE_OBJECT DeviceObject,
1892 IN PIRP Irp
1893 )
1894 {
1895 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1896 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1897 NTSTATUS status;
1898
1899 ClassReleaseRemoveLock(DeviceObject, Irp);
1900 PoStartNextPowerIrp(Irp);
1901
1902 switch (irpStack->MinorFunction)
1903 {
1904 case IRP_MN_SET_POWER:
1905 {
1906 switch (irpStack->Parameters.Power.ShutdownType)
1907 {
1908 case PowerActionNone:
1909 case PowerActionSleep:
1910 case PowerActionHibernate:
1911 {
1912 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
1913 {
1914 if ((ClassGetVpb(DeviceObject) != NULL) && (ClassGetVpb(DeviceObject)->Flags & VPB_MOUNTED))
1915 {
1916 //
1917 // This flag will cause the filesystem to verify the
1918 // volume when coming out of hibernation or standby or runtime power
1919 //
1920 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
1921 }
1922 }
1923 }
1924 break;
1925 }
1926 }
1927
1928 //
1929 // Fall through
1930 //
1931
1932 case IRP_MN_QUERY_POWER:
1933 {
1934 if (!commonExtension->IsFdo)
1935 {
1936 Irp->IoStatus.Status = STATUS_SUCCESS;
1937 Irp->IoStatus.Information = 0;
1938 }
1939 }
1940 break;
1941 }
1942
1943 if (commonExtension->IsFdo)
1944 {
1945 IoCopyCurrentIrpStackLocationToNext(Irp);
1946 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
1947 }
1948 else
1949 {
1950 status = Irp->IoStatus.Status;
1951 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1952 }
1953
1954 return status;
1955 } // end ClassMinimalPowerHandler()
1956
1957 /*++////////////////////////////////////////////////////////////////////////////
1958
1959 ClassSpinDownPowerHandler()
1960
1961 Routine Description:
1962
1963 This routine is a callback for disks and other things which require both
1964 a start and a stop to be sent to the device. (actually the starts are
1965 almost always optional, since most device power themselves on to process
1966 commands, but i digress).
1967
1968 Determines proper use of spinup, spindown, and queue locking based upon
1969 ScanForSpecialFlags in the FdoExtension. This is the most common power
1970 handler passed into classpnp.sys
1971
1972 Arguments:
1973
1974 DeviceObject - Supplies the functional device object
1975
1976 Irp - Supplies the request to be retried.
1977
1978 Return Value:
1979
1980 None
1981
1982 --*/
__control_entrypoint(DeviceDriver)1983 __control_entrypoint(DeviceDriver)
1984 NTSTATUS
1985 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1986 ClassSpinDownPowerHandler(
1987 _In_ PDEVICE_OBJECT DeviceObject,
1988 _In_ PIRP Irp
1989 )
1990 {
1991 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1992 CLASS_POWER_OPTIONS options = {0};
1993
1994 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1995
1996 //
1997 // check the flags to see what options we need to worry about
1998 //
1999
2000 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
2001 CLASS_SPECIAL_DISABLE_SPIN_DOWN)) {
2002 options.HandleSpinDown = TRUE;
2003 }
2004
2005 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
2006 CLASS_SPECIAL_DISABLE_SPIN_UP)) {
2007 options.HandleSpinUp = TRUE;
2008 }
2009
2010 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
2011 CLASS_SPECIAL_NO_QUEUE_LOCK)) {
2012 options.LockQueue = TRUE;
2013 }
2014
2015 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "ClasspPowerHandler: Devobj %p\n"
2016 "\t%shandling spin down\n"
2017 "\t%shandling spin up\n"
2018 "\t%slocking queue\n",
2019 DeviceObject,
2020 (options.HandleSpinDown ? "" : "not "),
2021 (options.HandleSpinUp ? "" : "not "),
2022 (options.LockQueue ? "" : "not ")
2023 ));
2024
2025 //
2026 // do all the dirty work
2027 //
2028
2029 return ClasspPowerHandler(DeviceObject, Irp, options);
2030 } // end ClassSpinDownPowerHandler()
2031
2032 /*++////////////////////////////////////////////////////////////////////////////
2033
2034 ClassStopUnitPowerHandler()
2035
2036 Routine Description:
2037
2038 This routine is an outdated call. To achieve equivalent functionality,
2039 the driver should set the following flags in ScanForSpecialFlags in the
2040 FdoExtension:
2041
2042 CLASS_SPECIAL_DISABLE_SPIN_UP
2043 CLASS_SPECIAL_NO_QUEUE_LOCK
2044
2045 --*/
2046 NTSTATUS
2047 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClassStopUnitPowerHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)2048 ClassStopUnitPowerHandler(
2049 _In_ PDEVICE_OBJECT DeviceObject,
2050 _In_ PIRP Irp
2051 )
2052 {
2053 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
2054
2055 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_POWER, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
2056 "Drivers should set the following flags in ScanForSpecialFlags "
2057 " in the FDO extension:\n"
2058 "\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
2059 "\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
2060 "This will provide equivalent functionality if the power "
2061 "routine is then set to ClassSpinDownPowerHandler\n\n",
2062 DeviceObject));
2063
2064 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2065
2066 SET_FLAG(fdoExtension->ScanForSpecialFlags,
2067 CLASS_SPECIAL_DISABLE_SPIN_UP);
2068 SET_FLAG(fdoExtension->ScanForSpecialFlags,
2069 CLASS_SPECIAL_NO_QUEUE_LOCK);
2070
2071 return ClassSpinDownPowerHandler(DeviceObject, Irp);
2072 } // end ClassStopUnitPowerHandler()
2073
2074 /*++////////////////////////////////////////////////////////////////////////////
2075
2076 RetryPowerRequest()
2077
2078 Routine Description:
2079
2080 This routine reinitalizes the necessary fields, and sends the request
2081 to the lower driver.
2082
2083 Arguments:
2084
2085 DeviceObject - Supplies the device object associated with this request.
2086
2087 Irp - Supplies the request to be retried.
2088
2089 Context - Supplies a pointer to the power up context for this request.
2090
2091 Return Value:
2092
2093 None
2094
2095 --*/
2096 VOID
RetryPowerRequest(PDEVICE_OBJECT DeviceObject,PIRP Irp,PCLASS_POWER_CONTEXT Context)2097 RetryPowerRequest(
2098 PDEVICE_OBJECT DeviceObject,
2099 PIRP Irp,
2100 PCLASS_POWER_CONTEXT Context
2101 )
2102 {
2103 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
2104 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
2105 (PFUNCTIONAL_DEVICE_EXTENSION)Context->DeviceObject->DeviceExtension;
2106 PSTORAGE_REQUEST_BLOCK_HEADER srb;
2107 LONGLONG dueTime;
2108 ULONG srbFlags;
2109 ULONG srbFunction;
2110
2111 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tDelaying retry by queueing DPC\n", Irp));
2112
2113 //NT_ASSERT(Context->Irp == Irp);
2114 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2115 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(fdoExtension->PrivateFdoData->PowerSrb.SrbEx);
2116
2117 //
2118 // Check if reverted to using legacy SRB.
2119 //
2120 if (Context->Srb.Length == sizeof(SCSI_REQUEST_BLOCK)) {
2121 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(Context->Srb);
2122 srbFunction = srb->Function;
2123 } else {
2124 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction;
2125 }
2126 } else {
2127 srb = (PSTORAGE_REQUEST_BLOCK_HEADER)&(Context->Srb);
2128 srbFunction = srb->Function;
2129 }
2130
2131 NT_ASSERT(Context->DeviceObject == DeviceObject);
2132 srbFlags = SrbGetSrbFlags(srb);
2133 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
2134 NT_ASSERT(!TEST_FLAG(srbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
2135
2136 if (Context->RetryInterval == 0) {
2137
2138 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tDelaying minimum time (.2 sec)\n", Irp));
2139 dueTime = (LONGLONG)1000000 * 2;
2140
2141 } else {
2142
2143 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tDelaying %x seconds\n",
2144 Irp, Context->RetryInterval));
2145 dueTime = (LONGLONG)1000000 * 10 * Context->RetryInterval;
2146
2147 }
2148
2149 //
2150 // reset the retry interval
2151 //
2152
2153 Context->RetryInterval = 0;
2154
2155 //
2156 // Reset byte count of transfer in SRB Extension.
2157 //
2158
2159 SrbSetDataTransferLength(srb, 0);
2160
2161 //
2162 // Zero SRB statuses.
2163 //
2164
2165 srb->SrbStatus = 0;
2166 if (srbFunction == SRB_FUNCTION_EXECUTE_SCSI) {
2167 SrbSetScsiStatus(srb, 0);
2168 }
2169
2170 //
2171 // Set up major SCSI function.
2172 //
2173
2174 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2175
2176 //
2177 // Save SRB address in next stack for port driver.
2178 //
2179
2180 nextIrpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srb;
2181
2182 //
2183 // Set the completion routine up again.
2184 //
2185
2186 IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context,
2187 TRUE, TRUE, TRUE);
2188
2189 ClassRetryRequest(DeviceObject, Irp, dueTime);
2190
2191 return;
2192
2193 } // end RetryRequest()
2194
2195 /*++////////////////////////////////////////////////////////////////////////////
2196
2197 ClasspStartNextPowerIrpCompletion()
2198
2199 Routine Description:
2200
2201 This routine guarantees that the next power irp (power up or down) is not
2202 sent until the previous one has fully completed.
2203
2204 --*/
2205 NTSTATUS
2206 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClasspStartNextPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)2207 ClasspStartNextPowerIrpCompletion(
2208 IN PDEVICE_OBJECT DeviceObject,
2209 IN PIRP Irp,
2210 IN PVOID Context
2211 )
2212 {
2213 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context;
2214
2215 UNREFERENCED_PARAMETER(DeviceObject);
2216
2217 if (Irp->PendingReturned) {
2218 IoMarkIrpPending(Irp);
2219 }
2220
2221 if (PowerContext != NULL)
2222 {
2223 PowerContext->InUse = FALSE;
2224 }
2225
2226
2227 PoStartNextPowerIrp(Irp);
2228 return STATUS_SUCCESS;
2229 } // end ClasspStartNextPowerIrpCompletion()
2230
2231 NTSTATUS
2232 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
ClasspDeviceLockFailurePowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)2233 ClasspDeviceLockFailurePowerIrpCompletion(
2234 IN PDEVICE_OBJECT DeviceObject,
2235 IN PIRP Irp,
2236 IN PVOID Context
2237 )
2238 {
2239 PCLASS_POWER_CONTEXT PowerContext = (PCLASS_POWER_CONTEXT)Context;
2240 PCOMMON_DEVICE_EXTENSION commonExtension;
2241 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
2242 PIO_STACK_LOCATION currentStack;
2243 BOOLEAN FailurePredictionEnabled = FALSE;
2244
2245 UNREFERENCED_PARAMETER(DeviceObject);
2246
2247 commonExtension = PowerContext->DeviceObject->DeviceExtension;
2248 fdoExtension = PowerContext->DeviceObject->DeviceExtension;
2249
2250 currentStack = IoGetCurrentIrpStackLocation(Irp);
2251
2252 //
2253 // Set the new power state
2254 //
2255
2256 fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState;
2257
2258 //
2259 // We reach here becasue LockQueue operation was not successful.
2260 // However, media change detection would not happen in case of resume becasue we
2261 // had disabled the timer while going into lower power state.
2262 // So, if the device goes into D0 then enable the tick timer.
2263 //
2264
2265 if (fdoExtension->DevicePowerState == PowerDeviceD0) {
2266 //
2267 // Check whether failure detection is enabled
2268 //
2269
2270 if ((fdoExtension->FailurePredictionInfo != NULL) &&
2271 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)) {
2272 FailurePredictionEnabled = TRUE;
2273 }
2274
2275 //
2276 // Enable tick timer at end of D0 processing if it was previously enabled.
2277 //
2278
2279 if ((commonExtension->DriverExtension->InitData.ClassTick != NULL) ||
2280 ((fdoExtension->MediaChangeDetectionInfo != NULL) &&
2281 (fdoExtension->FunctionSupportInfo != NULL) &&
2282 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) ||
2283 (FailurePredictionEnabled)) {
2284
2285 //
2286 // If failure prediction is turned on and we've been powered
2287 // off longer than the failure prediction query period then
2288 // force the query on the next timer tick.
2289 //
2290
2291 if ((FailurePredictionEnabled) && (ClasspFailurePredictionPeriodMissed(fdoExtension))) {
2292 fdoExtension->FailurePredictionInfo->CountDown = 1;
2293 }
2294
2295 //
2296 // Finally, enable the timer.
2297 //
2298
2299 ClasspEnableTimer(fdoExtension);
2300 }
2301 }
2302
2303 //
2304 // Indicate to Po that we've been successfully powered up so
2305 // it can do it's notification stuff.
2306 //
2307
2308 PoSetPowerState(PowerContext->DeviceObject,
2309 currentStack->Parameters.Power.Type,
2310 currentStack->Parameters.Power.State);
2311
2312 PowerContext->InUse = FALSE;
2313
2314
2315 ClassReleaseRemoveLock(commonExtension->DeviceObject, Irp);
2316
2317 //
2318 // Start the next power IRP
2319 //
2320
2321 if (Irp->PendingReturned) {
2322 IoMarkIrpPending(Irp);
2323 }
2324
2325 PoStartNextPowerIrp(Irp);
2326
2327 return STATUS_SUCCESS;
2328 }
2329
2330
2331 _IRQL_requires_same_
2332 NTSTATUS
ClasspSendEnableIdlePowerIoctl(_In_ PDEVICE_OBJECT DeviceObject)2333 ClasspSendEnableIdlePowerIoctl(
2334 _In_ PDEVICE_OBJECT DeviceObject
2335 )
2336 /*++
2337 Description:
2338
2339 This function is used to send IOCTL_STORAGE_ENABLE_IDLE_POWER to the port
2340 driver. It pulls the relevant idle power management properties from the
2341 FDO's device extension.
2342
2343 Arguments:
2344
2345 DeviceObject - The class FDO.
2346
2347 Return Value:
2348
2349 The NTSTATUS code returned from the port driver. STATUS_SUCCESS indicates
2350 this device is now enabled for idle (runtime) power management.
2351
2352 --*/
2353 {
2354 NTSTATUS status;
2355 STORAGE_IDLE_POWER idlePower = {0};
2356 IO_STATUS_BLOCK ioStatus = {0};
2357 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2358 PCOMMON_DEVICE_EXTENSION commonExtension = &(fdoExtension->CommonExtension);
2359
2360 idlePower.Version = 1;
2361 idlePower.Size = sizeof(STORAGE_IDLE_POWER);
2362 idlePower.WakeCapableHint = fdoExtension->FunctionSupportInfo->IdlePower.DeviceWakeable;
2363 idlePower.D3ColdSupported = fdoExtension->FunctionSupportInfo->IdlePower.D3ColdSupported;
2364 idlePower.D3IdleTimeout = fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout;
2365
2366 ClassSendDeviceIoControlSynchronous(
2367 IOCTL_STORAGE_ENABLE_IDLE_POWER,
2368 commonExtension->LowerDeviceObject,
2369 &idlePower,
2370 sizeof(STORAGE_IDLE_POWER),
2371 0,
2372 FALSE,
2373 &ioStatus
2374 );
2375
2376 status = ioStatus.Status;
2377
2378 TracePrint((TRACE_LEVEL_INFORMATION,
2379 TRACE_FLAG_POWER,
2380 "ClasspSendEnableIdlePowerIoctl: Port driver returned status (%x) for FDO (%p)\n"
2381 "\tWakeCapableHint: %u\n"
2382 "\tD3ColdSupported: %u\n"
2383 "\tD3IdleTimeout: %u (ms)",
2384 status,
2385 DeviceObject,
2386 idlePower.WakeCapableHint,
2387 idlePower.D3ColdSupported,
2388 idlePower.D3IdleTimeout));
2389
2390 return status;
2391 }
2392
_Function_class_(POWER_SETTING_CALLBACK)2393 _Function_class_(POWER_SETTING_CALLBACK)
2394 _IRQL_requires_same_
2395 NTSTATUS
2396 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2397 ClasspPowerSettingCallback(
2398 _In_ LPCGUID SettingGuid,
2399 _In_reads_bytes_(ValueLength) PVOID Value,
2400 _In_ ULONG ValueLength,
2401 _Inout_opt_ PVOID Context
2402 )
2403 /*++
2404 Description:
2405
2406 This function is the callback for power setting notifications (registered
2407 when ClasspGetD3IdleTimeout() is called for the first time).
2408
2409 Currently, this function is used to get the disk idle timeout value from
2410 the system power settings.
2411
2412 This function is guaranteed to be called at PASSIVE_LEVEL.
2413
2414 Arguments:
2415
2416 SettingGuid - The power setting GUID.
2417 Value - Pointer to the power setting value.
2418 ValueLength - Size of the Value buffer.
2419 Context - The FDO's device extension.
2420
2421 Return Value:
2422
2423 STATUS_SUCCESS
2424
2425 --*/
2426 {
2427 PIDLE_POWER_FDO_LIST_ENTRY fdoEntry = NULL;
2428
2429 #ifdef _MSC_VER
2430 #pragma warning(suppress:4054) // okay to type cast function pointer to PIRP for this use case
2431 #endif
2432 PIRP removeLockTag = (PIRP)&ClasspPowerSettingCallback;
2433
2434 UNREFERENCED_PARAMETER(Context);
2435
2436 PAGED_CODE();
2437
2438 if (IsEqualGUID(SettingGuid, &GUID_DISK_IDLE_TIMEOUT)) {
2439 if (ValueLength != sizeof(ULONG) || Value == NULL) {
2440 return STATUS_INVALID_PARAMETER;
2441 }
2442
2443 //
2444 // The value supplied by this GUID is already in milliseconds.
2445 //
2446 DiskIdleTimeoutInMS = *((PULONG)Value);
2447
2448 //
2449 // For each FDO on the idle power list, grab the remove lock and send
2450 // IOCTL_STORAGE_ENABLE_IDLE_POWER to the port driver to update the
2451 // idle timeout value.
2452 //
2453 KeAcquireGuardedMutex(&IdlePowerFDOListMutex);
2454 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)IdlePowerFDOList.Flink;
2455 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) {
2456
2457 ULONG isRemoved = ClassAcquireRemoveLock(fdoEntry->Fdo, removeLockTag);
2458
2459 if (!isRemoved) {
2460 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)fdoEntry->Fdo->DeviceExtension;
2461
2462 //
2463 // Apply the new timeout if the user hasn't overridden it via the registry.
2464 //
2465 if (!fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeoutOverridden) {
2466 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout = DiskIdleTimeoutInMS;
2467 ClasspSendEnableIdlePowerIoctl(fdoEntry->Fdo);
2468 }
2469 }
2470
2471 ClassReleaseRemoveLock(fdoEntry->Fdo, removeLockTag);
2472
2473 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink;
2474 }
2475 KeReleaseGuardedMutex(&IdlePowerFDOListMutex);
2476
2477 } else if (IsEqualGUID(SettingGuid, &GUID_CONSOLE_DISPLAY_STATE)) {
2478
2479 //
2480 // If monitor is off, change media change requests to not
2481 // keep device active. This allows removable media devices to
2482 // go to sleep if there are no other active requests. Otherwise,
2483 // let media change requests keep the device active.
2484 //
2485 if ((ValueLength == sizeof(ULONG)) && (Value != NULL)) {
2486 if (*((PULONG)Value) == PowerMonitorOff) {
2487 ClasspScreenOff = TRUE;
2488 } else {
2489 ClasspScreenOff = FALSE;
2490 }
2491
2492 KeAcquireGuardedMutex(&IdlePowerFDOListMutex);
2493 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)IdlePowerFDOList.Flink;
2494 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) {
2495
2496 ULONG isRemoved = ClassAcquireRemoveLock(fdoEntry->Fdo, removeLockTag);
2497 if (!isRemoved) {
2498 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)fdoEntry->Fdo->DeviceExtension;
2499
2500 if (ClasspScreenOff == FALSE) {
2501 //
2502 // Now that the screen is on, we may need to check for media
2503 // for devices that are not in D0 and may have removable media.
2504 // This is because the media change polling has been disabled
2505 // for devices in D3 and now that the screen is on the user may
2506 // have inserted some media that they want to interact with.
2507 //
2508 if ((fdoExtension->DevicePowerState != PowerDeviceD0) &&
2509 (fdoExtension->MediaChangeDetectionInfo != NULL) &&
2510 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) {
2511 ClassCheckMediaState(fdoExtension);
2512 }
2513
2514 //
2515 // We disabled failure prediction polling during screen-off
2516 // so now check to see if we missed a failure prediction
2517 // period and if so, force the IOCTL to be sent now.
2518 //
2519 if ((fdoExtension->FailurePredictionInfo != NULL) &&
2520 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)) {
2521 if (ClasspFailurePredictionPeriodMissed(fdoExtension)) {
2522 fdoExtension->FailurePredictionInfo->CountDown = 1;
2523 }
2524 }
2525 }
2526
2527 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
2528 //
2529 // Screen state has changed so attempt to update the tick
2530 // timer's no-wake tolerance accordingly.
2531 //
2532 ClasspUpdateTimerNoWakeTolerance(fdoExtension);
2533 #endif
2534 }
2535 ClassReleaseRemoveLock(fdoEntry->Fdo, removeLockTag);
2536
2537 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink;
2538 }
2539 KeReleaseGuardedMutex(&IdlePowerFDOListMutex);
2540 }
2541
2542 }
2543
2544 return STATUS_SUCCESS;
2545 }
2546
2547
2548 _IRQL_requires_same_
2549 NTSTATUS
ClasspEnableIdlePower(_In_ PDEVICE_OBJECT DeviceObject)2550 ClasspEnableIdlePower(
2551 _In_ PDEVICE_OBJECT DeviceObject
2552 )
2553 /*++
2554 Description:
2555
2556 This function is used to enable idle (runtime) power management for the
2557 device. It will do the work to determine D3Cold support, idle timeout,
2558 etc. and then notify the port driver that it wants to enable idle power
2559 management.
2560
2561 This function may modify some of the idle power fields in the FDO's device
2562 extension.
2563
2564 Arguments:
2565
2566 DeviceObject - The class FDO.
2567
2568 Return Value:
2569
2570 An NTSTATUS code indicating the status of the operation.
2571
2572 --*/
2573 {
2574 NTSTATUS status = STATUS_SUCCESS;
2575 ULONG d3ColdDisabledByUser = FALSE;
2576 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2577 ULONG idleTimeoutOverrideInSeconds = 0;
2578
2579 //
2580 // This function should only be called once.
2581 //
2582 NT_ASSERT(fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled == FALSE);
2583
2584 ClassGetDeviceParameter(fdoExtension,
2585 CLASSP_REG_SUBKEY_NAME,
2586 CLASSP_REG_DISABLE_D3COLD,
2587 &d3ColdDisabledByUser);
2588
2589 //
2590 // If the device is hot-pluggable or the user has explicitly
2591 // disabled D3Cold, do not enable D3Cold for this device.
2592 //
2593 if (d3ColdDisabledByUser || fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug) {
2594 fdoExtension->FunctionSupportInfo->IdlePower.D3ColdSupported = 0;
2595 }
2596
2597 ClassGetDeviceParameter(fdoExtension,
2598 CLASSP_REG_SUBKEY_NAME,
2599 CLASSP_REG_IDLE_TIMEOUT_IN_SECONDS,
2600 &idleTimeoutOverrideInSeconds);
2601
2602 //
2603 // Set the idle timeout. If the user has not specified an override value,
2604 // this will either be a default value or will have been updated by the
2605 // power setting notification callback.
2606 //
2607 if (idleTimeoutOverrideInSeconds != 0) {
2608 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout = (idleTimeoutOverrideInSeconds * 1000);
2609 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeoutOverridden = TRUE;
2610 } else {
2611 fdoExtension->FunctionSupportInfo->IdlePower.D3IdleTimeout = DiskIdleTimeoutInMS;
2612 }
2613
2614 //
2615 // We don't allow disks to be wakeable.
2616 //
2617 fdoExtension->FunctionSupportInfo->IdlePower.DeviceWakeable = FALSE;
2618
2619 //
2620 // Send IOCTL_STORAGE_ENABLE_IDLE_POWER to the port driver to enable idle
2621 // power management by the port driver.
2622 //
2623 status = ClasspSendEnableIdlePowerIoctl(DeviceObject);
2624
2625 if (NT_SUCCESS(status)) {
2626 PIDLE_POWER_FDO_LIST_ENTRY fdoEntry = NULL;
2627
2628 //
2629 // Put this FDO on the list of devices that are idle power managed.
2630 //
2631 fdoEntry = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(IDLE_POWER_FDO_LIST_ENTRY), CLASS_TAG_POWER);
2632 if (fdoEntry) {
2633
2634 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled = TRUE;
2635
2636 fdoEntry->Fdo = DeviceObject;
2637
2638 KeAcquireGuardedMutex(&IdlePowerFDOListMutex);
2639 InsertHeadList(&IdlePowerFDOList, &(fdoEntry->ListEntry));
2640 KeReleaseGuardedMutex(&IdlePowerFDOListMutex);
2641
2642 //
2643 // If not registered already, register for disk idle timeout power
2644 // setting notifications. The power manager will call our power
2645 // setting callback very soon to set the idle timeout to the actual
2646 // value.
2647 //
2648 if (PowerSettingNotificationHandle == NULL) {
2649 PoRegisterPowerSettingCallback(DeviceObject,
2650 &GUID_DISK_IDLE_TIMEOUT,
2651 &ClasspPowerSettingCallback,
2652 NULL,
2653 &(PowerSettingNotificationHandle));
2654 }
2655 } else {
2656 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled = FALSE;
2657 status = STATUS_UNSUCCESSFUL;
2658 }
2659 }
2660
2661 return status;
2662 }
2663
2664