xref: /reactos/drivers/storage/class/classpnp/power.c (revision 682f85ad)
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 */
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 */
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 */
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
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 */
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 --*/
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 */
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
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 */
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 */
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
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 
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
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