ReactOS 0.4.16-dev-2633-g8dc9e50
dev_power.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ATA Port Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Power management
5 * COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "atapi.h"
11
12/* GLOBALS ********************************************************************/
13
14static IO_COMPLETION_ROUTINE AtaPdoPowerUpCompletionRoutine;
15static REQUEST_POWER_COMPLETE AtaPdoPowerSetSysStateWithDevStateComplete;
16
17/* FUNCTIONS ******************************************************************/
18
19static
25{
27
28 Irp->IoStatus.Status = Status;
30
31 IoReleaseRemoveLock(&CommonExt->RemoveLock, Irp);
32
33 return Status;
34}
35
36VOID
39{
40 while (TRUE)
41 {
43 PIRP PowerIrp;
44 KIRQL OldLevel;
45
46 KeAcquireSpinLock(&DevExt->Device.QueueLock, &OldLevel);
47 if (IsListEmpty(&DevExt->PowerIrpQueueList))
48 Entry = NULL;
49 else
50 Entry = RemoveHeadList(&DevExt->PowerIrpQueueList);
51 KeReleaseSpinLock(&DevExt->Device.QueueLock, OldLevel);
52
53 if (!Entry)
54 break;
55
56 PowerIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
58 AtaPowerCompleteIrp(&DevExt->Common, PowerIrp, STATUS_NO_SUCH_DEVICE);
59 }
60}
61
65{
66 UCHAR Command = 0;
67
68 if (!IS_ATAPI(&DevExt->Device))
69 {
70 if ((DevExt->Device.DeviceFlags & DEVICE_LBA48) &&
71 AtaDevHasFlushCacheExt(&DevExt->IdentifyDeviceData))
72 {
74 }
75 else if (AtaDevHasFlushCache(&DevExt->IdentifyDeviceData))
76 {
78 }
79 }
80
81 return Command;
82}
83
84static
85VOID
89{
91
92 PowerState.DeviceState = DevExt->Common.DevicePowerState;
93 PoSetPowerState(DevExt->Common.Self, DevicePowerState, PowerState);
94
95 AtaPowerCompleteIrp(&DevExt->Common, Irp, STATUS_SUCCESS);
96}
97
98static
101 _In_ PATAPORT_PORT_DATA PortData,
103{
104 PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
106
108 if (Command == 0)
109 return STATUS_SUCCESS;
110
111 Request->Flags = 0;
112 Request->TimeOut = 30;
113 RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
114 Request->TaskFile.Command = Command;
115
116 return AtaPortSendRequest(PortData, DevExt);
117}
118
119static
122 _In_ PATAPORT_PORT_DATA PortData,
124{
125 PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
126
127 Request->Flags = 0;
128 Request->TimeOut = 20;
129 Request->TaskFile.Feature = 0;
130 Request->TaskFile.Command = IDE_COMMAND_IDLE_IMMEDIATE;
131
132 return AtaPortSendRequest(PortData, DevExt);
133}
134
135static
138 _In_ PATAPORT_PORT_DATA PortData,
140{
141 PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
142
143 Request->Flags = 0;
144 Request->TimeOut = 20;
145 Request->TaskFile.Command = IDE_COMMAND_STANDBY_IMMEDIATE;
146
147 return AtaPortSendRequest(PortData, DevExt);
148}
149
152 _In_ PATAPORT_PORT_DATA PortData,
154{
156 PIRP PowerIrp;
157 PIO_STACK_LOCATION IoStack;
158 DEVICE_POWER_STATE NewState;
159 KIRQL OldLevel;
161
162 KeAcquireSpinLock(&DevExt->Device.QueueLock, &OldLevel);
163 if (IsListEmpty(&DevExt->PowerIrpQueueList))
164 Entry = NULL;
165 else
166 Entry = RemoveHeadList(&DevExt->PowerIrpQueueList);
167 KeReleaseSpinLock(&DevExt->Device.QueueLock, OldLevel);
168 if (!Entry)
169 return STATUS_SUCCESS;
170
171 PowerIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
172
173 IoStack = IoGetCurrentIrpStackLocation(PowerIrp);
175
176 NewState = IoStack->Parameters.Power.State.DeviceState;
177 if (NewState == DevExt->Common.DevicePowerState)
178 {
179 AtaDeviceCompletePowerIrp(DevExt, PowerIrp);
180 return STATUS_SUCCESS;
181 }
182
183 if (NewState != PowerDeviceD3)
184 {
186
187 /* Power up the device */
188 Status = AtaDeviceSetIdleMode(PortData, DevExt);
190 return Status;
191
192 /* Restore the software settings after power up */
193 _InterlockedOr(&DevExt->Worker.EventsPending, ACTION_DEVICE_CONFIG);
194 _InterlockedOr(&PortData->Worker.EventsPending, ACTION_DEVICE_CONFIG);
195 }
196 else
197 {
199
200 /* Flush device caches */
201 Status = AtaDeviceFlushCache(PortData, DevExt);
203 return Status;
204
205 /* Power down the device */
206 Status = AtaDeviceSetStandbyMode(PortData, DevExt);
208 return Status;
209 }
210
211 AtaDeviceCompletePowerIrp(DevExt, PowerIrp);
212
213 DevExt->Common.DevicePowerState = NewState;
214 return Status;
215}
216
219 _In_ PATAPORT_PORT_DATA PortData,
221{
223
224 if (DevExt->Common.DevicePowerState == PowerDeviceD0)
225 return STATUS_SUCCESS;
226
227 INFO("CH %lu: Powering up idle device '%s'\n", PortData->PortNumber, DevExt->FriendlyName);
228
229 Status = AtaDeviceSetIdleMode(PortData, DevExt);
230 if (!NT_SUCCESS(Status))
231 {
232 /*
233 * If the power on device has failed, the next command can still work.
234 * The media access will result in a transition from the PM1:Idle/PM2:Standby state
235 * to the PM0:Active state by the ATA spec.
236 */
237 ERR("CH %lu: Failed to power up device '%s' %lx\n",
238 PortData->PortNumber, DevExt->FriendlyName, Status);
239 }
240 else
241 {
242 DevExt->Common.DevicePowerState = PowerDeviceD0;
243 }
244
245 return Status;
246}
247
248static
249VOID
252 _In_ PIRP Irp)
253{
254 KIRQL OldLevel;
255
256 KeAcquireSpinLock(&DevExt->Device.QueueLock, &OldLevel);
257 InsertTailList(&DevExt->PowerIrpQueueList, &Irp->Tail.Overlay.ListEntry);
258 KeReleaseSpinLock(&DevExt->Device.QueueLock, OldLevel);
259
260 AtaDeviceQueueEvent(DevExt->Device.PortData, DevExt, ACTION_DEVICE_POWER);
261}
262
263static
265NTAPI
268 _In_ PIRP Irp,
269 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
270{
273
275
276 Status = Irp->IoStatus.Status;
277
278 INFO("Powering up device, lower driver status %lx\n", Status);
279
280 if (!NT_SUCCESS(Status))
281 {
283
286 }
287
288 AtaPdoQueuePowerIrp(DevExt, Irp);
289
290 /* Defer IRP completion */
292}
293
294static
298 _In_ PIRP Irp)
299{
300 PIO_STACK_LOCATION IoStack;
301 DEVICE_POWER_STATE NewState;
302
304 NewState = IoStack->Parameters.Power.State.DeviceState;
305
307
308 if (NewState < DevExt->Common.DevicePowerState)
309 {
310 PATAPORT_CHANNEL_EXTENSION ChanExt = DevExt->Common.FdoExt;
311
315 DevExt,
316 TRUE,
317 TRUE,
318 TRUE);
319 (VOID)PoCallDriver(ChanExt->Common.Self, Irp);
320 }
321 else
322 {
323 INFO("Powering down device\n");
324
325 AtaPdoQueuePowerIrp(DevExt, Irp);
326 }
327
328 return STATUS_PENDING;
329}
330
331static
332VOID
333NTAPI
340{
341 PATAPORT_DEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
342 PIRP Irp = Context;
343
345
346 if (DevExt->Common.SystemPowerState != PowerState.SystemState)
347 {
348 DevExt->Common.SystemPowerState = PowerState.SystemState;
350 }
351
352 AtaPowerCompleteIrp(&DevExt->Common, Irp, IoStatus->Status);
353}
354
355static
356VOID
358 _In_ SYSTEM_POWER_STATE SystemState,
360{
361 if (SystemState == PowerSystemWorking)
362 {
364 }
365 else
366 {
368 }
369}
370
371static
375 _In_ PIRP Irp)
376{
377 PIO_STACK_LOCATION IoStack;
379 POWER_STATE NewPowerState;
380 SYSTEM_POWER_STATE NewSystemState;
381
383 NewSystemState = IoStack->Parameters.Power.State.SystemState;
384
386
387 AtaPdoPowerGetDevStateForSysState(NewSystemState, &NewPowerState.DeviceState);
388 Status = PoRequestPowerIrp(DevExt->Common.Self,
390 NewPowerState,
392 Irp,
393 NULL);
394 if (!NT_SUCCESS(Status))
395 {
397
398 ERR("Failed to change power state for device '%s' %lx\n", DevExt->FriendlyName, Status);
399
403 NewPowerState,
404 Irp,
406 }
407
408 return Status;
409}
410
411static
416{
417 // FIXME: Investigate how to fix this kernel bug
418 // *** Assertion failed: KeGetCurrentThread()->SystemAffinityActive == FALSE
419 // *** Source File: ../ntoskrnl/ke/dpc.c, line 926
420#if 1
422
429
430 Status = Irp->IoStatus.Status;
433 return Status;
434#else
436 PIO_STACK_LOCATION IoStack;
437
438 Status = IoAcquireRemoveLock(&DevExt->Common.RemoveLock, Irp);
439 if (!NT_SUCCESS(Status))
440 {
442
443 Irp->IoStatus.Status = Status;
445 return Status;
446 }
447
449 switch (IoStack->MinorFunction)
450 {
452 {
453 switch (IoStack->Parameters.Power.Type)
454 {
455 case SystemPowerState:
456 case DevicePowerState:
457 Status = AtaPowerCompleteIrp(&DevExt->Common, Irp, STATUS_SUCCESS);
458 break;
459
460 default:
461 Status = AtaPowerCompleteIrp(&DevExt->Common, Irp, Irp->IoStatus.Status);
462 break;
463 }
464 break;
465 }
466
467 case IRP_MN_SET_POWER:
468 {
469 switch (IoStack->Parameters.Power.Type)
470 {
471 case SystemPowerState:
473 break;
474 case DevicePowerState:
476 break;
477
478 default:
479 Status = AtaPowerCompleteIrp(&DevExt->Common, Irp, Irp->IoStatus.Status);
480 break;
481 }
482 break;
483 }
484
485 default:
486 Status = AtaPowerCompleteIrp(&DevExt->Common, Irp, Irp->IoStatus.Status);
487 break;
488 }
489
490 return Status;
491#endif
492}
493
494static
499{
501
502 Status = IoAcquireRemoveLock(&ChanExt->Common.RemoveLock, Irp);
503 if (!NT_SUCCESS(Status))
504 {
506
507 Irp->IoStatus.Status = Status;
509 return Status;
510 }
511
514 Status = PoCallDriver(ChanExt->Common.LowerDeviceObject, Irp);
515
516 IoReleaseRemoveLock(&ChanExt->Common.RemoveLock, Irp);
517
518 return Status;
519}
520
522NTAPI
526{
527 if (IS_FDO(DeviceObject->DeviceExtension))
528 return AtaFdoPower(DeviceObject->DeviceExtension, Irp);
529 else
530 return AtaPdoPower(DeviceObject->DeviceExtension, Irp);
531}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
#define VOID
Definition: acefi.h:82
#define IDE_COMMAND_FLUSH_CACHE_EXT
Definition: ata.h:699
#define IDE_COMMAND_STANDBY_IMMEDIATE
Definition: ata.h:694
#define IDE_COMMAND_IDLE_IMMEDIATE
Definition: ata.h:695
@ ACTION_DEVICE_CONFIG
Definition: atapi.h:248
@ ACTION_DEVICE_POWER
Definition: atapi.h:250
#define QUEUE_FLAG_FROZEN_POWER
Definition: atapi.h:110
#define IS_FDO(p)
Definition: atapi.h:173
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaReqThawQueue(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG ReasonFlags)
Definition: scsi.c:1365
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaDeviceQueueEvent(_In_ PATAPORT_PORT_DATA PortData, _In_opt_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ATA_PORT_ACTION Action)
Definition: portstate.c:992
NTSTATUS AtaPortSendRequest(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: portstate.c:831
#define DEVICE_LBA48
Definition: atapi.h:84
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaReqFreezeQueue(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ ULONG ReasonFlags)
Definition: scsi.c:1351
#define IS_ATAPI(Device)
Definition: atapi.h:176
LONG NTSTATUS
Definition: precomp.h:26
#define ERR(fmt,...)
Definition: precomp.h:57
_In_ PIRP Irp
Definition: csq.h:116
static VOID AtaPdoQueuePowerIrp(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ PIRP Irp)
Definition: dev_power.c:250
static IO_COMPLETION_ROUTINE AtaPdoPowerUpCompletionRoutine
Definition: dev_power.c:14
VOID AtaDeviceFlushPowerIrpQueue(_In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:37
static VOID AtaPdoPowerGetDevStateForSysState(_In_ SYSTEM_POWER_STATE SystemState, _Out_ PDEVICE_POWER_STATE DeviceState)
Definition: dev_power.c:357
static NTSTATUS AtaDeviceSetStandbyMode(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:137
static REQUEST_POWER_COMPLETE AtaPdoPowerSetSysStateWithDevStateComplete
Definition: dev_power.c:15
static NTSTATUS AtaDeviceSetIdleMode(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:121
NTSTATUS NTAPI AtaDispatchPower(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
Definition: dev_power.c:523
static VOID AtaDeviceCompletePowerIrp(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ PIRP Irp)
Definition: dev_power.c:86
static NTSTATUS AtaPowerCompleteIrp(_In_ PATAPORT_COMMON_EXTENSION CommonExt, _In_ PIRP Irp, _In_ NTSTATUS Status)
Definition: dev_power.c:21
static NTSTATUS AtaPdoPowerSetDevicePowerState(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ PIRP Irp)
Definition: dev_power.c:296
UCHAR AtaDeviceGetFlushCacheCommand(_In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:63
NTSTATUS AtaPortCheckDevicePowerState(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:218
static NTSTATUS AtaPdoPowerSetSystemPowerState(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _In_ PIRP Irp)
Definition: dev_power.c:373
static NTSTATUS AtaDeviceFlushCache(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:100
static NTSTATUS AtaPdoPower(_In_ PATAPORT_DEVICE_EXTENSION DevExt, _Inout_ PIRP Irp)
Definition: dev_power.c:413
static NTSTATUS AtaFdoPower(_In_ PATAPORT_CHANNEL_EXTENSION ChanExt, _Inout_ PIRP Irp)
Definition: dev_power.c:496
NTSTATUS AtaPortDeviceProcessPowerChange(_In_ PATAPORT_PORT_DATA PortData, _In_ PATAPORT_DEVICE_EXTENSION DevExt)
Definition: dev_power.c:151
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define INFO
Definition: debug.h:89
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
Status
Definition: gdiplustypes.h:25
FORCEINLINE BOOLEAN AtaDevHasFlushCache(_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
FORCEINLINE BOOLEAN AtaDevHasFlushCacheExt(_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
IoMarkIrpPending(Irp)
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
#define ASSERT(a)
Definition: mode.c:44
__in UCHAR __in POWER_STATE __in_opt PVOID __in PIO_STATUS_BLOCK IoStatus
Definition: mxum.h:159
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define IoSkipCurrentIrpStackLocation(Irp)
Definition: ntifs_ex.h:421
#define IoCopyCurrentIrpStackLocationToNext(Irp)
Definition: ntifs_ex.h:413
#define IoCompleteRequest
Definition: irp.c:1240
POWER_STATE NTAPI PoSetPowerState(IN PDEVICE_OBJECT DeviceObject, IN POWER_STATE_TYPE Type, IN POWER_STATE State)
Definition: power.c:729
VOID NTAPI PoStartNextPowerIrp(IN PIRP Irp)
Definition: power.c:758
NTSTATUS NTAPI PoRequestPowerIrp(_In_ PDEVICE_OBJECT DeviceObject, _In_ UCHAR MinorFunction, _In_ POWER_STATE PowerState, _In_opt_ PREQUEST_POWER_COMPLETE CompletionFunction, _In_opt_ __drv_aliasesMem PVOID Context, _Outptr_opt_ PIRP *pIrp)
Definition: power.c:659
@ PowerSystemWorking
Definition: ntpoapi.h:36
@ DevicePowerState
Definition: ntpoapi.h:63
enum _DEVICE_POWER_STATE * PDEVICE_POWER_STATE
@ PowerDeviceD0
Definition: ntpoapi.h:49
@ PowerDeviceD3
Definition: ntpoapi.h:52
enum _DEVICE_POWER_STATE DEVICE_POWER_STATE
enum _SYSTEM_POWER_STATE SYSTEM_POWER_STATE
#define STATUS_ADAPTER_HARDWARE_ERROR
Definition: ntstatus.h:524
long _InterlockedOr(_Interlocked_operand_ long volatile *_Value, long _Mask)
Entry
Definition: section.c:5210
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
#define STATUS_SUCCESS
Definition: shellext.h:65
_In_ PVOID Context
Definition: storport.h:2269
Definition: shell.h:41
ATAPORT_COMMON_EXTENSION Common
Definition: atapi.h:440
PDEVICE_OBJECT Self
Definition: atapi.h:432
IO_REMOVE_LOCK RemoveLock
Definition: atapi.h:434
SYSTEM_POWER_STATE SystemPowerState
Definition: atapi.h:418
ATAPORT_COMMON_EXTENSION Common
Definition: atapi.h:455
union _IO_STACK_LOCATION::@1696 Parameters
struct _IO_STACK_LOCATION::@4366::@4402 Power
Definition: typedefs.h:120
#define STATUS_PENDING
Definition: telnetd.h:14
unsigned char UCHAR
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
#define IDE_COMMAND_FLUSH_CACHE
Definition: atapi.h:401
DEVICE_POWER_STATE DeviceState
Definition: ntpoapi.h:58
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_In_ WDFDEVICE _Out_ PWDF_DEVICE_STATE DeviceState
Definition: wdfdevice.h:2005
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_ WDF_DEVICE_POWER_STATE PowerState
Definition: wdfdevice.h:3040
_In_ UCHAR _In_ UCHAR MinorFunction
Definition: wdfdevice.h:1705
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define IoAcquireRemoveLock(RemoveLock, Tag)
#define IoReleaseRemoveLock(_RemoveLock, _Tag)
Definition: iofuncs.h:2764
#define STATUS_CONTINUE_COMPLETION
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define IRP_MN_SET_POWER
_In_ SYSTEM_POWER_STATE SystemPowerState
Definition: iotypes.h:7522
#define IRP_MN_QUERY_POWER