I am writing a virtual storport miniport driver to mount a Windows software raid as a virtual disk so that it will be available when write blocked. I have modified the storport miniport driver example from the NT Insider at http://www.osronline.com/article.cfm?article=538 but I am having an error that I cannot solve in the OsrVmUserUtil.cpp file and the NTSTATUS CreateConnection function. When I try to get a handle to the disk I am getting the STATUS_OBJECT_NAME_INVALID error and I cannot figure it out. I am passing in \.\PhysicalDrive1 which I know is a good path as my application reads it to get all of the raid information before passing that info onto the driver. I have a few years experience with C++ but this is my first driver as I am writing it for my Masters thesis.
Anyway here is the CreateConnection function code:
///////////////////////////////////////////////////////////////////////////////
//
// CreateConnection
//
// Creates a connection to the specified volume, if it does not already
// exists.
//
// INPUTS:
//
// PGInfo - Pointer to the Global Information BLock.
//
// PConnectInfo - Pointer to the connection information to create
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS if okay, an error otherwise.
//
// IRQL:
//
// This routine is called at any IRQL PASSIVE_LEVEL.
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS CreateConnection(PUSER_GLOBAL_INFORMATION PGInfo, PCONNECT_IN PConnectInfo)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK ioStatus;
BOOLEAN bInserted = FALSE;
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING uString;
KIRQL oldIrql;
GUID tmpGuid;
ULONG bytesReturned;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRVMINIPT_DEBUG_FUNCTRACE,(FUNCTION": Enter\n"));
//
// See if we already have a connection that matches this.
//
if(FindConnectionMatch(PGInfo,PConnectInfo,NULL)) {
return STATUS_OBJECT_NAME_COLLISION;
}
RtlZeroMemory(&tmpGuid,sizeof(GUID));
//
// Add the connection to the list.
//
PCONNECTION_LIST_ENTRY pEntry = (PCONNECTION_LIST_ENTRY)
ExAllocatePoolWithTag(NonPagedPool,sizeof(CONNECTION_LIST_ENTRY),‘pCLE’);
if(!pEntry) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(pEntry,sizeof(CONNECTION_LIST_ENTRY));
RtlCopyMemory(&pEntry->ConnectionInfo,PConnectInfo,sizeof(CONNECT_IN));
OsrAcquireSpinLock(&PGInfo->ConnectionListLock,&oldIrql);
InsertTailList(&PGInfo->ConnectionList,&pEntry->ListEntry);
OsrReleaseSpinLock(&PGInfo->ConnectionListLock,oldIrql);
bInserted = TRUE;
pEntry->DiskSize = (ULONG) ((ULONG) PConnectInfo->Disk0SizeMB + (ULONG) PConnectInfo->Disk1SizeMB + (ULONG) PConnectInfo->Disk2SizeMB + (ULONG) PConnectInfo->Disk3SizeMB + (ULONG) PConnectInfo->Disk4SizeMB + (ULONG) PConnectInfo->Disk5SizeMB) * 1024 * 1024;
OBJECT_ATTRIBUTES Disk0, Disk1, Disk2, Disk3, Disk4, Disk5;
IO_STATUS_BLOCK Disk0Comp, Disk1Comp, Disk2Comp, Disk3Comp, Disk4Comp, Disk5Comp;
UNICODE_STRING Disk0Path, Disk1Path, Disk2Path, Disk3Path, Disk4Path, Disk5Path;
RtlInitUnicodeString(&Disk0Path, PConnectInfo->Disk0Path);
//CODE CUT FOR EXAMPLE
InitializeObjectAttributes(&Disk0, &Disk0Path, OBJ_OPENIF, NULL, NULL);
//CODE CUT FOR EXAMPLE
if(PConnectInfo->Disk0SizeMB != 0)
{
status = ZwCreateFile(
&(pEntry->Disk0BaseAddress), //File HANDLE
FILE_READ_DATA, //Desired Access
&Disk0, //Object Attributes
&Disk0Comp, //IO_STATUS_BLOCK
NULL, //Allocation Size
FILE_ATTRIBUTE_NORMAL, //File Attributes
FILE_SHARE_READ, //Share Access
FILE_OPEN, //Create Disposition
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS, //Create Options
NULL, //EABuffer
0 //EALength
);
if(!NT_SUCCESS(status)) {
switch(status){
case STATUS_OBJECT_NAME_INVALID:
default:
goto cleanupAfterError;
}
}
else {
switch(Disk0Comp.Status){
case FILE_CREATED:
goto cleanupAfterError;
case FILE_OPENED:
break;
case FILE_OVERWRITTEN:
goto cleanupAfterError;
case FILE_SUPERSEDED:
goto cleanupAfterError;
case FILE_EXISTS:
goto cleanupAfterError;
case FILE_DOES_NOT_EXIST:
goto cleanupAfterError;
default:
goto cleanupAfterError;
}
}
}
//CODE CUT FOR EXAMPLE
//
// For our Virtual Disks, it comes from the Disk Header.
//
status = ExUuidCreate(&tmpGuid);
if(!NT_SUCCESS(status)) {
goto cleanupAfterError;
}
//
// We now have the information about the file that this disk, which we are about to
// create, represents. We need to build some SCSI inquiry information about the
// disk, so that the Disk Class Driver knows about us.
//
#pragma prefast(suppress:28197,“This memory is not leaked”)
PINQUIRYDATA pInquiryData = (PINQUIRYDATA) ExAllocatePoolWithTag(NonPagedPool,
sizeof(INQUIRYDATA),
‘diSO’);
if(pInquiryData) {
// typedef struct _INQUIRYDATA {
// UCHAR DeviceType : 5;
// UCHAR DeviceTypeQualifier : 3;
// UCHAR DeviceTypeModifier : 7;
// UCHAR RemovableMedia : 1;
// UCHAR Versions;
// UCHAR ResponseDataFormat : 4;
// UCHAR HiSupport : 1;
// UCHAR NormACA : 1;
// UCHAR ReservedBit : 1;
// UCHAR AERC : 1;
// UCHAR AdditionalLength;
// UCHAR Reserved[2];
// UCHAR SoftReset : 1;
// UCHAR CommandQueue : 1;
// UCHAR Reserved2 : 1;
// UCHAR LinkedCommands : 1;
// UCHAR Synchronous : 1;
// UCHAR Wide16Bit : 1;
// UCHAR Wide32Bit : 1;
// UCHAR RelativeAddressing : 1;
// UCHAR VendorId[8];
// UCHAR ProductId[16];
// UCHAR ProductRevisionLevel[4];
// UCHAR VendorSpecific[20];
// UCHAR Reserved3[40];
// } INQUIRYDATA, *PINQUIRYDATA;
RtlZeroMemory(pInquiryData,sizeof(INQUIRYDATA));
//
// The media is now either an OSR Disk or a regular disk, either way
// we return the same information.
//
pInquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
pInquiryData->DeviceTypeQualifier = DEVICE_CONNECTED;
pInquiryData->DeviceTypeModifier = 0;
pInquiryData->RemovableMedia = TRUE;
pInquiryData->Versions = 2; // SCSI-2 support
pInquiryData->ResponseDataFormat = 2; // Same as Version?? according to SCSI book
pInquiryData->Wide32Bit = TRUE; // 32 bit wide transfers
pInquiryData->Synchronous = TRUE; // Synchronous commands
pInquiryData->CommandQueue = FALSE; // Does not support tagged commands
pInquiryData->AdditionalLength = INQUIRYDATABUFFERSIZE-5; // Amount of data we are returning
pInquiryData->LinkedCommands = FALSE; // No Linked Commands
RtlCopyMemory((PUCHAR) &pInquiryData->VendorId[0],OSR_INQUIRY_VENDOR_ID,
strlen(OSR_INQUIRY_VENDOR_ID));
RtlCopyMemory((PUCHAR) &pInquiryData->ProductId[0],OSR_INQUIRY_PRODUCT_ID,
strlen(OSR_INQUIRY_PRODUCT_ID));
RtlCopyMemory((PUCHAR) &pInquiryData->ProductRevisionLevel[0],OSR_INQUIRY_PRODUCT_REVISION,
strlen(OSR_INQUIRY_PRODUCT_REVISION));
RtlCopyMemory((PUCHAR) &pInquiryData->VendorSpecific[0],OSR_INQUIRY_VENDOR_SPECIFIC,
strlen(OSR_INQUIRY_VENDOR_SPECIFIC));
ULONG bitNumber = RtlFindClearBitsAndSet(&ScsiBitMapHeader,1,0);
if(bitNumber == 0xFFFFFFFF) {
status = STATUS_INSUFFICIENT_RESOURCES;
DoClose(PGInfo,pEntry);
goto cleanupAfterError;
}
ULONG targetId = bitNumber % SCSI_MAXIMUM_TARGETS_PER_BUS;
ULONG BusId = bitNumber / SCSI_MAXIMUM_BUSES;
#pragma prefast(suppress:28197,“This memory is not leaked”)
PUSER_INSTANCE_INFORMATION pLocalInfo = (PUSER_INSTANCE_INFORMATION)
ExAllocatePoolWithTag(NonPagedPool,
sizeof(USER_INSTANCE_INFORMATION),
‘DLUp’);
if(!pLocalInfo) {
status = STATUS_INSUFFICIENT_RESOURCES;
DoClose(PGInfo,pEntry);
goto cleanupAfterError;
}
RtlZeroMemory(pLocalInfo,sizeof(USER_INSTANCE_INFORMATION));
pLocalInfo->MagicNumber = USER_INSTANCE_INFORMATION_MAGIC_NUMBER;
pLocalInfo->PInquiryData = pInquiryData;
//
// Create a PDO for this new disk.
//
pLocalInfo->OsrSPLocalHandle = OsrSPCreateScsiDevice(PGInfo->OsrSPHandle,
BusId /*IN ULONG BusIndex*/,
targetId /*IN ULONG TargetIndex*/,
LunId /*IN ULONG LunIndex*/,
pLocalInfo, /* Our local Data for Device */
FALSE,
pInquiryData,
1);
//
// Okay, we’ve got a PDO, we can now invalidate relations and see what happens.
//
if(pLocalInfo) {
static ULONG indexNumber = 0x08051958;
pLocalInfo->PGInfo = PGInfo;
//
// Get the infor for the unique ID.
//
GUID* pUniqueId = &tmpGuid;
RtlCopyMemory(&pLocalInfo->UniqueID.UniqueID,pUniqueId,sizeof(GUID));
pLocalInfo->UniqueID.FileId = (ULONGLONG) InterlockedIncrement((volatile LONG*) &indexNumber);
//
// Store away some other useful information.
//
pLocalInfo->ConnectionInformation = pEntry;
pLocalInfo->TargetIndex = targetId;
pLocalInfo->BusIndex = BusId;
pLocalInfo->LunIndex = LunId;
if(STATUS_SUCCESS != RtlStringCbPrintfA(&pLocalInfo->AsciiSignature[0],
sizeof(pLocalInfo->AsciiSignature),
“%08x%04x%04x%2x%2x%02x%02x%02x%02x%02x%02x%0I64x”,
pUniqueId->Data1,pUniqueId->Data2,pUniqueId->Data3,
pUniqueId->Data4[0],pUniqueId->Data4[1],pUniqueId->Data4[2],pUniqueId->Data4[3],
pUniqueId->Data4[5],pUniqueId->Data4[5],pUniqueId->Data4[6],pUniqueId->Data4[7],
pLocalInfo->UniqueID.FileId)) {
status = STATUS_INSUFFICIENT_RESOURCES;
DoClose(PGInfo,pEntry);
goto cleanupAfterError;
}
pEntry->PIInfo = pLocalInfo;
pEntry->BusIndex = BusId;
pEntry->TargetIndex = targetId;
pEntry->LunIndex = LunId;
InterlockedIncrement(&PGInfo->ConnectionCount);
targetId++;
//
// Tell the OSR SP that our bus has changed.
//
OsrSPAnnounceArrival(PGInfo->OsrSPHandle);
pEntry->Connected = TRUE;
status = STATUS_SUCCESS;
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRVMINIPT_DEBUG_FUNCTRACE,(FUNCTION": Exit\n"));
return status;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
cleanupAfterError:
if(bInserted) {
DeleteConnectionEntry(PGInfo,pEntry,PConnectInfo);
}
if(pEntry) {
ExFreePool(pEntry);
}
OsrTracePrint(TRACE_LEVEL_ERROR,OSRVMINIPT_DEBUG_FUNCTRACE,(FUNCTION": Exit\n"));
return status;
}