910 lines
24 KiB
C
910 lines
24 KiB
C
#include "mpio.h"
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MPIOQueryDeviceText(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles the QUERY_DEVICE_TEXT Irp for
|
||
Pseudo disks.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
|
||
PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
|
||
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
||
UCHAR ansiBuffer[256];
|
||
ANSI_STRING ansiString;
|
||
UNICODE_STRING unicodeString;
|
||
PUCHAR index;
|
||
PUCHAR inquiryField;
|
||
|
||
//
|
||
// Get the Storage Descriptor from the type extension.
|
||
//
|
||
deviceDescriptor = diskExtension->DeviceDescriptor;
|
||
|
||
//
|
||
// Set the inquiry data pointer to the front of the descriptor.
|
||
//
|
||
inquiryField = (PUCHAR)deviceDescriptor;
|
||
|
||
//
|
||
// Zero the string array.
|
||
//
|
||
RtlZeroMemory(ansiBuffer, sizeof(ansiBuffer));
|
||
|
||
switch (irpStack->Parameters.QueryDeviceText.DeviceTextType) {
|
||
case DeviceTextDescription:
|
||
|
||
//
|
||
// Build <Product><Vendor><"Multi-Path Disk Device">.
|
||
//
|
||
// Push the inquiry pointer to the VendorId.
|
||
//
|
||
(ULONG_PTR)inquiryField += deviceDescriptor->VendorIdOffset;
|
||
|
||
//
|
||
// Copy the VendorId to the temp. buffer, and adjust indices.
|
||
//
|
||
index = ansiBuffer;
|
||
RtlCopyMemory(index, inquiryField, 8);
|
||
index += 7;
|
||
|
||
//
|
||
// go back and eat all the spaces except for one.
|
||
//
|
||
while (*index == ' ') {
|
||
*index = '\0';
|
||
index--;
|
||
}
|
||
index++;
|
||
*index = ' ';
|
||
index++;
|
||
|
||
//
|
||
// Handle the ProductID.
|
||
//
|
||
inquiryField = (PUCHAR)deviceDescriptor;
|
||
(ULONG_PTR)inquiryField += deviceDescriptor->ProductIdOffset;
|
||
RtlCopyMemory(index, inquiryField, 16);
|
||
index += 15;
|
||
|
||
//
|
||
// go back and eat all the spaces except for one.
|
||
//
|
||
while (*index == ' ') {
|
||
*index = '\0';
|
||
index--;
|
||
}
|
||
index++;
|
||
*index = ' ';
|
||
index++;
|
||
|
||
//
|
||
// Don't use rev or serial number (at least for now)
|
||
// TODO: remove or reenable.
|
||
//
|
||
//inquiryField = (PUCHAR)deviceDescriptor;
|
||
//(ULONG_PTR)inquiryField += deviceDescriptor->ProductRevisionOffset;
|
||
//RtlCopyMemory(index, inquiryField, 4);
|
||
//index += 4;
|
||
|
||
//
|
||
// Append this to the end to distinquish this from the regular scsi drive.
|
||
//
|
||
sprintf(index, "%s", " Multi-Path Disk Device");
|
||
|
||
//
|
||
// The real wchar buffer is built below.
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case DeviceTextLocationInformation: {
|
||
PSCSI_ADDRESS scsiAddress = NULL;
|
||
ULONG i;
|
||
PUCHAR index;
|
||
UCHAR groupString[25];
|
||
|
||
//
|
||
// Build the group string. Each value in it is the port number of the
|
||
// device backing the pseudo disk.
|
||
// Adapters(X,Y)
|
||
//
|
||
RtlZeroMemory(groupString, sizeof(groupString));
|
||
sprintf(groupString, "%s", "Port(");
|
||
index = groupString;
|
||
index += strlen(groupString);
|
||
|
||
for (i = 0; i < diskExtension->TargetInfoCount; i++) {
|
||
|
||
//
|
||
// Get the SCSI Address for this scsiport PDO
|
||
//
|
||
status = MPIOGetScsiAddress(diskExtension->TargetInfo[i].PortPdo,
|
||
&scsiAddress);
|
||
|
||
diskExtension->TargetInfo[i].ScsiAddress.PortNumber = scsiAddress->PortNumber;
|
||
diskExtension->TargetInfo[i].ScsiAddress.PathId = scsiAddress->PathId;
|
||
diskExtension->TargetInfo[i].ScsiAddress.TargetId = scsiAddress->TargetId;
|
||
diskExtension->TargetInfo[i].ScsiAddress.Lun = scsiAddress->Lun;
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Jam in the PortNumber for this device.
|
||
//
|
||
sprintf(index, "%d", scsiAddress->PortNumber);
|
||
index += strlen(index);
|
||
|
||
if ((i + 1) == diskExtension->TargetInfoCount) {
|
||
|
||
//
|
||
// Last one, finish off with the closing bracket.
|
||
//
|
||
sprintf(index,"%s", ")");
|
||
|
||
} else {
|
||
|
||
//
|
||
// Stick a comma in between each of the port
|
||
// numbers.
|
||
//
|
||
sprintf(index,"%s", ",");
|
||
index += strlen(index);
|
||
|
||
//
|
||
// Free the buffer that GetScsiAddress allocated.
|
||
//
|
||
ExFreePool(scsiAddress);
|
||
scsiAddress = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Free the last one.
|
||
//
|
||
if (scsiAddress) {
|
||
|
||
// NOTE: This was above the 'if'. TODO validate and remove this comment.
|
||
//
|
||
// The last scsiAddress buffer was not freed yet.
|
||
// Add in Bus Target Lun based on this Scsi Address.
|
||
//
|
||
sprintf(ansiBuffer, "%s Bus %d, Target ID %d, LUN %d",
|
||
groupString,
|
||
scsiAddress->PathId,
|
||
scsiAddress->TargetId,
|
||
scsiAddress->Lun);
|
||
|
||
ExFreePool(scsiAddress);
|
||
}
|
||
break;
|
||
}
|
||
|
||
default:
|
||
status = STATUS_NOT_SUPPORTED;
|
||
Irp->IoStatus.Information = (ULONG_PTR)NULL;
|
||
break;
|
||
}
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Finally, build the unicode string based on whatever text
|
||
// was built above.
|
||
//
|
||
RtlInitAnsiString(&ansiString, ansiBuffer);
|
||
status = RtlAnsiStringToUnicodeString(&unicodeString,
|
||
&ansiString,
|
||
TRUE);
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
Irp->IoStatus.Information = (ULONG_PTR)unicodeString.Buffer;
|
||
}
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPIOPdoQdr(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles QueryDeviceRelations requests sent to the PDO (PseudoDisks).
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PDEVICE_RELATIONS deviceRelations;
|
||
NTSTATUS status = Irp->IoStatus.Status;
|
||
|
||
if (irpStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation) {
|
||
|
||
//
|
||
// Allocate the return buffer.
|
||
//
|
||
deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
||
if (deviceRelations == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
} else {
|
||
status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Indicate, of course, there is One, and it's us.
|
||
//
|
||
deviceRelations->Count = 1;
|
||
deviceRelations->Objects[0] = DeviceObject;
|
||
|
||
//
|
||
// Reference our devObj so that it's not removed.
|
||
// PnP will deref it when it's finished with the request.
|
||
//
|
||
ObReferenceObject(DeviceObject);
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPIOHardwareIDs(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
OUT PUNICODE_STRING UnicodeString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles QueryHardwareId requests sent to the PDO (PseudoDisks).
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
|
||
NTSTATUS status;
|
||
PUCHAR inquiryField;
|
||
PUCHAR index;
|
||
ULONG bufferLength;
|
||
ULONG i;
|
||
ANSI_STRING ansiString;
|
||
UNICODE_STRING unicodeEntry;
|
||
PSTR hwStrings[7];
|
||
UCHAR hwId[64];
|
||
UCHAR inquiryData[32];
|
||
UCHAR savedInquiryData[32];
|
||
|
||
|
||
deviceDescriptor = diskExtension->DeviceDescriptor;
|
||
inquiryField = (PUCHAR)deviceDescriptor;
|
||
|
||
//
|
||
// Zero the string array.
|
||
//
|
||
RtlZeroMemory(hwStrings, sizeof(hwStrings));
|
||
RtlZeroMemory(inquiryData, sizeof(inquiryData));
|
||
|
||
//
|
||
// Build the full inquiry data for the device.
|
||
// Go through each of the fields in raw data and get
|
||
// their offsets. Copy the fields into the buffer.
|
||
//
|
||
(ULONG_PTR)inquiryField += deviceDescriptor->VendorIdOffset;
|
||
index = inquiryData;
|
||
RtlCopyMemory(index, inquiryField, 8);
|
||
index += 8;
|
||
|
||
inquiryField = (PUCHAR)deviceDescriptor;
|
||
(ULONG_PTR)inquiryField += deviceDescriptor->ProductIdOffset;
|
||
RtlCopyMemory(index, inquiryField, 16);
|
||
index += 16;
|
||
|
||
inquiryField = (PUCHAR)deviceDescriptor;
|
||
(ULONG_PTR)inquiryField += deviceDescriptor->ProductRevisionOffset;
|
||
RtlCopyMemory(index, inquiryField, 4);
|
||
|
||
//
|
||
// Run through and fixup spaces.
|
||
//
|
||
index = inquiryData;
|
||
while (*index != '\0') {
|
||
if (*index == ' ') {
|
||
*index = '_';
|
||
}
|
||
index++;
|
||
}
|
||
|
||
//
|
||
// Copy this to the saved buffer.
|
||
// This is used below while building up each of the HW ID strings.
|
||
//
|
||
RtlCopyMemory(savedInquiryData, inquiryData, 32);
|
||
|
||
for (i = 0; i < 6; i++) {
|
||
|
||
//
|
||
// Zero the buffer
|
||
//
|
||
RtlZeroMemory(hwId, sizeof(hwId));
|
||
|
||
//
|
||
// Each time through the loop, build one of the hardware id strings.
|
||
//
|
||
// (0) SCSI\DISK\Full Inquiry
|
||
// (1) SCSI\Disk\Inquiry - Rev
|
||
// (2) SCSI\Disk\Inquiry - Product and rev.
|
||
// (3) SCSI\Inquiry with only one char of rev.
|
||
// (4) Inquiry with only one char of rev.
|
||
// (5) GenDisk
|
||
//
|
||
switch (i) {
|
||
case 0:
|
||
|
||
//
|
||
// Build the header (SCSI\Disk) plus the full inquiry data
|
||
//
|
||
sprintf(hwId, "%s", "MPIO\\Disk");
|
||
index = hwId;
|
||
index += strlen(hwId);
|
||
RtlMoveMemory(index, inquiryData, strlen(inquiryData));
|
||
|
||
break;
|
||
|
||
case 1:
|
||
|
||
//
|
||
// Get rid of the product revision in the inquiryData.
|
||
//
|
||
index = inquiryData + 24;
|
||
*index = '\0';
|
||
|
||
sprintf(hwId, "%s", "MPIO\\Disk");
|
||
index = hwId;
|
||
index += strlen(hwId);
|
||
RtlMoveMemory(index, inquiryData, strlen(inquiryData));
|
||
break;
|
||
|
||
case 2:
|
||
|
||
//
|
||
// Get rid of the product id.
|
||
//
|
||
index = inquiryData + 8;
|
||
*index = '\0';
|
||
|
||
sprintf(hwId, "%s", "MPIO\\Disk");
|
||
index = hwId;
|
||
index += strlen(hwId);
|
||
RtlMoveMemory(index, inquiryData, strlen(inquiryData));
|
||
break;
|
||
|
||
case 3:
|
||
|
||
//
|
||
// Remake inquiryData.
|
||
//
|
||
RtlCopyMemory(inquiryData, savedInquiryData, 32);
|
||
|
||
//
|
||
// Need to strip off all but the first character of revision.
|
||
//
|
||
inquiryData[25] = '\0';
|
||
|
||
sprintf(hwId, "%s", "MPIO\\");
|
||
index = hwId;
|
||
index += strlen(hwId);
|
||
RtlMoveMemory(index, inquiryData, strlen(inquiryData));
|
||
|
||
break;
|
||
case 4:
|
||
|
||
//
|
||
// This is like 3, but no SCSI\ in front.
|
||
//
|
||
sprintf(hwId, "%s", inquiryData);
|
||
break;
|
||
case 5:
|
||
|
||
//
|
||
// Only the GenDisk
|
||
//
|
||
sprintf(hwId, "%s", "GenDisk");
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Allocate and build the hwString entry.
|
||
//
|
||
hwStrings[i] = ExAllocatePool(PagedPool, strlen(hwId) + sizeof(UCHAR));
|
||
if (hwStrings == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(hwStrings[i], strlen(hwId) + sizeof(UCHAR));
|
||
RtlCopyMemory(hwStrings[i], hwId, strlen(hwId));
|
||
|
||
MPDebugPrint((2,
|
||
"MPathHwIds: Hw String[%x] - %s\n",
|
||
i,
|
||
hwStrings[i]));
|
||
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Convert the hwString entry into the unicode version that the caller wants.
|
||
//
|
||
for (i = 0, bufferLength = 0; i < 6; i++) {
|
||
bufferLength += strlen(hwStrings[i]) * sizeof(WCHAR);
|
||
|
||
//
|
||
// Make room for the NULL after the string.
|
||
//
|
||
bufferLength += sizeof(UNICODE_NULL);
|
||
}
|
||
|
||
UnicodeString->Length = (USHORT)bufferLength;
|
||
|
||
//
|
||
// Add room for the final terminating NULL
|
||
//
|
||
bufferLength += sizeof(UNICODE_NULL);
|
||
|
||
//
|
||
// Allocate the buffer.
|
||
//
|
||
UnicodeString->Buffer = ExAllocatePool(PagedPool, bufferLength);
|
||
if (UnicodeString->Buffer) {
|
||
|
||
RtlZeroMemory(UnicodeString->Buffer, bufferLength);
|
||
UnicodeString->MaximumLength = (USHORT)bufferLength;
|
||
|
||
unicodeEntry = *UnicodeString;
|
||
|
||
for (i = 0; i < 6; i++) {
|
||
|
||
//
|
||
// Convert ascii to ansi.
|
||
//
|
||
RtlInitAnsiString(&ansiString, hwStrings[i]);
|
||
status = RtlAnsiStringToUnicodeString(&unicodeEntry,
|
||
&ansiString,
|
||
FALSE);
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// update the unicode fields.
|
||
//
|
||
((PSTR)unicodeEntry.Buffer) += unicodeEntry.Length + sizeof(WCHAR);
|
||
unicodeEntry.MaximumLength -= unicodeEntry.Length + sizeof(WCHAR);
|
||
|
||
}
|
||
|
||
} else {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPIODeviceId(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN OUT PUNICODE_STRING UnicodeString
|
||
)
|
||
//
|
||
// Need to build up a name like MPATH#<DevType>&VenXXX&ProdXXX&RevXXX
|
||
//
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
|
||
PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
|
||
ANSI_STRING ansiIdString;
|
||
CHAR deviceStrings[4][255];
|
||
UCHAR deviceId[256];
|
||
PUCHAR scsiField;
|
||
PUCHAR currentId;
|
||
NTSTATUS status;
|
||
ULONG i;
|
||
ULONG deviceIndex = 0;
|
||
|
||
RtlZeroMemory(deviceId, 256);
|
||
currentId = deviceId;
|
||
deviceDescriptor = diskExtension->DeviceDescriptor;
|
||
scsiField = (PUCHAR)deviceDescriptor;
|
||
|
||
//
|
||
// Preload the deviceId with MPIO\<deviceType>
|
||
//
|
||
sprintf(currentId, "%s", "MPIO\\Disk&Ven_");
|
||
|
||
//
|
||
// Push the current pointer past the above field.
|
||
//
|
||
currentId += strlen(currentId);
|
||
|
||
//
|
||
// Push the scsiField pointer to that of the vendor id.
|
||
//
|
||
ASSERT(deviceDescriptor->VendorIdOffset != 0);
|
||
ASSERT(deviceDescriptor->ProductIdOffset != 0);
|
||
ASSERT(deviceDescriptor->ProductRevisionOffset != 0);
|
||
|
||
(ULONG_PTR)scsiField += deviceDescriptor->VendorIdOffset;
|
||
|
||
//
|
||
// Copy in the Vendor name.
|
||
//
|
||
for (i = 0; i < VENDOR_ID_LENGTH; i++) {
|
||
*currentId = *scsiField;
|
||
currentId++;
|
||
scsiField++;
|
||
}
|
||
*currentId = '\0';
|
||
currentId++;
|
||
|
||
//
|
||
// Bump the scsiField to that of the product id.
|
||
//
|
||
scsiField = (PUCHAR)deviceDescriptor;
|
||
(ULONG_PTR)scsiField += deviceDescriptor->ProductIdOffset;
|
||
|
||
//
|
||
// Remove any trailing spaces
|
||
//
|
||
while (*currentId == ' ' || *currentId == '\0') {
|
||
currentId--;
|
||
}
|
||
currentId++;
|
||
|
||
//
|
||
// Jam in &Prod
|
||
//
|
||
sprintf(currentId, "%s", "&Prod_");
|
||
currentId += strlen(currentId);
|
||
|
||
//
|
||
// Copy in the Product Id.
|
||
//
|
||
for (i = 0; i < PRODUCT_ID_LENGTH; i++) {
|
||
*currentId = *scsiField;
|
||
currentId++;
|
||
scsiField++;
|
||
}
|
||
|
||
*currentId = '\0';
|
||
currentId++;
|
||
|
||
//
|
||
// Remove any trailing spaces
|
||
//
|
||
while (*currentId == ' ' || *currentId == '\0') {
|
||
currentId--;
|
||
}
|
||
currentId++;
|
||
|
||
//
|
||
// Handle the revision.
|
||
//
|
||
scsiField = (PUCHAR)deviceDescriptor;
|
||
(ULONG_PTR)scsiField += deviceDescriptor->ProductRevisionOffset;
|
||
|
||
sprintf(currentId, "%s", "&Rev_");
|
||
currentId += strlen(currentId);
|
||
|
||
for (i = 0; i < REVISION_LENGTH; i++) {
|
||
*currentId = *scsiField;
|
||
currentId++;
|
||
scsiField++;
|
||
}
|
||
*currentId = '\0';
|
||
currentId++;
|
||
|
||
|
||
//
|
||
// Remove any trailing spaces
|
||
//
|
||
while (*currentId == ' ' || *currentId == '\0') {
|
||
currentId--;
|
||
}
|
||
|
||
//
|
||
// Run through and fixup spaces.
|
||
//
|
||
currentId = deviceId;
|
||
while (*currentId != '\0') {
|
||
if (*currentId == ' ') {
|
||
*currentId = '_';
|
||
}
|
||
currentId++;
|
||
}
|
||
|
||
MPDebugPrint((2,
|
||
"MPathDeviceId - %s\n",
|
||
deviceId));
|
||
|
||
//
|
||
// Finally make the unicode string that will be returned to PnP.
|
||
//
|
||
RtlInitAnsiString(&ansiIdString,deviceId);
|
||
|
||
status = RtlAnsiStringToUnicodeString(UnicodeString,
|
||
&ansiIdString,
|
||
TRUE);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MPIOPdoQueryId(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles QueryId requests sent to the PDO (PseudoDisks).
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status;
|
||
UNICODE_STRING unicodeID;
|
||
UNICODE_STRING unicodeString;
|
||
ANSI_STRING ansiString;
|
||
UNICODE_STRING unicodeIndex;
|
||
ULONG bufferLength = 0;
|
||
UCHAR deviceId[256];
|
||
|
||
RtlZeroMemory(deviceId, 256);
|
||
|
||
switch (irpStack->Parameters.QueryId.IdType) {
|
||
case BusQueryHardwareIDs: {
|
||
|
||
status = MPIOHardwareIDs(DeviceObject,
|
||
Irp,
|
||
&unicodeString);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Set the hardware ID buffer.
|
||
//
|
||
Irp->IoStatus.Information = (ULONG_PTR)unicodeString.Buffer;
|
||
}
|
||
break;
|
||
}
|
||
case BusQueryDeviceID: {
|
||
|
||
status = MPIODeviceId(DeviceObject,
|
||
Irp,
|
||
&unicodeString);
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR)unicodeString.Buffer;
|
||
}
|
||
break;
|
||
}
|
||
case BusQueryInstanceID: {
|
||
PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
|
||
ULONG serialNumberLength;
|
||
PUCHAR serialNumber;
|
||
UCHAR fakeSerialNumber[20];
|
||
ANSI_STRING ansiSerialNumber;
|
||
|
||
deviceDescriptor = diskExtension->DeviceDescriptor;
|
||
serialNumber = (PUCHAR)deviceDescriptor;
|
||
|
||
//
|
||
// If the device has no serial number, need to make something up.
|
||
// TODO
|
||
//
|
||
if (deviceDescriptor->SerialNumberOffset == (ULONG)-1) {
|
||
|
||
RtlZeroMemory(fakeSerialNumber, 20);
|
||
sprintf(fakeSerialNumber, "00%d", diskExtension->DeviceOrdinal);
|
||
serialNumber = fakeSerialNumber;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Move serialNumber to the correct position in RawData.
|
||
//
|
||
(ULONG_PTR)serialNumber += deviceDescriptor->SerialNumberOffset;
|
||
|
||
}
|
||
|
||
//
|
||
// Get it's length.
|
||
//
|
||
serialNumberLength = strlen(serialNumber);
|
||
|
||
//
|
||
// Build the ansi string based on the serial number information.
|
||
// Then convert to unicode.
|
||
//
|
||
RtlInitAnsiString(&ansiSerialNumber, serialNumber);
|
||
RtlAnsiStringToUnicodeString(&unicodeString, &ansiSerialNumber, TRUE);
|
||
|
||
status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = (ULONG_PTR)unicodeString.Buffer;
|
||
|
||
break;
|
||
}
|
||
case BusQueryCompatibleIDs: {
|
||
UNICODE_STRING unicodeString;
|
||
ULONG i;
|
||
PSTR deviceStrings[] = {"SCSI\\Disk", "SCSI\\RAW", NULL};
|
||
|
||
//
|
||
// Determine length needed for the unicode buffer.
|
||
//
|
||
for (i = 0; deviceStrings[i] != NULL; i++) {
|
||
bufferLength += strlen(deviceStrings[i]) * sizeof(WCHAR);
|
||
|
||
//
|
||
// Make room for the NULL after the string.
|
||
//
|
||
bufferLength += sizeof(UNICODE_NULL);
|
||
}
|
||
|
||
unicodeString.Length = (USHORT)bufferLength;
|
||
|
||
//
|
||
// Add room for the final terminating NULL
|
||
//
|
||
bufferLength += sizeof(UNICODE_NULL);
|
||
|
||
//
|
||
// Allocate the buffer.
|
||
//
|
||
unicodeString.Buffer = ExAllocatePool(PagedPool, bufferLength);
|
||
|
||
if (unicodeString.Buffer == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Finish initing the unicode string.
|
||
//
|
||
RtlZeroMemory(unicodeString.Buffer, bufferLength);
|
||
unicodeString.MaximumLength = (USHORT)bufferLength;
|
||
|
||
//
|
||
// Set the index string to the front of the real unicode string.
|
||
// This index will be pushed along so that the creation of the MULTI string
|
||
// can be done.
|
||
//
|
||
unicodeIndex = unicodeString;
|
||
|
||
for (i = 0, status = STATUS_SUCCESS; deviceStrings[i] != NULL; i++) {
|
||
RtlInitAnsiString(&ansiString, deviceStrings[i]);
|
||
status = RtlAnsiStringToUnicodeString(&unicodeIndex,
|
||
&ansiString,
|
||
FALSE);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// push the index past the last unicode string built.
|
||
//
|
||
((PSTR)unicodeIndex.Buffer) += unicodeIndex.Length + sizeof(WCHAR);
|
||
|
||
//
|
||
// Ensure the max length is correct.
|
||
//
|
||
unicodeIndex.MaximumLength -= unicodeIndex.Length + sizeof(WCHAR);
|
||
|
||
} else {
|
||
|
||
//
|
||
// TODO: Something.
|
||
//
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR)unicodeString.Buffer;
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
default:
|
||
|
||
status = Irp->IoStatus.Status;
|
||
Irp->IoStatus.Information = 0;
|
||
break;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MPIOPdoDeviceUsage(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
|
||
//
|
||
// TODO
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|