📄 power.c
字号:
/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
power.c
Abstract:
SCSI class driver routines
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "stddef.h"
#include "ntddk.h"
#include "scsi.h"
#include "classp.h"
#include <stdarg.h>
#define CLASS_TAG_POWER 'WLcS'
NTSTATUS
ClasspPowerHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN CLASS_POWER_OPTIONS Options
);
NTSTATUS
ClasspPowerDownCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PCLASS_POWER_CONTEXT Context
);
NTSTATUS
ClasspPowerUpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PCLASS_POWER_CONTEXT Context
);
VOID
RetryPowerRequest(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PCLASS_POWER_CONTEXT Context
);
NTSTATUS
ClasspStartNextPowerIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
/*++////////////////////////////////////////////////////////////////////////////
ClassDispatchPower()
Routine Description:
This routine acquires the removelock for the irp and then calls the
appropriate power callback.
Arguments:
DeviceObject -
Irp -
Return Value:
--*/
NTSTATUS
ClassDispatchPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
ULONG isRemoved;
PCLASS_POWER_DEVICE powerRoutine = NULL;
//
// NOTE: This code may be called at PASSIVE or DISPATCH, depending
// upon the device object it is being called for.
// don't do anything that would break under either circumstance.
//
NTSTATUS status;
isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
if(isRemoved) {
ClassReleaseRemoveLock(DeviceObject, Irp);
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
PoStartNextPowerIrp(Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
return commonExtension->DevInfo->ClassPowerDevice(DeviceObject, Irp);
} // end ClassDispatchPower()
/*++////////////////////////////////////////////////////////////////////////////
ClasspPowerUpCompletion()
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
ClasspPowerUpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PCLASS_POWER_CONTEXT Context
)
{
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
DebugPrint((1, "ClasspPowerUpCompletion: 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 == FALSE);
ASSERT(Context->Options.HandleSpinUp);
if(Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
Context->PowerChangeState.PowerUp++;
switch(Context->PowerChangeState.PowerUp) {
case PowerUpDeviceLocked: {
DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp));
//
// Issue the actual power request to the lower driver.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// If the lock wasn't successful then just bail out on the power
// request unless we can ignore failed locks
//
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));
//
// Lock was not successful - throw down the power IRP
// by itself and don't try to spin up the drive or unlock
// the queue.
//
Context->InUse = FALSE;
Context = NULL;
//
// Set the new power state
//
fdoExtension->DevicePowerState =
currentStack->Parameters.Power.State.DeviceState;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
ClasspStartNextPowerIrpCompletion,
NULL,
TRUE,
TRUE,
TRUE);
//
// 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);
PoCallDriver(commonExtension->LowerDeviceObject, Irp);
ClassReleaseRemoveLock(commonExtension->DeviceObject,
Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
} else {
Context->QueueLocked = (UCHAR) Context->Options.LockQueue;
}
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
Context->PowerChangeState.PowerUp = PowerUpDeviceLocked;
IoSetCompletionRoutine(Irp,
ClasspPowerUpCompletion,
Context,
TRUE,
TRUE,
TRUE);
status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status));
break;
}
case PowerUpDeviceOn: {
PCDB cdb;
if(NT_SUCCESS(Irp->IoStatus.Status)) {
DebugPrint((1, "(%p)\tSending start 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.SrbStatus = Context->Srb.ScsiStatus = 0;
Context->Srb.DataTransferLength = 0;
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;
if(Context->Options.LockQueue) {
SET_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
}
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 = 1;
Context->PowerChangeState.PowerUp = PowerUpDeviceOn;
IoSetCompletionRoutine(Irp,
ClasspPowerUpCompletion,
Context,
TRUE,
TRUE,
TRUE);
nextStack->Parameters.Scsi.Srb = &(Context->Srb);
nextStack->MajorFunction = IRP_MJ_SCSI;
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status));
} else {
//
// we're done.
//
Context->FinalStatus = Irp->IoStatus.Status;
goto ClasspPowerUpCompletionFailure;
}
break;
}
case PowerUpDeviceStarted: { // 3
//
// First deal with an error if one occurred.
//
if(SRB_STATUS(Context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) {
BOOLEAN retry;
DebugPrint((1, "%p\tError occured when issuing START_UNIT "
"command to device. Srb %p, Status %x\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.PowerUp--;
RetryPowerRequest(commonExtension->DeviceObject,
Irp,
Context);
break;
}
// reset retries
Context->RetryCount = MAXIMUM_RETRIES;
}
ClasspPowerUpCompletionFailure:
DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp));
if (Context->QueueLocked) {
DebugPrint((1, "(%p)\tUnlocking queue\n", Irp));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -