📄 power.c
字号:
retry = ClassInterpretSenseInfo(
commonExtension->DeviceObject,
&Context->Srb,
IRP_MJ_SCSI,
IRP_MJ_POWER,
MAXIMUM_RETRIES - Context->RetryCount,
&status,
&Context->RetryInterval);
if((retry == TRUE) && (Context->RetryCount-- != 0)) {
DebugPrint((1, "(%p)\tRetrying failed request\n", Irp));
//
// decrement the state so we come back through here
// the next time.
//
Context->PowerChangeState.PowerDown2--;
RetryPowerRequest(commonExtension->DeviceObject,
Irp,
Context);
break;
}
DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp));
Context->RetryCount = MAXIMUM_RETRIES;
} // end !SRB_STATUS_SUCCESS
DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp));
//
// some operations, such as a physical format in progress,
// should not be ignored and should fail the power operation.
//
if (!NT_SUCCESS(status)) {
PSENSE_DATA senseBuffer = Context->Srb.SenseInfoBuffer;
if (TEST_FLAG(Context->Srb.SrbStatus,
SRB_STATUS_AUTOSENSE_VALID) &&
((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
(senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
(senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)
) {
ignoreError = FALSE;
Context->FinalStatus = STATUS_DEVICE_BUSY;
status = Context->FinalStatus;
}
}
if (NT_SUCCESS(status) || ignoreError) {
//
// Issue the actual power request to the lower driver.
//
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
ClasspPowerDownCompletion,
Context,
TRUE,
TRUE,
TRUE);
status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
break;
}
// else fall through w/o sending the power irp, since the device
// is reporting an error that would be "really bad" to power down
// during.
}
case PowerDownDeviceOff2: {
//
// SpinDown request completed ... whether it succeeded or not is
// another matter entirely.
//
DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp));
if (Context->QueueLocked) {
DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
Context->Srb.DataTransferLength = 0;
Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
nextStack->Parameters.Scsi.Srb = &(Context->Srb);
nextStack->MajorFunction = IRP_MJ_SCSI;
IoSetCompletionRoutine(Irp,
ClasspPowerDownCompletion,
Context,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
Irp,
status));
break;
}
}
case PowerDownDeviceUnlocked2: {
//
// This is the end of the dance. Free the srb and complete the
// request finally. We're ignoring possible intermediate
// error conditions ....
//
if (Context->QueueLocked == FALSE) {
DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp));
} else {
DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
}
DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
Context->InUse = FALSE;
status = Context->FinalStatus; // allow failure to propogate
Context = NULL;
if(Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
if (NT_SUCCESS(status)) {
//
// Set the new power state
//
fdoExtension->DevicePowerState =
currentStack->Parameters.Power.State.DeviceState;
}
DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
ClassReleaseRemoveLock(DeviceObject, Irp);
PoStartNextPowerIrp(Irp);
fdoExtension->PowerDownInProgress = FALSE;
return status;
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
} // end ClasspPowerDownCompletion()
/*++////////////////////////////////////////////////////////////////////////////
ClasspPowerHandler()
Routine Description:
This routine reduces the number of useless spinups and spindown requests
sent to a given device by ignoring transitions to power states we are
currently in.
ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be
allowing the drive
Arguments:
DeviceObject - the device object which is transitioning power states
Irp - the power irp
Options - a set of flags indicating what the device handles
Return Value:
--*/
NTSTATUS
ClasspPowerHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct
)
{
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack;
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PCLASS_POWER_CONTEXT context;
if (!commonExtension->IsFdo) {
//
// certain assumptions are made here,
// particularly: having the fdoExtension
//
DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n",
DeviceObject));
ASSERT(!"PDO using ClasspPowerHandler");
return STATUS_NOT_SUPPORTED;
}
DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n",
Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject));
switch(irpStack->MinorFunction) {
case IRP_MN_SET_POWER: {
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp));
DebugPrint((1, "(%p)\tSetting %s state to %d\n",
Irp,
(irpStack->Parameters.Power.Type == SystemPowerState ?
"System" : "Device"),
irpStack->Parameters.Power.State.SystemState));
switch (irpStack->Parameters.Power.ShutdownType){
case PowerActionSleep:
case PowerActionHibernate:
if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){
/*
* We are suspending and this drive is either hot-pluggable
* or contains removeable media.
* Set the media dirty bit, since the media may change while
* we are suspended.
*/
SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
//
// Bumping the media change count will force the
// file system to verify the volume when we resume
//
InterlockedIncrement(&fdoExtension->MediaChangeCount);
}
break;
}
break;
}
default: {
DebugPrint((1, "(%p)\tIrp minor code = %#x\n",
Irp, irpStack->MinorFunction));
break;
}
}
if (irpStack->Parameters.Power.Type != DevicePowerState ||
irpStack->MinorFunction != IRP_MN_SET_POWER) {
DebugPrint((1, "(%p)\tSending to lower device\n", Irp));
goto ClasspPowerHandlerCleanup;
}
nextIrpStack = IoGetNextIrpStackLocation(Irp);
//
// already in exact same state, don't work to transition to it.
//
if(irpStack->Parameters.Power.State.DeviceState ==
fdoExtension->DevicePowerState) {
DebugPrint((1, "(%p)\tAlready in device state %x\n",
Irp, fdoExtension->DevicePowerState));
goto ClasspPowerHandlerCleanup;
}
//
// or powering down from non-d0 state (device already stopped)
// NOTE -- we're not sure whether this case can exist or not (the
// power system may never send this sort of request) but it's trivial
// to deal with.
//
if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) &&
(fdoExtension->DevicePowerState != PowerDeviceD0)) {
DebugPrint((1, "(%p)\tAlready powered down to %x???\n",
Irp, fdoExtension->DevicePowerState));
fdoExtension->DevicePowerState =
irpStack->Parameters.Power.State.DeviceState;
goto ClasspPowerHandlerCleanup;
}
//
// or going into a hibernation state when we're in the hibernation path.
// If the device is spinning then we should leave it spinning - if it's not
// then the dump driver will start it up for us.
//
if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) &&
(irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) &&
(commonExtension->HibernationPathCount != 0)) {
DebugPrint((1, "(%p)\tdoing nothing for hibernation request for "
"state %x???\n",
Irp, fdoExtension->DevicePowerState));
fdoExtension->DevicePowerState =
irpStack->Parameters.Power.State.DeviceState;
goto ClasspPowerHandlerCleanup;
}
//
// or when not handling powering up and are powering up
//
if ((!Options.HandleSpinUp) &&
(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) {
DebugPrint((2, "(%p)\tNot handling spinup to state %x\n",
Irp, fdoExtension->DevicePowerState));
fdoExtension->DevicePowerState =
irpStack->Parameters.Power.State.DeviceState;
goto ClasspPowerHandlerCleanup;
}
//
// or when not handling powering down and are powering down
//
if ((!Options.HandleSpinDown) &&
(irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) {
DebugPrint((2, "(%p)\tNot handling spindown to state %x\n",
Irp, fdoExtension->DevicePowerState));
fdoExtension->DevicePowerState =
irpStack->Parameters.Power.State.DeviceState;
goto ClasspPowerHandlerCleanup;
}
context = &(fdoExtension->PowerContext);
#if DBG
//
// Mark the context as in use. We should be synchronizing this but
// since it's just for debugging purposes we don't worry too much.
//
ASSERT(context->InUse == FALSE);
#endif
RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT));
context->InUse = TRUE;
nextIrpStack->Parameters.Scsi.Srb = &(context->Srb);
nextIrpStack->MajorFunction = IRP_MJ_SCSI;
context->FinalStatus = STATUS_SUCCESS;
context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
context->Srb.OriginalRequest = Irp;
context->Srb.SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE
| SRB_FLAGS_NO_QUEUE_FREEZE;
context->Srb.Function = SRB_FUNCTION_LOCK_QUEUE;
context->Srb.SenseInfoBuffer =
commonExtension->PartitionZeroExtension->SenseData;
context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
context->RetryCount = MAXIMUM_RETRIES;
context->Options = Options;
context->DeviceObject = DeviceObject;
context->Irp = Irp;
if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
ASSERT(Options.HandleSpinUp);
DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp));
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -