|
|
/*++
Copyright (C) 1997-99 Microsoft Corporation
Module Name:
pdopower.c
Abstract:
--*/
#include "ideport.h"
VOID IdePowerCheckBusyCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIDE_POWER_CONTEXT Context, IN NTSTATUS Status );
NTSTATUS DeviceQueryPowerState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION irpStack; PPDO_EXTENSION pdoExtension;
pdoExtension = RefPdoWithTag( DeviceObject, FALSE, Irp );
if (pdoExtension) {
#if defined (DONT_POWER_DOWN_PAGING_DEVICE)
irpStack = IoGetCurrentIrpStackLocation (Irp);
if (!pdoExtension->CrashDumpPathCount || ((irpStack->Parameters.Power.Type == SystemPowerState) && (irpStack->Parameters.Power.State.SystemState == PowerSystemWorking)) || ((irpStack->Parameters.Power.Type == DevicePowerState) && (irpStack->Parameters.Power.State.SystemState == PowerDeviceD0))) {
Irp->IoStatus.Status = STATUS_SUCCESS;
} else {
Irp->IoStatus.Status = STATUS_DEVICE_POWER_FAILURE; } #else
Irp->IoStatus.Status = STATUS_SUCCESS;
#endif // DONT_POWER_DOWN_PAGING_DEVICE
UnrefPdoWithTag (pdoExtension, Irp);
} else {
Irp->IoStatus.Status = STATUS_SUCCESS; }
PoStartNextPowerIrp (Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// Do not send this Irp down
//
return STATUS_SUCCESS; }
NTSTATUS IdePortSetPdoPowerState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; PPDO_EXTENSION pdoExtension;
irpStack = IoGetCurrentIrpStackLocation (Irp); pdoExtension = DeviceObject->DeviceExtension;
DebugPrint ((DBG_POWER, "0x%x target %d got power irp 0x%x\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp ));
DebugPrint ((DBG_POWER, "IdePort: 0x%x device %d: current System Power State = 0x%x\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, pdoExtension->SystemPowerState)); DebugPrint ((DBG_POWER, "IdePort: 0x%x device %d: current Device Power State = 0x%x\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, pdoExtension->DevicePowerState));
IoMarkIrpPending(Irp);
// if (!(pdoExtension->LuFlags & PD_LOGICAL_UNIT_POWER_OK)) {
//
// //
// // The device does support power management commands
// // just STATUS_SUCCESS everything. If ACPI is around,
// // it will power manage our device
// //
// status = STATUS_SUCCESS;
//
// } else
if (irpStack->Parameters.Power.Type == SystemPowerState) {
DebugPrint ((DBG_POWER, "IdePortSetPdoPowerState: 0x%x target %d got a SYSTEM power irp 0x%x for system state 0x%x \n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, irpStack->Parameters.Power.State.SystemState));
ASSERT (pdoExtension->PendingSystemPowerIrp == NULL); #if DBG
pdoExtension->PendingSystemPowerIrp = Irp; ASSERT (pdoExtension->PendingSystemPowerIrp); #endif // DBG
status = IdePortSetPdoSystemPowerState (DeviceObject, Irp);
} else if (irpStack->Parameters.Power.Type == DevicePowerState) {
DebugPrint ((DBG_POWER, "IdePortSetPdoPowerState: 0x%x target %d got a DEVICE power irp 0x%x for device state 0x%x \n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, irpStack->Parameters.Power.State.DeviceState));
ASSERT (pdoExtension->PendingDevicePowerIrp == NULL); #if DBG
pdoExtension->PendingDevicePowerIrp = Irp; ASSERT (pdoExtension->PendingDevicePowerIrp); #endif // DBG
status = IdePortSetPdoDevicePowerState (DeviceObject, Irp);
} else {
status = STATUS_NOT_IMPLEMENTED; }
if (status != STATUS_PENDING) {
Irp->IoStatus.Status = status;
IdePortPdoCompletePowerIrp ( DeviceObject, Irp ); }
return STATUS_PENDING; }
NTSTATUS IdePortSetPdoSystemPowerState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; PPDO_EXTENSION pdoExtension; SYSTEM_POWER_STATE newSystemState; POWER_STATE powerState; POWER_ACTION shutdownType;
pdoExtension = DeviceObject->DeviceExtension; status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp); newSystemState = irpStack->Parameters.Power.State.SystemState; shutdownType = irpStack->Parameters.Power.ShutdownType;
if (pdoExtension->SystemPowerState != newSystemState) {
//
// new system state request
//
if (pdoExtension->SystemPowerState == PowerSystemWorking) {
//
// Getting out of working state.
//
if ((newSystemState == PowerSystemShutdown) && (shutdownType == PowerActionShutdownReset)) {
//
// spin up for BIOS POST
//
powerState.DeviceState = PowerDeviceD0;
} else {
//
// put the device to D3 and freeze the device queue
//
//
// Issue a D3 to top of my drive stack
//
powerState.DeviceState = PowerDeviceD3;
pdoExtension->PendingPowerDownSystemIrp = Irp; }
status = PoRequestPowerIrp ( pdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, IdePortPdoRequestPowerCompletionRoutine, Irp, NULL );
if (NT_SUCCESS(status)) {
status = STATUS_PENDING; }
} else {
if (newSystemState == PowerSystemHibernate) {
//
// we can't hibernate when we are in some sleep state
//
ASSERT (FALSE); } } } return status; }
NTSTATUS IdePortSetPdoDevicePowerState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PPDO_EXTENSION pdoExtension; PIO_STACK_LOCATION irpStack; NTSTATUS status;
DEVICE_POWER_STATE newDeviceState; POWER_ACTION shutdownType;
BOOLEAN issueIdeCommand; IDEREGS ideReg;
PIDE_POWER_CONTEXT context; BOOLEAN powerUpParent; BOOLEAN noopPassThrough;
pdoExtension = DeviceObject->DeviceExtension; status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp); newDeviceState = irpStack->Parameters.Power.State.DeviceState; shutdownType = irpStack->Parameters.Power.ShutdownType;
powerUpParent = FALSE;
issueIdeCommand = FALSE; RtlZeroMemory (&ideReg, sizeof(ideReg)); if (pdoExtension->DevicePowerState != newDeviceState) {
if (pdoExtension->DevicePowerState == PowerDeviceD0) {
POWER_STATE newPowerState;
newPowerState.DeviceState = newDeviceState;
//
// getting out of D0 state, better call PoSetPowerState now
// this gives the system a chance to flush before we
// get out of D0
//
PoSetPowerState ( pdoExtension->DeviceObject, DevicePowerState, newPowerState ); }
if (pdoExtension->DevicePowerState < newDeviceState) {
KIRQL currentIrql;
//
// we are powering down, try to clean out the Lu device queue
//
KeAcquireSpinLock(&pdoExtension->ParentDeviceExtension->SpinLock, ¤tIrql);
pdoExtension->CurrentKey = 0;
KeReleaseSpinLock(&pdoExtension->ParentDeviceExtension->SpinLock, currentIrql); }
if ((newDeviceState == PowerDeviceD0) || (newDeviceState == PowerDeviceD1)) {
//
// spinning up to D0 or D1...
//
DebugPrint ((DBG_POWER, "IdePort: Irp 0x%x to spin UP 0x%x %d...\n", Irp, pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId));
if (pdoExtension->DevicePowerState == PowerDeviceD1) {
//
// D0-->D1
// can't do much here
DebugPrint ((DBG_POWER, "ATAPI: reqeust for PowerDeviceD1 to PowerDeviceD0\n"));
} else if ((pdoExtension->DevicePowerState == PowerDeviceD0) || (pdoExtension->DevicePowerState == PowerDeviceD2)) {
//
// D1-->D0 or
// D2-->D0 or D1
//
issueIdeCommand = TRUE; if (pdoExtension->ScsiDeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) {
ideReg.bCommandReg = IDE_COMMAND_ATAPI_RESET; ideReg.bReserved = ATA_PTFLAGS_URGENT;
} else {
ideReg.bCommandReg = IDE_COMMAND_IDLE_IMMEDIATE; ideReg.bReserved = ATA_PTFLAGS_URGENT | ATA_PTFLAGS_STATUS_DRDY_REQUIRED; }
} else {
PFDO_EXTENSION fdoExtension = pdoExtension->ParentDeviceExtension;
//
// D3-->D0 or D1
//
issueIdeCommand = TRUE; ideReg.bReserved = ATA_PTFLAGS_BUS_RESET | ATA_PTFLAGS_URGENT;
//
// wait for busy to clear
//
if (fdoExtension->WaitOnPowerUp) { ideReg.bSectorNumberReg = 3; }
//
// we are coming out of deeeeep sleep, make sure our parent
// is awake (power up) before we can wake up
//
powerUpParent = TRUE; }
} else if ((newDeviceState == PowerDeviceD2) || (newDeviceState == PowerDeviceD3)) {
//
// spinning down to D2 or D3...
//
DebugPrint ((DBG_POWER, "IdePort: Irp 0x%x to spin DOWN 0x%x %d...\n", Irp, pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId));
if ((pdoExtension->DevicePowerState == PowerDeviceD0) || (pdoExtension->DevicePowerState == PowerDeviceD1) || (pdoExtension->DevicePowerState == PowerDeviceD2)) {
//
// going to D3
//
if ((pdoExtension->PdoState & PDOS_NO_POWER_DOWN) || (shutdownType == PowerActionHibernate)) { //
// send an no-op command to block the queue
//
issueIdeCommand = TRUE; ideReg.bReserved = ATA_PTFLAGS_NO_OP; } else { //
// spin down
//
issueIdeCommand = TRUE; ideReg.bCommandReg = IDE_COMMAND_STANDBY_IMMEDIATE; ideReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED; }
} else if (pdoExtension->DevicePowerState == PowerDeviceD3) {
//
// PowerDeviceD3 -> PowerDeviceD2
//
// need to do a bus reset (spin up) and issue IDE_COMMAND_STANDBY_IMMEDIATE
// (spin down). this will cause uncessary INRUSH current. bad
// idea. fail the request for now
DebugPrint ((DBG_POWER, "ATAPI: reqeust for PowerDeviceD3 to PowerDeviceD2\n"));
status = STATUS_INVALID_DEVICE_STATE;
} else {
status = STATUS_INVALID_DEVICE_STATE; }
} else {
status = STATUS_INVALID_DEVICE_STATE; } } /*************
else if ( pdoExtension->DevicePowerState == PowerDeviceD0) {
//
// Send a no-op so that it can drain the device queue
//
issueIdeCommand = TRUE; ideReg.bSectorCountReg = 1; ideReg.bReserved = ATA_PTFLAGS_NO_OP; } ***************/
if (issueIdeCommand && NT_SUCCESS(status)) {
if ((pdoExtension->PdoState & PDOS_DEADMEAT) || (!(pdoExtension->PdoState & PDOS_STARTED))) { DebugPrint ((DBG_ALWAYS, "ATAPI: power irp 0x%x for not-yet-started or deadmeat device 0x%x\n", Irp, DeviceObject)); //
// even the device may not be ready to be
// "power-managed", we still need to go
// through all the power code so that all
// the flags/states will be consistent
//
RtlZeroMemory (&ideReg, sizeof(ideReg)); ideReg.bReserved = ATA_PTFLAGS_NO_OP | ATA_PTFLAGS_URGENT; } //context = ExAllocatePool (NonPagedPool, sizeof(IDE_POWER_CONTEXT));
ASSERT(InterlockedCompareExchange(&(pdoExtension->PowerContextLock), 1, 0) == 0); context = &(pdoExtension->PdoPowerContext);
if (context) {
context->PdoExtension = pdoExtension; context->PowerIrp = Irp;
RtlZeroMemory (&context->AtaPassThroughData, sizeof(ATA_PASS_THROUGH)); RtlMoveMemory (&context->AtaPassThroughData.IdeReg, &ideReg, sizeof(ideReg));
} else {
status = STATUS_NO_MEMORY; issueIdeCommand = FALSE; } }
if (issueIdeCommand && NT_SUCCESS(status)) {
if (powerUpParent) {
status = FdoChildRequestPowerUp ( pdoExtension->ParentDeviceExtension, pdoExtension, context ); ASSERT (NT_SUCCESS(status));
//
// the pass through will be issued by FdoChildRequestPowerUp() callback
//
issueIdeCommand = FALSE; status = STATUS_PENDING; } }
if (issueIdeCommand && NT_SUCCESS(status)) {
status = PdoRequestParentPowerUpCompletionRoutine ( context, STATUS_SUCCESS );
//
// this call will complete the power irp
// always return STATUS_PENDING so that out callee
// will not try to complete the same irp
//
status = STATUS_PENDING; }
return status; }
NTSTATUS PdoRequestParentPowerUpCompletionRoutine ( PVOID Context, NTSTATUS ParentPowerUpStatus ) { PIDE_POWER_CONTEXT context = Context; NTSTATUS status;
if (NT_SUCCESS(ParentPowerUpStatus)) {
PIDEREGS ideReg; PATA_PASS_THROUGH ataPassThrough;
DebugPrint ((DBG_POWER, "PdoRequestParentPowerUpCompletionRoutine: calling IssueAsyncAtaPassThrough for pdo 0x%x\n", context->PdoExtension));
//
// hack. We need to check if the device is busy before we issue
// the reset. Since there are no bits left in the bReserved
// register, we use the sectorCount register. It serves 2 purposes.
// If it is non zero (and reserved has NO_OP set) then we would
// perform a waitForBusy. It also indicates the time to wiat
// in seconds.
//
ataPassThrough = &context->AtaPassThroughData; ideReg = &ataPassThrough->IdeReg;
if ((ideReg->bReserved & ATA_PTFLAGS_BUS_RESET) && (ideReg->bSectorNumberReg != 0)) {
ideReg->bReserved = ATA_PTFLAGS_NO_OP | ATA_PTFLAGS_URGENT;
status = IssueAsyncAtaPassThroughSafe ( context->PdoExtension->ParentDeviceExtension, context->PdoExtension, &context->AtaPassThroughData, FALSE, IdePowerCheckBusyCompletion, context, TRUE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE ); } else {
//
// parent woke up
//
status = IssueAsyncAtaPassThroughSafe ( context->PdoExtension->ParentDeviceExtension, context->PdoExtension, &context->AtaPassThroughData, FALSE, IdePowerPassThroughCompletion, context, TRUE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE ); }
} else {
status = ParentPowerUpStatus; }
if (!NT_SUCCESS(status)) {
context->PowerIrp->IoStatus.Status = status;
IdePortPdoCompletePowerIrp ( context->PdoExtension->DeviceObject, context->PowerIrp );
ASSERT(InterlockedCompareExchange(&(context->PdoExtension->PowerContextLock), 0, 1) == 1); //ExFreePool (context);
}
return status; }
VOID IdePortPdoRequestPowerCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) { PPDO_EXTENSION pdoExtension; PIO_STACK_LOCATION irpStack; PIRP irp = Context;
pdoExtension = (PPDO_EXTENSION) DeviceObject->DeviceExtension; irp->IoStatus.Status = IoStatus->Status; IdePortPdoCompletePowerIrp ( pdoExtension->DeviceObject, irp ); return; }
VOID IdePortPdoCompletePowerIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PPDO_EXTENSION pdoExtension; PFDO_EXTENSION fdoExtension; PIO_STACK_LOCATION irpStack; BOOLEAN callPoSetPowerState; KIRQL currentIrql; NTSTATUS status; POWER_ACTION shutdownType;
irpStack = IoGetCurrentIrpStackLocation (Irp); pdoExtension = DeviceObject->DeviceExtension; //shutdownType = irpStack->Parameters.Power.ShutdownType;
fdoExtension = pdoExtension->ParentDeviceExtension;
status = Irp->IoStatus.Status;
if (NT_SUCCESS(status)) {
callPoSetPowerState = TRUE;
Irp->IoStatus.Information = irpStack->Parameters.Power.State.DeviceState;
if (irpStack->Parameters.Power.Type == SystemPowerState) {
if (pdoExtension->SystemPowerState != irpStack->Parameters.Power.State.SystemState) {
DebugPrint ((DBG_POWER, "ATAPI: 0x%x target%d completing power Irp 0x%x with a new system state 0x%x\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, irpStack->Parameters.Power.State.SystemState));
if (pdoExtension->SystemPowerState == PowerSystemWorking) {
KeAcquireSpinLock(&fdoExtension->SpinLock, ¤tIrql);
//
// got out of S0, block the device queue
//
pdoExtension->PdoState |= PDOS_QUEUE_FROZEN_BY_SLEEPING_SYSTEM;
DebugPrint ((DBG_POWER, "IdePort: 0x%x target %d is powered down with 0x%x items queued\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, pdoExtension->NumberOfIrpQueued));
KeReleaseSpinLock(&fdoExtension->SpinLock, currentIrql); }
if (irpStack->Parameters.Power.State.SystemState == PowerSystemWorking) {
KeAcquireSpinLock(&fdoExtension->SpinLock, ¤tIrql);
//
// got into S0, unblock and restart the device queue
//
CLRMASK (pdoExtension->PdoState, PDOS_QUEUE_FROZEN_BY_SLEEPING_SYSTEM);
DebugPrint ((DBG_POWER, "IdePort: 0x%x target %d is power up with 0x%x items queued\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, pdoExtension->NumberOfIrpQueued));
GetNextLuPendingRequest (fdoExtension, pdoExtension);
KeLowerIrql(currentIrql); }
pdoExtension->SystemPowerState = (int)Irp->IoStatus.Information; }
pdoExtension->PendingPowerDownSystemIrp = NULL;
} else /* if (irpStack->Parameters.Power.Type == DevicePowerState) */ {
if (pdoExtension->DevicePowerState == PowerDeviceD0) {
//
// PoSetPowerState is called before we power down
//
callPoSetPowerState = FALSE; }
if (pdoExtension->DevicePowerState != irpStack->Parameters.Power.State.DeviceState) {
DebugPrint ((DBG_POWER, "ATAPI: 0x%x target %d completing power Irp 0x%x with a new device state 0x%x\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, irpStack->Parameters.Power.State.DeviceState));
if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) {
#if 0
if (shutdownType == PowerActionHibernate) { DebugPrint((0, "Don't power down the controller yet\n")); } else { #endif
//
// should never do that if we are crashdump pointer
// tell parent that we just fell to sleep
//
FdoChildReportPowerDown ( fdoExtension, pdoExtension ); #if 0
} #endif
KeAcquireSpinLock(&fdoExtension->SpinLock, ¤tIrql);
//
// device is powered down. block the device queue
//
SETMASK(pdoExtension->PdoState, PDOS_QUEUE_FROZEN_BY_POWER_DOWN);
DebugPrint ((DBG_POWER, "IdePort: 0x%x target %d is powered down with 0x%x items queued\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, pdoExtension->NumberOfIrpQueued));
KeReleaseSpinLock(&fdoExtension->SpinLock, currentIrql);
if (pdoExtension->PendingPowerDownSystemIrp) {
//
// We get this power down irp
// because we are going to non-working state
// block the device queue
//
KeAcquireSpinLock(&fdoExtension->SpinLock, ¤tIrql);
DebugPrint ((DBG_POWER, "ATAPI: blocking 0x%x target %d device queue\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId));
pdoExtension->PdoState |= PDOS_QUEUE_FROZEN_BY_SLEEPING_SYSTEM;
KeReleaseSpinLock(&fdoExtension->SpinLock, currentIrql); } }
if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) {
//
// get ready to reinit. the device via acpi data when
// we get out of D3
//
InterlockedIncrement (&pdoExtension->InitDeviceWithAcpiGtf); }
if (pdoExtension->DevicePowerState == PowerDeviceD3) {
//
// just get out out D3, re-init. pdo
//
DebugPrint((DBG_POWER, "Calling DeviceInitDeviceState for irp 0x%x\n", Irp)); status = DeviceInitDeviceState ( pdoExtension, DevicePowerUpInitCompletionRoutine, Irp ); if (!NT_SUCCESS(status)) {
DevicePowerUpInitCompletionRoutine ( Irp, status ); }
return; }
pdoExtension->DevicePowerState = (int) Irp->IoStatus.Information; } }
if ((callPoSetPowerState) && NT_SUCCESS(status)) {
//
// we didn't get out of device D0 state. calling PoSetPowerState now
//
PoSetPowerState ( pdoExtension->DeviceObject, irpStack->Parameters.Power.Type, irpStack->Parameters.Power.State ); } } else {
if (irpStack->Parameters.Power.Type == SystemPowerState) {
if (pdoExtension->SystemPowerState != irpStack->Parameters.Power.State.SystemState) {
if (pdoExtension->SystemPowerState == PowerSystemWorking) {
//
// failed a system power down irp
//
KeAcquireSpinLock(&fdoExtension->SpinLock, ¤tIrql);
//
// got into S0, unblock and restart the device queue
//
if (pdoExtension->PdoState & PDOS_QUEUE_FROZEN_BY_SLEEPING_SYSTEM) {
CLRMASK (pdoExtension->PdoState, PDOS_QUEUE_FROZEN_BY_SLEEPING_SYSTEM);
GetNextLuPendingRequest (fdoExtension, pdoExtension);
KeLowerIrql(currentIrql);
} else {
KeReleaseSpinLock(&fdoExtension->SpinLock, currentIrql); } } }
pdoExtension->PendingPowerDownSystemIrp = NULL; } }
if (!NT_SUCCESS(status)) {
DebugPrint ((DBG_ALWAYS, "ATAPI: 0x%x target %d failed power Irp 0x%x. status = 0x%x\n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, Irp->IoStatus.Status));
if (irpStack->Parameters.Power.Type == DevicePowerState) {
//
// ISSUE: 08/20/2000: Just failed a power D0 request...fail all pending irp
//
//ASSERT (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0);
//
// we will fail all the pending irps if we failed with status
// no such device
//
if (status == STATUS_NO_SUCH_DEVICE) {
DebugPrint ((0, "Restarting the Lu queue after marking the device dead\n" ));
DebugPrint((0, "Device Power up irp failed with status 0x%x\n", status )); //
// mark the pdo as dead
// ISSUE: 12/19/2001. We should update deadmeat reason
// for ease of debugging.
//
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
SETMASK (pdoExtension->PdoState, PDOS_DEADMEAT);
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
//
// ISSUE: 12/19/2001: Should we call IoInvalidateDeviceRelations?
// we should get a remove irp in this case anyway.
//
IoInvalidateDeviceRelations ( fdoExtension->AttacheePdo, BusRelations );
//
// start any pending requests
// ISSUE: 12/19/2001: We should hold the pdospinlock at
// this time. But in the other routines we seem to be
// holding just the fdospinlock before modifying the
// pdostate. We will leave it as such to minimise regressions.
//
KeAcquireSpinLock(&fdoExtension->SpinLock, ¤tIrql);
if (pdoExtension->PdoState & PDOS_QUEUE_FROZEN_BY_POWER_DOWN) {
//
// ISSUE: 12/19/2001: We are not updating the device power
// state to D0. This would cause all the further requests
// to ask for a new power up irp. The system would be slow
// if we get too many requests. The remove irp should arrive
// eventually and end the misery.
//
CLRMASK (pdoExtension->PdoState, PDOS_QUEUE_FROZEN_BY_POWER_DOWN);
//
// restart the lu queue (on an lu that is marked dead)
// we didn't run GTF or do any of the other initialization.
// Since we marked the device dead above, we can restart the
// queue.They will get completed with status
// device_does_not_exist.
//
GetNextLuPendingRequest (fdoExtension, pdoExtension);
KeLowerIrql(currentIrql);
} else {
KeReleaseSpinLock(&fdoExtension->SpinLock, currentIrql); } } else {
//
// ISSUE: 12/192001: we handle only status_no_such device
//
ASSERT (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0); } } }
#if DBG
if (irpStack->Parameters.Power.Type == SystemPowerState) {
DebugPrint ((DBG_POWER, "IdePortPdoCompletePowerIrp: 0x%x target %d completing a SYSTEM power irp 0x%x for system state 0x%x \n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, irpStack->Parameters.Power.State.SystemState));
ASSERT (pdoExtension->PendingSystemPowerIrp == Irp); pdoExtension->PendingSystemPowerIrp = NULL;
} else if (irpStack->Parameters.Power.Type == DevicePowerState) {
DebugPrint ((DBG_POWER, "IdePortPdoCompletePowerIrp: 0x%x target %d completing a DEVICE power irp 0x%x for device state 0x%x \n", pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->TargetId, Irp, irpStack->Parameters.Power.State.SystemState));
ASSERT (pdoExtension->PendingDevicePowerIrp == Irp); pdoExtension->PendingDevicePowerIrp = NULL; } #endif
PoStartNextPowerIrp (Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); }
VOID IdePowerCheckBusyCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIDE_POWER_CONTEXT Context, IN NTSTATUS Status ) /*++
Routine Description
Completion routine for ide pass through that would check if the device is busy. This is typically done before a reset to salvage drives that hang when a reset is issued while they are busy (due to a hardware reset) Arguments:
DeviceObject Context Status : Not used Return Value
None. --*/ { PATA_PASS_THROUGH ataPassThrough; PIDEREGS ideReg; NTSTATUS status;
ataPassThrough = &Context->AtaPassThroughData; ideReg = &ataPassThrough->IdeReg;
//
// send down the reset
//
RtlZeroMemory(ideReg, sizeof(IDEREGS));
ideReg->bReserved = ATA_PTFLAGS_BUS_RESET | ATA_PTFLAGS_URGENT;
status = IssueAsyncAtaPassThroughSafe ( Context->PdoExtension->ParentDeviceExtension, Context->PdoExtension, &Context->AtaPassThroughData, FALSE, IdePowerPassThroughCompletion, Context, TRUE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE );
return; }
VOID IdePowerPassThroughCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIDE_POWER_CONTEXT Context, IN NTSTATUS Status ) { if (!NT_SUCCESS(Status)) {
//
// device failed power management command
// will not try it anymore
//
KIRQL currentIrql;
KeAcquireSpinLock(&Context->PdoExtension->PdoSpinLock, ¤tIrql);
SETMASK (Context->PdoExtension->PdoState, PDOS_NO_POWER_DOWN);
KeReleaseSpinLock(&Context->PdoExtension->PdoSpinLock, currentIrql);
Status = STATUS_SUCCESS; }
Context->PowerIrp->IoStatus.Status = Status;
IdePortPdoCompletePowerIrp ( DeviceObject, Context->PowerIrp );
ASSERT(InterlockedCompareExchange(&(Context->PdoExtension->PowerContextLock), 0, 1) == 1); //ExFreePool (Context);
}
VOID DevicePowerUpInitCompletionRoutine ( PVOID Context, NTSTATUS Status ) { PIRP irp = Context; PIO_STACK_LOCATION irpStack; PPDO_EXTENSION pdoExtension; KIRQL currentIrql;
irpStack = IoGetCurrentIrpStackLocation (irp); pdoExtension = (PPDO_EXTENSION) irpStack->DeviceObject->DeviceExtension;
if (!NT_SUCCESS(Status)) {
//ASSERT (!"DevicePowerUpInitCompletionRoutine Failed\n");
DebugPrint((DBG_ALWAYS, "ATAPI: ERROR: DevicePowerUpInitComplete failed with status %x\n", Status)); }
ASSERT (pdoExtension->PendingDevicePowerIrp == irp); pdoExtension->PendingDevicePowerIrp = NULL;
pdoExtension->DevicePowerState = (ULONG)irp->IoStatus.Information;
PoSetPowerState ( pdoExtension->DeviceObject, irpStack->Parameters.Power.Type, irpStack->Parameters.Power.State );
KeAcquireSpinLock(&pdoExtension->ParentDeviceExtension->SpinLock, ¤tIrql);
//
// got into D0, restart device queue
//
DebugPrint((DBG_POWER, "Clearing QUEUE_FROZEN_BY_POWER_DOWN flag\n")); CLRMASK(pdoExtension->PdoState, PDOS_QUEUE_FROZEN_BY_POWER_DOWN);
GetNextLuPendingRequest (pdoExtension->ParentDeviceExtension, pdoExtension);
KeLowerIrql(currentIrql);
PoStartNextPowerIrp (irp); IoCompleteRequest(irp, IO_NO_INCREMENT); }
|