You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1620 lines
44 KiB
1620 lines
44 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
pdo.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the dispatch routines for scsiport's physical device
|
|
objects
|
|
|
|
Authors:
|
|
|
|
Peter Wieland
|
|
|
|
Environment:
|
|
|
|
Kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define KEEP_COMPLETE_REQUEST
|
|
|
|
#include "port.h"
|
|
|
|
#define __FILE_ID__ 'pdo '
|
|
|
|
#if DBG
|
|
static const char *__file__ = __FILE__;
|
|
#endif
|
|
|
|
LONG SpPowerIdleTimeout = -1; // use system default
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlStorageQueryProperty(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlScsiGetAddress(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlScsiPassthrough(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlScsiPassthroughDirect(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpPagingPathNotificationCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP LowerIrp,
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, ScsiPortPdoPnp)
|
|
#pragma alloc_text(PAGE, ScsiPortPdoCreateClose)
|
|
#pragma alloc_text(PAGE, ScsiPortStartLogicalUnit)
|
|
#pragma alloc_text(PAGE, ScsiPortInitPdoWmi)
|
|
#pragma alloc_text(PAGE, SpPdoHandleIoctlStorageQueryProperty)
|
|
#pragma alloc_text(PAGE, SpPdoHandleIoctlScsiGetAddress)
|
|
#pragma alloc_text(PAGE, SpPdoHandleIoctlScsiPassthrough)
|
|
#pragma alloc_text(PAGE, SpPdoHandleIoctlScsiPassthroughDirect)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlStorageQueryProperty(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the IOCTL_STORAGE_QUERY_PROPERTY request for a PDO.
|
|
It validates the input buffer and passes calls a helper routine to do the
|
|
work. The helper routine handles completing or forwarding the request and
|
|
releasing the remove lock.
|
|
|
|
Arguments:
|
|
|
|
Pdo - Supplies a pointer to the physical device object
|
|
|
|
Irp - Supplies a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
PAGED_CODE();
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(STORAGE_PROPERTY_QUERY)) {
|
|
|
|
//
|
|
// The input buffer is not big enough to hold a STORAGE_PROPERTY_QUERY
|
|
// structure. Fail the request.
|
|
//
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Status = status;
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
} else {
|
|
|
|
//
|
|
// Call helper routine to do the bulk of the work. The helper completes
|
|
// or forwards the request down the stack and releases the remove lock.
|
|
//
|
|
|
|
status = ScsiPortQueryPropertyPdo(Pdo, Irp);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlScsiGetAddress(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the IOCTL_SCSI_GET_ADDRESS. It validates the input
|
|
that the output buffer is big enough to hold a SCSI_ADDRESS structure. If
|
|
the buffer is big enough, it copies the address information into the buffer.
|
|
|
|
Arguments:
|
|
|
|
Pdo - Supplies a pointer to the physical device object
|
|
|
|
Irp - Supplies a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the supplied buffer is big enough to hold the address.
|
|
|
|
STATUS_BUFFER_TOO_SMALL if the supplied buffer is too small.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PLOGICAL_UNIT_EXTENSION luExtension = Pdo->DeviceExtension;
|
|
PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SCSI_ADDRESS)) {
|
|
|
|
//
|
|
// The output buffer is too small to hold a SCSI_ADDRESS structure,
|
|
// so we fail the request.
|
|
//
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
|
|
//
|
|
// Fill in the address information and set the IoStatus.Information
|
|
// to the sizeof the SCSI_ADDRESS structure.
|
|
//
|
|
|
|
scsiAddress->Length = sizeof(SCSI_ADDRESS);
|
|
scsiAddress->PortNumber = (UCHAR) luExtension->PortNumber;
|
|
scsiAddress->PathId = luExtension->PathId;
|
|
scsiAddress->TargetId = luExtension->TargetId;
|
|
scsiAddress->Lun = luExtension->Lun;
|
|
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
|
|
}
|
|
|
|
//
|
|
// Complete the request and release the remove lock.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlScsiPassthrough(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles IOCTL_SCSI_PASS_THROUGH. It checks that the input
|
|
buffer is big enough to hold a SCSI_PASS_THROUGH structure, fills in the
|
|
address information for this LU and passes the request down to the FDO
|
|
handler to do the real work.
|
|
|
|
Arguments:
|
|
|
|
Pdo - Supplies a pointer to the physical device object
|
|
|
|
Irp - Supplies a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PLOGICAL_UNIT_EXTENSION luExtension = Pdo->DeviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize the address of the SCSI_PASS_THROUGH structure embedded
|
|
// in the supplied IRP. This routine verifies that the size of the
|
|
// SystemBuffer is big enough to hold a SCSI_PASS_THROUGH structure
|
|
// before it touches it.
|
|
//
|
|
|
|
status = PortSetPassThroughAddress(
|
|
Irp,
|
|
luExtension->PathId,
|
|
luExtension->TargetId,
|
|
luExtension->Lun
|
|
);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Forward the request down to the FDO handler.
|
|
//
|
|
|
|
PCOMMON_EXTENSION commonExtension = Pdo->DeviceExtension;
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpPdoHandleIoctlScsiPassthroughDirect(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles IOCTL_SCSI_PASS_THROUGH_DIRECT. It simply delegates
|
|
to the handler for IOCTL_SCSI_PASS_THROUGH since they both do exactly the
|
|
same thing.
|
|
|
|
Arguments:
|
|
|
|
Pdo - Supplies a pointer to the physical device object
|
|
|
|
Irp - Supplies a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return SpPdoHandleIoctlScsiPassthrough(Pdo, Irp);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoDeviceControl(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles device control requests for scsi target devices
|
|
|
|
Arguments:
|
|
|
|
Pdo - a pointer to the physical device object
|
|
|
|
Irp - a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ULONG ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
|
|
PCOMMON_EXTENSION commonExtension = Pdo->DeviceExtension;
|
|
NTSTATUS status;
|
|
ULONG isRemoved;
|
|
|
|
//
|
|
// If the device has been removed or is in the process of being removed,
|
|
// we must fail this request.
|
|
//
|
|
|
|
isRemoved = SpAcquireRemoveLock(Pdo, Irp);
|
|
if (isRemoved) {
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
ASSERT(commonExtension->IsPdo);
|
|
|
|
//
|
|
// Initialize the status.
|
|
//
|
|
|
|
Irp->IoStatus.Status = 0;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
switch (ioControlCode) {
|
|
|
|
case IOCTL_STORAGE_QUERY_PROPERTY:
|
|
status = SpPdoHandleIoctlStorageQueryProperty(Pdo, Irp);
|
|
break;
|
|
|
|
case IOCTL_SCSI_GET_ADDRESS:
|
|
status = SpPdoHandleIoctlScsiGetAddress(Pdo, Irp);
|
|
break;
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
status = SpPdoHandleIoctlScsiPassthrough(Pdo, Irp);
|
|
break;
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
|
|
status = SpPdoHandleIoctlScsiPassthroughDirect(Pdo, Irp);
|
|
break;
|
|
|
|
case IOCTL_SCSI_GET_DUMP_POINTERS:
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
|
|
break;
|
|
|
|
default: {
|
|
|
|
DebugPrint((1, "ScsiPortPdoDeviceControl: unsupported IOCTL %08x\n",
|
|
ioControlCode));
|
|
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
Irp->IoStatus.Status = status;
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoPnp(
|
|
IN PDEVICE_OBJECT LogicalUnit,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles pnp-power requests. Currently it will just be
|
|
successful
|
|
|
|
Arguments:
|
|
|
|
LogicalUnit - pointer to the physical device object
|
|
Irp - pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOGICAL_UNIT_EXTENSION logicalUnitExtension = LogicalUnit->DeviceExtension;
|
|
PCOMMON_EXTENSION commonExtension = LogicalUnit->DeviceExtension;
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
static ULONG i = 0;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ULONG isRemoved;
|
|
|
|
PAGED_CODE();
|
|
|
|
isRemoved = SpAcquireRemoveLock(LogicalUnit, Irp);
|
|
|
|
#if 0
|
|
if(isRemoved != ) {
|
|
|
|
ASSERT(isRemoved != REMOVE_PENDING);
|
|
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
#else
|
|
ASSERT(isRemoved != REMOVE_COMPLETE);
|
|
#endif
|
|
|
|
switch(irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE: {
|
|
|
|
//
|
|
// If the device is in the paging path then mark it as
|
|
// not-disableable.
|
|
//
|
|
|
|
PPNP_DEVICE_STATE deviceState =
|
|
(PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
|
|
|
|
DebugPrint((1, "ScsiPortPdoPnp: QUERY_DEVICE_STATE for PDO %#x\n", LogicalUnit));
|
|
|
|
if(commonExtension->PagingPathCount != 0) {
|
|
SET_FLAG((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
|
|
DebugPrint((1, "ScsiPortPdoPnp: QUERY_DEVICE_STATE: %#x - not disableable\n",
|
|
LogicalUnit));
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
SpReleaseRemoveLock(LogicalUnit, Irp);
|
|
SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
case IRP_MN_START_DEVICE: {
|
|
|
|
if(commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) {
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if(commonExtension->IsInitialized == FALSE) {
|
|
status = ScsiPortInitLogicalUnit(logicalUnitExtension);
|
|
}
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
commonExtension->IsInitialized = TRUE;
|
|
status = ScsiPortStartLogicalUnit(logicalUnitExtension);
|
|
}
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
commonExtension->CurrentPnpState = IRP_MN_START_DEVICE;
|
|
commonExtension->PreviousPnpState = 0xff;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_ID: {
|
|
|
|
UCHAR rawIdString[64] = "UNKNOWN ID TYPE";
|
|
ANSI_STRING ansiIdString;
|
|
UNICODE_STRING unicodeIdString;
|
|
BOOLEAN multiStrings;
|
|
|
|
PINQUIRYDATA inquiryData = &(logicalUnitExtension->InquiryData);
|
|
|
|
//
|
|
// We've been asked for the id of one of the physical device objects
|
|
//
|
|
|
|
DebugPrint((2, "ScsiPortPnp: got IRP_MN_QUERY_ID\n"));
|
|
|
|
RtlInitUnicodeString(&unicodeIdString, NULL);
|
|
RtlInitAnsiString(&ansiIdString, NULL);
|
|
|
|
switch(irpStack->Parameters.QueryId.IdType) {
|
|
|
|
case BusQueryDeviceID: {
|
|
|
|
status = ScsiPortGetDeviceId(LogicalUnit, &unicodeIdString);
|
|
multiStrings = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
case BusQueryInstanceID: {
|
|
|
|
status = ScsiPortGetInstanceId(LogicalUnit, &unicodeIdString);
|
|
multiStrings = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
case BusQueryHardwareIDs: {
|
|
|
|
status = ScsiPortGetHardwareIds(
|
|
LogicalUnit->DriverObject,
|
|
&(logicalUnitExtension->InquiryData),
|
|
&unicodeIdString);
|
|
multiStrings = TRUE;
|
|
break;
|
|
}
|
|
|
|
case BusQueryCompatibleIDs: {
|
|
|
|
status = ScsiPortGetCompatibleIds(
|
|
LogicalUnit->DriverObject,
|
|
&(logicalUnitExtension->InquiryData),
|
|
&unicodeIdString);
|
|
multiStrings = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
Irp->IoStatus.Information = 0;
|
|
multiStrings = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
|
|
PWCHAR idString;
|
|
|
|
//
|
|
// fix up all invalid characters
|
|
//
|
|
idString = unicodeIdString.Buffer;
|
|
while (*idString) {
|
|
|
|
if ((*idString <= L' ') ||
|
|
(*idString > (WCHAR)0x7F) ||
|
|
(*idString == L',')) {
|
|
*idString = L'_';
|
|
}
|
|
idString++;
|
|
|
|
if ((*idString == L'\0') && multiStrings) {
|
|
idString++;
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) unicodeIdString.Buffer;
|
|
} else {
|
|
Irp->IoStatus.Information = (ULONG_PTR) NULL;
|
|
}
|
|
|
|
SpReleaseRemoveLock(LogicalUnit, Irp);
|
|
SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_RESOURCES:
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: {
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR) NULL;
|
|
SpReleaseRemoveLock(LogicalUnit, Irp);
|
|
SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
case IRP_MN_REMOVE_DEVICE: {
|
|
|
|
BOOLEAN destroyed;
|
|
|
|
//
|
|
// Release the lock for this IRP before going in.
|
|
//
|
|
|
|
if(commonExtension->IsRemoved == NO_REMOVE) {
|
|
commonExtension->IsRemoved = REMOVE_PENDING;
|
|
}
|
|
|
|
SpReleaseRemoveLock(LogicalUnit, Irp);
|
|
|
|
destroyed = SpRemoveLogicalUnit(logicalUnitExtension,
|
|
irpStack->MinorFunction);
|
|
|
|
if(destroyed) {
|
|
commonExtension->PreviousPnpState =
|
|
commonExtension->CurrentPnpState;
|
|
commonExtension->CurrentPnpState = irpStack->MinorFunction;
|
|
} else {
|
|
commonExtension->CurrentPnpState = 0xff;
|
|
commonExtension->PreviousPnpState = irpStack->MinorFunction;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT: {
|
|
|
|
Irp->IoStatus.Status =
|
|
SpQueryDeviceText(
|
|
LogicalUnit,
|
|
irpStack->Parameters.QueryDeviceText.DeviceTextType,
|
|
irpStack->Parameters.QueryDeviceText.LocaleId,
|
|
(PWSTR *) &Irp->IoStatus.Information
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES: {
|
|
|
|
PDEVICE_CAPABILITIES capabilities =
|
|
irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
PSCSIPORT_DEVICE_TYPE deviceType = NULL;
|
|
|
|
capabilities->RawDeviceOK = 1;
|
|
|
|
deviceType = SpGetDeviceTypeInfo(
|
|
logicalUnitExtension->InquiryData.DeviceType
|
|
);
|
|
|
|
if((deviceType != NULL) && (deviceType->IsStorage)) {
|
|
capabilities->SilentInstall = 1;
|
|
}
|
|
|
|
capabilities->Address = logicalUnitExtension->TargetId;
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE: {
|
|
|
|
if ((commonExtension->PagingPathCount != 0) ||
|
|
(logicalUnitExtension->IsLegacyClaim == TRUE)) {
|
|
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
} else {
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
commonExtension->PreviousPnpState =
|
|
commonExtension->CurrentPnpState;
|
|
commonExtension->CurrentPnpState = irpStack->MinorFunction;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE: {
|
|
|
|
if(commonExtension->CurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) {
|
|
commonExtension->CurrentPnpState =
|
|
commonExtension->PreviousPnpState;
|
|
commonExtension->PreviousPnpState = 0xff;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE: {
|
|
|
|
if(commonExtension->CurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) {
|
|
commonExtension->CurrentPnpState =
|
|
commonExtension->PreviousPnpState;
|
|
commonExtension->PreviousPnpState = 0xff;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_STOP_DEVICE: {
|
|
|
|
ASSERT(commonExtension->CurrentPnpState == IRP_MN_QUERY_STOP_DEVICE);
|
|
|
|
status = ScsiPortStopLogicalUnit(logicalUnitExtension);
|
|
|
|
ASSERT(NT_SUCCESS(status));
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = (ULONG_PTR) NULL;
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
commonExtension->CurrentPnpState = IRP_MN_STOP_DEVICE;
|
|
commonExtension->PreviousPnpState = 0xff;
|
|
}
|
|
|
|
SpReleaseRemoveLock(LogicalUnit, Irp);
|
|
SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: {
|
|
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
|
|
if(irpStack->Parameters.QueryDeviceRelations.Type !=
|
|
TargetDeviceRelation) {
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// DEVICE_RELATIONS definition contains one object pointer.
|
|
//
|
|
|
|
deviceRelations = SpAllocatePool(PagedPool,
|
|
sizeof(DEVICE_RELATIONS),
|
|
SCSIPORT_TAG_DEVICE_RELATIONS,
|
|
LogicalUnit->DriverObject);
|
|
|
|
if(deviceRelations == NULL) {
|
|
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RtlZeroMemory(deviceRelations, sizeof(DEVICE_RELATIONS));
|
|
|
|
deviceRelations->Count = 1;
|
|
deviceRelations->Objects[0] = LogicalUnit;
|
|
|
|
ObReferenceObject(deviceRelations->Objects[0]);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
|
|
|
|
PIRP newIrp;
|
|
PIO_STACK_LOCATION nextStack;
|
|
|
|
DebugPrint((1, "Pdo - IRP_MN_DEVICE_USAGE_NOTIFICATION %#p received for "
|
|
"logical unit %#p\n",
|
|
Irp,
|
|
LogicalUnit));
|
|
|
|
newIrp = SpAllocateIrp(
|
|
commonExtension->LowerDeviceObject->StackSize,
|
|
FALSE,
|
|
LogicalUnit->DriverObject);
|
|
|
|
if(newIrp == NULL) {
|
|
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
newIrp->AssociatedIrp.MasterIrp = Irp;
|
|
|
|
newIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
nextStack = IoGetNextIrpStackLocation(newIrp);
|
|
*nextStack = *IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
IoSetCompletionRoutine(newIrp,
|
|
SpPagingPathNotificationCompletion,
|
|
commonExtension->LowerDeviceObject,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
status = IoCallDriver(commonExtension->LowerDeviceObject,
|
|
newIrp);
|
|
return status;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SpReleaseRemoveLock(LogicalUnit, Irp);
|
|
|
|
status = Irp->IoStatus.Status;
|
|
SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpPagingPathNotificationCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP LowerIrp,
|
|
IN PDEVICE_OBJECT Fdo
|
|
)
|
|
{
|
|
PIRP upperIrp = LowerIrp->AssociatedIrp.MasterIrp;
|
|
|
|
PIO_STACK_LOCATION lowerStack = IoGetCurrentIrpStackLocation(LowerIrp);
|
|
PIO_STACK_LOCATION upperStack = IoGetCurrentIrpStackLocation(upperIrp);
|
|
|
|
PDEVICE_OBJECT pdo = upperStack->DeviceObject;
|
|
|
|
PADAPTER_EXTENSION lowerExtension;
|
|
PLOGICAL_UNIT_EXTENSION upperExtension;
|
|
|
|
ASSERT(Fdo != NULL);
|
|
ASSERT(pdo != NULL);
|
|
|
|
DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: Completion of "
|
|
"paging notification irp %#p sent due to irp %#p\n",
|
|
LowerIrp, upperIrp));
|
|
|
|
lowerExtension = (PADAPTER_EXTENSION) Fdo->DeviceExtension;
|
|
upperExtension = (PLOGICAL_UNIT_EXTENSION) pdo->DeviceExtension;
|
|
|
|
ASSERT_FDO(lowerExtension->DeviceObject);
|
|
ASSERT_PDO(upperExtension->DeviceObject);
|
|
|
|
DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: irp status %#08lx\n",
|
|
LowerIrp->IoStatus.Status));
|
|
|
|
if(NT_SUCCESS(LowerIrp->IoStatus.Status)) {
|
|
|
|
PUCHAR typeName = "INSERT TYPE HERE";
|
|
PULONG lowerCount;
|
|
PULONG upperCount;
|
|
|
|
//
|
|
// The parameters have already been erased from the lower irp stack
|
|
// location - use the parameters from the upper once since they're
|
|
// just a copy.
|
|
//
|
|
|
|
switch(upperStack->Parameters.UsageNotification.Type) {
|
|
|
|
case DeviceUsageTypePaging: {
|
|
|
|
lowerCount = &(lowerExtension->CommonExtension.PagingPathCount);
|
|
upperCount = &(upperExtension->CommonExtension.PagingPathCount);
|
|
typeName = "PagingPathCount";
|
|
break;
|
|
}
|
|
|
|
case DeviceUsageTypeHibernation: {
|
|
|
|
lowerCount = &(lowerExtension->CommonExtension.HibernatePathCount);
|
|
upperCount = &(upperExtension->CommonExtension.HibernatePathCount);
|
|
typeName = "HibernatePathCount";
|
|
break;
|
|
}
|
|
|
|
case DeviceUsageTypeDumpFile: {
|
|
|
|
lowerCount = &(lowerExtension->CommonExtension.DumpPathCount);
|
|
upperCount = &(upperExtension->CommonExtension.DumpPathCount);
|
|
typeName = "DumpPathCount";
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
|
|
typeName = "unknown type";
|
|
lowerCount = upperCount = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(lowerCount != NULL) {
|
|
IoAdjustPagingPathCount(
|
|
lowerCount,
|
|
upperStack->Parameters.UsageNotification.InPath
|
|
);
|
|
DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: "
|
|
"Fdo %s count - %d\n",
|
|
typeName, *lowerCount));
|
|
IoInvalidateDeviceState(lowerExtension->LowerPdo);
|
|
}
|
|
|
|
if(upperCount != NULL) {
|
|
IoAdjustPagingPathCount(
|
|
upperCount,
|
|
upperStack->Parameters.UsageNotification.InPath
|
|
);
|
|
DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: "
|
|
"Pdo %s count - %d\n",
|
|
typeName, *upperCount));
|
|
IoInvalidateDeviceState(upperExtension->DeviceObject);
|
|
}
|
|
}
|
|
|
|
upperIrp->IoStatus = LowerIrp->IoStatus;
|
|
|
|
SpReleaseRemoveLock(upperExtension->CommonExtension.DeviceObject, upperIrp);
|
|
|
|
SpCompleteRequest(upperExtension->CommonExtension.DeviceObject,
|
|
upperIrp,
|
|
NULL,
|
|
IO_NO_INCREMENT);
|
|
|
|
IoFreeIrp(LowerIrp);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoCreateClose(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles creates and closes for bus device pdo's
|
|
|
|
Arguments:
|
|
|
|
Pdo - a pointer to the physical device object
|
|
Irp - a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOGICAL_UNIT_EXTENSION logicalUnit = Pdo->DeviceExtension;
|
|
|
|
ULONG isRemoved;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT_PDO(Pdo);
|
|
|
|
isRemoved = SpAcquireRemoveLock(Pdo, Irp);
|
|
|
|
if(IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_CREATE) {
|
|
|
|
if(isRemoved) {
|
|
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
} else if(logicalUnit->IsTemporary == TRUE) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ScsiPortScsi1PdoScsi(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a wrapper around ScsiPortPdoScsi. It inserts the LUN number
|
|
into the CDB before calling the generic version. this is for use with
|
|
older target controllers which don't pay attention to the identify message
|
|
sent before the command phase.
|
|
|
|
Arguments:
|
|
|
|
Pdo - a pointer to the physical device object
|
|
Irp - a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOGICAL_UNIT_EXTENSION lun = Pdo->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
//
|
|
// NOTICE: The SCSI-II specification indicates that this field should be
|
|
// zero; however, some target controllers ignore the logical unit number
|
|
// in the INDENTIFY message and only look at the logical unit number field
|
|
// in the CDB.
|
|
//
|
|
|
|
srb->Cdb[1] |= lun->Lun << 5;
|
|
|
|
return ScsiPortPdoScsi(Pdo, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoScsi(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dispatches SRB's for a particular target device. It will fill
|
|
in the Port, Path, Target and Lun values and then forward the request
|
|
through to the FDO for the bus
|
|
|
|
Arguments:
|
|
|
|
Pdo - a pointer to the physical device object
|
|
Irp - a pointer to the io request packet
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOGICAL_UNIT_EXTENSION lun = Pdo->DeviceExtension;
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
#if DBG
|
|
PDRIVER_OBJECT lowerDriverObject =
|
|
lun->CommonExtension.LowerDeviceObject->DriverObject;
|
|
#endif
|
|
|
|
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
ULONG isRemoved;
|
|
|
|
PSRB_DATA srbData;
|
|
BOOLEAN isLock = FALSE;
|
|
|
|
NTSTATUS status;
|
|
|
|
isRemoved = SpAcquireRemoveLock(Pdo, Irp);
|
|
|
|
if(isRemoved &&
|
|
!IS_CLEANUP_REQUEST(irpStack) &&
|
|
(srb->Function != SRB_FUNCTION_CLAIM_DEVICE)) {
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
srb->PathId = lun->PathId;
|
|
srb->TargetId = lun->TargetId;
|
|
srb->Lun = lun->Lun;
|
|
|
|
//
|
|
// Queue tags should be assigned only by the StartIo routine. Set it to
|
|
// a benign value here so we can tell later on that we don't have to
|
|
// clear the tag value in the bitmap.
|
|
//
|
|
|
|
srb->QueueTag = SP_UNTAGGED;
|
|
|
|
#if DBG
|
|
ASSERT(lowerDriverObject->MajorFunction[IRP_MJ_SCSI] != NULL);
|
|
ASSERT(lowerDriverObject->MajorFunction[IRP_MJ_SCSI] == ScsiPortGlobalDispatch);
|
|
#endif
|
|
|
|
switch(srb->Function) {
|
|
|
|
|
|
case SRB_FUNCTION_ABORT_COMMAND: {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
}
|
|
|
|
case SRB_FUNCTION_CLAIM_DEVICE:
|
|
case SRB_FUNCTION_RELEASE_DEVICE:
|
|
case SRB_FUNCTION_REMOVE_DEVICE: {
|
|
|
|
status = SpClaimLogicalUnit(
|
|
lun->CommonExtension.LowerDeviceObject->DeviceExtension,
|
|
lun,
|
|
Irp,
|
|
FALSE);
|
|
break;
|
|
}
|
|
|
|
case SRB_FUNCTION_UNLOCK_QUEUE:
|
|
case SRB_FUNCTION_LOCK_QUEUE: {
|
|
|
|
SpStartLockRequest(lun, Irp);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
case SRB_FUNCTION_RELEASE_QUEUE:
|
|
case SRB_FUNCTION_FLUSH_QUEUE: {
|
|
|
|
srbData = SpAllocateBypassSrbData(lun);
|
|
ASSERT(srbData != NULL);
|
|
|
|
goto RunSrb;
|
|
}
|
|
|
|
default: {
|
|
|
|
if(TEST_FLAG(srb->SrbFlags, (SRB_FLAGS_BYPASS_LOCKED_QUEUE |
|
|
SRB_FLAGS_BYPASS_FROZEN_QUEUE))) {
|
|
|
|
srbData = SpAllocateBypassSrbData(lun);
|
|
ASSERT(srbData != NULL);
|
|
} else {
|
|
srbData = SpAllocateSrbData( lun->AdapterExtension, Irp, lun);
|
|
|
|
if(srbData == NULL) {
|
|
|
|
//
|
|
// There wasn't an SRB_DATA block available for this
|
|
// request so it's been queued waiting for resources -
|
|
// leave the logical unit remove-locked and return pending.
|
|
//
|
|
|
|
DebugPrint((1, "ScsiPortPdoScsi: Insufficient resources "
|
|
"to allocate SRB_DATA structure\n"));
|
|
return STATUS_PENDING;
|
|
}
|
|
}
|
|
RunSrb:
|
|
srbData->CurrentIrp = Irp;
|
|
srbData->CurrentSrb = srb;
|
|
srbData->LogicalUnit = lun;
|
|
|
|
srb->OriginalRequest = srbData;
|
|
return SpDispatchRequest(lun, Irp);
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
SpReleaseRemoveLock(Pdo, Irp);
|
|
SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ScsiPortStartLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to start the specified device object.
|
|
|
|
Currently this involves clearing the INITIALIZING flag if it was set,
|
|
and running through to the device node and marking itself as started. This
|
|
last is a kludge
|
|
|
|
Arguments:
|
|
|
|
LogicalUnit - a pointer to the PDO being started
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
|
|
|
|
HANDLE instanceHandle;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Open the devnode for this PDO and see if anyone's given us some
|
|
// default SRB flags.
|
|
//
|
|
|
|
status = IoOpenDeviceRegistryKey(LogicalUnit->DeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
KEY_READ,
|
|
&instanceHandle);
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
|
|
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
|
ULONG zero = 0;
|
|
|
|
RtlZeroMemory(queryTable, sizeof(queryTable));
|
|
|
|
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
queryTable[0].Name = L"DefaultRequestFlags";
|
|
queryTable[0].EntryContext = &(LogicalUnit->CommonExtension.SrbFlags);
|
|
queryTable[0].DefaultType = REG_DWORD;
|
|
queryTable[0].DefaultData = &zero;
|
|
queryTable[0].DefaultLength = sizeof(ULONG);
|
|
|
|
status = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL,
|
|
(PWSTR) instanceHandle,
|
|
queryTable,
|
|
NULL,
|
|
NULL);
|
|
|
|
//
|
|
// CODEWORK: need a way to turn off tagged queuing and caching. Ie.
|
|
// keep track of negative flags as well.
|
|
//
|
|
|
|
LogicalUnit->CommonExtension.SrbFlags &=
|
|
( SRB_FLAGS_DISABLE_DISCONNECT |
|
|
SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
|
|
SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
|
|
|
DebugPrint((1, "SpStartDevice: Default SRB flags for (%d,%d,%d) are "
|
|
"%#08lx\n",
|
|
LogicalUnit->PathId,
|
|
LogicalUnit->TargetId,
|
|
LogicalUnit->Lun,
|
|
LogicalUnit->CommonExtension.SrbFlags));
|
|
|
|
ZwClose(instanceHandle);
|
|
|
|
} else {
|
|
|
|
DebugPrint((1, "SpStartDevice: Error opening instance key for pdo "
|
|
"[%#08lx]\n",
|
|
status));
|
|
}
|
|
|
|
//
|
|
// If the queue is locked then unlock it to start i/o processing.
|
|
//
|
|
|
|
if(LogicalUnit->QueueLockCount > 0) {
|
|
status = SpLockUnlockQueue(LogicalUnit->DeviceObject,
|
|
FALSE,
|
|
TRUE);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
ScsiPortInitPdoWmi(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt WMI initialization for the PDO.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the PDO being started
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PCOMMON_EXTENSION commonExtension = &(LogicalUnit->CommonExtension);
|
|
PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Now that we have a LUN, we can initialize WMI support for the adapter if
|
|
// the miniport supports WMI. This may be a re-register if we've already
|
|
// registered on behalf of scsiport itself. We have to wait until we have
|
|
// a LUN when the miniport supports WMI because we send it an SRB to do
|
|
// its own initialization. We can't send it an SRB until we have a logical
|
|
// unit.
|
|
//
|
|
|
|
if (adapterExtension->CommonExtension.WmiMiniPortInitialized == FALSE &&
|
|
adapterExtension->CommonExtension.WmiMiniPortSupport == TRUE) {
|
|
|
|
ULONG action;
|
|
|
|
//
|
|
// Decide whether we are registering or reregistering WMI for the FDO.
|
|
//
|
|
|
|
action = (adapterExtension->CommonExtension.WmiInitialized == FALSE) ?
|
|
WMIREG_ACTION_REGISTER : WMIREG_ACTION_REREGISTER;
|
|
|
|
//
|
|
// Register/reregister. We can get WMI irps as soon as we do this.
|
|
//
|
|
|
|
IoWMIRegistrationControl(adapterExtension->DeviceObject, action);
|
|
adapterExtension->CommonExtension.WmiMiniPortInitialized = TRUE;
|
|
adapterExtension->CommonExtension.WmiInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Initialize WMI support.
|
|
//
|
|
|
|
if (commonExtension->WmiInitialized == FALSE) {
|
|
|
|
//
|
|
// Build the SCSIPORT WMI registration information buffer for this PDO.
|
|
//
|
|
|
|
SpWmiInitializeSpRegInfo(LogicalUnit->DeviceObject);
|
|
|
|
//
|
|
// Register this device object only if the miniport supports WMI and/or
|
|
// SCSIPORT will support certain WMI GUIDs on behalf of the miniport.
|
|
//
|
|
|
|
if (commonExtension->WmiMiniPortSupport ||
|
|
commonExtension->WmiScsiPortRegInfoBuf) {
|
|
|
|
//
|
|
// Register this physical device object as a WMI data provider,
|
|
// instructing WMI that it is ready to receive WMI IRPs.
|
|
//
|
|
|
|
IoWMIRegistrationControl(LogicalUnit->DeviceObject,
|
|
WMIREG_ACTION_REGISTER);
|
|
commonExtension->WmiInitialized = TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate several WMI_MINIPORT_REQUEST_ITEM blocks to satisfy a
|
|
// potential onslaught of WMIEvent notifications by the miniport.
|
|
//
|
|
|
|
if (commonExtension->WmiMiniPortSupport) {
|
|
|
|
//
|
|
// Currently we only allocate two per new SCSI target (PDO).
|
|
//
|
|
SpWmiInitializeFreeRequestList(LogicalUnit->DeviceObject, 2);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScsiPortInitLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to start the specified device object.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the PDO being started
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PCOMMON_EXTENSION commonExtension = &(LogicalUnit->CommonExtension);
|
|
PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
|
|
|
|
HANDLE instanceHandle;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize the idle detection timer. Tell the system to put us into a
|
|
// D3 state when we're not being used.
|
|
//
|
|
|
|
LogicalUnit->CommonExtension.IdleTimer =
|
|
PoRegisterDeviceForIdleDetection(LogicalUnit->DeviceObject,
|
|
SpPowerIdleTimeout,
|
|
SpPowerIdleTimeout,
|
|
PowerDeviceD3);
|
|
|
|
ScsiPortInitPdoWmi(LogicalUnit);
|
|
|
|
//
|
|
// Build a device map entry for this logical unit.
|
|
//
|
|
|
|
SpBuildDeviceMapEntry(commonExtension);
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
SpStartLockRequest(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN PIRP Irp OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is responsible for queueing, starting or restarting a lock
|
|
request.
|
|
|
|
If Irp is provided then it will dispatched iff no existing lock or unlock
|
|
request is already running. If one is already running this request will
|
|
be queued.
|
|
|
|
If Irp is not provided then the next request on the LockRequestQueue will
|
|
be removed and dispatched.
|
|
|
|
This routine relies on the device queue to provide synchronization. Since
|
|
we can only have one request get past the device queue at any given time we
|
|
should only have one call at any given time with Irp set to NULL.
|
|
|
|
Arguments:
|
|
|
|
LogicalUnit - the logical unit to which this lock request was sent.
|
|
|
|
Irp - the irp for the lock request.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
--*/
|
|
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
PIO_STACK_LOCATION irpStack;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
|
|
PSRB_DATA srbData;
|
|
|
|
BOOLEAN lock;
|
|
|
|
oldIrql = KeRaiseIrqlToDpcLevel();
|
|
|
|
//
|
|
// If no IRP was provided then get one out of the device queue.
|
|
// Otherwise make sure the device queue is not busy.
|
|
//
|
|
|
|
if(Irp == NULL) {
|
|
PKDEVICE_QUEUE_ENTRY entry;
|
|
|
|
ASSERT(LogicalUnit->CurrentLockRequest != NULL);
|
|
LogicalUnit->CurrentLockRequest = NULL;
|
|
|
|
entry = KeRemoveDeviceQueue(&(LogicalUnit->LockRequestQueue));
|
|
|
|
if(entry == NULL) {
|
|
|
|
//
|
|
// No more requests have come in while processing this one -
|
|
// we can just return.
|
|
//
|
|
|
|
KeLowerIrql(oldIrql);
|
|
return;
|
|
|
|
} else {
|
|
Irp = CONTAINING_RECORD(entry,
|
|
IRP,
|
|
Tail.Overlay.DeviceQueueEntry);
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
lock = (srb->Function == SRB_FUNCTION_LOCK_QUEUE);
|
|
|
|
}
|
|
|
|
} else {
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
lock = (srb->Function == SRB_FUNCTION_LOCK_QUEUE);
|
|
|
|
|
|
DebugPrint((2, "SpStartLockRequest: called to %s queue %#p\n",
|
|
lock ? "lock" : "unlock",
|
|
LogicalUnit));
|
|
|
|
//
|
|
// See if we can let this request keep processing or if we'll
|
|
// have to queue it.
|
|
//
|
|
|
|
IoMarkIrpPending(Irp);
|
|
if(KeInsertDeviceQueue(&(LogicalUnit->LockRequestQueue),
|
|
&(Irp->Tail.Overlay.DeviceQueueEntry))) {
|
|
KeLowerIrql(oldIrql);
|
|
return;
|
|
}
|
|
}
|
|
|
|
ASSERT(Irp != NULL);
|
|
ASSERT(LogicalUnit->CurrentLockRequest == NULL);
|
|
|
|
//
|
|
// This srb function is only valid as part of a power up request
|
|
// and will be ignored if the power state is D0.
|
|
//
|
|
|
|
CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
|
|
SET_FLAG(srb->SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
|
|
|
|
//
|
|
// Throw this request down so it gets processed as a real
|
|
// request. We need to get the completion dpc to start
|
|
// things running again. there are too many flags to set
|
|
// to do it from here.
|
|
//
|
|
|
|
DebugPrint((2, "SpStartLockRequest: %s %#p into "
|
|
"queue %#p ... issuing request\n",
|
|
lock ? "lock" : "unlock", srb, LogicalUnit));
|
|
|
|
//
|
|
// There are four bypass srb data blocks available - we should have at most
|
|
// one lock request awaiting completion and the one we're about to start
|
|
// so this call should never, ever fail.
|
|
//
|
|
|
|
srbData = SpAllocateBypassSrbData(LogicalUnit);
|
|
ASSERT(srbData != NULL);
|
|
|
|
//
|
|
// Set the current lock request. As long as this is cleared
|
|
// before the next item is removed from the queue everything
|
|
// will be happy.
|
|
//
|
|
|
|
ASSERT(LogicalUnit->CurrentLockRequest == NULL);
|
|
LogicalUnit->CurrentLockRequest = srbData;
|
|
|
|
srbData->CurrentIrp = Irp;
|
|
srbData->CurrentSrb = srb;
|
|
srbData->LogicalUnit = LogicalUnit;
|
|
srb->OriginalRequest = srbData;
|
|
|
|
SpDispatchRequest(LogicalUnit, Irp);
|
|
|
|
KeLowerIrql(oldIrql);
|
|
return;
|
|
}
|