ReactOS 0.4.15-dev-7942-gd23573b
power.c File Reference
#include "stddef.h"
#include "ntddk.h"
#include "scsi.h"
#include "classp.h"
Include dependency graph for power.c:

Go to the source code of this file.

Macros

#define CLASS_TAG_POWER   'WLcS'
 
#define DEFAULT_POWER_IRP_TIMEOUT_VALUE   10*60
 
#define TIME_LEFT_FOR_LOWER_DRIVERS   30
 
#define TIME_LEFT_FOR_UPPER_DRIVERS   5
 
#define DEFAULT_IO_TIMEOUT_VALUE   10
 
#define MINIMUM_STOP_UNIT_TIMEOUT_VALUE   2
 
#define MINIMAL_START_UNIT_TIMEOUT_VALUE   60
 
#define MINIMUM_START_UNIT_TIMEOUT_VALUE   30
 

Functions

NTSTATUS ClasspPowerHandler (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN CLASS_POWER_OPTIONS Options)
 
VOID RetryPowerRequest (PDEVICE_OBJECT DeviceObject, PIRP Irp, PCLASS_POWER_CONTEXT Context)
 
NTSTATUS NTAPI ClassDispatchPower (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
 
NTSTATUS NTAPI ClasspPowerUpCompletion (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
 
NTSTATUS NTAPI ClasspPowerDownCompletion (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
 
NTSTATUS NTAPI ClassMinimalPowerHandler (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
 
 __control_entrypoint (DeviceDriver)
 
NTSTATUS NTAPI ClassStopUnitPowerHandler (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
 
NTSTATUS NTAPI ClasspStartNextPowerIrpCompletion (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
 
NTSTATUS NTAPI ClasspDeviceLockFailurePowerIrpCompletion (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
 
_IRQL_requires_same_ NTSTATUS ClasspSendEnableIdlePowerIoctl (_In_ PDEVICE_OBJECT DeviceObject)
 
 _Function_class_ (POWER_SETTING_CALLBACK)
 
_IRQL_requires_same_ NTSTATUS ClasspEnableIdlePower (_In_ PDEVICE_OBJECT DeviceObject)
 

Variables

IO_COMPLETION_ROUTINE ClasspPowerDownCompletion
 
IO_COMPLETION_ROUTINE ClasspPowerUpCompletion
 
IO_COMPLETION_ROUTINE ClasspStartNextPowerIrpCompletion
 
IO_COMPLETION_ROUTINE ClasspDeviceLockFailurePowerIrpCompletion
 

Macro Definition Documentation

◆ CLASS_TAG_POWER

#define CLASS_TAG_POWER   'WLcS'

Definition at line 37 of file power.c.

◆ DEFAULT_IO_TIMEOUT_VALUE

#define DEFAULT_IO_TIMEOUT_VALUE   10

Definition at line 43 of file power.c.

◆ DEFAULT_POWER_IRP_TIMEOUT_VALUE

#define DEFAULT_POWER_IRP_TIMEOUT_VALUE   10*60

Definition at line 40 of file power.c.

◆ MINIMAL_START_UNIT_TIMEOUT_VALUE

#define MINIMAL_START_UNIT_TIMEOUT_VALUE   60

Definition at line 52 of file power.c.

◆ MINIMUM_START_UNIT_TIMEOUT_VALUE

#define MINIMUM_START_UNIT_TIMEOUT_VALUE   30

Definition at line 53 of file power.c.

◆ MINIMUM_STOP_UNIT_TIMEOUT_VALUE

#define MINIMUM_STOP_UNIT_TIMEOUT_VALUE   2

Definition at line 44 of file power.c.

◆ TIME_LEFT_FOR_LOWER_DRIVERS

#define TIME_LEFT_FOR_LOWER_DRIVERS   30

Definition at line 41 of file power.c.

◆ TIME_LEFT_FOR_UPPER_DRIVERS

#define TIME_LEFT_FOR_UPPER_DRIVERS   5

Definition at line 42 of file power.c.

Function Documentation

◆ __control_entrypoint()

__control_entrypoint ( DeviceDriver  )

Definition at line 1983 of file power.c.

1990{
1991 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
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,
2002 options.HandleSpinDown = TRUE;
2003 }
2004
2005 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
2007 options.HandleSpinUp = TRUE;
2008 }
2009
2010 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
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",
2020 (options.HandleSpinDown ? "" : "not "),
2021 (options.HandleSpinUp ? "" : "not "),
2022 (options.LockQueue ? "" : "not ")
2023 ));
2024
2025 //
2026 // do all the dirty work
2027 //
2028
2030} // end ClassSpinDownPowerHandler()
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
#define CLASS_SPECIAL_DISABLE_SPIN_DOWN
Definition: classpnp.h:165
struct _FUNCTIONAL_DEVICE_EXTENSION * PFUNCTIONAL_DEVICE_EXTENSION
#define CLASS_SPECIAL_NO_QUEUE_LOCK
Definition: classpnp.h:167
#define CLASS_SPECIAL_DISABLE_SPIN_UP
Definition: classpnp.h:166
_In_ PIRP Irp
Definition: csq.h:116
#define TRUE
Definition: types.h:120
NTSTATUS ClasspPowerHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN CLASS_POWER_OPTIONS Options)
Definition: power.c:1554
if(dx< 0)
Definition: linetemp.h:194
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055

◆ _Function_class_()

_Function_class_ ( POWER_SETTING_CALLBACK  )

Definition at line 2393 of file power.c.

2426{
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
2435
2436 PAGED_CODE();
2437
2438 if (IsEqualGUID(SettingGuid, &GUID_DISK_IDLE_TIMEOUT)) {
2439 if (ValueLength != sizeof(ULONG) || Value == NULL) {
2441 }
2442
2443 //
2444 // The value supplied by this GUID is already in milliseconds.
2445 //
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 //
2455 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) {
2456
2457 ULONG isRemoved = ClassAcquireRemoveLock(fdoEntry->Fdo, removeLockTag);
2458
2459 if (!isRemoved) {
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;
2468 }
2469 }
2470
2471 ClassReleaseRemoveLock(fdoEntry->Fdo, removeLockTag);
2472
2473 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink;
2474 }
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) {
2488 } else {
2490 }
2491
2494 while ((PLIST_ENTRY)fdoEntry != &IdlePowerFDOList) {
2495
2496 ULONG isRemoved = ClassAcquireRemoveLock(fdoEntry->Fdo, removeLockTag);
2497 if (!isRemoved) {
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 //
2533#endif
2534 }
2535 ClassReleaseRemoveLock(fdoEntry->Fdo, removeLockTag);
2536
2537 fdoEntry = (PIDLE_POWER_FDO_LIST_ENTRY)fdoEntry->ListEntry.Flink;
2538 }
2540 }
2541
2542 }
2543
2544 return STATUS_SUCCESS;
2545}
struct _IRP * PIRP
#define PAGED_CODE()
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
struct _IDLE_POWER_FDO_LIST_ENTRY * PIDLE_POWER_FDO_LIST_ENTRY
POWER_SETTING_CALLBACK ClasspPowerSettingCallback
Definition: classp.h:1619
BOOLEAN ClasspUpdateTimerNoWakeTolerance(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3653
BOOLEAN ClasspScreenOff
Definition: autorun.c:124
BOOLEAN ClasspFailurePredictionPeriodMissed(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:4391
VOID NTAPI ClassCheckMediaState(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:1752
#define ClassAcquireRemoveLock(devobj, tag)
Definition: classpnp.h:100
@ FailurePredictionNone
Definition: classpnp.h:234
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
KGUARDED_MUTEX IdlePowerFDOListMutex
Definition: class.c:114
ULONG DiskIdleTimeoutInMS
Definition: class.c:132
LIST_ENTRY IdlePowerFDOList
Definition: class.c:113
VOID NTAPI ClassReleaseRemoveLock(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Tag)
Definition: lock.c:251
_IRQL_requires_same_ NTSTATUS ClasspSendEnableIdlePowerIoctl(_In_ PDEVICE_OBJECT DeviceObject)
Definition: power.c:2333
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
@ PowerDeviceD0
Definition: ntpoapi.h:49
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
#define STATUS_SUCCESS
Definition: shellext.h:65
PVOID DeviceExtension
Definition: env_spec_w32.h:418
struct _FAILURE_PREDICTION_INFO * FailurePredictionInfo
Definition: classpnp.h:919
DEVICE_POWER_STATE DevicePowerState
Definition: classpnp.h:878
PMEDIA_CHANGE_DETECTION_INFO MediaChangeDetectionInfo
Definition: classpnp.h:905
Definition: classp.h:1033
LIST_ENTRY ListEntry
Definition: classp.h:1034
PDEVICE_OBJECT Fdo
Definition: classp.h:1035
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
uint32_t * PULONG
Definition: typedefs.h:59
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_In_ LPCGUID SettingGuid
Definition: pofuncs.h:120
@ PowerMonitorOff
Definition: potypes.h:151

◆ ClassDispatchPower()

NTSTATUS NTAPI ClassDispatchPower ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp 
)

Definition at line 105 of file power.c.

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
129 return PoCallDriver(commonExtension->LowerDeviceObject, Irp);
130 }
131
133
134 if (isRemoved) {
136 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
140 }
141
142 return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
143} // end ClassDispatchPower()
VOID NTAPI ClassCompleteRequest(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ CCHAR PriorityBoost)
Definition: lock.c:401
#define IoSkipCurrentIrpStackLocation(Irp)
Definition: ntifs_ex.h:421
VOID NTAPI PoStartNextPowerIrp(IN PIRP Irp)
Definition: power.c:758
#define STATUS_DEVICE_DOES_NOT_EXIST
Definition: ntstatus.h:428
PCLASS_POWER_DEVICE ClassPowerDevice
Definition: classpnp.h:529
PDEVICE_OBJECT LowerDeviceObject
Definition: classpnp.h:598
PCLASS_DEV_INFO DevInfo
Definition: classpnp.h:620
#define IO_NO_INCREMENT
Definition: iotypes.h:598

Referenced by ClassInitializeDispatchTables().

◆ ClassMinimalPowerHandler()

NTSTATUS NTAPI ClassMinimalPowerHandler ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp 
)

Definition at line 1890 of file power.c.

1894{
1895 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1898
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:
1911 {
1912 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
1913 {
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 //
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 {
1946 status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
1947 }
1948 else
1949 {
1950 status = Irp->IoStatus.Status;
1952 }
1953
1954 return status;
1955} // end ClassMinimalPowerHandler()
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
LONG NTSTATUS
Definition: precomp.h:26
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
PVPB NTAPI ClassGetVpb(_In_ PDEVICE_OBJECT DeviceObject)
Definition: class.c:11473
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
#define IoCopyCurrentIrpStackLocationToNext(Irp)
Definition: ntifs_ex.h:413
@ PowerActionNone
Definition: ntpoapi.h:123
@ PowerActionHibernate
Definition: ntpoapi.h:126
@ PowerActionSleep
Definition: ntpoapi.h:125
struct _IO_STACK_LOCATION::@3978::@4014 Power
union _IO_STACK_LOCATION::@1564 Parameters
Definition: ps.c:97
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define VPB_MOUNTED
Definition: iotypes.h:1807
#define IRP_MN_SET_POWER
#define IRP_MN_QUERY_POWER

Referenced by _IRQL_requires_max_().

◆ ClasspDeviceLockFailurePowerIrpCompletion()

NTSTATUS NTAPI ClasspDeviceLockFailurePowerIrpCompletion ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp,
IN PVOID  Context 
)

Definition at line 2233 of file power.c.

2238{
2240 PCOMMON_DEVICE_EXTENSION commonExtension;
2241 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
2242 PIO_STACK_LOCATION currentStack;
2243 BOOLEAN FailurePredictionEnabled = FALSE;
2244
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) {
2323 }
2324
2326
2327 return STATUS_SUCCESS;
2328}
unsigned char BOOLEAN
VOID ClasspEnableTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3857
struct _CLASS_POWER_CONTEXT * PCLASS_POWER_CONTEXT
IoMarkIrpPending(Irp)
POWER_STATE NTAPI PoSetPowerState(IN PDEVICE_OBJECT DeviceObject, IN POWER_STATE_TYPE Type, IN POWER_STATE State)
Definition: power.c:729
CLASS_INIT_DATA InitData
Definition: classpnp.h:577
PCLASS_TICK ClassTick
Definition: classpnp.h:545
PDEVICE_OBJECT DeviceObject
Definition: classpnp.h:688
PDEVICE_OBJECT DeviceObject
Definition: pci.h:46
PCLASS_DRIVER_EXTENSION DriverExtension
Definition: classpnp.h:600

◆ ClasspEnableIdlePower()

_IRQL_requires_same_ NTSTATUS ClasspEnableIdlePower ( _In_ PDEVICE_OBJECT  DeviceObject)

Definition at line 2550 of file power.c.

2573{
2575 ULONG d3ColdDisabledByUser = FALSE;
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,
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,
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 //
2624
2625 if (NT_SUCCESS(status)) {
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
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 //
2650 &GUID_DISK_IDLE_TIMEOUT,
2652 NULL,
2654 }
2655 } else {
2656 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled = FALSE;
2658 }
2659 }
2660
2661 return status;
2662}
#define CLASSP_REG_SUBKEY_NAME
Definition: cdromp.h:120
#define CLASSP_REG_IDLE_TIMEOUT_IN_SECONDS
Definition: classp.h:124
#define CLASSP_REG_DISABLE_D3COLD
Definition: classp.h:125
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PVOID PowerSettingNotificationHandle
Definition: class.c:119
#define CLASS_TAG_POWER
Definition: power.c:37
#define InsertHeadList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
NTKRNLVISTAAPI NTSTATUS NTAPI PoRegisterPowerSettingCallback(_In_opt_ PDEVICE_OBJECT DeviceObject, _In_ LPCGUID SettingGuid, _In_ PPOWER_SETTING_CALLBACK Callback, _In_opt_ PVOID Context, _Outptr_opt_ PVOID *Handle)
Definition: po.c:14
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define NT_ASSERT
Definition: rtlfuncs.h:3310

◆ ClasspPowerDownCompletion()

NTSTATUS NTAPI ClasspPowerDownCompletion ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp,
IN PVOID  Context 
)

Definition at line 769 of file power.c.

774{
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
783 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(fdoExtension->PrivateFdoData->PowerProcessIrp);
784
787 ULONG srbFlags;
788
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);
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
817 }
818
819 PowerContext->PowerChangeState.PowerDown3++;
820
821 switch(PowerContext->PowerChangeState.PowerDown3) {
822
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
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,
873
874 PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
875
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 //
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 //
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,
929
930 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
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
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,
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) {
974 1,
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.
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);
1004 SrbSetTimeOutValue(srbHeader, fdoExtension->TimeOutValue);
1005
1006 SrbAssignSrbFlags(srbHeader,
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,
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
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;
1077 fdoExtension->DeviceObject,
1078 Irp,
1079 (PSCSI_REQUEST_BLOCK)srbHeader,
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;
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 =
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) {
1199 1,
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 //
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);
1229 SrbSetTimeOutValue(srbHeader, timeoutValue);
1230
1231
1232 SrbAssignSrbFlags(srbHeader,
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,
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
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;
1291 fdoExtension->DeviceObject,
1292 Irp,
1293 (PSCSI_REQUEST_BLOCK)srbHeader,
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
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
1351 UCHAR senseKey = 0;
1354
1355 validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
1356 SrbGetSenseInfoBufferLength(srbHeader),
1358 &senseKey,
1361
1362 if (validSense) {
1363 if ((senseKey == SCSI_SENSE_NOT_READY) &&
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
1382
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 //
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 //
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);
1450
1451 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
1452 nextStack->MajorFunction = IRP_MJ_SCSI;
1453
1454 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
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
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
1509
1510 PowerContext->InUse = FALSE;
1511
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.
1522 }
1523
1524 return status;
1525 }
1526 }
1527
1529} // end ClasspPowerDownCompletion()
#define MAXIMUM_RETRIES
Definition: cdrom.h:124
#define SCSI_ADSENSE_LUN_NOT_READY
Definition: cdrw_hw.h:1218
#define SCSIOP_START_STOP_UNIT
Definition: cdrw_hw.h:897
#define SCSI_SENSE_NOT_READY
Definition: cdrw_hw.h:1189
#define SCSI_SENSEQ_FORMAT_IN_PROGRESS
Definition: cdrw_hw.h:1316
#define SCSIOP_SYNCHRONIZE_CACHE
Definition: cdrw_hw.h:918
NTSTATUS InitializeStorageRequestBlock(_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb, _In_ USHORT AddressType, _In_ ULONG ByteSize, _In_ ULONG NumSrbExData,...)
Definition: srblib.c:206
_In_ PTRANSFER_PACKET _In_ ULONG _In_ PIRP OriginalIrp
Definition: classp.h:1757
#define FDO_HACK_NO_SYNC_CACHE
Definition: classp.h:137
FORCEINLINE UCHAR GET_FDO_EXTENSON_SENSE_DATA_LENGTH(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: classpnp.h:1437
#define CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE
Definition: classpnp.h:696
@ PowerDownDeviceUnlocked3
Definition: classpnp.h:264
@ PowerDownDeviceOff3
Definition: classpnp.h:263
@ PowerDownDeviceFlushed3
Definition: classpnp.h:261
@ PowerDownDeviceLocked3
Definition: classpnp.h:259
@ PowerDownDeviceStopped3
Definition: classpnp.h:262
@ PowerDownDeviceQuiesced3
Definition: classpnp.h:260
#define CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE
Definition: classpnp.h:695
BOOLEAN InterpretSenseInfoWithoutHistory(_In_ PDEVICE_OBJECT Fdo, _In_opt_ PIRP OriginalRequest, _In_ PSCSI_REQUEST_BLOCK Srb, UCHAR MajorFunctionCode, ULONG IoDeviceCode, ULONG PreviousRetryCount, _Out_ NTSTATUS *Status, _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) LONGLONG *RetryIn100nsUnits)
Definition: class.c:12844
VOID RetryPowerRequest(PDEVICE_OBJECT DeviceObject, PIRP Irp, PCLASS_POWER_CONTEXT Context)
Definition: power.c:2097
IO_COMPLETION_ROUTINE ClasspPowerDownCompletion
Definition: power.c:61
#define DEFAULT_IO_TIMEOUT_VALUE
Definition: power.c:43
IO_COMPLETION_ROUTINE ClasspStartNextPowerIrpCompletion
Definition: power.c:65
#define TIME_LEFT_FOR_LOWER_DRIVERS
Definition: power.c:41
#define MINIMUM_STOP_UNIT_TIMEOUT_VALUE
Definition: power.c:44
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
#define SRB_FLAGS_FREE_SENSE_BUFFER
Definition: srb.h:406
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:315
#define SRB_FLAGS_NO_DATA_TRANSFER
Definition: srb.h:402
#define SRB_FLAGS_PORT_DRIVER_ALLOCSENSE
Definition: srb.h:413
#define SRB_STATUS_AUTOSENSE_VALID
Definition: srb.h:387
#define SRB_FLAGS_DISABLE_AUTOSENSE
Definition: srb.h:399
struct _SCSI_REQUEST_BLOCK * PSCSI_REQUEST_BLOCK
#define SRB_FUNCTION_UNLOCK_QUEUE
Definition: srb.h:333
#define SRB_FLAGS_BYPASS_LOCKED_QUEUE
Definition: srb.h:410
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:397
#define SRB_STATUS(Status)
Definition: srb.h:389
#define SRB_STATUS_QUEUE_FROZEN
Definition: srb.h:386
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:404
#define SRB_STATUS_SUCCESS
Definition: srb.h:341
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
#define IoCallDriver
Definition: irp.c:1225
@ PowerDeviceD3
Definition: ntpoapi.h:52
UCHAR additionalSenseCode
Definition: scsi.h:4020
UCHAR additionalSenseCodeQualifier
Definition: scsi.h:4021
#define SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED
Definition: scsi.h:3839
UCHAR senseKey
Definition: scsi.h:4019
BOOLEAN validSense
Definition: scsi.h:4018
#define SRB_FLAGS_D3_PROCESSING
Definition: srb.h:165
#define SRB_TYPE_STORAGE_REQUEST_BLOCK
Definition: srb.h:664
#define STORAGE_ADDRESS_TYPE_BTL8
Definition: srb.h:666
* PSTORAGE_REQUEST_BLOCK
Definition: srb.h:661
@ SrbExDataTypeScsiCdb16
Definition: srb.h:459
struct SRB_ALIGN _STORAGE_REQUEST_BLOCK_HEADER * PSTORAGE_REQUEST_BLOCK_HEADER
#define SRB_FUNCTION_QUIESCE_DEVICE
Definition: srb.h:99
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
FORCEINLINE VOID SrbAssignSrbFlags(_In_ PVOID Srb, _In_ ULONG Flags)
Definition: srbhelper.h:946
FORCEINLINE VOID SrbSetOriginalRequest(_In_ PVOID Srb, _In_opt_ PVOID OriginalRequest)
Definition: srbhelper.h:710
FORCEINLINE VOID SrbSetSenseInfoBufferLength(_In_ PVOID Srb, _In_ UCHAR SenseInfoBufferLength)
Definition: srbhelper.h:675
FORCEINLINE ULONG SrbGetSrbFlags(_In_ PVOID Srb)
Definition: srbhelper.h:927
FORCEINLINE VOID SrbSetSenseInfoBuffer(_In_ PVOID Srb, _In_opt_ PVOID SenseInfoBuffer)
Definition: srbhelper.h:657
FORCEINLINE VOID SrbSetCdbLength(_In_ PVOID Srb, _In_ UCHAR CdbLength)
Definition: srbhelper.h:1093
FORCEINLINE VOID SrbSetTimeOutValue(_In_ PVOID Srb, _In_ ULONG TimeOutValue)
Definition: srbhelper.h:821
FORCEINLINE PVOID SrbGetSenseInfoBuffer(_In_ PVOID Srb)
Definition: srbhelper.h:619
FORCEINLINE UCHAR SrbGetSenseInfoBufferLength(_In_ PVOID Srb)
Definition: srbhelper.h:638
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
NTSTATUS FinalStatus
Definition: classpnp.h:684
union _CLASS_POWER_CONTEXT::@1912 PowerChangeState
CLASS_POWER_DOWN_STATE3 PowerDown3
Definition: classpnp.h:678
SCSI_REQUEST_BLOCK Srb
Definition: classpnp.h:690
CLASS_POWER_OPTIONS Options
Definition: classpnp.h:681
struct _FUNCTIONAL_DEVICE_EXTENSION * PartitionZeroExtension
Definition: classpnp.h:599
PDEVICE_OBJECT DeviceObject
Definition: classpnp.h:871
PDEVICE_OBJECT LowerPdo
Definition: classpnp.h:875
PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor
Definition: classpnp.h:877
struct _IO_STACK_LOCATION::@3978::@4000 Scsi
USHORT Length
Definition: srb.h:249
int64_t LONGLONG
Definition: typedefs.h:68
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define STATUS_DEVICE_BUSY
Definition: udferr_usr.h:129
Definition: cdrw_hw.h:28
struct _CDB::_START_STOP START_STOP
struct _CDB::_SYNCHRONIZE_CACHE10 SYNCHRONIZE_CACHE10
#define SrbGetCdb(srb)
Definition: usbstor.h:18
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define IRP_MJ_SCSI
#define IRP_MJ_POWER
unsigned char UCHAR
Definition: xmlstorage.h:181

◆ ClasspPowerHandler()

NTSTATUS ClasspPowerHandler ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp,
IN CLASS_POWER_OPTIONS  Options 
)

Definition at line 1554 of file power.c.

1559{
1560 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1561 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
1563 PIO_STACK_LOCATION nextIrpStack;
1564 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1567 ULONG srbFlags;
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
1588 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
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:
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 */
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
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 //
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 //
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);
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
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);
1825
1826 //
1827 // Mark the original power irp pending.
1828 //
1829
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
1860ClasspPowerHandlerCleanup:
1861
1862 //
1863 // Send the original power irp down, we will start the next power irp in completion routine.
1864 //
1866
1867 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, "(%p)\tStarting next power irp\n", Irp));
1871 NULL,
1872 TRUE,
1873 TRUE,
1874 TRUE);
1875 return PoCallDriver(lowerDevice, Irp);
1876} // end ClasspPowerHandler()
#define InterlockedIncrement
Definition: armddk.h:53
@ PowerUpDeviceInitial
Definition: cdrom.h:420
VOID ClasspDisableTimer(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:3956
@ PowerDownDeviceInitial3
Definition: classpnp.h:258
IO_COMPLETION_ROUTINE ClasspPowerUpCompletion
Definition: power.c:63
#define SRB_FUNCTION_LOCK_QUEUE
Definition: srb.h:332
#define _Analysis_assume_(expr)
Definition: ms_sal.h:2901
VOID NTAPI IoReuseIrp(IN OUT PIRP Irp, IN NTSTATUS Status)
Definition: irp.c:1971
@ DevicePowerState
Definition: ntpoapi.h:63
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423
long LONG
Definition: pedump.c:60
FORCEINLINE VOID SrbSetSrbFlags(_In_ PVOID Srb, _In_ ULONG Flags)
Definition: srbhelper.h:964
STORAGE_HOTPLUG_INFO HotplugInfo
Definition: classp.h:739
CLASS_POWER_CONTEXT PowerContext
Definition: classpnp.h:928
BOOLEAN MediaRemovable
Definition: imports.h:246
BOOLEAN MediaHotplug
Definition: imports.h:247
Definition: http.c:7252
_In_ PWDFDEVICE_INIT _In_ PWDF_REMOVE_LOCK_OPTIONS Options
Definition: wdfdevice.h:3534
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2680
_In_ SYSTEM_POWER_STATE SystemPowerState
Definition: iotypes.h:7519

Referenced by __control_entrypoint().

◆ ClasspPowerUpCompletion()

NTSTATUS NTAPI ClasspPowerUpCompletion ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp,
IN PVOID  Context 
)

Definition at line 186 of file power.c.

191{
193 PCOMMON_DEVICE_EXTENSION commonExtension;
194 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
196 PIO_STACK_LOCATION currentStack;
197 PIO_STACK_LOCATION nextStack;
198
201 ULONG srbFlags;
202 BOOLEAN FailurePredictionEnabled = FALSE;
203
205
206 if (PowerContext == NULL) {
207 NT_ASSERT(PowerContext != NULL);
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
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);
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
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
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
279 PowerContext,
280 TRUE,
281 TRUE,
282 TRUE);
283
284 PoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
285
287
288 } else {
289 PowerContext->QueueLocked = (UCHAR)PowerContext->Options.LockQueue;
290 }
291
292 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
293
295
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 =
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) {
387 1,
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 //
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);
417
418 SrbSetTimeOutValue(srbHeader, timeoutValue);
419 SrbAssignSrbFlags(srbHeader,
424
425 if (PowerContext->Options.LockQueue) {
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
438
439 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
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;
491 fdoExtension->DeviceObject,
492 Irp,
493 (PSCSI_REQUEST_BLOCK)srbHeader,
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
552ClasspPowerUpCompletionFailure:
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 //
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.
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 }
590 SrbSetOriginalRequest(srbHeader, fdoExtension->PrivateFdoData->PowerProcessIrp);
591
592 nextStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)srbHeader;
593 nextStack->MajorFunction = IRP_MJ_SCSI;
594
596
597 IoSetCompletionRoutine(fdoExtension->PrivateFdoData->PowerProcessIrp,
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
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
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
702
703 PowerContext->InUse = FALSE;
704
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.
713 }
714
715 return status;
716 }
717 }
718
720} // end ClasspPowerUpCompletion()
@ PowerUpDeviceOn
Definition: cdrom.h:422
@ PowerUpDeviceUnlocked
Definition: cdrom.h:424
@ PowerUpDeviceStarted
Definition: cdrom.h:423
@ PowerUpDeviceLocked
Definition: cdrom.h:421
#define START_UNIT_TIMEOUT
Definition: cdrom.h:132
#define MINIMUM_START_UNIT_TIMEOUT_VALUE
Definition: power.c:53
#define DEFAULT_POWER_IRP_TIMEOUT_VALUE
Definition: power.c:40
IO_COMPLETION_ROUTINE ClasspDeviceLockFailurePowerIrpCompletion
Definition: power.c:66
#define TIME_LEFT_FOR_UPPER_DRIVERS
Definition: power.c:42
#define MINIMAL_START_UNIT_TIMEOUT_VALUE
Definition: power.c:52
#define min(a, b)
Definition: monoChain.cc:55
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:322
CLASS_POWER_UP_STATE PowerUp
Definition: classpnp.h:679

◆ ClasspSendEnableIdlePowerIoctl()

_IRQL_requires_same_ NTSTATUS ClasspSendEnableIdlePowerIoctl ( _In_ PDEVICE_OBJECT  DeviceObject)

Definition at line 2333 of file power.c.

2353{
2355 STORAGE_IDLE_POWER idlePower = {0};
2356 IO_STATUS_BLOCK ioStatus = {0};
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
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,
2386 idlePower.WakeCapableHint,
2387 idlePower.D3ColdSupported,
2388 idlePower.D3IdleTimeout));
2389
2390 return status;
2391}
VOID NTAPI ClassSendDeviceIoControlSynchronous(_In_ ULONG IoControlCode, _In_ PDEVICE_OBJECT TargetDeviceObject, _Inout_updates_opt_(_Inexpressible_(max(InputBufferLength, OutputBufferLength))) PVOID Buffer, _In_ ULONG InputBufferLength, _In_ ULONG OutputBufferLength, _In_ BOOLEAN InternalDeviceIoControl, _Out_ PIO_STATUS_BLOCK IoStatus)
Definition: class.c:11065
#define IOCTL_STORAGE_ENABLE_IDLE_POWER
Definition: ntddstor.h:214
struct _STORAGE_IDLE_POWER STORAGE_IDLE_POWER
COMMON_DEVICE_EXTENSION CommonExtension
Definition: classpnp.h:873

Referenced by _Function_class_(), and ClasspEnableIdlePower().

◆ ClasspStartNextPowerIrpCompletion()

NTSTATUS NTAPI ClasspStartNextPowerIrpCompletion ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp,
IN PVOID  Context 
)

Definition at line 2207 of file power.c.

2212{
2214
2216
2217 if (Irp->PendingReturned) {
2219 }
2220
2221 if (PowerContext != NULL)
2222 {
2223 PowerContext->InUse = FALSE;
2224 }
2225
2226
2228 return STATUS_SUCCESS;
2229} // end ClasspStartNextPowerIrpCompletion()

◆ ClassStopUnitPowerHandler()

NTSTATUS NTAPI ClassStopUnitPowerHandler ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp 
)

Definition at line 2048 of file power.c.

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,
2068 SET_FLAG(fdoExtension->ScanForSpecialFlags,
2070
2072} // end ClassStopUnitPowerHandler()
SCSIPORT_API NTSTATUS NTAPI ClassSpinDownPowerHandler(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)

◆ RetryPowerRequest()

VOID RetryPowerRequest ( PDEVICE_OBJECT  DeviceObject,
PIRP  Irp,
PCLASS_POWER_CONTEXT  Context 
)

Definition at line 2097 of file power.c.

2102{
2104 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
2105 (PFUNCTIONAL_DEVICE_EXTENSION)Context->DeviceObject->DeviceExtension;
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)) {
2122 srbFunction = srb->Function;
2123 } else {
2124 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction;
2125 }
2126 } else {
2128 srbFunction = srb->Function;
2129 }
2130
2131 NT_ASSERT(Context->DeviceObject == DeviceObject);
2132 srbFlags = SrbGetSrbFlags(srb);
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
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
2190
2191 return;
2192
2193} // end RetryRequest()
VOID ClassRetryRequest(IN PDEVICE_OBJECT SelfDeviceObject, IN PIRP Irp, _In_ _In_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) IN LONGLONG TimeDelta100ns)
Definition: class.c:12317
FORCEINLINE VOID SrbSetDataTransferLength(_In_ PVOID Srb, _In_ ULONG DataTransferLength)
Definition: srbhelper.h:784
FORCEINLINE VOID SrbSetScsiStatus(_In_ PVOID Srb, _In_ UCHAR ScsiStatus)
Definition: srbhelper.h:1056

Referenced by ClasspPowerDownCompletion(), and ClasspPowerUpCompletion().

Variable Documentation

◆ ClasspDeviceLockFailurePowerIrpCompletion

IO_COMPLETION_ROUTINE ClasspDeviceLockFailurePowerIrpCompletion

Definition at line 66 of file power.c.

Referenced by ClasspPowerUpCompletion().

◆ ClasspPowerDownCompletion

IO_COMPLETION_ROUTINE ClasspPowerDownCompletion

Definition at line 61 of file power.c.

Referenced by ClasspPowerDownCompletion(), and ClasspPowerHandler().

◆ ClasspPowerUpCompletion

IO_COMPLETION_ROUTINE ClasspPowerUpCompletion

Definition at line 63 of file power.c.

Referenced by ClasspPowerHandler(), and ClasspPowerUpCompletion().

◆ ClasspStartNextPowerIrpCompletion

IO_COMPLETION_ROUTINE ClasspStartNextPowerIrpCompletion

Definition at line 65 of file power.c.

Referenced by ClasspPowerDownCompletion(), and ClasspPowerHandler().