|
|
#include <wdm.h>
#include <wmistr.h>
#include <wmiguid.h>
#include <wmilib.h>
#include "mpio.h"
#include "wmi.h"
#include "pdowmi.h"
#include <stdio.h>
#define USE_BINARY_MOF_QUERY
UCHAR MPIOBinaryMofData[] = { #include "wmi.x"
};
UCHAR PdoBinaryMofData[] = { #include "pdowmi.x"
}; //
// Guid Index Symbolic Names.
//
#define MPIO_DISK_INFOGuidIndex 0
#define MPIO_PATH_INFORMATIONGuidIndex 1
#define MPIO_CONTROLLER_CONFIGURATIONGuidIndex 2
#define MPIO_EventEntryGuidIndex 3
#define MPIO_WmiBinaryMofGuidIndex 4
//
// Guid Index for Pdos
//
#define MPIO_GET_DESCRIPTORGuidIndex 0
#define BinaryMofGuidIndex 1
//
// List of supported Guids.
//
GUID MPIO_DISK_INFOGUID = MPIO_DISK_INFOGuid; GUID MPIO_PATH_INFORMATIONGUID = MPIO_PATH_INFORMATIONGuid; GUID MPIO_CONTROLLER_CONFIGURATIONGUID = MPIO_CONTROLLER_CONFIGURATIONGuid; GUID MPIO_EventEntryGUID = MPIO_EventEntryGuid; GUID MPIOWmiBinaryMofGUID = BINARY_MOF_GUID;
WMIGUIDREGINFO MPIOWmiGuidList[] = { { &MPIO_DISK_INFOGUID, 1, 0 }, { &MPIO_PATH_INFORMATIONGUID, 1, 0 }, { &MPIO_CONTROLLER_CONFIGURATIONGUID, 1, 0 }, { &MPIO_EventEntryGUID, 1, 0 }, { &MPIOWmiBinaryMofGUID, 1, 0 } };
#define MPIO_GUID_COUNT (sizeof(MPIOWmiGuidList) / sizeof(WMIGUIDREGINFO))
GUID MPIO_GET_DESCRIPTORGUID = MPIO_GET_DESCRIPTORGuid; GUID PdowmiBinaryMofGUID = BINARY_MOF_GUID; WMIGUIDREGINFO PdowmiGuidList[] = { { &MPIO_GET_DESCRIPTORGUID, 1, 0 }, { &PdowmiBinaryMofGUID, 1, 0 } };
#define PdowmiGuidCount (sizeof(PdowmiGuidList) / sizeof(WMIGUIDREGINFO))
NTSTATUS MPIOQueryRegInfo( 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; UNICODE_STRING nameString; ANSI_STRING ansiString; UCHAR instanceName[] = "Multi-Path Disk";
//
// Return a pointer to the reg. path. Wmi needs this for some reason.
//
*RegistryPath = &deviceExtension->RegistryPath;
if (FALSE) { //deviceExtension->Type == MPIO_MPDISK) {
RtlInitAnsiString(&ansiString, instanceName); RtlAnsiStringToUnicodeString(InstanceName, &ansiString, TRUE);
*RegFlags = WMIREG_FLAG_INSTANCE_BASENAME; } else { //
// Indicate that instance names should be auto-generated.
//
*RegFlags = WMIREG_FLAG_INSTANCE_PDO;
//
// Set the PDO.
//
*Pdo = deviceExtension->Pdo; }
return STATUS_SUCCESS; }
ULONG MPIOGetDriveInfoSize( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PDSM_ENTRY dsm = &diskExtension->DsmInfo; ULONG length; WCHAR buffer[64]; PUCHAR serialNumber; ULONG serialNumberLength;
//
// Determine name length.
// \Device\MPIODisk(N)
//
swprintf(buffer, L"MPIO Disk%0d", diskExtension->DeviceOrdinal); length = wcslen(buffer) + 1; length *= sizeof(WCHAR);
//
// Add in a USHORT to account for the 'Length' field.
//
length += sizeof(USHORT);
//
// Add a ULONG size. (NumberPaths)
//
length += sizeof(ULONG); //
// Determine SN size.
//
serialNumber = (PUCHAR)diskExtension->DeviceDescriptor; (ULONG_PTR)serialNumber += diskExtension->DeviceDescriptor->SerialNumberOffset; serialNumberLength = strlen(serialNumber) + 1;
//
// Length of the buffer.
//
length += (serialNumberLength * sizeof(WCHAR));
//
// Length of the 'length' field.
//
length += sizeof(USHORT);
//
// Get the DSM Name.
//
length += dsm->DisplayName.Length; length += sizeof(USHORT); length += sizeof(UNICODE_NULL);
if (length & 3) {
length += sizeof(ULONG); length &= ~(sizeof(ULONG) - 1); } return length; }
ULONG MPIOBuildDriveInfo( IN PDEVICE_OBJECT DeviceObject, IN OUT PWCHAR Buffer ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PDSM_ENTRY dsm = &diskExtension->DsmInfo; PREAL_DEV_INFO targetInfo; WCHAR nameBuffer[64]; PWCHAR buffer; PUCHAR serialNumber; ANSI_STRING ansiSerialNumber; UNICODE_STRING unicodeString; ULONG i; ULONG stringLength; ULONG totalLength; BOOLEAN freeBuffer = FALSE;
buffer = Buffer; *((PULONG)buffer) = diskExtension->DsmIdList.Count;
totalLength = sizeof(ULONG); (PUCHAR)buffer += sizeof(ULONG); //
// Build the string locally.
//
swprintf(nameBuffer, L"MPIO Disk%0d", diskExtension->DeviceOrdinal);
//
// Get the number of characters + 1 (for the terminating NULL).
//
stringLength = wcslen(nameBuffer) + 1;
//
// Convert length to WCHAR sized.
//
stringLength *= sizeof(WCHAR);
//
// The WMI strings are sort-of unicode strings. They have a length, but not
// maximum length.
// Indicate the Length.
//
*((PUSHORT)buffer) = (USHORT)stringLength; (PUCHAR)buffer += sizeof(USHORT); MPDebugPrint((0, "Buffer (%x) Length (%x)\n", buffer, stringLength)); //
// Copy the string.
//
RtlCopyMemory(buffer, nameBuffer, stringLength);
//
// Return the length of the string (plus NULL term.) + the USHORT length field.
//
totalLength += stringLength + sizeof(USHORT); //
// Build the serial Number.
//
(PUCHAR)buffer += stringLength; if (diskExtension->DeviceDescriptor->SerialNumberOffset == (ULONG)-1) { *((PUSHORT)Buffer) = 0; unicodeString.Length = sizeof(USHORT);
//
// No buffer to free.
//
freeBuffer = FALSE; } else { serialNumber = (PUCHAR)diskExtension->DeviceDescriptor; (ULONG_PTR)serialNumber += diskExtension->DeviceDescriptor->SerialNumberOffset; RtlInitAnsiString(&ansiSerialNumber, serialNumber); RtlAnsiStringToUnicodeString(&unicodeString, &ansiSerialNumber, TRUE);
//
// Set the serial Number Length, and move the pointer
// to the string location.
//
*((PUSHORT)buffer) = unicodeString.Length + sizeof(UNICODE_NULL); (PUCHAR)buffer += sizeof(USHORT); MPDebugPrint((0, "Buffer (%x) Length (%x)\n", buffer, unicodeString.Length));
//
// Copy the serialNumber.
//
RtlCopyMemory(buffer, unicodeString.Buffer, unicodeString.Length); totalLength += unicodeString.Length + sizeof(USHORT); totalLength += sizeof(UNICODE_NULL);
//
// Indicate that the unicode buffer was actually allocated.
//
freeBuffer = TRUE; }
//
// Push the buffer to the next string location.
//
// CHUCKP - just added the sizeof(UNICOE_NULL)...
//
(PUCHAR)buffer += unicodeString.Length; (PUCHAR)buffer += sizeof(UNICODE_NULL);
//
// Free up the Unicode string, as it's no longer needed.
//
if (freeBuffer) { RtlFreeUnicodeString(&unicodeString); } MPDebugPrint((0, "Buffer (%x) Length (%x)\n", buffer, dsm->DisplayName.Length)); //
// Set the size of the DSM's name.
//
*((PUSHORT)buffer) = dsm->DisplayName.Length + sizeof(UNICODE_NULL); (PUCHAR)buffer += sizeof(USHORT); RtlCopyMemory(buffer, dsm->DisplayName.Buffer, dsm->DisplayName.Length);
//
// Need to account for a NULL at the end of this.
//
totalLength += sizeof(UNICODE_NULL);
//
// update the returned length for the Length field and
// the string itself.
//
totalLength += dsm->DisplayName.Length + sizeof(USHORT); return totalLength; }
MPIOGetPathInfoSize( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; PLIST_ENTRY entry; PID_ENTRY id; ULONG dataLength; ULONG stringLength; ULONG i;
dataLength = sizeof(ULONG); entry = controlExtension->IdList.Flink; for (i = 0; i < controlExtension->NumberPaths; i++) {
if (dataLength & 7) { dataLength += sizeof(LONGLONG); dataLength &= ~(sizeof(LONGLONG) - 1); } dataLength += sizeof(LONGLONG); dataLength += sizeof(UCHAR) * 4;
id = CONTAINING_RECORD(entry, ID_ENTRY, ListEntry); stringLength = id->AdapterName.Length + sizeof(USHORT); if (stringLength & 3) { stringLength += sizeof(ULONG); stringLength &= ~(sizeof(ULONG) -1); } dataLength += stringLength;
} return dataLength; }
NTSTATUS MPIOBuildPathInfo( IN PDEVICE_OBJECT DeviceObject, IN PUCHAR Buffer ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; ULONG dataLength; PLIST_ENTRY entry; PID_ENTRY id; ULONG i; USHORT stringLength; PUCHAR buffer = Buffer; *((PULONG)buffer) = controlExtension->NumberPaths; buffer += sizeof(ULONG);
entry = controlExtension->IdList.Flink; for (i = 0; i < controlExtension->NumberPaths; i++) {
if ((ULONG_PTR)buffer & 7) { (ULONG_PTR)buffer += sizeof(LONGLONG); (ULONG_PTR)buffer &= ~(sizeof(LONGLONG) - 1); }
id = CONTAINING_RECORD(entry, ID_ENTRY, ListEntry); if (id->UIDValid == FALSE) {
id->UID = MPIOCreateUID(DeviceObject, id->PathID); } *((PLONGLONG)buffer) = id->UID;
//
// Need the adapter location.
// The Bus Number.
//
(ULONG_PTR)buffer += sizeof(LONGLONG); *buffer = id->Address.Bus;
//
// The device.
//
(ULONG_PTR)buffer += 1; *buffer = id->Address.Device;
//
// The function.
//
(ULONG_PTR)buffer += 1; *buffer = id->Address.Function;
//
// Zero the padding byte.
//
(ULONG_PTR)buffer += 1; *buffer = 0; (ULONG_PTR)buffer += 1; //
// Need the adapter friendly name...
//
stringLength = id->AdapterName.Length; *((PUSHORT)buffer) = stringLength; (ULONG_PTR)buffer += sizeof(USHORT); RtlCopyMemory(buffer, id->AdapterName.Buffer, id->AdapterName.Length); (ULONG_PTR)buffer += stringLength; //
// Get the next path struct.
//
entry = entry->Flink; } return STATUS_SUCCESS; }
ULONG MPIOGetControllerInfoSize( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; PLIST_ENTRY entry; PCONTROLLER_ENTRY controller; ULONG dataLength; ULONG stringLength; ULONG i;
dataLength = sizeof(ULONG); entry = controlExtension->ControllerList.Flink; for (i = 0; i < controlExtension->NumberControllers; i++) {
//
// ControllerId.
//
if (dataLength & 7) { dataLength += sizeof(LONGLONG); dataLength &= ~(sizeof(LONGLONG) - 1); } dataLength += sizeof(LONGLONG);
//
// ControllerSate.
//
dataLength += sizeof(ULONG);
controller = CONTAINING_RECORD(entry, CONTROLLER_ENTRY, ListEntry); stringLength = controller->Dsm->DisplayName.Length + sizeof(USHORT); if (stringLength & 3) { stringLength += sizeof(ULONG); stringLength &= ~(sizeof(ULONG) -1); } dataLength += stringLength; entry = entry->Flink;
} return dataLength; }
NTSTATUS MPIOGetControllerInfo( IN PDEVICE_OBJECT DeviceObject, IN PUCHAR Buffer ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; ULONG dataLength; PLIST_ENTRY entry; PCONTROLLER_ENTRY controller; ULONG i; USHORT stringLength; PUCHAR buffer = Buffer; *((PULONG)buffer) = controlExtension->NumberControllers; buffer += sizeof(ULONG);
entry = controlExtension->ControllerList.Flink; for (i = 0; i < controlExtension->NumberControllers; i++) {
if ((ULONG_PTR)buffer & 7) { (ULONG_PTR)buffer += sizeof(LONGLONG); (ULONG_PTR)buffer &= ~(sizeof(LONGLONG) - 1); }
controller = CONTAINING_RECORD(entry, CONTROLLER_ENTRY, ListEntry); *((PLONGLONG)buffer) = controller->ControllerInfo->ControllerIdentifier;
(ULONG_PTR)buffer += sizeof(LONGLONG); *((PULONG)buffer) = controller->ControllerInfo->State;
(ULONG_PTR)buffer += sizeof(ULONG); //
// Build the dsm name.
//
stringLength = controller->Dsm->DisplayName.Length; *((PUSHORT)buffer) = stringLength; (ULONG_PTR)buffer += sizeof(USHORT); RtlCopyMemory(buffer, controller->Dsm->DisplayName.Buffer, controller->Dsm->DisplayName.Length); (ULONG_PTR)buffer += stringLength; //
// Get the next path struct.
//
entry = entry->Flink; } return STATUS_SUCCESS;
}
NTSTATUS MPIOQueryDataBlock( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG InstanceCount, IN OUT PULONG InstanceLengthArray, IN ULONG BufferAvailable, OUT PUCHAR Buffer ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; NTSTATUS status; ULONG dataLength; ULONG i; PDISK_ENTRY diskEntry; switch (GuidIndex) { case MPIO_DISK_INFOGuidIndex: { PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; PMPIO_DISK_INFO diskInfo; LARGE_INTEGER systemTime; ULONG stringLength; ULONG driveInfoLength; ULONG length2; //
// Check data length to ensure buffer is large enough.
//
dataLength = sizeof(ULONG); //
// Add the length to handle the DRIVE_INFO structs for each
// MPDisk.
//
for (i = 0; i < controlExtension->NumberDevices; i++) { diskEntry = MPIOGetDiskEntry(DeviceObject, i); driveInfoLength = MPIOGetDriveInfoSize(diskEntry->PdoObject); MPDebugPrint((0, "QueryDataBlock: DriveInfoLength (%x)\n", driveInfoLength)); dataLength += driveInfoLength; } MPDebugPrint((0, "MPIOQueryDataBlock: Length is (%x)\n", dataLength));
if (dataLength > BufferAvailable) {
//
// It's not. Report the size needed back to WMI.
//
status = STATUS_BUFFER_TOO_SMALL; } else {
PWCHAR buffer; ULONG length;
RtlZeroMemory(Buffer, dataLength); //
// Indicate the number of PDO's we've created.
//
diskInfo = (PMPIO_DISK_INFO)Buffer; diskInfo->NumberDrives = controlExtension->NumberDevices; buffer = (PWCHAR)diskInfo->DriveInfo; for (i = 0; i < controlExtension->NumberDevices; i++) { diskEntry = MPIOGetDiskEntry(DeviceObject, i); length = MPIOBuildDriveInfo(diskEntry->PdoObject, buffer); MPDebugPrint((0, "BuildDriveInfo Length (%x) buffer (%x)\n", length, buffer)); (PUCHAR)buffer += length; if ((ULONG_PTR)buffer & 3) { (ULONG_PTR)buffer += sizeof(ULONG); (ULONG_PTR)buffer &= ~(sizeof(ULONG) - 1); } MPDebugPrint((0, "After fixup buffer (%x)\n",buffer)); } *InstanceLengthArray = dataLength; status = STATUS_SUCCESS; } break; } case MPIO_PATH_INFORMATIONGuidIndex: { dataLength = MPIOGetPathInfoSize(DeviceObject); if (dataLength > BufferAvailable) { status = STATUS_BUFFER_TOO_SMALL; } else { status = MPIOBuildPathInfo(DeviceObject, Buffer); *InstanceLengthArray = dataLength; } break; } case MPIO_CONTROLLER_CONFIGURATIONGuidIndex: { //
// Determine the buffer size needed.
//
dataLength = MPIOGetControllerInfoSize(DeviceObject);
if (dataLength > BufferAvailable) { status = STATUS_BUFFER_TOO_SMALL; } else {
status = MPIOGetControllerInfo(DeviceObject, Buffer); *InstanceLengthArray = dataLength; }
break; } case MPIO_EventEntryGuidIndex:
//
// This is an event. Set zero info and
// return.
//
*InstanceLengthArray = 0; status = STATUS_SUCCESS; break; case MPIO_WmiBinaryMofGuidIndex:
//
// Need to copy over the mof data.
//
dataLength = sizeof(MPIOBinaryMofData);
//
// Ensure that the buffer is large enough.
//
if (dataLength > BufferAvailable) {
//
// dataLength is passed back to the WmiLib
// so it can adjust.
//
status = STATUS_BUFFER_TOO_SMALL; } else {
RtlCopyMemory(Buffer, MPIOBinaryMofData, dataLength); *InstanceLengthArray = dataLength; status = STATUS_SUCCESS; } break; default: status = STATUS_WMI_GUID_NOT_FOUND; break; } //
// Complete the request.
//
status = WmiCompleteRequest(DeviceObject, Irp, status, dataLength, IO_NO_INCREMENT); return status; }
NTSTATUS MPIOWmiControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN WMIENABLEDISABLECONTROL Function, IN BOOLEAN Enable ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; NTSTATUS status;
switch (GuidIndex) { case MPIO_EventEntryGuidIndex: if (Enable) {
//
// Indicate that it's OK to fire the Log event.
//
deviceExtension->FireLogEvent = TRUE; } else {
//
// Turn off firing the logger.
//
deviceExtension->FireLogEvent = FALSE; } MPDebugPrint((0, "MPIOWmiControl: Turning the Logger (%s) on (%x)\n", Enable ? "ON" : "OFF", DeviceObject)); break; default: status = STATUS_WMI_GUID_NOT_FOUND; break; }
status = WmiCompleteRequest(DeviceObject, Irp, status, 0, IO_NO_INCREMENT); return status; }
//
// PDO Call-Backs.
//
ULONG MPIOGetDescriptorSize( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PREAL_DEV_INFO targetInfo = diskExtension->TargetInfo; ULONG dataLength = 0; NTSTATUS status; ULONG i; ULONG stringLength; ULONG bytesRequired;
//
// NumberPdos
//
dataLength = sizeof(ULONG);
if (diskExtension->HasName == FALSE) { //
// Get the name of the first PortPdo - being as it's
// the same device, the name remains the same for all.
//
status = IoGetDeviceProperty(targetInfo->PortPdo, DevicePropertyFriendlyName, diskExtension->PdoName.MaximumLength, diskExtension->PdoName.Buffer, &bytesRequired); if (status == STATUS_SUCCESS) { MPDebugPrint((0, "GetDescriptor: size of name is (%x)\n", bytesRequired)); //
// The buffer is NULL terminated. Reduce it.
//
bytesRequired -= sizeof(UNICODE_NULL);
stringLength = sizeof(USHORT); stringLength += bytesRequired; diskExtension->HasName = TRUE; //
// Align the buffer size.
//
if (stringLength & 3) { MPDebugPrint((0, "GetDescriptor: Need to align (%x\n", stringLength));
stringLength += sizeof(ULONG); stringLength &= ~(sizeof(ULONG) -1); } MPDebugPrint((0, "GetDescriptor: size of name is now (%x). StrLeng (%x)\n", bytesRequired, stringLength));
diskExtension->PdoName.Length = (USHORT)bytesRequired;
} else { MPDebugPrint((0, "MPIOGetDescriptor: Buffer not large enough (%lu)\n", bytesRequired)); } } else { stringLength = sizeof(USHORT); stringLength += diskExtension->PdoName.Length; if (stringLength & 3) { stringLength += sizeof(ULONG); stringLength &= ~(sizeof(ULONG) -1); } }
//
// Length of the string + the size field.
//
dataLength += stringLength;
for (i = 0; i < diskExtension->DsmIdList.Count; i++) {
//
// Length of the scsi address.
//
dataLength += sizeof(SCSI_ADDR);
//
// Path Identifier.
//
dataLength += sizeof(LONGLONG);
//
// Controller ID.
//
dataLength += sizeof(ULONGLONG); if (dataLength & 7) { dataLength += sizeof(LONGLONG); dataLength &= ~(sizeof(LONGLONG) - 1); }
//
// Get the next targetInfo.
//
targetInfo++; }
MPDebugPrint((0, "GetDescriptor: Total Length (%x)\n", dataLength));
return dataLength; }
NTSTATUS MPIOBuildDescriptor( IN PDEVICE_OBJECT DeviceObject, IN PUCHAR Buffer ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PREAL_DEV_INFO targetInfo = diskExtension->TargetInfo; PMPIO_GET_DESCRIPTOR descriptor = (PMPIO_GET_DESCRIPTOR)Buffer; NTSTATUS status; PUCHAR buffer; ULONG i; PSCSI_ADDR scsiAddress;
descriptor->NumberPdos = diskExtension->DsmIdList.Count; buffer = Buffer; buffer += sizeof(ULONG);
//
// Set the string length.
//
*((PUSHORT)buffer) = diskExtension->PdoName.Length; buffer += sizeof(USHORT);
//
// Copy it over.
//
RtlCopyMemory(buffer, diskExtension->PdoName.Buffer, diskExtension->PdoName.Length);
//
// Push it to the end of the string.
//
buffer += diskExtension->PdoName.Length;
//
// ULONG align.
//
if ((ULONG_PTR)buffer & 3) {
(ULONG_PTR)buffer += sizeof(ULONG); (ULONG_PTR)buffer &= ~(sizeof(ULONG) - 1); } for (i = 0; i < diskExtension->DsmIdList.Count; i++) {
scsiAddress = (PSCSI_ADDR)buffer; scsiAddress->PortNumber = targetInfo->ScsiAddress.PortNumber; scsiAddress->ScsiPathId = targetInfo->ScsiAddress.PathId; scsiAddress->TargetId = targetInfo->ScsiAddress.TargetId; scsiAddress->Lun = targetInfo->ScsiAddress.Lun;
buffer += sizeof(SCSI_ADDR);
if (targetInfo->PathUIDValue == FALSE) { targetInfo->Identifier = MPIOCreateUID(diskExtension->ControlObject, targetInfo->PathId); ASSERT(targetInfo->Identifier != 0); targetInfo->PathUIDValue = TRUE; }
//
// Align the buffer
//
if ((ULONG_PTR)buffer & 7) { (ULONG_PTR)buffer += sizeof(LONGLONG); (ULONG_PTR)buffer &= ~(sizeof(LONGLONG) - 1); } *((PLONGLONG)buffer) = targetInfo->Identifier; buffer += sizeof(LONGLONG);
//
// Get the controllerID.
//
*((PULONGLONG)buffer) = targetInfo->ControllerId; buffer += sizeof(ULONGLONG);
//
// Handle the next device.
//
targetInfo++; } return STATUS_SUCCESS; }
NTSTATUS MPIOPdoQueryDataBlock( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG InstanceCount, IN OUT PULONG InstanceLengthArray, IN ULONG BufferAvailable, OUT PUCHAR Buffer ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PDSM_ENTRY dsm = &diskExtension->DsmInfo; NTSTATUS status; ULONG dataLength; switch(GuidIndex) { case MPIO_GET_DESCRIPTORGuidIndex: {
dataLength = MPIOGetDescriptorSize(DeviceObject); if (dataLength > BufferAvailable) { status = STATUS_BUFFER_TOO_SMALL; } else { RtlZeroMemory(Buffer, dataLength); status = MPIOBuildDescriptor(DeviceObject, Buffer); *InstanceLengthArray = dataLength; status = STATUS_SUCCESS; } break; }
case BinaryMofGuidIndex: { //
// TODO: If the driver supports reporting MOF dynamically,
// change this code to handle multiple instances of the
// binary mof guid and return only those instances that
// should be reported to the schema
//
dataLength = sizeof(PdoBinaryMofData);
if (BufferAvailable < dataLength) { status = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory(Buffer, PdoBinaryMofData, dataLength); *InstanceLengthArray = dataLength; status = STATUS_SUCCESS; } break; }
default: { status = STATUS_WMI_GUID_NOT_FOUND; break; } }
//
// Complete the request.
//
status = WmiCompleteRequest(DeviceObject, Irp, status, dataLength, IO_NO_INCREMENT); return status; }
NTSTATUS MPIOGetDiskDescriptorSize( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; ULONG dataLength; NTSTATUS status; ULONG i;
//
// Length is ULONG (NumberDisks) + sizeof(MPDISK_DESCRIPTOR)
//
dataLength = sizeof(ULONG);
//
// For the string length field.
//
dataLength += sizeof(USHORT); //
// Length of the product/vendor/rev string
// (8 + 16+ 4 + 2 (spaces between vendor/product/rev) + 1 (trailing NULL)) * sizeof(WCHAR)
//
dataLength += 0x3C;
//
// Ensure that the start of each array entry is ULONG aligned.
//
dataLength += sizeof(ULONG); dataLength &= ~(sizeof(ULONG) - 1);
for (i = 0; i < diskExtension->DsmIdList.Count; i++) {
//
// SCSI_ADDR (almost like SCSI_ADDRESS, but without the length field)
//
dataLength += sizeof(SCSI_ADDR); } return dataLength; }
NTSTATUS MPIOGetDiskDescriptor( IN PDEVICE_OBJECT DeviceObject, IN PUCHAR Buffer, IN ULONG BufferLength )
{ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PUCHAR buffer = Buffer; PREAL_DEV_INFO targetInfo; PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor; PUCHAR inquiryField; PUCHAR index; UCHAR inquiryData[32]; ANSI_STRING ansiInquiry; UNICODE_STRING unicodeString; PSCSI_ADDR scsiAddress; ULONG i; NTSTATUS status;
RtlZeroMemory(Buffer, BufferLength);
*((PULONG)buffer) = diskExtension->DsmIdList.Count; targetInfo = diskExtension->TargetInfo;
//
// Set the number of drives underlying this mpdisk.
//
(ULONG_PTR)buffer += sizeof(ULONG);
//
// Preload the inquiry buffer with spaces and a null-terminator.
//
for (i = 0; i < 32; i++) { inquiryData[i] = ' '; } inquiryData[30] = '\0'; inquiryData[31] = '\0'; //
// Merge the ascii inquiry data into one long string.
//
deviceDescriptor = diskExtension->DeviceDescriptor; inquiryField = (PUCHAR)deviceDescriptor; (ULONG_PTR)inquiryField += deviceDescriptor->VendorIdOffset; index = inquiryData;
//
// Copy the vendorId.
//
RtlCopyMemory(index, inquiryField, 8);
//
// Account for vendorId + a space.
//
index += 9; inquiryField = (PUCHAR)deviceDescriptor; (ULONG_PTR)inquiryField += deviceDescriptor->ProductIdOffset; //
// Copy ProductId.
//
RtlCopyMemory(index, inquiryField, 16);
//
// Account for product + space.
//
index += 17;
inquiryField = (PUCHAR)deviceDescriptor; (ULONG_PTR)inquiryField += deviceDescriptor->ProductRevisionOffset; RtlCopyMemory(index, inquiryField, 4); //
// Convert to WCHAR.
//
RtlInitAnsiString(&ansiInquiry, inquiryData); RtlAnsiStringToUnicodeString(&unicodeString, &ansiInquiry, TRUE);
//
// Build the name string. First is the length.
//
// BUGBUG: Note the hack of +2
//
*((PUSHORT)buffer) = unicodeString.Length + 2; (ULONG_PTR)buffer += sizeof(USHORT);
//
// Copy the serialNumber.
//
RtlCopyMemory(buffer, unicodeString.Buffer, unicodeString.Length); //
// Advance the pointer past the inquiry string.
//
(ULONG_PTR)buffer += unicodeString.Length; RtlFreeUnicodeString(&unicodeString);
//
// ULONG align it.
//
(ULONG_PTR)buffer += sizeof(ULONG); (ULONG_PTR)buffer &= ~(sizeof(ULONG) - 1); for (i = 0; i < diskExtension->DsmIdList.Count; i++) { scsiAddress = (PSCSI_ADDR)buffer;
scsiAddress->PortNumber = targetInfo->ScsiAddress.PortNumber; scsiAddress->ScsiPathId = targetInfo->ScsiAddress.PathId; scsiAddress->TargetId = targetInfo->ScsiAddress.TargetId; scsiAddress->Lun = targetInfo->ScsiAddress.Lun; targetInfo++;
(ULONG_PTR)buffer += sizeof(SCSI_ADDR); #if 0
//
// Fake the WWN.
// TODO get the real stuff.
//
*((PLONGLONG)buffer) = 0;
(ULONG_PTR)buffer += sizeof(LONGLONG); #endif
} return STATUS_SUCCESS; }
NTSTATUS MPIOExecuteMethod( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN ULONG InstanceIndex, IN ULONG MethodId, IN ULONG InBufferSize, IN ULONG OutBufferSize, IN PUCHAR Buffer ) /*++
Routine Description: Arguments: 'aReturn Value:
status
--*/ { ULONG dataLength = 0; ULONG ordinal; PDISK_ENTRY diskEntry; NTSTATUS status;
switch(GuidIndex) { #if 0
case MPIO_GET_DESCRIPTORSGuidIndex: { switch(MethodId) { case MPIOGetMPIODiskDescriptor: { //
// Check the input buffer size.
//
if (InBufferSize != sizeof(ULONG)) { status = STATUS_INVALID_PARAMETER; dataLength = 0; break; }
//
// The input buffer is the ordinal of the device in which
// the caller has interest.
//
ordinal = *((PULONG)Buffer);
//
// Ensure that ordinal is with-in range.
// TODO
diskEntry = MPIOGetDiskEntry(DeviceObject, ordinal); //
// Get the size of the return info.
//
dataLength = MPIOGetDiskDescriptorSize(diskEntry->PdoObject);
if (dataLength > OutBufferSize) {
status = STATUS_BUFFER_TOO_SMALL; break; } //
//
status = MPIOGetDiskDescriptor(diskEntry->PdoObject, Buffer, OutBufferSize);
break; }
default: { status = STATUS_WMI_ITEMID_NOT_FOUND; break; } } break; } #endif
default: { status = STATUS_WMI_GUID_NOT_FOUND; } }
status = WmiCompleteRequest(DeviceObject, Irp, status, dataLength, IO_NO_INCREMENT);
return(status); }
NTSTATUS MPIOPdoWmiControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN WMIENABLEDISABLECONTROL Function, IN BOOLEAN Enable ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; NTSTATUS status;
switch (GuidIndex) { case MPIO_EventEntryGuidIndex: if (Enable) {
//
// Indicate that it's OK to fire the Log event.
//
deviceExtension->FireLogEvent = TRUE; } else {
//
// Turn off firing the logger.
//
deviceExtension->FireLogEvent = FALSE; } MPDebugPrint((0, "MPIOWmiControl: Turning the Logger (%s) on (%x)\n", Enable ? "ON" : "OFF", DeviceObject)); break; default: status = STATUS_WMI_GUID_NOT_FOUND; break; }
status = WmiCompleteRequest(DeviceObject, Irp, status, 0, IO_NO_INCREMENT); return status; }
VOID MPIOSetupWmi( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension; PWMILIB_CONTEXT wmiLibContext = &deviceExtension->WmiLib; NTSTATUS status; PDSM_ENTRY dsm; PDSM_WMILIB_CONTEXT wmiContext; ULONG guids; ULONG guidListSize; PUCHAR index;
//
// This simply jams in all the fields of the wmilib context for
// use by WmiSystemControl.
//
if (deviceExtension->Type == MPIO_MPDISK) {
//
// TODO: Revisit piggybacking off of the PDO. It may be
// better to use the FDO.
//
diskExtension = deviceExtension->TypeExtension; dsm = &diskExtension->DsmInfo; //
// Get the DSM's Wmi Info and append it to ours.
//
//wmiContext = &dsm->WmiContext;
//
// Currently, there are no PDO associated GUIDs. As soon as they are in place
// this needs to be updated accordingly.
//
#if 0
guids = wmiContext->GuidCount + MPIO_PDO_GUID_COUNT; guidListSize = sizeof(MPIOPdoGuidList) + sizeof(wmiContext->GuidList); guidListSize = sizeof(wmiContext->GuidList); deviceExtension->WmiLib.GuidList = ExAllocatePool(NonPagedPool,guidListSize); RtlZeroMemory(deviceExtension->WmiLib.GuidList, guidListSize);
//
// Copy over the pdo's list.
//
index = (PUCHAR)deviceExtension->WmiLib.GuidList; RtlCopyMemory(index, MPIOPdoGuidList, sizeof(MPIOPdoGuidList)); index += sizeof(MPIOPdoGuidList);
wmiLibContext->GuidCount = guids;
//
// copy over the DSM's.
//
RtlCopyMemory(index, wmiContext->GuidList, sizeof(wmiContext->GuidList)); #endif
wmiLibContext->GuidCount = PdowmiGuidCount; wmiLibContext->GuidList = PdowmiGuidList; wmiLibContext->QueryWmiRegInfo = MPIOQueryRegInfo; wmiLibContext->QueryWmiDataBlock = MPIOPdoQueryDataBlock; //wmiLibContext->SetWmiDataBlock = MPIOPdoSetDataBlock;
//wmiLibContext->SetWmiDataItem = MPIOPdoSetDataItem;
//wmiLibContext->ExecuteWmiMethod = MPIOPdoExecuteMethod;
//wmiLibContext->WmiFunctionControl = MPIOPdoWmiControl;
} else { wmiLibContext->GuidCount = MPIO_GUID_COUNT; wmiLibContext->GuidList = MPIOWmiGuidList; wmiLibContext->QueryWmiRegInfo = MPIOQueryRegInfo; wmiLibContext->QueryWmiDataBlock = MPIOQueryDataBlock; //wmiLibContext->SetWmiDataBlock = MPIOSetDataBlock;
//wmiLibContext->SetWmiDataItem = MPIOSetDataItem;
wmiLibContext->ExecuteWmiMethod = MPIOExecuteMethod; wmiLibContext->WmiFunctionControl = MPIOWmiControl;
}
return; }
NTSTATUS MPIOPdoWmi( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) {
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); SYSCTL_IRP_DISPOSITION disposition; NTSTATUS status;
//
// Using the WMI Library, so call it with the request.
// This will call the appropriate DpWmi function.
//
status = WmiSystemControl(&deviceExtension->WmiLib, DeviceObject, Irp, &disposition);
switch (disposition) { case IrpProcessed: //
// Already handled by one of the DpWmi call-backs.
//
break; case IrpNotCompleted:
//
// Probably an error, or the IRP_MN_REGINFO
//
MPDebugPrint((0, "MPIOrPdoWmi: Irp (%x) Mn (%x) Status (%x)\n", Irp, irpStack->MinorFunction, status)); IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IrpNotWmi: case IrpForward: default: //
// Forward this irp.
//
status = MPIOForwardRequest(DeviceObject, Irp); break; } return status; }
NTSTATUS MPIOFdoWmi( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); SYSCTL_IRP_DISPOSITION disposition; NTSTATUS status;
//
// Using the WMI Library, so call it with the request.
// This will call the appropriate DpWmi function.
//
status = WmiSystemControl(&deviceExtension->WmiLib, DeviceObject, Irp, &disposition);
switch (disposition) { case IrpProcessed: //
// Already handled by one of the DpWmi call-backs.
//
break; case IrpNotCompleted:
//
// Probably an error, or the IRP_MN_REGINFO
//
MPDebugPrint((0, "MPIOFdoWmi: Irp (%x) Mn (%x) Status (%x)\n", Irp, irpStack->MinorFunction, status)); IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IrpNotWmi: case IrpForward: default: //
// Forward this irp.
//
status = MPIOForwardRequest(DeviceObject, Irp); break; } return status;
}
NTSTATUS MPIOFireEvent( IN PDEVICE_OBJECT DeviceObject, IN PWCHAR ComponentName, IN PWCHAR EventDescription, IN ULONG Severity ) { PMPIO_EventEntry eventEntry; ULONG dataLength; PWCHAR nameString; LARGE_INTEGER systemTime; NTSTATUS status; USHORT componentLength; USHORT eventLength; PUCHAR index;
//
// Determine the total allocation length based on the
// structure and string lengths.
//
componentLength = wcslen(ComponentName) * sizeof(WCHAR); componentLength += sizeof(UNICODE_NULL); eventLength = wcslen(EventDescription) * sizeof(WCHAR); eventLength += sizeof(UNICODE_NULL);
if ((componentLength > MPIO_STRING_LENGTH) || (eventLength > MPIO_STRING_LENGTH)) { return STATUS_INVALID_PARAMETER; }
dataLength = sizeof(MPIO_EventEntry);
//
// Allocate the EventData.
//
eventEntry = ExAllocatePool(NonPagedPool, dataLength); if (eventEntry == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(eventEntry, dataLength);
//
// Set the severity of the event.
//
eventEntry->Severity = Severity; KeQuerySystemTime(&systemTime); eventEntry->TimeStamp = systemTime.QuadPart;
//
// Copy the Component Name.
//
nameString = eventEntry->Component; *((PUSHORT)nameString) = componentLength; nameString++; wcscpy(nameString, ComponentName);
MPDebugPrint((0, "NameString (%x). Length (%d)\n", nameString, componentLength));
//
// Copy over the Object name.
//
nameString = eventEntry->EventDescription; *((PUSHORT)nameString) = eventLength; nameString++; wcscpy(nameString, EventDescription);
//
// Send the event.
//
status = WmiFireEvent(DeviceObject, &MPIO_EventEntryGUID, 0, dataLength, eventEntry); if (status != STATUS_SUCCESS) { MPDebugPrint((0, "MPIOFireEvent: Status (%x)\n", status));
//
// TODO: Queue these for when we get the Enable request.
//
ExFreePool(eventEntry); } return status; }
|