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;
|
|||
|
}
|
|||
|
|