mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 11:35:58 +00:00
cbe88e287f
This way, these drivers are more compatible with classpnp and cdrom used by ReactOS (and don't fire asserts)
553 lines
18 KiB
C
553 lines
18 KiB
C
/*
|
|
* PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: IOCTL handlers
|
|
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
|
|
* Aleksey Bragin (aleksey@reactos.org)
|
|
* 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
|
|
*/
|
|
|
|
#include "scsiport.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
static
|
|
NTSTATUS
|
|
SpiGetInquiryData(
|
|
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
|
|
_In_ PIRP Irp)
|
|
{
|
|
ULONG InquiryDataSize;
|
|
ULONG BusCount, Length;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
|
|
PSCSI_INQUIRY_DATA InquiryData;
|
|
PUCHAR Buffer;
|
|
|
|
DPRINT("SpiGetInquiryData() called\n");
|
|
|
|
/* Get pointer to the buffer */
|
|
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
/* Initialize bus and LUN counters */
|
|
BusCount = DeviceExtension->NumberOfBuses;
|
|
|
|
/* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
|
|
InquiryDataSize = ALIGN_UP(sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE, ULONG);
|
|
|
|
/* Calculate data size */
|
|
Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA);
|
|
|
|
Length += InquiryDataSize * DeviceExtension->TotalLUCount;
|
|
|
|
/* Check, if all data is going to fit into provided buffer */
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
/* Store data size in the IRP */
|
|
Irp->IoStatus.Information = Length;
|
|
|
|
DPRINT("Data size: %lu\n", Length);
|
|
|
|
AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
|
|
|
|
AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
|
|
|
|
/* Point InquiryData to the corresponding place inside Buffer */
|
|
InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
|
|
(BusCount - 1) * sizeof(SCSI_BUS_DATA));
|
|
|
|
/* Loop each bus */
|
|
for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
|
|
{
|
|
PSCSI_BUS_DATA BusData = &AdapterBusInfo->BusData[pathId];
|
|
|
|
/* Calculate and save an offset of the inquiry data */
|
|
BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
|
|
|
|
/* Store Initiator Bus Id */
|
|
BusData->InitiatorBusId = DeviceExtension->Buses[pathId].BusIdentifier;
|
|
|
|
/* Store LUN count */
|
|
BusData->NumberOfLogicalUnits = DeviceExtension->Buses[pathId].LogicalUnitsCount;
|
|
|
|
/* Loop all LUNs */
|
|
PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
|
|
|
|
for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
|
|
lunEntry != &bus->LunsListHead;
|
|
lunEntry = lunEntry->Flink)
|
|
{
|
|
PSCSI_PORT_LUN_EXTENSION lunExt =
|
|
CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
|
|
|
|
DPRINT("(Bus %lu Target %lu Lun %lu)\n", pathId, lunExt->TargetId, lunExt->Lun);
|
|
|
|
/* Fill InquiryData with values */
|
|
InquiryData->PathId = lunExt->PathId;
|
|
InquiryData->TargetId = lunExt->TargetId;
|
|
InquiryData->Lun = lunExt->Lun;
|
|
InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
|
|
InquiryData->DeviceClaimed = lunExt->DeviceClaimed;
|
|
InquiryData->NextInquiryDataOffset =
|
|
(ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
|
|
|
|
/* Copy data in it */
|
|
RtlCopyMemory(InquiryData->InquiryData,
|
|
&lunExt->InquiryData,
|
|
INQUIRYDATABUFFERSIZE);
|
|
|
|
/* Move to the next LUN */
|
|
InquiryData = (PSCSI_INQUIRY_DATA) ((ULONG_PTR)InquiryData + InquiryDataSize);
|
|
}
|
|
|
|
/* Either mark the end, or set offset to 0 */
|
|
if (BusData->NumberOfLogicalUnits != 0)
|
|
((PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
|
|
else
|
|
BusData->InquiryDataOffset = 0;
|
|
}
|
|
|
|
/* Finish with success */
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
UINT32
|
|
GetFieldLength(
|
|
_In_ PUCHAR Name,
|
|
_In_ UINT32 MaxLength)
|
|
{
|
|
UINT32 Index;
|
|
UINT32 LastCharacterPosition = 0;
|
|
|
|
// scan the field and return last position which contains a valid character
|
|
for (Index = 0; Index < MaxLength; Index++)
|
|
{
|
|
if (Name[Index] != ' ')
|
|
{
|
|
// trim white spaces from field
|
|
LastCharacterPosition = Index;
|
|
}
|
|
}
|
|
|
|
// convert from zero based index to length
|
|
return LastCharacterPosition + 1;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
PdoHandleQueryProperty(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_Inout_ PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
|
|
ASSERT(ioStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY));
|
|
ASSERT(Irp->AssociatedIrp.SystemBuffer);
|
|
ASSERT(!lunExt->Common.IsFDO);
|
|
|
|
PSTORAGE_PROPERTY_QUERY PropertyQuery = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
// check property type
|
|
if (PropertyQuery->PropertyId != StorageDeviceProperty &&
|
|
PropertyQuery->PropertyId != StorageAdapterProperty)
|
|
{
|
|
// only device property / adapter property are supported
|
|
status = STATUS_INVALID_PARAMETER_1;
|
|
goto completeIrp;
|
|
}
|
|
|
|
// check query type
|
|
if (PropertyQuery->QueryType == PropertyExistsQuery)
|
|
{
|
|
// device property / adapter property is supported
|
|
status = STATUS_SUCCESS;
|
|
goto completeIrp;
|
|
}
|
|
|
|
if (PropertyQuery->QueryType != PropertyStandardQuery)
|
|
{
|
|
// only standard query and exists query are supported
|
|
status = STATUS_INVALID_PARAMETER_2;
|
|
goto completeIrp;
|
|
}
|
|
|
|
switch (PropertyQuery->PropertyId)
|
|
{
|
|
case StorageDeviceProperty:
|
|
{
|
|
PINQUIRYDATA inquiryData = &lunExt->InquiryData;
|
|
|
|
// compute extra parameters length
|
|
UINT32 FieldLengthVendor = GetFieldLength(inquiryData->VendorId, 8),
|
|
FieldLengthProduct = GetFieldLength(inquiryData->ProductId, 16),
|
|
FieldLengthRevision = GetFieldLength(inquiryData->ProductRevisionLevel, 4);
|
|
|
|
// total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1
|
|
// -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
|
|
UINT32 TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR)
|
|
+ FieldLengthVendor
|
|
+ FieldLengthProduct
|
|
+ FieldLengthRevision
|
|
+ 3;
|
|
|
|
// check if output buffer is long enough
|
|
if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < TotalLength)
|
|
{
|
|
// buffer too small
|
|
PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader = Irp->AssociatedIrp.SystemBuffer;
|
|
ASSERT(ioStack->Parameters.DeviceIoControl.OutputBufferLength >=
|
|
sizeof(STORAGE_DESCRIPTOR_HEADER));
|
|
|
|
// return required size
|
|
DescriptorHeader->Version = TotalLength;
|
|
DescriptorHeader->Size = TotalLength;
|
|
|
|
Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
|
|
status = STATUS_SUCCESS;
|
|
goto completeIrp;
|
|
}
|
|
|
|
// initialize the device descriptor
|
|
PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
deviceDescriptor->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
|
|
deviceDescriptor->Size = TotalLength;
|
|
deviceDescriptor->DeviceType = inquiryData->DeviceType;
|
|
deviceDescriptor->DeviceTypeModifier = inquiryData->DeviceTypeModifier;
|
|
deviceDescriptor->RemovableMedia = inquiryData->RemovableMedia;
|
|
deviceDescriptor->CommandQueueing = inquiryData->CommandQueue;
|
|
deviceDescriptor->BusType = BusTypeScsi;
|
|
deviceDescriptor->VendorIdOffset =
|
|
FIELD_OFFSET(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties);
|
|
deviceDescriptor->ProductIdOffset =
|
|
deviceDescriptor->VendorIdOffset + FieldLengthVendor + 1;
|
|
deviceDescriptor->ProductRevisionOffset =
|
|
deviceDescriptor->ProductIdOffset + FieldLengthProduct + 1;
|
|
deviceDescriptor->SerialNumberOffset = 0;
|
|
deviceDescriptor->RawPropertiesLength =
|
|
FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + 3;
|
|
|
|
// copy descriptors
|
|
PUCHAR Buffer = deviceDescriptor->RawDeviceProperties;
|
|
|
|
RtlCopyMemory(Buffer, inquiryData->VendorId, FieldLengthVendor);
|
|
Buffer[FieldLengthVendor] = '\0';
|
|
Buffer += FieldLengthVendor + 1;
|
|
|
|
RtlCopyMemory(Buffer, inquiryData->ProductId, FieldLengthProduct);
|
|
Buffer[FieldLengthProduct] = '\0';
|
|
Buffer += FieldLengthProduct + 1;
|
|
|
|
RtlCopyMemory(Buffer, inquiryData->ProductRevisionLevel, FieldLengthRevision);
|
|
Buffer[FieldLengthRevision] = '\0';
|
|
Buffer += FieldLengthRevision + 1;
|
|
|
|
DPRINT("Vendor %s\n",
|
|
(LPCSTR)((ULONG_PTR)deviceDescriptor + deviceDescriptor->VendorIdOffset));
|
|
DPRINT("Product %s\n",
|
|
(LPCSTR)((ULONG_PTR)deviceDescriptor + deviceDescriptor->ProductIdOffset));
|
|
DPRINT("Revision %s\n",
|
|
(LPCSTR)((ULONG_PTR)deviceDescriptor + deviceDescriptor->ProductRevisionOffset));
|
|
|
|
Irp->IoStatus.Information = TotalLength;
|
|
status = STATUS_SUCCESS;
|
|
goto completeIrp;
|
|
}
|
|
case StorageAdapterProperty:
|
|
{
|
|
// forward to the lower device
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(lunExt->Common.LowerDevice, Irp);
|
|
}
|
|
case StorageDeviceIdProperty:
|
|
{
|
|
// TODO
|
|
}
|
|
default:
|
|
{
|
|
UNREACHABLE;
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
goto completeIrp;
|
|
}
|
|
}
|
|
|
|
completeIrp:
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
FdoHandleQueryProperty(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_Inout_ PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_PORT_DEVICE_EXTENSION portExt = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
|
|
ASSERT(ioStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY));
|
|
ASSERT(Irp->AssociatedIrp.SystemBuffer);
|
|
ASSERT(portExt->Common.IsFDO);
|
|
|
|
PSTORAGE_PROPERTY_QUERY PropertyQuery = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
// check property type (handle only StorageAdapterProperty)
|
|
if (PropertyQuery->PropertyId != StorageAdapterProperty)
|
|
{
|
|
if (PropertyQuery->PropertyId == StorageDeviceProperty ||
|
|
PropertyQuery->PropertyId == StorageDeviceIdProperty)
|
|
{
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INVALID_PARAMETER_1;
|
|
}
|
|
|
|
goto completeIrp;
|
|
}
|
|
|
|
// check query type
|
|
if (PropertyQuery->QueryType == PropertyExistsQuery)
|
|
{
|
|
// device property / adapter property is supported
|
|
status = STATUS_SUCCESS;
|
|
goto completeIrp;
|
|
}
|
|
|
|
if (PropertyQuery->QueryType != PropertyStandardQuery)
|
|
{
|
|
// only standard query and exists query are supported
|
|
status = STATUS_INVALID_PARAMETER_2;
|
|
goto completeIrp;
|
|
}
|
|
|
|
if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8))
|
|
{
|
|
// buffer too small
|
|
PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader = Irp->AssociatedIrp.SystemBuffer;
|
|
ASSERT(ioStack->Parameters.DeviceIoControl.OutputBufferLength
|
|
>= sizeof(STORAGE_DESCRIPTOR_HEADER));
|
|
|
|
// return required size
|
|
DescriptorHeader->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8);
|
|
DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8);
|
|
|
|
Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
|
|
status = STATUS_SUCCESS;
|
|
goto completeIrp;
|
|
}
|
|
|
|
// get adapter descriptor, information is returned in the same buffer
|
|
PSTORAGE_ADAPTER_DESCRIPTOR_WIN8 adapterDescriptor = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
// fill out descriptor
|
|
// NOTE: STORAGE_ADAPTER_DESCRIPTOR_WIN8 may vary in size, so it's important to zero out
|
|
// all unused fields
|
|
*adapterDescriptor = (STORAGE_ADAPTER_DESCRIPTOR_WIN8) {
|
|
.Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8),
|
|
.Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8),
|
|
.MaximumTransferLength = portExt->PortCapabilities.MaximumTransferLength,
|
|
.MaximumPhysicalPages = portExt->PortCapabilities.MaximumPhysicalPages,
|
|
.AlignmentMask = portExt->PortCapabilities.AlignmentMask,
|
|
.AdapterUsesPio = portExt->PortCapabilities.AdapterUsesPio,
|
|
.AdapterScansDown = portExt->PortCapabilities.AdapterScansDown,
|
|
.CommandQueueing = portExt->PortCapabilities.TaggedQueuing,
|
|
.AcceleratedTransfer = TRUE,
|
|
.BusType = BusTypeScsi, // FIXME
|
|
.BusMajorVersion = 2,
|
|
.BusMinorVersion = 0
|
|
};
|
|
|
|
// store returned length
|
|
Irp->IoStatus.Information = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8);
|
|
status = STATUS_SUCCESS;
|
|
|
|
completeIrp:
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* NAME INTERNAL
|
|
* ScsiPortDeviceControl
|
|
*
|
|
* DESCRIPTION
|
|
* Answer requests for device control calls
|
|
*
|
|
* RUN LEVEL
|
|
* PASSIVE_LEVEL
|
|
*
|
|
* ARGUMENTS
|
|
* Standard dispatch arguments
|
|
*
|
|
* RETURNS
|
|
* NTSTATUS
|
|
*/
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ScsiPortDeviceControl(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_In_ PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION Stack;
|
|
PSCSI_PORT_COMMON_EXTENSION comExt = DeviceObject->DeviceExtension;
|
|
PSCSI_PORT_DEVICE_EXTENSION portExt;
|
|
PSCSI_PORT_LUN_EXTENSION lunExt;
|
|
NTSTATUS status;
|
|
|
|
DPRINT("ScsiPortDeviceControl()\n");
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_STORAGE_QUERY_PROPERTY:
|
|
{
|
|
DPRINT(" IOCTL_STORAGE_QUERY_PROPERTY\n");
|
|
|
|
if (!VerifyIrpInBufferSize(Irp, sizeof(STORAGE_PROPERTY_QUERY)))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
if (comExt->IsFDO)
|
|
return FdoHandleQueryProperty(DeviceObject, Irp);
|
|
else
|
|
return PdoHandleQueryProperty(DeviceObject, Irp);
|
|
}
|
|
case IOCTL_SCSI_GET_ADDRESS:
|
|
{
|
|
DPRINT(" IOCTL_SCSI_GET_ADDRESS\n");
|
|
|
|
if (comExt->IsFDO)
|
|
{
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
PSCSI_ADDRESS address = Irp->AssociatedIrp.SystemBuffer;
|
|
if (!VerifyIrpOutBufferSize(Irp, sizeof(*address)))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
lunExt = DeviceObject->DeviceExtension;
|
|
portExt = comExt->LowerDevice->DeviceExtension;
|
|
|
|
address->Length = sizeof(SCSI_ADDRESS);
|
|
address->PortNumber = portExt->PortNumber;
|
|
address->PathId = lunExt->PathId;
|
|
address->TargetId = lunExt->TargetId;
|
|
address->Lun = lunExt->Lun;
|
|
|
|
Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IOCTL_SCSI_GET_DUMP_POINTERS:
|
|
{
|
|
DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
|
|
|
|
if (!comExt->IsFDO)
|
|
{
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(comExt->LowerDevice, Irp);
|
|
}
|
|
|
|
PDUMP_POINTERS dumpPointers = Irp->AssociatedIrp.SystemBuffer;
|
|
if (!VerifyIrpOutBufferSize(Irp, sizeof(*dumpPointers)))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
dumpPointers->DeviceObject = DeviceObject;
|
|
/* More data.. ? */
|
|
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
|
|
break;
|
|
}
|
|
case IOCTL_SCSI_GET_CAPABILITIES:
|
|
{
|
|
DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
|
|
|
|
if (!comExt->IsFDO)
|
|
{
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
if (!VerifyIrpOutBufferSize(Irp, sizeof(IO_SCSI_CAPABILITIES)))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
portExt = DeviceObject->DeviceExtension;
|
|
|
|
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
|
&portExt->PortCapabilities,
|
|
sizeof(IO_SCSI_CAPABILITIES));
|
|
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
|
|
break;
|
|
}
|
|
case IOCTL_SCSI_GET_INQUIRY_DATA:
|
|
{
|
|
DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
|
|
|
|
if (!comExt->IsFDO)
|
|
{
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
/* Copy inquiry data to the port device extension */
|
|
status = SpiGetInquiryData(DeviceObject->DeviceExtension, Irp);
|
|
break;
|
|
}
|
|
case IOCTL_SCSI_MINIPORT:
|
|
DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
/* Complete the request with the given status */
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|