#include "mpath.h" #include #include #include #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; }