829 lines
19 KiB
C
829 lines
19 KiB
C
|
||
/*++
|
||
|
||
Copyright (C) 1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
mpdev.c
|
||
|
||
Abstract:
|
||
|
||
This driver acts as a lower-filter over the device pdo's and provides the support necessary for multipathing.
|
||
It's main function is keep mpctl.sys (main multipath module) informed of system state.
|
||
|
||
Author:
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <ntddk.h>
|
||
#include <stdio.h>
|
||
#include <stdarg.h>
|
||
#include "mpdevf.h"
|
||
#include "scsi.h"
|
||
#include "mplib.h"
|
||
|
||
|
||
typedef struct _DEVICE_EXTENSION {
|
||
//
|
||
// Backpointer to our device object.
|
||
//
|
||
PDEVICE_OBJECT DeviceObject;
|
||
|
||
//
|
||
// Pointer to the lower object.
|
||
//
|
||
PDEVICE_OBJECT TargetDevice;
|
||
|
||
//
|
||
// The PDisk device object information.
|
||
//
|
||
MPIO_PDO_INFO PdoInfo;
|
||
|
||
//
|
||
// MpCtl's Control device Object.
|
||
//
|
||
PDEVICE_OBJECT ControlDevice;
|
||
|
||
//
|
||
// State flags of this (and the lower device).
|
||
//
|
||
ULONG DeviceState;
|
||
|
||
//
|
||
// General purpose event.
|
||
//
|
||
KEVENT Event;
|
||
|
||
//
|
||
// Counters for IOs
|
||
//
|
||
ULONG NumberReads;
|
||
ULONG NumberWrites;
|
||
BOOLEAN FailureSimulation;
|
||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
||
|
||
//
|
||
// Entry point decls
|
||
//
|
||
NTSTATUS
|
||
MpDevDefaultDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
MpDevInternalDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
MpDevDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
MpDevPnPDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
MpDevPowerDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
MpDevAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject
|
||
);
|
||
|
||
NTSTATUS
|
||
MpDevUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
|
||
|
||
|
||
//
|
||
// Internal function decls
|
||
//
|
||
NTSTATUS
|
||
MpDevStartDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
|
||
//
|
||
// The code.
|
||
//
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the driver loads loads.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Supplies the driver object.
|
||
RegistryPath - Supplies the registry path.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
|
||
MPDebugPrint((0,
|
||
"MpDev: DriverEntry\n"));
|
||
|
||
//
|
||
// Setup forwarder for ALL Irp functions.
|
||
//
|
||
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
||
DriverObject->MajorFunction[i] = MpDevDefaultDispatch;
|
||
}
|
||
|
||
//
|
||
// Specify those that we are interested in.
|
||
//
|
||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MpDevInternalDeviceControl;
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MpDevDeviceControl;
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = MpDevPnPDispatch;
|
||
DriverObject->MajorFunction[IRP_MJ_POWER] = MpDevPowerDispatch;
|
||
|
||
DriverObject->DriverUnload = MpDevUnload;
|
||
DriverObject->DriverExtension->AddDevice = MpDevAddDevice;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevDefaultDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends the Irp to the next driver in line
|
||
when the Irp is not processed by this driver.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
IoSkipCurrentIrpStackLocation(Irp);
|
||
return IoCallDriver(deviceExtension->TargetDevice, Irp);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MpDevClaimDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN BOOLEAN Claim
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is used to claim the underlying port pdo, so that only the mpdisk will be used
|
||
by the class drivers.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the scsiport device object.
|
||
Claim - Indica0tes whether the device should be claimed or released.
|
||
|
||
Return Value:
|
||
|
||
Returns a status indicating success or failure of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
IO_STATUS_BLOCK ioStatus;
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpStack;
|
||
KEVENT event;
|
||
NTSTATUS status;
|
||
SCSI_REQUEST_BLOCK srb;
|
||
|
||
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
|
||
|
||
//
|
||
// Set the event object to the unsignaled state.
|
||
// It will be used to signal request completion
|
||
//
|
||
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
||
|
||
//
|
||
// Build synchronous request with no transfer.
|
||
//
|
||
irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
|
||
DeviceObject,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0,
|
||
TRUE,
|
||
&event,
|
||
&ioStatus);
|
||
|
||
if (irp == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
irpStack = IoGetNextIrpStackLocation(irp);
|
||
|
||
//
|
||
// Save SRB address in next stack for port driver.
|
||
//
|
||
irpStack->Parameters.Scsi.Srb = &srb;
|
||
|
||
//
|
||
// Setup the SRB.
|
||
//
|
||
srb.Length = SCSI_REQUEST_BLOCK_SIZE;
|
||
srb.Function = Claim ? SRB_FUNCTION_CLAIM_DEVICE : SRB_FUNCTION_RELEASE_DEVICE;
|
||
srb.OriginalRequest = irp;
|
||
|
||
//
|
||
// Call the port driver with the request and wait for it to complete.
|
||
//
|
||
status = IoCallDriver(DeviceObject, irp);
|
||
if (status == STATUS_PENDING) {
|
||
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MpDevInternalDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles IRM_MJ_INTERNAL_DEVICE_CONTROL and IRP_MJ_SCSI requests.
|
||
It's main function is to simulate failed devices or adapters, based on IOCTLs
|
||
sent from test applications.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
Irp - Supplies the IO request packet.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
||
|
||
return MpDevDefaultDispatch(DeviceObject, Irp);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MpDevDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This device control routine handles only the interactions between this driver and mpctl.
|
||
The rest are passed down to scsiport.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
Irp - Supplies the IO request packet.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status;
|
||
|
||
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
|
||
|
||
default:
|
||
return MpDevDefaultDispatch(DeviceObject, Irp);
|
||
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevPowerDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatch routine for Power Irps.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
Irp - Supplies the I/O request packet.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
//
|
||
// TODO: Snoop these, and if the device is changing state notify mpctl.sys
|
||
//
|
||
PoStartNextPowerIrp(Irp);
|
||
IoSkipCurrentIrpStackLocation(Irp);
|
||
|
||
return PoCallDriver(deviceExtension->TargetDevice, Irp);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevPnPDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatch routine for PNP Irps.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
Irp - Supplies the I/O request packet.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status;
|
||
|
||
KeClearEvent(&deviceExtension->Event);
|
||
|
||
MPDebugPrint((2,
|
||
"MpDevPnPDispatch: Minor Function (%x) for (%x)\n",
|
||
irpStack->MinorFunction,
|
||
DeviceObject));
|
||
|
||
//
|
||
// TODO: signal the associated pdisk of all power and pnp events.
|
||
//
|
||
switch (irpStack->MinorFunction) {
|
||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||
MPDebugPrint((2,
|
||
"MPDevPnP: QueryRemove (%x)\n",
|
||
DeviceObject));
|
||
status = STATUS_DEVICE_BUSY;
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return status;
|
||
|
||
case IRP_MN_STOP_DEVICE:
|
||
MPDebugPrint((2,
|
||
"MpDevPnP: StopDevice (%x)\n",
|
||
DeviceObject));
|
||
break;
|
||
case IRP_MN_REMOVE_DEVICE:
|
||
case IRP_MN_SURPRISE_REMOVAL:
|
||
MPDebugPrint((2,
|
||
"MpDevPnP: RemoveDevice (%x)\n",
|
||
DeviceObject));
|
||
//status = STATUS_SUCCESS;
|
||
//Irp->IoStatus.Status = status;
|
||
//IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
//return status;
|
||
break;
|
||
|
||
case IRP_MN_START_DEVICE:
|
||
return MpDevStartDevice(DeviceObject, Irp);
|
||
|
||
case IRP_MN_QUERY_CAPABILITIES:
|
||
case IRP_MN_QUERY_ID:
|
||
default:
|
||
return MpDevDefaultDispatch(DeviceObject, Irp);
|
||
}
|
||
return MpDevDefaultDispatch(DeviceObject, Irp);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Creates and initializes a new filter device object for the
|
||
corresponding PDO. Then it attaches the device object to the device
|
||
stack of the drivers for the device.
|
||
|
||
Arguments:
|
||
|
||
DriverObject
|
||
PhysicalDeviceObject - Physical Device Object from the underlying layered driver
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVICE_OBJECT controlDeviceObject;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
UNICODE_STRING unicodeName;
|
||
PFILE_OBJECT fileObject;
|
||
WCHAR dosDeviceName[40];
|
||
MPIO_REG_INFO ctlRegInfo;
|
||
NTSTATUS status;
|
||
PIRP irp;
|
||
PDEVICE_OBJECT attachedDevice;
|
||
|
||
//
|
||
// Build the mpctl name.
|
||
//
|
||
swprintf(dosDeviceName, L"\\DosDevices\\MPathControl");
|
||
RtlInitUnicodeString(&unicodeName, dosDeviceName);
|
||
|
||
//
|
||
// Get mpctl's deviceObject.
|
||
//
|
||
status = IoGetDeviceObjectPointer(&unicodeName,
|
||
FILE_READ_ATTRIBUTES,
|
||
&fileObject,
|
||
&controlDeviceObject);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
MPIO_PDO_QUERY pdoQuery;
|
||
|
||
pdoQuery.DeviceObject = PhysicalDeviceObject;
|
||
|
||
//
|
||
// Call mpctl to determine whether PhysicalDeviceObject is
|
||
// one of it's children or a 'real' scsiport pdo.
|
||
//
|
||
MPLIBSendDeviceIoControlSynchronous(IOCTL_MPDEV_QUERY_PDO,
|
||
controlDeviceObject,
|
||
&pdoQuery,
|
||
NULL,
|
||
sizeof(MPIO_PDO_QUERY),
|
||
0,
|
||
TRUE,
|
||
&ioStatus);
|
||
status = ioStatus.Status;
|
||
|
||
MPDebugPrint((2,
|
||
"MPDevAddDevice: Query on (%x). Status (%x)\n",
|
||
PhysicalDeviceObject,
|
||
status));
|
||
#if 0
|
||
if (status == STATUS_SUCCESS) {
|
||
|
||
//
|
||
// This indicates that PhysicalDeviceObject is really an MPDisk.
|
||
// Don't want to load on this.
|
||
//
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
} else {
|
||
|
||
//
|
||
// This indicates that PhysicalDeviceObject is a real one.
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// This indicates that PhysicalDeviceObject is really an MPDisk object or
|
||
// that getting the control object failed.
|
||
//
|
||
return status;
|
||
}
|
||
|
||
|
||
if (DontLoad) {
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
status = IoCreateDevice(DriverObject,
|
||
sizeof(DEVICE_EXTENSION),
|
||
NULL,
|
||
FILE_DEVICE_DISK,
|
||
FILE_DEVICE_SECURE_OPEN,
|
||
FALSE,
|
||
&deviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
MPDebugPrint((0,
|
||
"MpDevAddDevice: Couldn't create device object (%x)\n",
|
||
status));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Start building the deviceExtension and attach to the lower device.
|
||
//
|
||
deviceExtension = deviceObject->DeviceExtension;
|
||
deviceExtension->DeviceObject = deviceObject;
|
||
|
||
deviceExtension->TargetDevice = IoAttachDeviceToDeviceStack(deviceObject,
|
||
PhysicalDeviceObject);
|
||
if (deviceExtension->TargetDevice == NULL) {
|
||
|
||
MPDebugPrint((0,
|
||
"MpDevAddDevice: Couldn't attach to device stack\n"));
|
||
IoDeleteDevice(deviceObject);
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
//
|
||
// Build IOCTL_MPDEV_REGISTER. This gives the port pdo to
|
||
// mpctl to match up with one of it's children.
|
||
// Mpctl then returns the PdoRegistration routine
|
||
//
|
||
ctlRegInfo.FilterObject = deviceObject;
|
||
ctlRegInfo.LowerDevice = deviceExtension->TargetDevice;
|
||
|
||
MPLIBSendDeviceIoControlSynchronous(IOCTL_MPDEV_REGISTER,
|
||
controlDeviceObject,
|
||
&ctlRegInfo,
|
||
&ctlRegInfo,
|
||
sizeof(MPIO_REG_INFO),
|
||
sizeof(MPIO_REG_INFO),
|
||
TRUE,
|
||
&ioStatus);
|
||
status = ioStatus.Status;
|
||
|
||
//
|
||
// Save off mpctls deviceObject.
|
||
//
|
||
deviceExtension->ControlDevice = controlDeviceObject;
|
||
|
||
//
|
||
// Update the flags by ORing in all of the set flags below.
|
||
//
|
||
deviceObject->Flags |= deviceExtension->TargetDevice->Flags & (DO_DIRECT_IO |
|
||
DO_BUFFERED_IO |
|
||
DO_POWER_PAGABLE |
|
||
DO_POWER_INRUSH);
|
||
//
|
||
// Sync up other devObj stuff.
|
||
//
|
||
deviceObject->DeviceType = deviceExtension->TargetDevice->DeviceType;
|
||
deviceObject->Characteristics = deviceExtension->TargetDevice->Characteristics;
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Register with the MPDisk PDO. It will give back some notification
|
||
// functions and update it's own internal structures to match
|
||
// this filter with it's knowledge of scsiport's children.
|
||
//
|
||
status = ctlRegInfo.DevicePdoRegister(ctlRegInfo.MPDiskObject,
|
||
deviceObject,
|
||
PhysicalDeviceObject,
|
||
&deviceExtension->PdoInfo);
|
||
MPDebugPrint((2,
|
||
"MpDevAddDevice: Status of PdoRegister (%x)\n",
|
||
status));
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
status = MpDevClaimDevice(deviceExtension->TargetDevice,
|
||
TRUE);
|
||
if (status == STATUS_SUCCESS) {
|
||
MPDebugPrint((2,
|
||
"MpDevAddDevice: Claim of (%x) successful.\n",
|
||
deviceExtension->TargetDevice));
|
||
} else {
|
||
|
||
MPDebugPrint((1,
|
||
"MpDevAddDevice: Claim of (%x) not successful. Status (%x)\n",
|
||
deviceExtension->TargetDevice,
|
||
status));
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Indicate that we are ready.
|
||
//
|
||
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
MPDebugPrint((2,
|
||
"MPDevAddDevice: Returning (%x) on D.O. (%x)\n",
|
||
status,
|
||
PhysicalDeviceObject));
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
{
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevSyncCompletion(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completion routine for sync forwarding of Irps.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
Context
|
||
|
||
Return Value:
|
||
|
||
STATUS_MORE_PROCESSING_REQUIRED
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)Context;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status;
|
||
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
//
|
||
// Set the event on which the dispatch handler is waiting.
|
||
//
|
||
KeSetEvent(&deviceExtension->Event,
|
||
0,
|
||
FALSE);
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MpDevStartDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles Start requests by sending the start down to scsiport. The completion will signal
|
||
the event and then device object flags and characteristics are updated.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
Irp - Supplies the I/O request packet.
|
||
|
||
Return Value:
|
||
|
||
Status of the operations.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Setup initial status.
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Clone the stack location.
|
||
//
|
||
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||
|
||
//
|
||
// Setup the completion routine. It will set the event that we wait on below.
|
||
//
|
||
IoSetCompletionRoutine(Irp,
|
||
MpDevSyncCompletion,
|
||
deviceExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
KeInitializeEvent(&deviceExtension->Event,
|
||
NotificationEvent,
|
||
FALSE);
|
||
|
||
//
|
||
// Call port with the request.
|
||
//
|
||
status = IoCallDriver(deviceExtension->TargetDevice, Irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&deviceExtension->Event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Sync up our stuff with scsiport's.
|
||
//
|
||
DeviceObject->Flags |= deviceExtension->TargetDevice->Flags;
|
||
DeviceObject->Characteristics |= deviceExtension->TargetDevice->Characteristics;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|