1104 lines
26 KiB
C
1104 lines
26 KiB
C
|
|
|||
|
#include "mpio.h"
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOStopDevice(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles PnP Stop irps for the FDO (Control).
|
|||
|
Currently, it only sets status and forwards the Irp.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// TODO: Any stop stuff.
|
|||
|
//
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
return MPIOForwardRequest(DeviceObject, Irp);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOStartDevice(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles PnP Start requests for the FDO
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject,
|
|||
|
Irp
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
KEVENT event;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
//
|
|||
|
// The above minor functions need status set to success, set a completion routine,
|
|||
|
// send to the next driver, and wait. Once the event is signaled, complete the request.
|
|||
|
//
|
|||
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Setup the initial status of the request.
|
|||
|
//
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// Clone the stack location.
|
|||
|
//
|
|||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Set the completion routine.
|
|||
|
//
|
|||
|
IoSetCompletionRoutine(Irp,
|
|||
|
MPIOSyncCompletion,
|
|||
|
&event,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// Call down.
|
|||
|
//
|
|||
|
status = IoCallDriver(deviceExtension->LowerDevice, Irp);
|
|||
|
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
|
|||
|
KeWaitForSingleObject(&event,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
if (status == STATUS_SUCCESS) {
|
|||
|
|
|||
|
//
|
|||
|
// TODO: Other 'start' stuff.
|
|||
|
//
|
|||
|
MPDebugPrint((2,
|
|||
|
"MPIOStartDevice: Successful start on (%x)\n",
|
|||
|
DeviceObject));
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
} else {
|
|||
|
|
|||
|
MPDebugPrint((2,
|
|||
|
"MPIOStartDevice: Failure (%x) start on (%x)\n",
|
|||
|
status,
|
|||
|
DeviceObject));
|
|||
|
}
|
|||
|
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOQDR(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PDEVICE_RELATIONS deviceRelations;
|
|||
|
PLIST_ENTRY entry;
|
|||
|
PDISK_ENTRY diskEntry;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG allocationLength;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
if (irpStack->Parameters.QueryDeviceRelations.Type == BusRelations) {
|
|||
|
|
|||
|
//
|
|||
|
// Allocate enough memory for NumberDevices.
|
|||
|
//
|
|||
|
allocationLength = (controlExtension->NumberDevices - 1) * sizeof(PDEVICE_OBJECT);
|
|||
|
allocationLength += sizeof(DEVICE_RELATIONS);
|
|||
|
|
|||
|
deviceRelations = ExAllocatePool(PagedPool, allocationLength);
|
|||
|
if (deviceRelations == NULL) {
|
|||
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(deviceRelations, allocationLength);
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the structure.
|
|||
|
//
|
|||
|
deviceRelations->Count = controlExtension->NumberDevices;
|
|||
|
|
|||
|
for (i = 0; i < controlExtension->NumberDevices; i++) {
|
|||
|
diskEntry = MPIOGetDiskEntry(DeviceObject,
|
|||
|
i);
|
|||
|
ASSERT(diskEntry);
|
|||
|
deviceRelations->Objects[i] = diskEntry->PdoObject;
|
|||
|
ObReferenceObject(deviceRelations->Objects[i]);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Link it in and set status.
|
|||
|
//
|
|||
|
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
MPDebugPrint((2,
|
|||
|
"MPIOQDR: Returned %x children. List %x\n",
|
|||
|
controlExtension->NumberDevices,
|
|||
|
deviceRelations));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Send it down.
|
|||
|
//
|
|||
|
return MPIOForwardRequest(DeviceObject, Irp);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOQueryId(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles QueryId irps for the FDO (Control).
|
|||
|
Used by PnP to determine the id's used to locate the inf.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
NTSTATUS status;
|
|||
|
PWCHAR idString;
|
|||
|
PWCHAR returnString;
|
|||
|
ULONG length;
|
|||
|
ULONG size;
|
|||
|
|
|||
|
switch (irpStack->Parameters.QueryId.IdType) {
|
|||
|
case BusQueryHardwareIDs:
|
|||
|
idString = L"ROOT\\MPIO";
|
|||
|
break;
|
|||
|
|
|||
|
case BusQueryDeviceID:
|
|||
|
idString = L"ROOT\\MPIO";
|
|||
|
break;
|
|||
|
|
|||
|
case BusQueryInstanceID:
|
|||
|
idString = L"0000";
|
|||
|
break;
|
|||
|
default:
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(deviceExtension->LowerDevice, Irp);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
length = wcslen(idString);
|
|||
|
size = (length + 2) * sizeof(WCHAR);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate storage for the id string
|
|||
|
//
|
|||
|
returnString = ExAllocatePool(PagedPool, size);
|
|||
|
if (returnString == NULL) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Copy it over
|
|||
|
//
|
|||
|
RtlZeroMemory(returnString, size);
|
|||
|
wcscpy(returnString, idString);
|
|||
|
|
|||
|
//
|
|||
|
// Link it in, set status and send it down.
|
|||
|
//
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Information = (ULONG_PTR)returnString;
|
|||
|
}
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
return IoCallDriver(deviceExtension->LowerDevice, Irp);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOFdoPnP(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles PnP irps for the FDO (Control).
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
KEVENT event;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
switch (irpStack->MinorFunction) {
|
|||
|
case IRP_MN_STOP_DEVICE:
|
|||
|
|
|||
|
//
|
|||
|
// Call the Stop handler.
|
|||
|
//
|
|||
|
return MPIOStopDevice(DeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
case IRP_MN_START_DEVICE:
|
|||
|
|
|||
|
//
|
|||
|
// 'Start' the FDO.
|
|||
|
//
|
|||
|
return MPIOStartDevice(DeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|||
|
|
|||
|
//
|
|||
|
// Build the list of children based on the current state of the world.
|
|||
|
//
|
|||
|
return MPIOQDR(DeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
case IRP_MN_QUERY_ID:
|
|||
|
|
|||
|
//
|
|||
|
// Call the QueryId routine. It will handle completion
|
|||
|
// of the request.
|
|||
|
//
|
|||
|
return MPIOQueryId(DeviceObject,
|
|||
|
Irp);
|
|||
|
|
|||
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|||
|
MPDebugPrint((2,
|
|||
|
"Got QueryDeviceText\n"));
|
|||
|
default:
|
|||
|
MPDebugPrint((2,
|
|||
|
"MPIOFdoPnP: Default handler for Control (%x)\n",
|
|||
|
irpStack->MinorFunction));
|
|||
|
return MPIOForwardRequest(DeviceObject, Irp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOFdoPower(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles Power irps for the FDO (Control). It'm main
|
|||
|
function is to sync up state with the adapter filter drivers.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
//
|
|||
|
// TODO: Everything.
|
|||
|
//
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
status = PoCallDriver(deviceExtension->LowerDevice, Irp);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOQueryPdo(
|
|||
|
IN PDEVICE_OBJECT ControlObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine determines whether the D.O. passed in the system buffer
|
|||
|
is one that mpctl created, or a real scsiport pdo.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the D.O. is a child of mpctl
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = ControlObject->DeviceExtension;
|
|||
|
PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
|
|||
|
PMPIO_PDO_QUERY pdoQuery = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
PDISK_ENTRY diskEntry;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Run the disk list to see whether this one is real
|
|||
|
// or one of ours.
|
|||
|
//
|
|||
|
for (i = 0; i < controlExtension->NumberDevices; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the next diskEntry.
|
|||
|
//
|
|||
|
diskEntry = MPIOGetDiskEntry(ControlObject,
|
|||
|
i);
|
|||
|
|
|||
|
MPDebugPrint((2,
|
|||
|
"MPIOQueryPdo: Checking (%x) against QueryObject (%x)",
|
|||
|
diskEntry->PdoObject,
|
|||
|
pdoQuery->DeviceObject));
|
|||
|
|
|||
|
//
|
|||
|
// The PdoObject is the D.O. for an MPDisk,
|
|||
|
// if the D.O. passed in from mpdev is the same, then
|
|||
|
// the filter should not load on this. Indicate the 'failure'
|
|||
|
// as success.
|
|||
|
//
|
|||
|
if (diskEntry->PdoObject == pdoQuery->DeviceObject) {
|
|||
|
MPDebugPrint((2,
|
|||
|
" -> Matched. Returning SUCCESS\n"));
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
} else {
|
|||
|
|
|||
|
MPDebugPrint((2,
|
|||
|
" -> No Match\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIODeviceRegistration(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the initial registration of a device filter
|
|||
|
by matching up scsiport pdo, with MPDisk PDO.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the LowerDevice was found in a MPDisk PDO's internal
|
|||
|
structures.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
|
|||
|
PMPIO_REG_INFO deviceReg = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
PMPIO_REG_INFO regInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
PDEVICE_OBJECT lowerDevice;
|
|||
|
PDEVICE_OBJECT targetDevice;
|
|||
|
PDISK_ENTRY diskEntry;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG i;
|
|||
|
BOOLEAN found = FALSE;
|
|||
|
|
|||
|
lowerDevice = deviceReg->LowerDevice;
|
|||
|
targetDevice = deviceReg->FilterObject;
|
|||
|
|
|||
|
//
|
|||
|
// Find the corresponding MPDisk for the 'LowerDevice'.
|
|||
|
// Call the magic routine with each of the MP PDO's, along with LowerDevice
|
|||
|
// It will return TRUE is the MP PDO controls it.
|
|||
|
//
|
|||
|
for (i = 0; i < controlExtension->NumberDevices; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the next diskEntry.
|
|||
|
//
|
|||
|
diskEntry = MPIOGetDiskEntry(DeviceObject,
|
|||
|
i);
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to find a match for the newly arrived DO.
|
|||
|
//
|
|||
|
found = MPIOFindLowerDevice(diskEntry->PdoObject,
|
|||
|
lowerDevice);
|
|||
|
if (found == TRUE) {
|
|||
|
|
|||
|
//
|
|||
|
// Indicate to the dev filter the MPDisk that
|
|||
|
// it talks to.
|
|||
|
//
|
|||
|
regInfo->MPDiskObject = diskEntry->PdoObject;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (found == FALSE) {
|
|||
|
status = STATUS_NO_SUCH_DEVICE;
|
|||
|
} else {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the rest.
|
|||
|
// Defined in pdo.c
|
|||
|
//
|
|||
|
regInfo->DevicePdoRegister = MPIOPdoRegistration;
|
|||
|
Irp->IoStatus.Information = sizeof(MPIO_REG_INFO);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The caller will fill in status and complete the request.
|
|||
|
//
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOAdpPnpNotify(
|
|||
|
IN PDEVICE_OBJECT ControlObject,
|
|||
|
IN PDEVICE_OBJECT FilterObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles PnP notifications that originate from the Adapter Filter.
|
|||
|
It checks the Minor function and notifies the filter(s) on what action to take
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ControlObject - Mpctl's D.O.
|
|||
|
FilterObject - The filter D.O.
|
|||
|
Irp - The pnp irp sent to FilterObject
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// TODO: Determine how best to handle this.
|
|||
|
//
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOAdpPowerNotify(
|
|||
|
IN PDEVICE_OBJECT ControlObject,
|
|||
|
IN PDEVICE_OBJECT FilterObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles Power notifications that originate from the Adapter Filter.
|
|||
|
It checks the Minor function and notifies the filter(s) on what action to take
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ControlObject - Mpctl's D.O.
|
|||
|
FilterObject - The filter D.O.
|
|||
|
Irp - The power irp sent to FilterObject
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status of the helper routines.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// TODO: Determine how best to handle this.
|
|||
|
//
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PDEVICE_RELATIONS
|
|||
|
MPIOBuildRelations(
|
|||
|
IN PADP_DEVICE_LIST DeviceList
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_RELATIONS relations;
|
|||
|
ULONG relationsSize;
|
|||
|
ULONG i;
|
|||
|
ULONG numberDevices = DeviceList->NumberDevices;
|
|||
|
|
|||
|
//
|
|||
|
// Determine the size needed.
|
|||
|
//
|
|||
|
relationsSize = sizeof(DEVICE_RELATIONS);
|
|||
|
relationsSize += (sizeof(PDEVICE_OBJECT) * numberDevices - 1);
|
|||
|
|
|||
|
relations = ExAllocatePool(NonPagedPool, relationsSize);
|
|||
|
RtlZeroMemory(relations, relationsSize);
|
|||
|
|
|||
|
//
|
|||
|
// Copy over the D.O.s
|
|||
|
//
|
|||
|
relations->Count = DeviceList->NumberDevices;
|
|||
|
for (i = 0; i < numberDevices; i++) {
|
|||
|
relations->Objects[i] = DeviceList->DeviceList[i].DeviceObject;
|
|||
|
}
|
|||
|
return relations;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
MPIODetermineDeviceArrival(
|
|||
|
IN PADP_DEVICE_LIST DeviceList,
|
|||
|
IN PDEVICE_RELATIONS CachedRelations,
|
|||
|
IN PDEVICE_RELATIONS NewCachedRelations
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG oldCount;
|
|||
|
ULONG newCount;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
oldCount = CachedRelations->Count;
|
|||
|
newCount = NewCachedRelations->Count;
|
|||
|
|
|||
|
if (newCount > oldCount) {
|
|||
|
|
|||
|
//
|
|||
|
// This always indicates a new device(s).
|
|||
|
//
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the weird case where the objects are differnet,
|
|||
|
// but count remains the same (or is less).
|
|||
|
// TODO
|
|||
|
//
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOAdpDeviceNotify(
|
|||
|
IN PDEVICE_OBJECT ControlObject,
|
|||
|
IN PDEVICE_OBJECT FilterObject,
|
|||
|
IN PDEVICE_OBJECT PortObject,
|
|||
|
IN PADP_DEVICE_LIST DeviceList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by the FilterObject when a QDR has occurred. It passes in a list
|
|||
|
of disk PDO's for processing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ControlObject - The Mpctl DO
|
|||
|
FilterObject - The adapter filter's DO
|
|||
|
DeviceList - List of PDO's and associated structs.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = ControlObject->DeviceExtension;
|
|||
|
PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
|
|||
|
PDSM_ENTRY entry;
|
|||
|
PDISK_ENTRY diskEntry;
|
|||
|
NTSTATUS status;
|
|||
|
PVOID dsmExtension;
|
|||
|
PFLTR_ENTRY fltrEntry;
|
|||
|
ULONG numberDevices = DeviceList->NumberDevices;
|
|||
|
PDEVICE_RELATIONS cachedRelations;
|
|||
|
PDEVICE_RELATIONS newCachedRelations;
|
|||
|
BOOLEAN newList = FALSE;
|
|||
|
BOOLEAN added = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// First, run through the lists and find out if any devices
|
|||
|
// have been removed.
|
|||
|
// Round One will be handling a removed path - ALL devices are gone.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Get the cached info, to see whether something has been removed.
|
|||
|
//
|
|||
|
fltrEntry = MPIOGetFltrEntry(ControlObject,
|
|||
|
PortObject,
|
|||
|
NULL);
|
|||
|
|
|||
|
ASSERT(fltrEntry);
|
|||
|
|
|||
|
//
|
|||
|
// See whether there is already a relations struct.
|
|||
|
//
|
|||
|
cachedRelations = fltrEntry->CachedRelations;
|
|||
|
if (cachedRelations == NULL) {
|
|||
|
|
|||
|
cachedRelations = MPIOBuildRelations(DeviceList);
|
|||
|
|
|||
|
//
|
|||
|
// Update the filter entry with the relations.
|
|||
|
//
|
|||
|
fltrEntry->CachedRelations = cachedRelations;
|
|||
|
newCachedRelations = cachedRelations;
|
|||
|
|
|||
|
//
|
|||
|
// Indicate that this is the 'original' list.
|
|||
|
//
|
|||
|
newList = TRUE;
|
|||
|
added = TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Determine if any devices need to be removed.
|
|||
|
// If so, this routine will handle it.
|
|||
|
//
|
|||
|
newCachedRelations = MPIOHandleDeviceRemovals(ControlObject,
|
|||
|
DeviceList,
|
|||
|
cachedRelations);
|
|||
|
//
|
|||
|
// Update the cachedRelations to reflect the new state.
|
|||
|
//
|
|||
|
fltrEntry->CachedRelations = newCachedRelations;
|
|||
|
|
|||
|
//
|
|||
|
// This is an update.
|
|||
|
//
|
|||
|
newList = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Determine whether any devices have been added.
|
|||
|
//
|
|||
|
added = MPIODetermineDeviceArrival(DeviceList,
|
|||
|
cachedRelations,
|
|||
|
newCachedRelations);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (added) {
|
|||
|
|
|||
|
if (fltrEntry->Flags & FLTR_FLAGS_NEED_RESCAN) {
|
|||
|
|
|||
|
//
|
|||
|
// Indicate that the rescan is complete.
|
|||
|
//
|
|||
|
fltrEntry->Flags &= ~FLTR_FLAGS_RESCANNING;
|
|||
|
|
|||
|
//
|
|||
|
// Clear the complete flags. The timer will handle
|
|||
|
// setting it.
|
|||
|
//
|
|||
|
fltrEntry->Flags &= ~FLTR_FLAGS_QDR_COMPLETE;
|
|||
|
|
|||
|
//
|
|||
|
// Indicate that this adapter had a QDR.
|
|||
|
//
|
|||
|
fltrEntry->Flags |= FLTR_FLAGS_QDR;
|
|||
|
MPDebugPrint((0,
|
|||
|
"DeviceNotify: Flags (%x) on (%x)\n",
|
|||
|
fltrEntry->Flags,
|
|||
|
fltrEntry));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Handle dealing with any new objects.
|
|||
|
//
|
|||
|
status = MPIOHandleDeviceArrivals(ControlObject,
|
|||
|
DeviceList,
|
|||
|
cachedRelations,
|
|||
|
newCachedRelations,
|
|||
|
PortObject,
|
|||
|
FilterObject,
|
|||
|
newList);
|
|||
|
}
|
|||
|
|
|||
|
if (newList == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// Free the old stuff.
|
|||
|
//
|
|||
|
ExFreePool(cachedRelations);
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOAdapterRegistration(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the main dispatch routine for Internal Device Controls sent
|
|||
|
to the FDO (Control). The control codes are those known to the device and adapter
|
|||
|
filters and to the DSMs.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status of the helper routines.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PADAPTER_REGISTER adapterReg = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
PFLTR_ENTRY fltrEntry;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate an entry for this filter.
|
|||
|
//
|
|||
|
fltrEntry = ExAllocatePool(NonPagedPool, sizeof(FLTR_ENTRY));
|
|||
|
if (fltrEntry == NULL) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
RtlZeroMemory(fltrEntry, sizeof(FLTR_ENTRY));
|
|||
|
|
|||
|
fltrEntry->FilterObject = adapterReg->FilterObject;
|
|||
|
fltrEntry->PortFdo = adapterReg->PortFdo;
|
|||
|
fltrEntry->FltrGetDeviceList = adapterReg->FltrGetDeviceList;
|
|||
|
|
|||
|
//
|
|||
|
// Add it to the list
|
|||
|
//
|
|||
|
ExInterlockedInsertTailList(&controlExtension->FilterList,
|
|||
|
&fltrEntry->ListEntry,
|
|||
|
&controlExtension->SpinLock);
|
|||
|
|
|||
|
InterlockedIncrement(&controlExtension->NumberFilters);
|
|||
|
//
|
|||
|
// Fill in the entry points for the filter
|
|||
|
//
|
|||
|
adapterReg->PnPNotify = MPIOAdpPnpNotify;
|
|||
|
adapterReg->PowerNotify = MPIOAdpPowerNotify;
|
|||
|
adapterReg->DeviceNotify = MPIOAdpDeviceNotify;
|
|||
|
|
|||
|
//
|
|||
|
// set Information
|
|||
|
//
|
|||
|
Irp->IoStatus.Information = sizeof(ADAPTER_REGISTER);
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIODsmRegistration(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
|
|||
|
PDSM_INIT_DATA initData = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
PDSM_MPIO_CONTEXT context = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
PDSM_ENTRY dsmEntry;
|
|||
|
PLIST_ENTRY oldEntry;
|
|||
|
PDSM_ENTRY oldDsm;
|
|||
|
WCHAR buffer[64];
|
|||
|
|
|||
|
ASSERT(initData->InitDataSize == sizeof(DSM_INIT_DATA));
|
|||
|
|
|||
|
//
|
|||
|
// Allocate an entry for the DSM Info.
|
|||
|
//
|
|||
|
dsmEntry = ExAllocatePool(NonPagedPool, sizeof(DSM_ENTRY));
|
|||
|
if (dsmEntry == NULL) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(dsmEntry, sizeof(DSM_ENTRY));
|
|||
|
|
|||
|
//
|
|||
|
// Extract the info from the DSM's buffer.
|
|||
|
//
|
|||
|
dsmEntry->InquireDriver = initData->DsmInquireDriver;
|
|||
|
dsmEntry->CompareDevices = initData->DsmCompareDevices;
|
|||
|
dsmEntry->SetDeviceInfo = initData->DsmSetDeviceInfo;
|
|||
|
dsmEntry->GetControllerInfo = initData->DsmGetControllerInfo;
|
|||
|
dsmEntry->IsPathActive = initData->DsmIsPathActive;
|
|||
|
dsmEntry->InvalidatePath = initData->DsmInvalidatePath;
|
|||
|
dsmEntry->PathVerify = initData->DsmPathVerify;
|
|||
|
dsmEntry->RemovePending = initData->DsmRemovePending;
|
|||
|
dsmEntry->RemoveDevice = initData->DsmRemoveDevice;
|
|||
|
dsmEntry->RemovePath = initData->DsmRemovePath;
|
|||
|
dsmEntry->SrbDeviceControl = initData->DsmSrbDeviceControl;
|
|||
|
dsmEntry->ReenablePath = initData->DsmReenablePath;
|
|||
|
dsmEntry->GetPath = initData->DsmLBGetPath;
|
|||
|
dsmEntry->InterpretError = initData->DsmInterpretError;
|
|||
|
dsmEntry->Unload = initData->DsmUnload;
|
|||
|
dsmEntry->SetCompletion = initData->DsmSetCompletion;
|
|||
|
dsmEntry->CategorizeRequest = initData->DsmCategorizeRequest;
|
|||
|
dsmEntry->BroadcastSrb = initData->DsmBroadcastSrb;
|
|||
|
RtlCopyMemory(&dsmEntry->WmiContext,
|
|||
|
&initData->DsmWmiInfo,
|
|||
|
sizeof(DSM_WMILIB_CONTEXT));
|
|||
|
|
|||
|
dsmEntry->DsmContext = initData->DsmContext;
|
|||
|
|
|||
|
//
|
|||
|
// Build the Name string.
|
|||
|
//
|
|||
|
dsmEntry->DisplayName.Buffer = ExAllocatePool(NonPagedPool,
|
|||
|
initData->DisplayName.MaximumLength);
|
|||
|
RtlZeroMemory(dsmEntry->DisplayName.Buffer,
|
|||
|
initData->DisplayName.MaximumLength);
|
|||
|
dsmEntry->DisplayName.Length = initData->DisplayName.Length;
|
|||
|
dsmEntry->DisplayName.MaximumLength = initData->DisplayName.MaximumLength;
|
|||
|
|
|||
|
RtlCopyUnicodeString(&dsmEntry->DisplayName,
|
|||
|
&initData->DisplayName);
|
|||
|
|
|||
|
//
|
|||
|
// Add it to the list
|
|||
|
//
|
|||
|
if (initData->Reserved == (ULONG)-1) {
|
|||
|
|
|||
|
//
|
|||
|
// Gendsm goes to the end of the list.
|
|||
|
//
|
|||
|
oldEntry = ExInterlockedInsertTailList(&controlExtension->DsmList,
|
|||
|
&dsmEntry->ListEntry,
|
|||
|
&controlExtension->SpinLock);
|
|||
|
MPDebugPrint((1,
|
|||
|
"Loading it Last. dsmEntry was (%x)\n",
|
|||
|
CONTAINING_RECORD(oldEntry, DSM_ENTRY, ListEntry)));
|
|||
|
} else {
|
|||
|
|
|||
|
oldEntry = ExInterlockedInsertHeadList(&controlExtension->DsmList,
|
|||
|
&dsmEntry->ListEntry,
|
|||
|
&controlExtension->SpinLock);
|
|||
|
MPDebugPrint((1,
|
|||
|
"Loading it first. dsmEntry was (%x)\n",
|
|||
|
CONTAINING_RECORD(oldEntry, DSM_ENTRY, ListEntry)));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update the list count.
|
|||
|
//
|
|||
|
InterlockedIncrement(&controlExtension->NumberDSMs);
|
|||
|
|
|||
|
//
|
|||
|
// Set-up the return buffer
|
|||
|
//
|
|||
|
context->MPIOContext = DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// Set Information
|
|||
|
//
|
|||
|
Irp->IoStatus.Information = sizeof(DSM_MPIO_CONTEXT);
|
|||
|
|
|||
|
swprintf(buffer, L"DSM %ws, registered.", dsmEntry->DisplayName.Buffer);
|
|||
|
MPIOFireEvent(DeviceObject,
|
|||
|
L"MPIO",
|
|||
|
buffer,
|
|||
|
MPIO_INFORMATION);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MPIOFdoInternalDeviceControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the main dispatch routine for Internal Device Controls sent
|
|||
|
to the FDO (Control). The control codes are those known to the device and adapter
|
|||
|
filters and to the DSMs.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject
|
|||
|
Irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status of the helper routines.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
|
|||
|
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|||
|
case IOCTL_MPDEV_QUERY_PDO:
|
|||
|
|
|||
|
//
|
|||
|
// Mpdev sends this request to determine if the PDO given it
|
|||
|
// in it's AddDevice is a real D.O., or an MPDisk.
|
|||
|
//
|
|||
|
status = MPIOQueryPdo(DeviceObject,
|
|||
|
Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_MPDEV_REGISTER:
|
|||
|
|
|||
|
//
|
|||
|
// Mpdev sends this on an AddDevice to notify that
|
|||
|
// an instatiation of the filter has arrived.
|
|||
|
//
|
|||
|
status = MPIODeviceRegistration(DeviceObject,
|
|||
|
Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_MPADAPTER_REGISTER:
|
|||
|
|
|||
|
//
|
|||
|
// Mpspfltr sens this on it's AddDevice to notify that
|
|||
|
// it has arrived.
|
|||
|
//
|
|||
|
status = MPIOAdapterRegistration(DeviceObject,
|
|||
|
Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_MPDSM_REGISTER:
|
|||
|
|
|||
|
//
|
|||
|
// A DSM has loaded. Handle getting it's entry point info.
|
|||
|
//
|
|||
|
status = MPIODsmRegistration(DeviceObject,
|
|||
|
Irp);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|