551 lines
16 KiB
C
551 lines
16 KiB
C
#include "mpath.h"
|
||
#include <wmistr.h>
|
||
#include <wmidata.h>
|
||
#include <stdio.h>
|
||
|
||
|
||
#ifdef USE_BINARY_MOF_QUERY
|
||
//
|
||
// MOF data can be reported by a device driver via a resource attached to
|
||
// the device drivers image file or in response to a query on the binary
|
||
// mof data guid. Here we define global variables containing the binary mof
|
||
// data to return in response to a binary mof guid query. Note that this
|
||
// data is defined to be in a PAGED data segment since it does not need to
|
||
// be in nonpaged memory. Note that instead of a single large mof file
|
||
// we could have broken it into multiple individual files. Each file would
|
||
// have its own binary mof data buffer and get reported via a different
|
||
// instance of the binary mof guid. By mixing and matching the different
|
||
// sets of binary mof data buffers a "dynamic" composite mof would be created.
|
||
|
||
#ifdef ALLOC_DATA_PRAGMA
|
||
#pragma data_seg("PAGED")
|
||
#endif
|
||
|
||
#pragma message ("USE_BINARY defined ChuckP")
|
||
UCHAR MPathBinaryMofData[] =
|
||
{
|
||
#include "mpathwmi.x"
|
||
};
|
||
#ifdef ALLOC_DATA_PRAGMA
|
||
#pragma data_seg()
|
||
#endif
|
||
#endif
|
||
|
||
|
||
WMIGUIDREGINFO MPathWmiGuidList[] = {
|
||
{
|
||
&MPath_Disk_Info_GUID,
|
||
1,
|
||
0
|
||
},
|
||
{
|
||
&MPath_Test_GUID,
|
||
1,
|
||
0
|
||
},
|
||
|
||
{
|
||
&MSWmi_MofData_GUID,
|
||
1,
|
||
#ifdef USE_BINARY_MOF_QUERY
|
||
0
|
||
#else
|
||
WMIREG_FLAG_REMOVE_GUID
|
||
#endif
|
||
}
|
||
};
|
||
|
||
#define DiskInformation 0
|
||
#define MPathTest 1
|
||
#define BinaryMofGuid 2
|
||
|
||
#define MPathGuidCount (sizeof(MPathWmiGuidList) / sizeof(WMIGUIDREGINFO))
|
||
|
||
//#define MPATH_GUID_PDISK_INFO 0
|
||
//#define MPATH_BINARY_MOF 1
|
||
//#define MPATH_GUID_FAILOVER_INFO 1
|
||
//#define MPATH_GUID_CONFIG_INFO 2
|
||
//#define MPATH_GUID_DSM_NAME 3
|
||
//#define MPATH_GUID_PATH_MAINTENACE 4
|
||
//
|
||
// Always update this for any guid additions.
|
||
// This indicates the dividing line between our and DSM
|
||
// guids.
|
||
//
|
||
//#define MPATH_MAX_GUID_INDEX MPATH_BINARY_MOF
|
||
//
|
||
|
||
|
||
NTSTATUS
|
||
MPathFdoWmi(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
|
||
IoSkipCurrentIrpStackLocation(Irp);
|
||
|
||
return IoCallDriver(deviceExtension->TargetObject, Irp);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPathQueryWmiRegInfo(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
OUT PULONG RegFlags,
|
||
OUT PUNICODE_STRING InstanceName,
|
||
OUT PUNICODE_STRING *RegistryPath,
|
||
OUT PUNICODE_STRING MofResourceName,
|
||
OUT PDEVICE_OBJECT *Pdo
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
|
||
*RegFlags = WMIREG_FLAG_INSTANCE_PDO;
|
||
*RegistryPath = &deviceExtension->RegistryPath;
|
||
*Pdo = deviceExtension->DeviceObject;
|
||
MPDebugPrint((0,
|
||
"MPathQueryWmiRegInfo: *Pdo (%x), DeviceObject (%x)\n",
|
||
*Pdo,
|
||
DeviceObject));
|
||
#ifndef USE_BINARY_MOF_QUERY
|
||
#pragma message ("BIN NOT - ChuckP")
|
||
//
|
||
// Return the name specified in the .rc file of the resource which
|
||
// contains the bianry mof data. By default WMI will look for this
|
||
// resource in the driver image (.sys) file, however if the value
|
||
// MofImagePath is specified in the driver's registry key
|
||
// then WMI will look for the resource in the file specified there.
|
||
RtlInitUnicodeString(MofResourceName, L"MofResourceName");
|
||
#endif
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPathQueryWmiDataBlock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN ULONG GuidIndex,
|
||
IN ULONG InstanceIndex,
|
||
IN ULONG InstanceCount,
|
||
IN OUT PULONG InstanceLengthArray,
|
||
IN ULONG BufferAvail,
|
||
OUT PUCHAR Buffer
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PPSEUDO_DISK_EXTENSION diskExtension = &deviceExtension->PseudoDiskExtension;
|
||
NTSTATUS status;
|
||
ULONG i;
|
||
ULONG bytesReturned = 0;
|
||
|
||
if (TRUE) { //(GuidIndex <= MPATH_MAX_GUID_INDEX) {
|
||
|
||
//
|
||
// This is for the pdisk
|
||
// Ensure that this is a QUERY_SINGLE_INSTANCE, as these data blocks
|
||
// are defined as having only one instance.
|
||
//
|
||
if (InstanceIndex != 0 || InstanceCount != 1) {
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
} else {
|
||
switch (GuidIndex) {
|
||
case MPathTest:
|
||
bytesReturned = sizeof(ULONG);
|
||
if (bytesReturned > BufferAvail) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
ULONG theValue = 0xaa55aa55;
|
||
|
||
RtlCopyMemory(Buffer,
|
||
&theValue,
|
||
sizeof(ULONG));
|
||
status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
case DiskInformation: {
|
||
PMPath_Disk_Info diskInfo = (PMPath_Disk_Info)Buffer;
|
||
PSTORAGE_DEVICE_DESCRIPTOR storageDescriptor;
|
||
ULONG serialNumberLength;
|
||
ULONG totalStringLength;
|
||
PUCHAR serialNumber;
|
||
ANSI_STRING ansiSerialNumber;
|
||
UNICODE_STRING unicodeString;
|
||
|
||
bytesReturned = sizeof(MPath_Disk_Info);
|
||
|
||
//
|
||
// Determine the serial number length.
|
||
//
|
||
storageDescriptor =
|
||
diskExtension->DeviceDescriptors[0].StorageDescriptor;
|
||
serialNumber = (PUCHAR)storageDescriptor;
|
||
|
||
//
|
||
// Move serialNumber to the correct position in RawData.
|
||
//
|
||
(ULONG_PTR)serialNumber += storageDescriptor->SerialNumberOffset;
|
||
|
||
//
|
||
// Get it's length.
|
||
//
|
||
serialNumberLength = strlen(serialNumber);
|
||
totalStringLength = serialNumberLength * sizeof(WCHAR);
|
||
totalStringLength += sizeof(USHORT);
|
||
totalStringLength *= diskExtension->NumberPhysicalPaths;
|
||
|
||
|
||
bytesReturned += totalStringLength;
|
||
bytesReturned += (diskExtension->NumberPhysicalPaths - 1) *
|
||
sizeof(PHYSICAL_DISK_INFO);
|
||
|
||
|
||
if (bytesReturned > BufferAvail) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
PWCHAR index;
|
||
PDEVICE_DESCRIPTOR deviceDescriptor;
|
||
PPHYSICAL_DISK_INFO deviceInfo = diskInfo->DeviceInfo;
|
||
|
||
diskInfo->NumberDrives = diskExtension->NumberPhysicalPaths;
|
||
diskInfo->IsLoadBalance = FALSE;
|
||
|
||
RtlInitAnsiString(&ansiSerialNumber, serialNumber);
|
||
RtlAnsiStringToUnicodeString(&unicodeString, &ansiSerialNumber, TRUE);
|
||
|
||
for (i = 0; i < diskExtension->NumberPhysicalPaths; i++) {
|
||
|
||
deviceDescriptor =
|
||
&diskExtension->DeviceDescriptors[i];
|
||
deviceInfo->BusType = 1;
|
||
deviceInfo->PortNumber =
|
||
deviceDescriptor->ScsiAddress->PortNumber;
|
||
deviceInfo->TargetId =
|
||
deviceDescriptor->ScsiAddress->TargetId;
|
||
deviceInfo->Lun =
|
||
deviceDescriptor->ScsiAddress->Lun;
|
||
|
||
deviceInfo->CorrespondingPathId =
|
||
(ULONG)deviceDescriptor->PhysicalPath->PhysicalPathId;
|
||
index = (PWCHAR)deviceInfo->VariableData;
|
||
*index++ = unicodeString.Length;
|
||
|
||
RtlCopyMemory(index,
|
||
unicodeString.Buffer,
|
||
unicodeString.Length);
|
||
(ULONG_PTR)deviceInfo +=
|
||
sizeof(PHYSICAL_DISK_INFO) + unicodeString.Length;
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
break;
|
||
}
|
||
#ifdef USE_BINARY_MOF_QUERY
|
||
case BinaryMofGuid:
|
||
{
|
||
bytesReturned = sizeof(MPathBinaryMofData);
|
||
MPDebugPrint((0,
|
||
"MPathQueryDataBlock: BinaryMofGuid\n"));
|
||
DbgBreakPoint();
|
||
if (BufferAvail < bytesReturned)
|
||
{
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
RtlCopyMemory(Buffer, MPathBinaryMofData, bytesReturned);
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
break;
|
||
}
|
||
#endif
|
||
default:
|
||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// This is for the DSM
|
||
//
|
||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
}
|
||
MPDebugPrint((0,
|
||
"MpathQueryDataBlock: Buffer (%x) BytesReturned (%x). Status (%x)\n",
|
||
Buffer,
|
||
bytesReturned,
|
||
status));
|
||
|
||
//
|
||
// Indicate the data length.
|
||
//
|
||
*InstanceLengthArray = bytesReturned;
|
||
|
||
status = WmiCompleteRequest(DeviceObject,
|
||
Irp,
|
||
status,
|
||
bytesReturned,
|
||
IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPathSetWmiDataBlock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN ULONG GuidIndex,
|
||
IN ULONG InstanceIndex,
|
||
IN ULONG BufferSize,
|
||
IN PUCHAR Buffer
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG bytesReturned = 0;
|
||
|
||
if (FALSE) { // (GuidIndex <= MPATH_MAX_GUID_INDEX) {
|
||
status = STATUS_WMI_READ_ONLY;
|
||
} else {
|
||
//
|
||
// DSM Guid
|
||
// If there is a GUID match, call the dsm. It will have to call
|
||
// DsmCompleteWMIRequest to finish the request.
|
||
// DONOT complete it here, rather return the status from the DSM routine
|
||
// TODO
|
||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
}
|
||
status = WmiCompleteRequest(DeviceObject,
|
||
Irp,
|
||
status,
|
||
bytesReturned,
|
||
IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MPathSetWmiDataItem(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN ULONG GuidIndex,
|
||
IN ULONG InstanceIndex,
|
||
IN ULONG DataItemId,
|
||
IN ULONG BufferSize,
|
||
IN PUCHAR Buffer
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG bytesReturned = 0;
|
||
|
||
if (TRUE) { // (GuidIndex <= MPATH_MAX_GUID_INDEX) {
|
||
status = STATUS_WMI_READ_ONLY;
|
||
} else {
|
||
//
|
||
// DSM Guid
|
||
// TODO
|
||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
}
|
||
status = WmiCompleteRequest(DeviceObject,
|
||
Irp,
|
||
status,
|
||
bytesReturned,
|
||
IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPathExecuteWmiMethod(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN ULONG GuidIndex,
|
||
IN ULONG InstanceIndex,
|
||
IN ULONG MethodId,
|
||
IN ULONG InBuffersize,
|
||
IN ULONG OutBufferSize,
|
||
IN OUT PUCHAR Buffer
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG bytesReturned = 0;
|
||
|
||
if (TRUE) { //(GuidIndex <= MPATH_MAX_GUID_INDEX ) {
|
||
switch (GuidIndex) {
|
||
//case MPATH_GUID_PATH_MAINTENACE: {
|
||
|
||
|
||
//
|
||
// Need to verify the parameters.
|
||
// TODO: Need data block that lists adapter
|
||
// (path) ids.
|
||
//
|
||
//status = MPathFailOver(id1, id2);
|
||
// status = STATUS_WMI_ITEMID_NOT_FOUND;
|
||
// }
|
||
// break;
|
||
|
||
default:
|
||
status = STATUS_WMI_ITEMID_NOT_FOUND;
|
||
break;
|
||
|
||
}
|
||
} else {
|
||
|
||
status = STATUS_WMI_ITEMID_NOT_FOUND;
|
||
}
|
||
status = WmiCompleteRequest(DeviceObject,
|
||
Irp,
|
||
status,
|
||
bytesReturned,
|
||
IO_NO_INCREMENT);
|
||
return status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPathWmiFunctionControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN ULONG GuidIndex,
|
||
IN WMIENABLEDISABLECONTROL Function,
|
||
IN BOOLEAN Enable
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PPSEUDO_DISK_EXTENSION diskExtension = &deviceExtension->PseudoDiskExtension;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Handle the enabling/disabling of the datablocks/events
|
||
//
|
||
#if 0
|
||
if (GuidIndex == MPATH_GUID_FAILOVER_INFO) {
|
||
if (Enable) {
|
||
diskExtension->WmiEventsEnabled = TRUE;
|
||
} else {
|
||
|
||
diskExtension->WmiEventsEnabled = FALSE;
|
||
}
|
||
|
||
} else {
|
||
#endif
|
||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||
//}
|
||
status = WmiCompleteRequest(DeviceObject,
|
||
Irp,
|
||
status,
|
||
0,
|
||
IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|
||
|
||
VOID
|
||
MPathSetupWmi(
|
||
IN PDEVICE_EXTENSION DeviceExtension
|
||
)
|
||
{
|
||
if (DeviceExtension->Type == DEV_MPATH_CONTROL) {
|
||
MPDebugPrint((0,
|
||
"MPathSetWmi: Control Object\n"));
|
||
DbgBreakPoint();
|
||
} else {
|
||
PPSEUDO_DISK_EXTENSION diskExtension = &DeviceExtension->PseudoDiskExtension;
|
||
|
||
diskExtension->WmiInfo.GuidCount = MPathGuidCount;
|
||
diskExtension->WmiInfo.GuidList = MPathWmiGuidList;
|
||
diskExtension->WmiInfo.QueryWmiRegInfo = MPathQueryWmiRegInfo;
|
||
diskExtension->WmiInfo.QueryWmiDataBlock = MPathQueryWmiDataBlock;
|
||
diskExtension->WmiInfo.SetWmiDataBlock = MPathSetWmiDataBlock;
|
||
diskExtension->WmiInfo.SetWmiDataItem = MPathSetWmiDataItem;
|
||
diskExtension->WmiInfo.ExecuteWmiMethod = MPathExecuteWmiMethod;
|
||
diskExtension->WmiInfo.WmiFunctionControl = MPathWmiFunctionControl;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPathWmi(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PUCHAR wmiBuffer = irpStack->Parameters.WMI.Buffer;
|
||
ULONG bufferSize = irpStack->Parameters.WMI.BufferSize;
|
||
ULONG savedLength = Irp->IoStatus.Information;
|
||
PPSEUDO_DISK_EXTENSION diskExtension;
|
||
SYSCTL_IRP_DISPOSITION disposition;
|
||
NTSTATUS status;
|
||
|
||
MPDebugPrint((0,
|
||
"MPathWmi: Irp (%x), MJ (%x), MN (%x)",
|
||
Irp,
|
||
irpStack->MajorFunction,
|
||
irpStack->MinorFunction));
|
||
|
||
|
||
diskExtension = &deviceExtension->PseudoDiskExtension;
|
||
|
||
status = WmiSystemControl(&diskExtension->WmiInfo,
|
||
DeviceObject,
|
||
Irp,
|
||
&disposition);
|
||
|
||
MPDebugPrint((0,
|
||
"Disposition is (%x). Status (%x)\n",
|
||
disposition,
|
||
status));
|
||
switch (disposition) {
|
||
case IrpProcessed:
|
||
|
||
//
|
||
// Already processed and the DpWmiXXX routines specified in WmiInfo will
|
||
// complete it.
|
||
//
|
||
break;
|
||
|
||
case IrpNotCompleted:
|
||
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
break;
|
||
|
||
case IrpNotWmi:
|
||
case IrpForward:
|
||
default:
|
||
//
|
||
// Need to ensure this is the pseudodisk
|
||
//
|
||
if (deviceExtension->Type == DEV_MPATH_CONTROL) {
|
||
|
||
MPDebugPrint((0,
|
||
" for Control\n"));
|
||
//
|
||
// Call the 'control' (FDO) handler.
|
||
//
|
||
return MPathFdoWmi(DeviceObject, Irp);
|
||
} else {
|
||
//
|
||
// This is the PDO, so just complete it without touching anything.
|
||
//
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
}
|
||
break;
|
||
|
||
}
|
||
|
||
return status;
|
||
|
||
}
|
||
|