mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1099 lines
29 KiB
1099 lines
29 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 2000
|
|
|
|
Module Name:
|
|
|
|
pnp.c
|
|
|
|
Abstract:
|
|
|
|
This file contains plug and play code for the NT iSCSI port driver.
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "port.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE, iScsiPortAddDevice)
|
|
#pragma alloc_text(PAGE, iScsiPortUnload)
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
#define NUM_DEVICE_TYPE_INFO_ENTRIES 18
|
|
|
|
extern ISCSI_DEVICE_TYPE DeviceTypeInfo[];
|
|
|
|
VOID
|
|
iSpInitFdoExtension(
|
|
IN OUT PISCSI_FDO_EXTENSION
|
|
);
|
|
|
|
ISCSI_DEVICE_TYPE DeviceTypeInfo[NUM_DEVICE_TYPE_INFO_ENTRIES] = {
|
|
{"Disk", "GenDisk", L"DiskPeripheral", TRUE},
|
|
{"Sequential", "", L"TapePeripheral", TRUE},
|
|
{"Printer", "GenPrinter", L"PrinterPeripheral", FALSE},
|
|
{"Processor", "", L"OtherPeripheral", FALSE},
|
|
{"Worm", "GenWorm", L"WormPeripheral", TRUE},
|
|
{"CdRom", "GenCdRom", L"CdRomPeripheral", TRUE},
|
|
{"Scanner", "GenScanner", L"ScannerPeripheral", FALSE},
|
|
{"Optical", "GenOptical", L"OpticalDiskPeripheral", TRUE},
|
|
{"Changer", "ScsiChanger", L"MediumChangerPeripheral", TRUE},
|
|
{"Net", "ScsiNet", L"CommunicationsPeripheral", FALSE},
|
|
{"ASCIT8", "ScsiASCIT8", L"ASCPrePressGraphicsPeripheral", FALSE},
|
|
{"ASCIT8", "ScsiASCIT8", L"ASCPrePressGraphicsPeripheral", FALSE},
|
|
{"Array", "ScsiArray", L"ArrayPeripheral", FALSE},
|
|
{"Enclosure", "ScsiEnclosure", L"EnclosurePeripheral", FALSE},
|
|
{"RBC", "ScsiRBC", L"RBCPeripheral", TRUE},
|
|
{"CardReader", "ScsiCardReader", L"CardReaderPeripheral", FALSE},
|
|
{"Bridge", "ScsiBridge", L"BridgePeripheral", FALSE},
|
|
{"Other", "ScsiOther", L"OtherPeripheral", FALSE}
|
|
};
|
|
|
|
PISCSI_FDO_EXTENSION iSpGlobalFdoExtension = NULL;
|
|
HANDLE iSpTdiNotificationHandle = NULL;
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
/*+++
|
|
Routine Description:
|
|
|
|
This routine handles add-device requests for the iSCSI port driver
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the driver object for this device
|
|
|
|
PhysicalDeviceObject - a pointer to the PDO we are being added to
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
Appropriate NTStatus code on error
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_OBJECT newDeviceObject;
|
|
PISCSI_FDO_EXTENSION fdoExtension;
|
|
PCOMMON_EXTENSION commonExtension;
|
|
NTSTATUS status;
|
|
UNICODE_STRING deviceName;
|
|
|
|
RtlInitUnicodeString(&deviceName, ISCSI_FDO_DEVICE_NAME);
|
|
status = IoCreateDevice(DriverObject,
|
|
sizeof(ISCSI_FDO_EXTENSION),
|
|
&deviceName,
|
|
FILE_DEVICE_NETWORK,
|
|
0,
|
|
FALSE,
|
|
&deviceObject);
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((1, "iScsiPortAddDevice failed. Status %lx\n",
|
|
status));
|
|
return status;
|
|
}
|
|
|
|
newDeviceObject = IoAttachDeviceToDeviceStack(deviceObject,
|
|
PhysicalDeviceObject);
|
|
if (newDeviceObject == NULL) {
|
|
DebugPrint((0,
|
|
"IoAttachDeviceToDeviceStack failed in iScsiAddDevice\n"));
|
|
IoDeleteDevice(deviceObject);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|
|
|
fdoExtension = deviceObject->DeviceExtension;
|
|
commonExtension = &(fdoExtension->CommonExtension);
|
|
|
|
iSpGlobalFdoExtension = fdoExtension;
|
|
|
|
RtlZeroMemory(fdoExtension, sizeof(ISCSI_FDO_EXTENSION));
|
|
|
|
fdoExtension->LowerPdo = PhysicalDeviceObject;
|
|
commonExtension->LowerDeviceObject = newDeviceObject;
|
|
|
|
commonExtension->DeviceObject = deviceObject;
|
|
commonExtension->IsPdo = FALSE;
|
|
commonExtension->CurrentPnpState = 0xff;
|
|
commonExtension->PreviousPnpState = 0xff;
|
|
commonExtension->IsNetworkReady = FALSE;
|
|
|
|
commonExtension->IsRemoved = NO_REMOVE;
|
|
commonExtension->RemoveLock = 0;
|
|
KeInitializeEvent(&(commonExtension->RemoveEvent),
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
KeInitializeSpinLock(&(fdoExtension->EnumerationSpinLock));
|
|
|
|
IoInitializeTimer(deviceObject, iSpTickHandler, NULL);
|
|
|
|
IoStartTimer(fdoExtension->DeviceObject);
|
|
|
|
//
|
|
// Initialize the entry points for this device
|
|
//
|
|
iScsiPortInitializeDispatchTables();
|
|
commonExtension->MajorFunction = FdoMajorFunctionTable;
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DebugPrint((3, "Add Device was successful\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
iScsiPortUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
PISCSIPORT_DRIVER_EXTENSION driverExtension;
|
|
|
|
driverExtension = IoGetDriverObjectExtension( DriverObject,
|
|
(PVOID)ISCSI_TAG_DRIVER_EXTENSION);
|
|
if (driverExtension != NULL) {
|
|
ExFreePool(driverExtension->RegistryPath.Buffer);
|
|
driverExtension->RegistryPath.Buffer = NULL;
|
|
driverExtension->RegistryPath.Length = 0;
|
|
driverExtension->RegistryPath.MaximumLength = 0;
|
|
}
|
|
|
|
iSpGlobalFdoExtension = NULL;
|
|
iSpTdiNotificationHandle = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortFdoPnp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
|
PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG isRemoved;
|
|
BOOLEAN forwardIrp = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DebugPrint((1, "FdoPnp for DeviceObject %x, Irp %x, MN %x\n",
|
|
DeviceObject, Irp, (irpStack->MinorFunction)));
|
|
|
|
isRemoved = iSpAcquireRemoveLock(DeviceObject, Irp);
|
|
if (isRemoved) {
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
|
}
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
case IRP_MN_START_DEVICE: {
|
|
|
|
status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
|
|
Irp);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Register for notification from network interface
|
|
// to be notified of network ready state
|
|
//
|
|
if ((commonExtension->IsNetworkReady) == FALSE) {
|
|
iSpRegisterForNetworkNotification();
|
|
}
|
|
|
|
//
|
|
// Initialize various fields in the
|
|
// FDO Extension.
|
|
//
|
|
iSpInitFdoExtension(fdoExtension);
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE: {
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
forwardIrp = TRUE;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE: {
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
forwardIrp = TRUE;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_STOP_DEVICE: {
|
|
|
|
if (iSpTdiNotificationHandle != NULL) {
|
|
TdiDeregisterPnPHandlers(iSpTdiNotificationHandle);
|
|
iSpTdiNotificationHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// If network node hasn't been released yet,
|
|
// release it now
|
|
//
|
|
if ((fdoExtension->LocalNodesInitialized) == TRUE) {
|
|
ULONG inx;
|
|
|
|
for (inx = 0; inx < (fdoExtension->NumberOfTargets);
|
|
inx++) {
|
|
iSpStopNetwork(fdoExtension->PDOList[inx]);
|
|
fdoExtension->PDOList[inx] = NULL;
|
|
}
|
|
|
|
fdoExtension->LocalNodesInitialized = FALSE;
|
|
fdoExtension->NumberOfTargets = 0;
|
|
}
|
|
|
|
fdoExtension->LocalNodesInitialized = FALSE;
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0L;
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
forwardIrp = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE: {
|
|
DebugPrint((0, "Query remove received.\n"));
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
forwardIrp = TRUE;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE: {
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = status;
|
|
forwardIrp = TRUE;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_REMOVE_DEVICE: {
|
|
|
|
//
|
|
// Deregister network notification if we
|
|
// already haven't
|
|
//
|
|
if (iSpTdiNotificationHandle != NULL) {
|
|
TdiDeregisterPnPHandlers(iSpTdiNotificationHandle);
|
|
iSpTdiNotificationHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// If network node hasn't been released yet,
|
|
// release it now
|
|
//
|
|
if ((fdoExtension->LocalNodesInitialized) == TRUE) {
|
|
ULONG inx;
|
|
|
|
for (inx = 0; inx < (fdoExtension->NumberOfTargets);
|
|
inx++) {
|
|
iSpStopNetwork(fdoExtension->PDOList[inx]);
|
|
IoDeleteDevice(fdoExtension->PDOList[inx]);
|
|
fdoExtension->PDOList[inx] = NULL;
|
|
}
|
|
|
|
fdoExtension->LocalNodesInitialized = FALSE;
|
|
fdoExtension->NumberOfTargets = 0;
|
|
}
|
|
|
|
fdoExtension->LocalNodesInitialized = FALSE;
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
commonExtension->IsRemoved = REMOVE_PENDING;
|
|
|
|
DebugPrint((1, "Waiting for remove event.\n"));
|
|
KeWaitForSingleObject(&(commonExtension->RemoveEvent),
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
DebugPrint((1, "Will process remove now.\n"));
|
|
|
|
status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
|
|
Irp);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
IoDetachDevice(commonExtension->LowerDeviceObject);
|
|
|
|
IoDeleteDevice(commonExtension->DeviceObject);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
} else {
|
|
commonExtension->IsRemoved = NO_REMOVE;
|
|
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: {
|
|
|
|
PIO_WORKITEM workItem = NULL;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
PDEVICE_OBJECT lowerDevice;
|
|
|
|
ULONG relationSize;
|
|
DEVICE_RELATION_TYPE relationType;
|
|
|
|
relationType =
|
|
irpStack->Parameters.QueryDeviceRelations.Type;
|
|
|
|
if (relationType != BusRelations) {
|
|
forwardIrp = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ((fdoExtension->EnumerationComplete) == TRUE) {
|
|
|
|
ASSERT((fdoExtension->NumberOfTargets) > 0);
|
|
|
|
relationSize = sizeof(DEVICE_RELATIONS) +
|
|
(sizeof(PDEVICE_OBJECT) *
|
|
(fdoExtension->NumberOfTargets));
|
|
|
|
deviceRelations = iSpAllocatePool(PagedPool,
|
|
relationSize,
|
|
ISCSI_TAG_DEVICE_RELATIONS);
|
|
if (deviceRelations != NULL) {
|
|
PDEVICE_OBJECT pdo;
|
|
ULONG inx;
|
|
|
|
deviceRelations->Count =
|
|
fdoExtension->NumberOfTargets;
|
|
for (inx = 0; (inx < (fdoExtension->NumberOfTargets));
|
|
inx++) {
|
|
|
|
pdo = fdoExtension->PDOList[inx];
|
|
ASSERT(pdo != NULL);
|
|
ObReferenceObject(pdo);
|
|
deviceRelations->Objects[inx] = pdo;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
lowerDevice =
|
|
fdoExtension->CommonExtension.LowerDeviceObject;
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
return IoCallDriver(lowerDevice, Irp);
|
|
} else {
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Information = 0L;
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Setup the local network nodes if not already done
|
|
//
|
|
if ((fdoExtension->LocalNodesInitialized) == FALSE) {
|
|
status = iSpInitializeLocalNodes(DeviceObject);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Allocate a workitem to perform device
|
|
// enumeration
|
|
//
|
|
fdoExtension->EnumerationThreadLaunched = FALSE;
|
|
workItem = IoAllocateWorkItem(DeviceObject);
|
|
if (workItem != NULL) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
fdoExtension->EnumerationIrp = Irp;
|
|
fdoExtension->EnumerationComplete = FALSE;
|
|
fdoExtension->EnumerationWorkItem = workItem;
|
|
|
|
IoQueueWorkItem(workItem,
|
|
iSpEnumerateDevicesAsynchronous,
|
|
DelayedWorkQueue,
|
|
fdoExtension);
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
return STATUS_PENDING;
|
|
} else {
|
|
Irp->IoStatus.Information = 0L;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
break;
|
|
} else {
|
|
DebugPrint((1, "Could not setup the node. Status : %x\n",
|
|
status));
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0L;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
forwardIrp = TRUE;
|
|
break;
|
|
}
|
|
} // switch (irpStack->MinorFunction)
|
|
|
|
iSpReleaseRemoveLock(DeviceObject, Irp);
|
|
|
|
if (forwardIrp == TRUE) {
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(commonExtension->LowerDeviceObject,
|
|
Irp);
|
|
} else {
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iSpSendIrpSynchronous(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
KEVENT event;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (DeviceObject == NULL) {
|
|
DebugPrint((1, "DeviceObject NULL. Irp %x\n",
|
|
Irp));
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
iSpSetEvent,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
status = IoCallDriver(DeviceObject, Irp);
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortGetDeviceId(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will allocate space for and fill in a device id string for
|
|
the specified Pdo. This string is generated from the bus type (scsi) and
|
|
the type of the device.
|
|
|
|
Arguments:
|
|
|
|
Pdo - a pointer to the physical device object being queried
|
|
|
|
UnicodeString - a pointer to an already allocated unicode string structure.
|
|
This routine will allocate and fill in the buffer of this
|
|
structure
|
|
|
|
Returns:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PISCSI_PDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
|
PINQUIRYDATA inquiryData = &(pdoExtension->InquiryData);
|
|
|
|
UCHAR buffer[256];
|
|
PUCHAR rawIdString = buffer;
|
|
ANSI_STRING ansiIdString;
|
|
|
|
ULONG whichString;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(UnicodeString != NULL);
|
|
|
|
RtlZeroMemory(buffer, sizeof(buffer));
|
|
|
|
sprintf(rawIdString,
|
|
"SCSI\\%s",
|
|
iSpGetDeviceTypeInfo(inquiryData->DeviceType)->DeviceTypeString);
|
|
|
|
rawIdString += strlen(rawIdString);
|
|
|
|
ASSERT(*rawIdString == '\0');
|
|
|
|
for(whichString = 0; whichString < 3; whichString++) {
|
|
|
|
PUCHAR headerString;
|
|
PUCHAR sourceString;
|
|
ULONG sourceStringLength;
|
|
|
|
ULONG i;
|
|
|
|
switch(whichString) {
|
|
|
|
//
|
|
// Vendor Id
|
|
//
|
|
case 0: {
|
|
sourceString = inquiryData->VendorId;
|
|
sourceStringLength = sizeof(inquiryData->VendorId);
|
|
headerString = "Ven";
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Product Id
|
|
//
|
|
case 1: {
|
|
sourceString = inquiryData->ProductId;
|
|
sourceStringLength = sizeof(inquiryData->ProductId);
|
|
headerString = "Prod";
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Product Revision Level
|
|
//
|
|
case 2: {
|
|
sourceString = inquiryData->ProductRevisionLevel;
|
|
sourceStringLength = sizeof(inquiryData->ProductRevisionLevel);
|
|
headerString = "Rev";
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Start at the end of the source string and back up until we find a
|
|
// non-space, non-null character.
|
|
//
|
|
|
|
for(; sourceStringLength > 0; sourceStringLength--) {
|
|
|
|
if((sourceString[sourceStringLength - 1] != ' ') &&
|
|
(sourceString[sourceStringLength - 1] != '\0')) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Throw the header string into the block
|
|
//
|
|
|
|
sprintf(rawIdString, "&%s_", headerString);
|
|
rawIdString += strlen(headerString) + 2;
|
|
|
|
//
|
|
// Spew the string into the device id
|
|
//
|
|
|
|
for(i = 0; i < sourceStringLength; i++) {
|
|
*rawIdString = (sourceString[i] != ' ') ? (sourceString[i]) :
|
|
('_');
|
|
rawIdString++;
|
|
}
|
|
ASSERT(*rawIdString == '\0');
|
|
}
|
|
|
|
RtlInitAnsiString(&ansiIdString, buffer);
|
|
|
|
DebugPrint((1, "DeviceId for logical unit %#p is %Z\n",
|
|
Pdo, &ansiIdString));
|
|
|
|
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortGetInstanceId(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will allocate space for and fill in an instance id string for
|
|
the specified Pdo. This string will be generated either from the device
|
|
type + serial number of the device (if it has a serial number) or from
|
|
the address of the device.
|
|
|
|
Arguments:
|
|
|
|
Pdo - a pointer to the physical device object being queried
|
|
|
|
UnicodeString - a pointer to an already allocated unicode string structure.
|
|
This routine will allocate and fill in the buffer of this
|
|
structure
|
|
|
|
Returns:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
PISCSI_PDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
|
|
|
PDRIVER_OBJECT driverObject = Pdo->DriverObject;
|
|
PISCSI_DEVICE_TYPE deviceTypeInfo;
|
|
|
|
UCHAR idStringBuffer[64];
|
|
ANSI_STRING ansiIdString;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(UnicodeString != NULL);
|
|
|
|
//
|
|
// can't use serial number even if it exists since a device which is
|
|
// multiply connected to the same bus (dual-ported device) will have
|
|
// the same serial number at each connection and would confuse the PNP.
|
|
//
|
|
|
|
sprintf(idStringBuffer,
|
|
"%x%x%x",
|
|
pdoExtension->PathId,
|
|
pdoExtension->TargetId,
|
|
pdoExtension->Lun
|
|
);
|
|
|
|
RtlInitAnsiString(&ansiIdString, idStringBuffer);
|
|
|
|
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortGetCompatibleIds(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PINQUIRYDATA InquiryData,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will allocate space for and fill in a compatible id multi
|
|
string for the specified Pdo. This string is generated using the bus and
|
|
device types for the device
|
|
|
|
Arguments:
|
|
|
|
InquiryData - the inquiry data to generate compatible ids from.
|
|
|
|
UnicodeString - a pointer to an already allocated unicode string structure.
|
|
This routine will allocate and fill in the buffer of this
|
|
structure
|
|
|
|
Returns:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR s[sizeof("SCSI\\DEVICE_TYPE_GOES_HERE")];
|
|
PSTR stringBuffer[] = {
|
|
s,
|
|
"SCSI\\RAW",
|
|
NULL};
|
|
|
|
//
|
|
// Fill in the scsi specific string
|
|
//
|
|
|
|
sprintf(stringBuffer[0],
|
|
"SCSI\\%s",
|
|
iSpGetDeviceTypeInfo(InquiryData->DeviceType)->DeviceTypeString);
|
|
|
|
//
|
|
// Set up the first id string
|
|
//
|
|
|
|
return iScsiPortStringArrayToMultiString(
|
|
DriverObject,
|
|
UnicodeString,
|
|
stringBuffer);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
iScsiPortGetHardwareIds(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PINQUIRYDATA InquiryData,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will allocate space for and fill in a hardware id multi
|
|
string for the specified Pdo. This string is generated using the device
|
|
type and the inquiry data.
|
|
|
|
Arguments:
|
|
|
|
InquiryData - the inquiry data to be converted into id strings.
|
|
|
|
UnicodeString - a pointer to an already allocated unicode string structure.
|
|
This routine will allocate and fill in the buffer of this
|
|
structure
|
|
|
|
Returns:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
#define NUMBER_HARDWARE_STRINGS 6
|
|
|
|
{
|
|
PISCSI_DEVICE_TYPE devTypeInfo =
|
|
iSpGetDeviceTypeInfo(InquiryData->DeviceType);
|
|
|
|
ULONG i;
|
|
|
|
PSTR strings[NUMBER_HARDWARE_STRINGS + 1];
|
|
UCHAR scratch[64];
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Zero out the string buffer
|
|
//
|
|
|
|
RtlZeroMemory(strings, sizeof(strings));
|
|
|
|
try {
|
|
|
|
for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
|
|
|
|
RtlZeroMemory(scratch, sizeof(scratch));
|
|
|
|
//
|
|
// Build each of the hardware id's
|
|
//
|
|
|
|
switch(i) {
|
|
|
|
//
|
|
// Bus + Dev Type + Vendor + Product + Revision
|
|
//
|
|
|
|
case 0: {
|
|
|
|
sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->VendorId,
|
|
8,
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->ProductId,
|
|
16,
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->ProductRevisionLevel,
|
|
4,
|
|
'_');
|
|
break;
|
|
}
|
|
|
|
//
|
|
// bus + device + vendor + product
|
|
//
|
|
|
|
case 1: {
|
|
|
|
sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->VendorId,
|
|
8,
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->ProductId,
|
|
16,
|
|
'_');
|
|
break;
|
|
}
|
|
|
|
//
|
|
// bus + device + vendor
|
|
//
|
|
|
|
case 2: {
|
|
|
|
sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->VendorId,
|
|
8,
|
|
'_');
|
|
break;
|
|
}
|
|
|
|
//
|
|
// bus \ vendor + product + revision[0]
|
|
//
|
|
|
|
case 3: {
|
|
sprintf(scratch, "SCSI\\");
|
|
|
|
//
|
|
// Fall through to the next set.
|
|
//
|
|
}
|
|
|
|
//
|
|
// vendor + product + revision[0] (win9x)
|
|
//
|
|
|
|
case 4: {
|
|
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->VendorId,
|
|
8,
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->ProductId,
|
|
16,
|
|
'_');
|
|
CopyField(scratch + strlen(scratch),
|
|
InquiryData->ProductRevisionLevel,
|
|
1,
|
|
'_');
|
|
|
|
break;
|
|
}
|
|
|
|
case 5: {
|
|
|
|
sprintf(scratch, "%s", devTypeInfo->GenericTypeString);
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(strlen(scratch) != 0) {
|
|
strings[i] =
|
|
iSpAllocatePool(PagedPool,
|
|
strlen(scratch) + sizeof(UCHAR),
|
|
ISCSI_TAG_PNP_ID);
|
|
|
|
if(strings[i] == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
leave;
|
|
}
|
|
|
|
strcpy(strings[i], scratch);
|
|
|
|
} else {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
status = iScsiPortStringArrayToMultiString(DriverObject,
|
|
UnicodeString,
|
|
strings);
|
|
leave;
|
|
|
|
} finally {
|
|
|
|
for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
|
|
|
|
if(strings[i]) {
|
|
ExFreePool(strings[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#undef NUMBER_HARDWARE_STRINGS
|
|
|
|
VOID
|
|
CopyField(
|
|
IN PUCHAR Destination,
|
|
IN PUCHAR Source,
|
|
IN ULONG Count,
|
|
IN UCHAR Change
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will copy Count string bytes from Source to Destination. If
|
|
it finds a nul byte in the Source it will translate that and any subsequent
|
|
bytes into Change. It will also replace spaces with the specified character.
|
|
|
|
Arguments:
|
|
|
|
Destination - the location to copy bytes
|
|
|
|
Source - the location to copy bytes from
|
|
|
|
Count - the number of bytes to be copied
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i = 0;
|
|
BOOLEAN pastEnd = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
for(i = 0; i < Count; i++) {
|
|
|
|
if(!pastEnd) {
|
|
|
|
if(Source[i] == 0) {
|
|
|
|
pastEnd = TRUE;
|
|
|
|
Destination[i] = Change;
|
|
|
|
} else if(Source[i] == ' ') {
|
|
|
|
Destination[i] = Change;
|
|
|
|
} else {
|
|
|
|
Destination[i] = Source[i];
|
|
|
|
}
|
|
} else {
|
|
Destination[i] = Change;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
PISCSI_DEVICE_TYPE
|
|
iSpGetDeviceTypeInfo(
|
|
IN UCHAR DeviceType
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if(DeviceType >= NUM_DEVICE_TYPE_INFO_ENTRIES) {
|
|
return &(DeviceTypeInfo[NUM_DEVICE_TYPE_INFO_ENTRIES - 1]);
|
|
} else {
|
|
return &(DeviceTypeInfo[DeviceType]);
|
|
}
|
|
};
|
|
|
|
VOID
|
|
iSpInitFdoExtension(
|
|
IN OUT PISCSI_FDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
PIO_SCSI_CAPABILITIES capabilities;
|
|
|
|
capabilities = &(FdoExtension->IoScsiCapabilities);
|
|
|
|
//
|
|
// For now, we are going to hard code most of the values
|
|
//
|
|
capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
|
|
|
|
capabilities->MaximumTransferLength = 0x8000;
|
|
|
|
capabilities->MaximumPhysicalPages = 9;
|
|
|
|
capabilities->SupportedAsynchronousEvents = 0;
|
|
|
|
capabilities->AlignmentMask = 0;
|
|
|
|
capabilities->TaggedQueuing = FALSE;
|
|
|
|
capabilities->AdapterScansDown = FALSE;
|
|
|
|
capabilities->AdapterUsesPio = FALSE;
|
|
}
|