📄 power.c
字号:
Context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE;
Context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE;
Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
Context->Srb.DataTransferLength = 0;
nextStack->Parameters.Scsi.Srb = &(Context->Srb);
nextStack->MajorFunction = IRP_MJ_SCSI;
Context->PowerChangeState.PowerUp = PowerUpDeviceStarted;
IoSetCompletionRoutine(Irp,
ClasspPowerUpCompletion,
Context,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n",
Irp, status));
break;
}
// Fall-through to next case...
}
case PowerUpDeviceUnlocked: {
//
// 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) {
DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp));
ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
ASSERT(Context->Srb.SrbStatus == SRB_STATUS_SUCCESS);
} else {
DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp));
}
DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp));
Context->InUse = FALSE;
status = Context->FinalStatus;
Irp->IoStatus.Status = status;
Context = NULL;
//
// Set the new power state
//
if(NT_SUCCESS(status)) {
fdoExtension->DevicePowerState =
currentStack->Parameters.Power.State.DeviceState;
}
//
// Indicate to Po that we've been successfully powered up so
// it can do it's notification stuff.
//
PoSetPowerState(DeviceObject,
currentStack->Parameters.Power.Type,
currentStack->Parameters.Power.State);
DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
ClassReleaseRemoveLock(DeviceObject, Irp);
PoStartNextPowerIrp(Irp);
return status;
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
} // end ClasspPowerUpCompletion()
/*++////////////////////////////////////////////////////////////////////////////
ClasspPowerDownCompletion()
Routine Description:
This routine is used for intermediate completion of a power up request.
PowerUp requires four requests to be sent to the lower driver in sequence.
* The queue is "power locked" to ensure that the class driver power-up
work can be done before request processing resumes.
* The power irp is sent down the stack for any filter drivers and the
port driver to return power and resume command processing for the
device. Since the queue is locked, no queued irps will be sent
immediately.
* A start unit command is issued to the device with appropriate flags
to override the "power locked" queue.
* The queue is "power unlocked" to start processing requests again.
This routine uses the function in the srb which just completed to determine
which state it is in.
Arguments:
DeviceObject - the device object being powered up
Irp - the IO_REQUEST_PACKET containing the power request
Srb - the SRB used to perform port/class operations.
Return Value:
STATUS_MORE_PROCESSING_REQUIRED or
STATUS_SUCCESS
--*/
NTSTATUS
ClasspPowerDownCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PCLASS_POWER_CONTEXT Context
)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, "
"Irp %p, Context %p\n",
DeviceObject, Irp, Context));
ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
ASSERT(Context->Options.PowerDown == TRUE);
ASSERT(Context->Options.HandleSpinDown);
if(Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
Context->PowerChangeState.PowerDown2++;
switch(Context->PowerChangeState.PowerDown2) {
case PowerDownDeviceLocked2: {
PCDB cdb;
DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
if((Context->Options.LockQueue == TRUE) &&
(!NT_SUCCESS(Irp->IoStatus.Status))) {
DebugPrint((1, "(%p)\tIrp status was %lx\n",
Irp,
Irp->IoStatus.Status));
DebugPrint((1, "(%p)\tSrb status was %lx\n",
Irp,
Context->Srb.SrbStatus));
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
//
// Lock was not successful - throw down the power IRP
// by itself and don't try to spin down the drive or unlock
// the queue.
//
Context->InUse = FALSE;
Context = NULL;
//
// Set the new power state
//
fdoExtension->DevicePowerState =
currentStack->Parameters.Power.State.DeviceState;
//
// Indicate to Po that we've been successfully powered down
// so it can do it's notification stuff.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
ClasspStartNextPowerIrpCompletion,
NULL,
TRUE,
TRUE,
TRUE);
PoSetPowerState(DeviceObject,
currentStack->Parameters.Power.Type,
currentStack->Parameters.Power.State);
fdoExtension->PowerDownInProgress = FALSE;
PoCallDriver(commonExtension->LowerDeviceObject, Irp);
ClassReleaseRemoveLock(commonExtension->DeviceObject,
Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
} else {
Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
}
if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags,
FDO_HACK_NO_SYNC_CACHE)) {
//
// send SCSIOP_SYNCHRONIZE_CACHE
//
Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Context->Srb.TimeOutValue = fdoExtension->TimeOutValue;
Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
SRB_FLAGS_DISABLE_AUTOSENSE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_NO_QUEUE_FREEZE |
SRB_FLAGS_BYPASS_LOCKED_QUEUE;
Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
Context->Srb.DataTransferLength = 0;
Context->Srb.CdbLength = 10;
cdb = (PCDB) Context->Srb.Cdb;
RtlZeroMemory(cdb, sizeof(CDB));
cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
IoSetCompletionRoutine(Irp,
ClasspPowerDownCompletion,
Context,
TRUE,
TRUE,
TRUE);
nextStack->Parameters.Scsi.Srb = &(Context->Srb);
nextStack->MajorFunction = IRP_MJ_SCSI;
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
break;
} else {
DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n",
DeviceObject));
Context->PowerChangeState.PowerDown2++;
Context->Srb.SrbStatus = SRB_STATUS_SUCCESS;
// and fall through....
}
// no break in case the device doesn't like synch_cache commands
}
case PowerDownDeviceFlushed2: {
PCDB cdb;
DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n",
Irp));
//
// SCSIOP_SYNCHRONIZE_CACHE was sent
//
if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
BOOLEAN retry;
DebugPrint((1, "(%p)\tError occured when issuing "
"SYNCHRONIZE_CACHE command to device. "
"Srb %p, Status %lx\n",
Irp,
&Context->Srb,
Context->Srb.SrbStatus));
ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
SRB_STATUS_QUEUE_FROZEN)));
ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
Context->RetryInterval = 0;
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)\tSYNCHRONIZE_CACHE not retried\n", Irp));
Context->RetryCount = MAXIMUM_RETRIES;
} // end !SRB_STATUS_SUCCESS
//
// note: we are purposefully ignoring any errors. if the drive
// doesn't support a synch_cache, then we're up a creek
// anyways.
//
DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp));
//
// Issue the start unit command to the device.
//
Context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Context->Srb.TimeOutValue = START_UNIT_TIMEOUT;
Context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
SRB_FLAGS_DISABLE_AUTOSENSE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
SRB_FLAGS_NO_QUEUE_FREEZE |
SRB_FLAGS_BYPASS_LOCKED_QUEUE;
Context->Srb.SrbStatus = Context->Srb.ScsiStatus = 0;
Context->Srb.DataTransferLength = 0;
Context->Srb.CdbLength = 6;
cdb = (PCDB) Context->Srb.Cdb;
RtlZeroMemory(cdb, sizeof(CDB));
cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
cdb->START_STOP.Start = 0;
cdb->START_STOP.Immediate = 1;
IoSetCompletionRoutine(Irp,
ClasspPowerDownCompletion,
Context,
TRUE,
TRUE,
TRUE);
nextStack->Parameters.Scsi.Srb = &(Context->Srb);
nextStack->MajorFunction = IRP_MJ_SCSI;
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
break;
}
case PowerDownDeviceStopped2: {
BOOLEAN ignoreError = TRUE;
//
// stop was sent
//
if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
BOOLEAN retry;
DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT "
"command to device. Srb %p, Status %lx\n",
Irp,
&Context->Srb,
Context->Srb.SrbStatus));
ASSERT(!(TEST_FLAG(Context->Srb.SrbStatus,
SRB_STATUS_QUEUE_FROZEN)));
ASSERT(Context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI);
Context->RetryInterval = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -