Source code of Windows XP (NT5)
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

/*++
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;
}