windows-nt/Source/XPSP1/NT/drivers/storage/mpath/control/mpiowmi.c

1698 lines
45 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#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;
}