[SCSIPORT] Make the driver PnP-aware

Basic functions are implemented in order to work in PnP stack,
only legacy (non-pnp) miniport drivers are supported.
Tested mostly with uniata

CORE-17132
This commit is contained in:
Victor Perevertkin 2020-10-28 02:42:56 +03:00
parent 582ca68696
commit a97c6e0aa9
No known key found for this signature in database
GPG key ID: C750B7222E9C7830
11 changed files with 2087 additions and 1050 deletions

View file

@ -2,20 +2,25 @@
spec2def(scsiport.sys scsiport.spec ADD_IMPORTLIB)
list(APPEND SOURCE
fdo.c
ioctl.c
pdo.c
registry.c
scsi.c
fdo.c
ioctl.c
pdo.c
power.c
registry.c
scsi.c
scsiport.c
stubs.c)
list(APPEND PCH_SKIP_SOURCE
guid.c)
add_library(scsiport MODULE
${SOURCE}
${PCH_SKIP_SOURCE}
scsiport.rc
${CMAKE_CURRENT_BINARY_DIR}/scsiport.def)
add_pch(scsiport scsiport.h "")
add_pch(scsiport scsiport.h "${PCH_SKIP_SOURCE}")
set_module_type(scsiport kernelmodedriver)
add_importlibs(scsiport ntoskrnl hal)
add_cd_file(TARGET scsiport DESTINATION reactos/system32/drivers NO_CAB FOR all)

View file

@ -4,6 +4,7 @@
* PURPOSE: Adapter device object (FDO) support routines
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
* Aleksey Bragin (aleksey@reactos.org)
* 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
#include "scsiport.h"
@ -14,9 +15,8 @@
static
NTSTATUS
SpiSendInquiry(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PSCSI_LUN_INFO LunInfo)
FdoSendInquiry(
_In_ PDEVICE_OBJECT DeviceObject)
{
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IrpStack;
@ -30,12 +30,12 @@ SpiSendInquiry(
ULONG RetryCount = 0;
SCSI_REQUEST_BLOCK Srb;
PCDB Cdb;
PSCSI_PORT_LUN_EXTENSION LunExtension;
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
DPRINT("SpiSendInquiry() called\n");
DPRINT("FdoSendInquiry() called\n");
DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
PSCSI_PORT_LUN_EXTENSION LunExtension = DeviceObject->DeviceExtension;
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension =
LunExtension->Common.LowerDevice->DeviceExtension;
InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
if (InquiryBuffer == NULL)
@ -80,9 +80,9 @@ SpiSendInquiry(
Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
Srb.OriginalRequest = Irp;
Srb.PathId = LunInfo->PathId;
Srb.TargetId = LunInfo->TargetId;
Srb.Lun = LunInfo->Lun;
Srb.PathId = LunExtension->PathId;
Srb.TargetId = LunExtension->TargetId;
Srb.Lun = LunExtension->Lun;
Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
Srb.TimeOutValue = 4;
@ -101,7 +101,7 @@ SpiSendInquiry(
/* Fill in CDB */
Cdb = (PCDB)Srb.Cdb;
Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
Cdb->CDB6INQUIRY.LogicalUnitNumber = LunExtension->Lun;
Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
/* Call the driver */
@ -110,7 +110,7 @@ SpiSendInquiry(
/* Wait for it to complete */
if (Status == STATUS_PENDING)
{
DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
DPRINT("FdoSendInquiry(): Waiting for the driver to process request...\n");
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
@ -119,12 +119,12 @@ SpiSendInquiry(
Status = IoStatusBlock.Status;
}
DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
DPRINT("FdoSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
{
/* All fine, copy data over */
RtlCopyMemory(LunInfo->InquiryData,
RtlCopyMemory(&LunExtension->InquiryData,
InquiryBuffer,
INQUIRYDATABUFFERSIZE);
@ -142,12 +142,7 @@ SpiSendInquiry(
/* Something weird happened, deal with it (unfreeze the queue) */
KeepTrying = FALSE;
DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
LunExtension = SpiGetLunExtension(DeviceExtension,
LunInfo->PathId,
LunInfo->TargetId,
LunInfo->Lun);
DPRINT("FdoSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
/* Clear frozen flag */
LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
@ -156,7 +151,7 @@ SpiSendInquiry(
KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
/* Process the request */
SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
/* SpiGetNextRequestFromLun() releases the spinlock,
so we just lower irql back to what it was before */
@ -166,10 +161,10 @@ SpiSendInquiry(
/* Check if data overrun happened */
if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
{
DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
DPRINT("Data overrun at TargetId %d\n", LunExtension->TargetId);
/* Nothing dramatic, just copy data, but limiting the size */
RtlCopyMemory(LunInfo->InquiryData,
RtlCopyMemory(&LunExtension->InquiryData,
InquiryBuffer,
(Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
@ -221,229 +216,141 @@ SpiSendInquiry(
ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
DPRINT("FdoSendInquiry() done with Status 0x%08X\n", Status);
return Status;
}
/* Scans all SCSI buses */
VOID
SpiScanAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
FdoScanAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION PortExtension)
{
PSCSI_PORT_LUN_EXTENSION LunExtension;
ULONG Bus;
ULONG Target;
ULONG Lun;
PSCSI_BUS_SCAN_INFO BusScanInfo;
PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
BOOLEAN DeviceExists;
ULONG Hint;
NTSTATUS Status;
ULONG DevicesFound;
NTSTATUS status;
UINT32 totalLUNs = PortExtension->TotalLUCount;
DPRINT("SpiScanAdapter() called\n");
DPRINT("FdoScanAdapter() called\n");
/* Scan all buses */
for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
for (UINT8 pathId = 0; pathId < PortExtension->NumberOfBuses; pathId++)
{
DPRINT(" Scanning bus %d\n", Bus);
DevicesFound = 0;
DPRINT(" Scanning bus/pathID %u\n", pathId);
/* Get pointer to the scan information */
BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
if (BusScanInfo)
{
/* Find the last LUN info in the list */
LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
LastLunInfo = LunInfo;
while (LunInfo != NULL)
{
LastLunInfo = LunInfo;
LunInfo = LunInfo->Next;
}
}
else
{
/* We need to allocate this buffer */
BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
if (!BusScanInfo)
{
DPRINT1("Out of resources!\n");
return;
}
/* Store the pointer in the BusScanInfo array */
DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
/* Fill this struct (length and bus ids for now) */
BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
BusScanInfo->LogicalUnitsCount = 0;
BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
BusScanInfo->LunInfo = NULL;
/* Set pointer to the last LUN info to NULL */
LastLunInfo = NULL;
}
/* Create LUN information structure */
LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
if (!LunInfo)
{
DPRINT1("Out of resources!\n");
return;
}
RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
/* Create LunExtension */
LunExtension = SpiAllocateLunExtension(DeviceExtension);
PSCSI_BUS_INFO currentBus = &PortExtension->Buses[pathId];
/* And send INQUIRY to every target */
for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
for (UINT8 targetId = 0;
targetId < PortExtension->PortConfig->MaximumNumberOfTargets;
targetId++)
{
BOOLEAN targetFound = FALSE;
/* TODO: Support scan bottom-up */
/* Skip if it's the same address */
if (Target == BusScanInfo->BusIdentifier)
continue;
/* Try to find an existing device here */
DeviceExists = FALSE;
LunInfoExists = BusScanInfo->LunInfo;
/* Find matching address on this bus */
while (LunInfoExists)
{
if (LunInfoExists->TargetId == Target)
{
DeviceExists = TRUE;
break;
}
/* Advance to the next one */
LunInfoExists = LunInfoExists->Next;
}
/* No need to bother rescanning, since we already did that before */
if (DeviceExists)
if (targetId == currentBus->BusIdentifier)
continue;
/* Scan all logical units */
for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
for (UINT8 lun = 0; lun < PortExtension->MaxLunCount; lun++)
{
if ((!LunExtension) || (!LunInfo))
break;
// try to find an existing device
PSCSI_PORT_LUN_EXTENSION lunExt = GetLunByPath(PortExtension,
pathId,
targetId,
lun);
/* Add extension to the list */
Hint = (Target + Lun) % LUS_NUMBER;
LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
DeviceExtension->LunExtensionList[Hint] = LunExtension;
/* Fill Path, Target, Lun fields */
LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
LunExtension->TargetId = LunInfo->TargetId = (UCHAR)Target;
LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
/* Set flag to prevent race conditions */
LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
/* Zero LU extension contents */
if (DeviceExtension->LunExtensionSize)
if (lunExt)
{
RtlZeroMemory(LunExtension + 1,
DeviceExtension->LunExtensionSize);
// check if the device still exists
status = FdoSendInquiry(lunExt->Common.DeviceObject);
if (!NT_SUCCESS(status))
{
// remove the device
UNIMPLEMENTED;
__debugbreak();
}
if (lunExt->InquiryData.DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
{
// remove the device
UNIMPLEMENTED;
__debugbreak();
}
/* Decide whether we are continuing or not */
if (status == STATUS_INVALID_DEVICE_REQUEST)
continue;
else
break;
}
/* Finally send the inquiry command */
Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
// create a new LUN device
PDEVICE_OBJECT lunPDO = PdoCreateLunDevice(PortExtension);
if (!lunPDO)
{
continue;
}
if (NT_SUCCESS(Status))
lunExt = lunPDO->DeviceExtension;
lunExt->PathId = pathId;
lunExt->TargetId = targetId;
lunExt->Lun = lun;
DPRINT("Add PDO to list: PDO: %p, FDOExt: %p, PDOExt: %p\n", lunPDO, PortExtension, lunExt);
/* Set flag to prevent race conditions */
lunExt->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
/* Finally send the inquiry command */
status = FdoSendInquiry(lunPDO);
if (NT_SUCCESS(status))
{
/* Let's see if we really found a device */
PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
PINQUIRYDATA InquiryData = &lunExt->InquiryData;
/* Check if this device is unsupported */
if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
{
DeviceExtension->LunExtensionList[Hint] =
DeviceExtension->LunExtensionList[Hint]->Next;
IoDeleteDevice(lunPDO);
continue;
}
/* Clear the "in scan" flag */
LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
lunExt->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
InquiryData->DeviceType, Bus, Target, Lun);
DPRINT("FdoScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
InquiryData->DeviceType, pathId, targetId, lun);
/*
* Cache the inquiry data into the LUN extension (or alternatively
* we could save a pointer to LunInfo within the LunExtension?)
*/
RtlCopyMemory(&LunExtension->InquiryData,
InquiryData,
INQUIRYDATABUFFERSIZE);
InsertTailList(&currentBus->LunsListHead, &lunExt->LunEntry);
/* Add this info to the linked list */
LunInfo->Next = NULL;
if (LastLunInfo)
LastLunInfo->Next = LunInfo;
else
BusScanInfo->LunInfo = LunInfo;
DPRINT1("SCSIPORT: created lun device: %p Status: %x\n", lunPDO, status);
/* Store the last LUN info */
LastLunInfo = LunInfo;
/* Store DeviceObject */
LunInfo->DeviceObject = DeviceExtension->DeviceObject;
/* Allocate another buffer */
LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
if (!LunInfo)
{
DPRINT1("Out of resources!\n");
break;
}
RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
/* Create a new LU extension */
LunExtension = SpiAllocateLunExtension(DeviceExtension);
DevicesFound++;
totalLUNs++;
currentBus->LogicalUnitsCount++;
targetFound = TRUE;
}
else
{
/* Remove this LUN from the list */
DeviceExtension->LunExtensionList[Hint] =
DeviceExtension->LunExtensionList[Hint]->Next;
/* Decide whether we are continuing or not */
if (Status == STATUS_INVALID_DEVICE_REQUEST)
if (status == STATUS_INVALID_DEVICE_REQUEST)
continue;
else
break;
}
}
if (targetFound)
{
currentBus->TargetsCount++;
}
}
/* Free allocated buffers */
if (LunExtension)
ExFreePoolWithTag(LunExtension, TAG_SCSIPORT);
if (LunInfo)
ExFreePoolWithTag(LunInfo, TAG_SCSIPORT);
/* Sum what we found */
BusScanInfo->LogicalUnitsCount += (UCHAR)DevicesFound;
DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus);
}
DPRINT("SpiScanAdapter() done\n");
PortExtension->TotalLUCount = totalLUNs;
}
/**
@ -456,11 +363,11 @@ SpiScanAdapter(
* @return NTSTATUS of the operation
*/
NTSTATUS
CallHWInitialize(
FdoCallHWInitialize(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{
PPORT_CONFIGURATION_INFORMATION PortConfig = DeviceExtension->PortConfig;
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS Status;
KIRQL OldIrql;
/* Deal with interrupts */
@ -508,9 +415,13 @@ CallHWInitialize(
}
if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
{
MaxDirql = Dirql[0];
}
else
{
MaxDirql = Dirql[1];
}
for (i = 0; i < DeviceExtension->InterruptCount; i++)
{
@ -525,10 +436,16 @@ CallHWInitialize(
InterruptShareable = FALSE;
}
Status = IoConnectInterrupt(
&DeviceExtension->Interrupt[i], (PKSERVICE_ROUTINE)ScsiPortIsr, DeviceExtension,
&DeviceExtension->IrqLock, MappedIrq[i], Dirql[i], MaxDirql, InterruptMode[i],
InterruptShareable, Affinity[i], FALSE);
Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i],
ScsiPortIsr,
DeviceExtension,
&DeviceExtension->IrqLock,
MappedIrq[i], Dirql[i],
MaxDirql,
InterruptMode[i],
InterruptShareable,
Affinity[i],
FALSE);
if (!(NT_SUCCESS(Status)))
{
@ -537,9 +454,6 @@ CallHWInitialize(
return Status;
}
}
if (!NT_SUCCESS(Status))
return Status;
}
/* Save IoAddress (from access ranges) */
@ -583,98 +497,96 @@ CallHWInitialize(
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
{
/* Call DPC right away, because we're already at DISPATCH_LEVEL */
ScsiPortDpcForIsr(NULL, DeviceExtension->DeviceObject, NULL, NULL);
ScsiPortDpcForIsr(NULL, DeviceExtension->Common.DeviceObject, NULL, NULL);
}
/* Lower irql back to what it was */
KeLowerIrql(OldIrql);
return Status;
return STATUS_SUCCESS;
}
VOID
SpiCleanupAfterInit(
NTSTATUS
FdoRemoveAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{
PSCSI_LUN_INFO LunInfo;
PVOID Ptr;
ULONG Bus, Lun;
IoStopTimer(DeviceExtension->Common.DeviceObject);
/* Check if we have something to clean up */
if (DeviceExtension == NULL)
return;
// release device interface
if (DeviceExtension->InterfaceName.Buffer)
{
IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE);
/* Stop the timer */
IoStopTimer(DeviceExtension->DeviceObject);
RtlFreeUnicodeString(&DeviceExtension->InterfaceName);
RtlInitUnicodeString(&DeviceExtension->InterfaceName, NULL);
}
/* Disconnect the interrupts */
// remove the dos device link
WCHAR dosNameBuffer[12];
UNICODE_STRING dosDeviceName;
swprintf(dosNameBuffer, L"\\??\\Scsi%lu:", DeviceExtension->PortNumber);
RtlInitUnicodeString(&dosDeviceName, dosNameBuffer);
IoDeleteSymbolicLink(&dosDeviceName); // don't check the result
// decrease the port count
if (DeviceExtension->DeviceStarted)
{
PCONFIGURATION_INFORMATION sysConfig = IoGetConfigurationInformation();
sysConfig->ScsiPortCount--;
}
// disconnect the interrupts
while (DeviceExtension->InterruptCount)
{
if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
}
/* Delete ConfigInfo */
if (DeviceExtension->BusesConfig)
// FIXME: delete LUNs
if (DeviceExtension->Buses)
{
for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
{
if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
continue;
LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
while (LunInfo)
PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
if (bus->RegistryMapKey)
{
/* Free current, but save pointer to the next one */
Ptr = LunInfo->Next;
ExFreePool(LunInfo);
LunInfo = Ptr;
ZwDeleteKey(bus->RegistryMapKey);
ZwClose(bus->RegistryMapKey);
bus->RegistryMapKey = NULL;
}
ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
}
ExFreePool(DeviceExtension->BusesConfig);
ExFreePoolWithTag(DeviceExtension->Buses, TAG_SCSIPORT);
}
/* Free PortConfig */
if (DeviceExtension->PortConfig)
ExFreePool(DeviceExtension->PortConfig);
/* Free LUNs*/
for(Lun = 0; Lun < LUS_NUMBER; Lun++)
{
while (DeviceExtension->LunExtensionList[Lun])
{
Ptr = DeviceExtension->LunExtensionList[Lun];
DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
ExFreePool(Ptr);
}
ExFreePoolWithTag(DeviceExtension->PortConfig, TAG_SCSIPORT);
}
/* Free common buffer (if it exists) */
if (DeviceExtension->SrbExtensionBuffer != NULL &&
DeviceExtension->CommonBufferLength != 0)
if (DeviceExtension->SrbExtensionBuffer != NULL && DeviceExtension->CommonBufferLength != 0)
{
if (!DeviceExtension->AdapterObject)
{
ExFreePool(DeviceExtension->SrbExtensionBuffer);
}
else
{
HalFreeCommonBuffer(DeviceExtension->AdapterObject,
DeviceExtension->CommonBufferLength,
DeviceExtension->PhysicalAddress,
DeviceExtension->SrbExtensionBuffer,
FALSE);
}
if (!DeviceExtension->AdapterObject)
{
ExFreePoolWithTag(DeviceExtension->SrbExtensionBuffer, TAG_SCSIPORT);
}
else
{
HalFreeCommonBuffer(DeviceExtension->AdapterObject,
DeviceExtension->CommonBufferLength,
DeviceExtension->PhysicalAddress,
DeviceExtension->SrbExtensionBuffer,
FALSE);
}
}
/* Free SRB info */
if (DeviceExtension->SrbInfo != NULL)
ExFreePool(DeviceExtension->SrbInfo);
ExFreePoolWithTag(DeviceExtension->SrbInfo, TAG_SCSIPORT);
/* Unmap mapped addresses */
while (DeviceExtension->MappedAddressList != NULL)
@ -682,13 +594,161 @@ SpiCleanupAfterInit(
MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
DeviceExtension->MappedAddressList->NumberOfBytes);
Ptr = DeviceExtension->MappedAddressList;
PVOID ptr = DeviceExtension->MappedAddressList;
DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
ExFreePool(Ptr);
ExFreePoolWithTag(ptr, TAG_SCSIPORT);
}
/* Finally delete the device object */
DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
IoDeleteDevice(DeviceExtension->DeviceObject);
IoDeleteDevice(DeviceExtension->Common.DeviceObject);
return STATUS_SUCCESS;
}
NTSTATUS
FdoStartAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION PortExtension)
{
WCHAR dosNameBuffer[12];
UNICODE_STRING dosDeviceName;
NTSTATUS status;
// Start our timer
IoStartTimer(PortExtension->Common.DeviceObject);
// Create the dos device link
swprintf(dosNameBuffer, L"\\??\\Scsi%u:", PortExtension->PortNumber);
RtlInitUnicodeString(&dosDeviceName, dosNameBuffer);
status = IoCreateSymbolicLink(&dosDeviceName, &PortExtension->DeviceName);
if (!NT_SUCCESS(status))
{
return status;
}
// start building a device map
RegistryInitAdapterKey(PortExtension);
// increase the port count
PCONFIGURATION_INFORMATION sysConfig = IoGetConfigurationInformation();
sysConfig->ScsiPortCount++;
// Register and enable the device interface
status = IoRegisterDeviceInterface(PortExtension->Common.DeviceObject,
&StoragePortClassGuid,
NULL,
&PortExtension->InterfaceName);
DPRINT("IoRegisterDeviceInterface status: %x, InterfaceName: %wZ\n",
status, &PortExtension->InterfaceName);
if (NT_SUCCESS(status))
{
IoSetDeviceInterfaceState(&PortExtension->InterfaceName, TRUE);
}
PortExtension->DeviceStarted = TRUE;
return STATUS_SUCCESS;
}
static
NTSTATUS
FdoHandleDeviceRelations(
_In_ PSCSI_PORT_DEVICE_EXTENSION PortExtension,
_Inout_ PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
// FDO always only handles bus relations
if (ioStack->Parameters.QueryDeviceRelations.Type == BusRelations)
{
FdoScanAdapter(PortExtension);
DPRINT("Found %u PD objects, FDOExt: %p\n", PortExtension->TotalLUCount, PortExtension);
// check that no filter driver has messed up this
ASSERT(Irp->IoStatus.Information == 0);
PDEVICE_RELATIONS deviceRelations =
ExAllocatePoolWithTag(PagedPool,
(sizeof(DEVICE_RELATIONS) +
sizeof(PDEVICE_OBJECT) * (PortExtension->TotalLUCount - 1)),
TAG_SCSIPORT);
if (!deviceRelations)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
deviceRelations->Count = 0;
for (UINT8 pathId = 0; pathId < PortExtension->NumberOfBuses; pathId++)
{
PSCSI_BUS_INFO bus = &PortExtension->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);
deviceRelations->Objects[deviceRelations->Count++] = lunExt->Common.DeviceObject;
ObReferenceObject(lunExt->Common.DeviceObject);
}
}
ASSERT(deviceRelations->Count == PortExtension->TotalLUCount);
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(PortExtension->Common.LowerDevice, Irp);
}
NTSTATUS
FdoDispatchPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
PSCSI_PORT_DEVICE_EXTENSION portExt = DeviceObject->DeviceExtension;
NTSTATUS status;
ASSERT(portExt->Common.IsFDO);
DPRINT("FDO PnP request %s\n", GetIRPMinorFunctionString(ioStack->MinorFunction));
switch (ioStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
// as we don't support PnP yet, this is a no-op for us
// (FdoStartAdapter is being called during initialization for legacy miniports)
status = STATUS_SUCCESS;
// status = FdoStartAdapter(DeviceExtension);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
return FdoHandleDeviceRelations(portExt, Irp);
}
default:
{
// forward irp to next device object
IoCopyCurrentIrpStackLocationToNext(Irp);
return IoCallDriver(portExt->Common.LowerDevice, Irp);
}
}
if (status != STATUS_PENDING)
{
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
}

View file

@ -0,0 +1,11 @@
/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
#include <ntdef.h>
#include <initguid.h>
#include <ioevent.h>
#include <wdmguid.h>
#define DEVICE_TYPE ULONG
#include <ntddstor.h>
/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */

View file

@ -4,6 +4,7 @@
* 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"
@ -19,13 +20,10 @@ SpiGetInquiryData(
_In_ PIRP Irp)
{
ULONG InquiryDataSize;
PSCSI_LUN_INFO LunInfo;
ULONG BusCount, LunCount, Length;
ULONG BusCount, Length;
PIO_STACK_LOCATION IrpStack;
PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
PSCSI_INQUIRY_DATA InquiryData;
PSCSI_BUS_DATA BusData;
ULONG Bus;
PUCHAR Buffer;
DPRINT("SpiGetInquiryData() called\n");
@ -35,22 +33,15 @@ SpiGetInquiryData(
Buffer = Irp->AssociatedIrp.SystemBuffer;
/* Initialize bus and LUN counters */
BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
LunCount = 0;
/* Calculate total number of LUNs */
for (Bus = 0; Bus < BusCount; Bus++)
LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
BusCount = DeviceExtension->NumberOfBuses;
/* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
InquiryDataSize =
((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
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 * LunCount;
Length += InquiryDataSize * DeviceExtension->TotalLUCount;
/* Check, if all data is going to fit into provided buffer */
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
@ -73,47 +64,47 @@ SpiGetInquiryData(
(BusCount - 1) * sizeof(SCSI_BUS_DATA));
/* Loop each bus */
for (Bus = 0; Bus < BusCount; Bus++)
for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
{
BusData = &AdapterBusInfo->BusData[Bus];
PSCSI_BUS_DATA BusData = &AdapterBusInfo->BusData[pathId];
/* Calculate and save an offset of the inquiry data */
BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
/* Get a pointer to the LUN information structure */
LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
/* Store Initiator Bus Id */
BusData->InitiatorBusId =
DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
BusData->InitiatorBusId = DeviceExtension->Buses[pathId].BusIdentifier;
/* Store LUN count */
BusData->NumberOfLogicalUnits =
DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
BusData->NumberOfLogicalUnits = DeviceExtension->Buses[pathId].LogicalUnitsCount;
/* Loop all LUNs */
while (LunInfo != NULL)
PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
lunEntry != &bus->LunsListHead;
lunEntry = lunEntry->Flink)
{
DPRINT("(Bus %lu Target %lu Lun %lu)\n",
Bus, LunInfo->TargetId, LunInfo->Lun);
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 = LunInfo->PathId;
InquiryData->TargetId = LunInfo->TargetId;
InquiryData->Lun = LunInfo->Lun;
InquiryData->PathId = lunExt->PathId;
InquiryData->TargetId = lunExt->TargetId;
InquiryData->Lun = lunExt->Lun;
InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
InquiryData->DeviceClaimed = lunExt->DeviceClaimed;
InquiryData->NextInquiryDataOffset =
(ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
/* Copy data in it */
RtlCopyMemory(InquiryData->InquiryData,
LunInfo->InquiryData,
&lunExt->InquiryData,
INQUIRYDATABUFFERSIZE);
/* Move to the next LUN */
LunInfo = LunInfo->Next;
InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
InquiryData = (PSCSI_INQUIRY_DATA) ((ULONG_PTR)InquiryData + InquiryDataSize);
}
/* Either mark the end, or set offset to 0 */
@ -128,6 +119,269 @@ SpiGetInquiryData(
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))
{
// 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);
DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
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 adapterDescriptor = Irp->AssociatedIrp.SystemBuffer;
// fill out descriptor
// NOTE: STORAGE_ADAPTER_DESCRIPTOR may vary in size, so it's important to zero out
// all unused fields
*adapterDescriptor = (STORAGE_ADAPTER_DESCRIPTOR) {
.Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR),
.Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR),
.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);
status = STATUS_SUCCESS;
completeIrp:
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
/**********************************************************************
* NAME INTERNAL
* ScsiPortDeviceControl
@ -152,104 +406,147 @@ ScsiPortDeviceControl(
_In_ PIRP Irp)
{
PIO_STACK_LOCATION Stack;
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PDUMP_POINTERS DumpPointers;
NTSTATUS Status;
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);
DeviceExtension = DeviceObject->DeviceExtension;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_SCSI_GET_DUMP_POINTERS:
DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
case IOCTL_STORAGE_QUERY_PROPERTY:
{
Status = STATUS_BUFFER_OVERFLOW;
Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
break;
}
DPRINT(" IOCTL_STORAGE_QUERY_PROPERTY\n");
DumpPointers = Irp->AssociatedIrp.SystemBuffer;
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 (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
{
*((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
Irp->IoStatus.Information = sizeof(PVOID);
Status = STATUS_SUCCESS;
break;
}
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
&DeviceExtension->PortCapabilities,
sizeof(IO_SCSI_CAPABILITIES));
Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
Status = STATUS_SUCCESS;
break;
case IOCTL_SCSI_GET_INQUIRY_DATA:
DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
/* Copy inquiry data to the port device extension */
Status = SpiGetInquiryData(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:
if (DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode) == MOUNTDEVCONTROLTYPE)
{
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
if (!VerifyIrpInBufferSize(Irp, sizeof(STORAGE_PROPERTY_QUERY)))
{
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
break;
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
break;
default:
DPRINT(" got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
status = STATUS_BUFFER_TOO_SMALL;
break;
}
} else {
DPRINT1(" unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
}
Status = STATUS_NOT_IMPLEMENTED;
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;
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
return status;
}

View file

@ -4,40 +4,48 @@
* PURPOSE: Logical Unit (PDO) functions
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
* Aleksey Bragin (aleksey@reactos.org)
* 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
#include "scsiport.h"
#include "scsitypes.h"
#define NDEBUG
#include <debug.h>
PSCSI_PORT_LUN_EXTENSION
SpiAllocateLunExtension(
PDEVICE_OBJECT
PdoCreateLunDevice(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{
PSCSI_PORT_LUN_EXTENSION LunExtension;
ULONG LunExtensionSize;
PDEVICE_OBJECT LunPDO;
DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension);
ULONG LunExtensionSize = DeviceExtension->LunExtensionSize + sizeof(SCSI_PORT_LUN_EXTENSION);
/* Round LunExtensionSize first to the sizeof LONGLONG */
LunExtensionSize = (DeviceExtension->LunExtensionSize +
sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
NTSTATUS Status = IoCreateDevice(DeviceExtension->Common.DeviceObject->DriverObject,
LunExtensionSize,
NULL,
FILE_DEVICE_DISK,
FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
FALSE,
&LunPDO);
LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
if (LunExtension == NULL)
if (!NT_SUCCESS(Status))
{
DPRINT1("Out of resources!\n");
DPRINT1("Failed to create a Lun PDO, status: %x\n", Status);
return NULL;
}
LunExtension = LunPDO->DeviceExtension;
/* Zero everything */
RtlZeroMemory(LunExtension, LunExtensionSize);
LunExtension->Common.IsFDO = FALSE;
LunExtension->Common.DeviceObject = LunPDO;
LunExtension->Common.LowerDevice = DeviceExtension->Common.DeviceObject;
/* Initialize a list of requests */
InitializeListHead(&LunExtension->SrbInfo.Requests);
@ -50,66 +58,54 @@ SpiAllocateLunExtension(
/* Initialize request queue */
KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
return LunExtension;
LunPDO->Flags |= DO_DIRECT_IO;
LunPDO->Flags &= ~DO_DEVICE_INITIALIZING;
return LunPDO;
}
PSCSI_PORT_LUN_EXTENSION
SpiGetLunExtension(
GetLunByPath(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ UCHAR PathId,
_In_ UCHAR TargetId,
_In_ UCHAR Lun)
{
PSCSI_PORT_LUN_EXTENSION LunExtension;
DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
DeviceExtension, PathId, TargetId, Lun);
/* Get appropriate list */
LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
/* Iterate it until we find what we need */
while (LunExtension)
if (PathId >= DeviceExtension->NumberOfBuses)
{
if (LunExtension->TargetId == TargetId &&
LunExtension->Lun == Lun &&
LunExtension->PathId == PathId)
{
/* All matches, return */
return LunExtension;
}
/* Advance to the next item */
LunExtension = LunExtension->Next;
DPRINT1("Invalid PathId: %u\n", PathId);
return NULL;
}
/* We did not find anything */
DPRINT("Nothing found\n");
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);
if (lunExt->PathId == PathId &&
lunExt->TargetId == TargetId &&
lunExt->Lun == Lun)
{
return lunExt;
}
}
DPRINT("SCSI LUN (%u, %u, %u) was not found\n", PathId, TargetId, Lun);
return NULL;
}
PSCSI_REQUEST_BLOCK_INFO
SpiGetSrbData(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ UCHAR PathId,
_In_ UCHAR TargetId,
_In_ UCHAR Lun,
_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,
_In_ UCHAR QueueTag)
{
PSCSI_PORT_LUN_EXTENSION LunExtension;
if (QueueTag == SP_UNTAGGED)
{
/* Untagged request, get LU and return pointer to SrbInfo */
LunExtension = SpiGetLunExtension(DeviceExtension,
PathId,
TargetId,
Lun);
/* Return NULL in case of error */
if (!LunExtension)
return(NULL);
/* Return the pointer to SrbInfo */
return &LunExtension->SrbInfo;
}
@ -122,3 +118,506 @@ SpiGetSrbData(
return &DeviceExtension->SrbInfo[QueueTag -1];
}
}
static
ULONG
CopyField(
IN PUCHAR Name,
IN PCHAR Buffer,
IN ULONG MaxLength)
{
ULONG Index;
for (Index = 0; Index < MaxLength; Index++)
{
if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',')
{
// convert to underscore
Buffer[Index] = '_';
}
else
{
// just copy character
Buffer[Index] = Name[Index];
}
}
return MaxLength;
}
static
ULONG
CopyFieldTruncate(
IN PUCHAR Name,
IN PCHAR Buffer,
IN ULONG MaxLength)
{
ULONG Index;
for (Index = 0; Index < MaxLength; Index++)
{
if (Name[Index] == '\0')
{
break;
}
else if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',')
{
// convert to space
Buffer[Index] = ' ';
}
else
{
// just copy character
Buffer[Index] = Name[Index];
}
}
return Index;
}
static
NTSTATUS
PdoHandleQueryDeviceText(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_LUN_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IoStack;
UINT32 Offset = 0;
PINQUIRYDATA InquiryData;
CHAR LocalBuffer[sizeof(InquiryData->VendorId) + sizeof(InquiryData->ProductId) + 2];
ANSI_STRING AnsiString;
UNICODE_STRING DeviceDescription;
IoStack = IoGetCurrentIrpStackLocation(Irp);
InquiryData = &DeviceExtension->InquiryData;
switch (IoStack->Parameters.QueryDeviceText.DeviceTextType)
{
case DeviceTextDescription:
case DeviceTextLocationInformation:
{
DPRINT("PdoHandleQueryDeviceText\n");
Offset += CopyFieldTruncate(InquiryData->VendorId,
&LocalBuffer[Offset],
sizeof(InquiryData->VendorId));
LocalBuffer[Offset++] = ' ';
Offset += CopyFieldTruncate(InquiryData->ProductId,
&LocalBuffer[Offset],
sizeof(InquiryData->ProductId));
LocalBuffer[Offset++] = '\0';
RtlInitAnsiString(&AnsiString, (PCSZ)&LocalBuffer);
DeviceDescription.Length = 0;
DeviceDescription.MaximumLength = (USHORT)(Offset * sizeof(WCHAR));
DeviceDescription.Buffer = ExAllocatePoolWithTag(PagedPool,
DeviceDescription.MaximumLength,
TAG_SCSIPORT);
if (!DeviceDescription.Buffer)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlAnsiStringToUnicodeString(&DeviceDescription, &AnsiString, FALSE);
Irp->IoStatus.Information = (ULONG_PTR)DeviceDescription.Buffer;
return STATUS_SUCCESS;
}
default:
{
Irp->IoStatus.Information = 0;
return Irp->IoStatus.Status;
}
}
}
static
NTSTATUS
PdoHandleQueryDeviceId(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_LUN_EXTENSION DeviceExtension;
NTSTATUS Status;
CHAR Buffer[100] = {0};
LPCSTR DeviceType;
ULONG Offset = 0;
PINQUIRYDATA InquiryData;
ANSI_STRING AnsiString;
UNICODE_STRING DeviceId;
DeviceExtension = DeviceObject->DeviceExtension;
InquiryData = &DeviceExtension->InquiryData;
DeviceType = GetDeviceType(InquiryData);
// lets create device string
Offset = sprintf(&Buffer[Offset], "SCSI\\");
Offset += sprintf(&Buffer[Offset], DeviceType);
Offset += sprintf(&Buffer[Offset], "&Ven_");
Offset += CopyField(InquiryData->VendorId, &Buffer[Offset], 8);
Offset += sprintf(&Buffer[Offset], "&Prod_");
Offset += CopyField(InquiryData->ProductId, &Buffer[Offset], 16);
Offset += sprintf(&Buffer[Offset], "&Rev_");
Offset += CopyField(InquiryData->ProductRevisionLevel, &Buffer[Offset], 4);
RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
// allocate DeviceId string
Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, TRUE);
if (NT_SUCCESS(Status))
{
Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
}
DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
return Status;
}
static
VOID
ConvertToUnicodeString(
IN CHAR * Buffer,
IN ULONG ResultBufferLength,
IN ULONG ResultBufferOffset,
OUT LPWSTR ResultBuffer,
OUT PULONG NewResultBufferOffset)
{
UNICODE_STRING DeviceString;
ANSI_STRING AnsiString;
NTSTATUS Status;
ASSERT(ResultBufferLength);
ASSERT(ResultBufferLength > ResultBufferOffset);
DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n",
ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
// construct destination string
DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
DeviceString.Length = 0;
DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
// initialize source string
RtlInitAnsiString(&AnsiString, Buffer);
Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
ASSERT(Status == STATUS_SUCCESS);
// subtract consumed bytes
ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
*NewResultBufferOffset = ResultBufferOffset;
}
static
NTSTATUS
PdoHandleQueryHardwareId(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_LUN_EXTENSION PDODeviceExtension = DeviceObject->DeviceExtension;
LPCSTR GenericType, DeviceType;
LPWSTR Buffer;
CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50], Id7[50];
ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length, Id6Length, Id7Length;
ULONG Offset, TotalLength, Length;
PINQUIRYDATA InquiryData;
InquiryData = &PDODeviceExtension->InquiryData;
DeviceType = GetDeviceType(InquiryData);
GenericType = GetGenericType(InquiryData);
ASSERT(GenericType);
// generate id 1
// SCSI\SCSIType_VendorId(8)_ProductId(16)_Revision(4)
RtlZeroMemory(Id1, sizeof(Id1));
Offset = 0;
Offset = sprintf(&Id1[Offset], "SCSI\\");
Offset += sprintf(&Id1[Offset], DeviceType);
Offset += CopyField(InquiryData->VendorId, &Id1[Offset], 8);
Offset += CopyField(InquiryData->ProductId, &Id1[Offset], 16);
Offset += CopyField(InquiryData->ProductRevisionLevel, &Id1[Offset], 4);
Id1Length = strlen(Id1) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
// generate id 2
// SCSI\SCSIType_VendorId(8)_ProductId(16)
RtlZeroMemory(Id2, sizeof(Id2));
Offset = 0;
Offset = sprintf(&Id2[Offset], "SCSI\\");
Offset += sprintf(&Id2[Offset], DeviceType);
Offset += CopyField(InquiryData->VendorId, &Id2[Offset], 8);
Offset += CopyField(InquiryData->ProductId, &Id2[Offset], 16);
Id2Length = strlen(Id2) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
// generate id 3
// SCSI\SCSIType_VendorId(8)
RtlZeroMemory(Id3, sizeof(Id3));
Offset = 0;
Offset = sprintf(&Id3[Offset], "SCSI\\");
Offset += sprintf(&Id3[Offset], DeviceType);
Offset += CopyField(InquiryData->VendorId, &Id3[Offset], 8);
Id3Length = strlen(Id3) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
// generate id 4
// SCSI\SCSIType_VendorId(8)_ProductId(16)_Revision(1)
RtlZeroMemory(Id4, sizeof(Id4));
Offset = 0;
Offset = sprintf(&Id4[Offset], "SCSI\\");
Offset += sprintf(&Id4[Offset], DeviceType);
Offset += CopyField(InquiryData->VendorId, &Id4[Offset], 8);
Offset += CopyField(InquiryData->ProductId, &Id4[Offset], 16);
Offset += CopyField(InquiryData->ProductRevisionLevel, &Id4[Offset], 1);
Id4Length = strlen(Id4) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
// generate id 5
// SCSIType_VendorId(8)_ProductId(16)_Revision(1)
RtlZeroMemory(Id5, sizeof(Id5));
Offset = 0;
Offset = sprintf(&Id5[Offset], DeviceType);
Offset += CopyField(InquiryData->VendorId, &Id5[Offset], 8);
Offset += CopyField(InquiryData->ProductId, &Id5[Offset], 16);
Offset += CopyField(InquiryData->ProductRevisionLevel, &Id5[Offset], 1);
Id5Length = strlen(Id5) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
// generate id 6
// SCSI\SCSIType
RtlZeroMemory(Id6, sizeof(Id6));
Offset = 0;
Offset = sprintf(&Id6[Offset], "SCSI\\");
Offset += sprintf(&Id6[Offset], GenericType);
Id6Length = strlen(Id6) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
// generate id 7
// SCSIType
RtlZeroMemory(Id7, sizeof(Id7));
Offset = 0;
Offset = sprintf(&Id7[Offset], GenericType);
Id7Length = strlen(Id7) + 1;
DPRINT("PdoHandleQueryHardwareId HardwareId7 %s\n", Id7);
TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + Id7Length + 1;
Buffer = ExAllocatePoolWithTag(PagedPool, TotalLength * sizeof(WCHAR), TAG_SCSIPORT);
if (!Buffer)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
// reset offset
Offset = 0;
Length = TotalLength;
ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
ConvertToUnicodeString(Id7, Length, Offset, Buffer, &Offset);
Buffer[Offset] = UNICODE_NULL;
ASSERT(Offset + 1 == Length);
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
}
static
NTSTATUS
PdoHandleQueryCompatibleId(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_LUN_EXTENSION PDODeviceExtension = DeviceObject->DeviceExtension;
CHAR Buffer[100] = {0};
ULONG Length, Offset;
LPWSTR InstanceId;
LPCSTR DeviceType;
DeviceType = GetDeviceType(&PDODeviceExtension->InquiryData);
// format instance id
Length = sprintf(Buffer, "%s", DeviceType) + 1;
Length += sprintf(&Buffer[Length], "%s", "RAW") + 2;
InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_SCSIPORT);
if (!InstanceId)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
InstanceId[Offset] = UNICODE_NULL;
DPRINT("PdoHandleQueryCompatibleId %S\n", InstanceId);
Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
return STATUS_SUCCESS;
}
static
NTSTATUS
PdoHandleQueryInstanceId(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension;
WCHAR Buffer[26];
ULONG Length;
LPWSTR InstanceId;
// use instance count and LUN
swprintf(Buffer, L"%x%x%x", lunExt->PathId, lunExt->TargetId, lunExt->Lun);
Length = wcslen(Buffer) + 1;
InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_SCSIPORT);
if (!InstanceId)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
wcscpy(InstanceId, Buffer);
DPRINT("PdoHandleQueryInstanceId %S\n", InstanceId);
Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
return STATUS_SUCCESS;
}
static
NTSTATUS
PdoHandleDeviceRelations(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PDEVICE_RELATIONS deviceRelations;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
// check if relation type is BusRelations
if (ioStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
{
// PDO handles only target device relation
return Irp->IoStatus.Status;
}
deviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_SCSIPORT);
if (!deviceRelations)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
// initialize device relations
deviceRelations->Count = 1;
deviceRelations->Objects[0] = DeviceObject;
ObReferenceObject(DeviceObject);
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
return STATUS_SUCCESS;
}
NTSTATUS
PdoDispatchPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension;
NTSTATUS status;
DPRINT("PDO PnP request %s\n", GetIRPMinorFunctionString(ioStack->MinorFunction));
ASSERT(!lunExt->Common.IsFDO);
switch (ioStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
RegistryInitLunKey(lunExt);
status = STATUS_SUCCESS;
break;
}
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
{
status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
status = PdoHandleDeviceRelations(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_DEVICE_TEXT:
{
status = PdoHandleQueryDeviceText(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_ID:
{
DPRINT("IRP_MN_QUERY_ID IdType %s\n",
DbgGetDeviceIDString(ioStack->Parameters.QueryId.IdType));
if (ioStack->Parameters.QueryId.IdType == BusQueryDeviceID)
{
status = PdoHandleQueryDeviceId(DeviceObject, Irp);
break;
}
else if (ioStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
{
status = PdoHandleQueryHardwareId(DeviceObject, Irp);
break;
}
else if (ioStack->Parameters.QueryId.IdType == BusQueryInstanceID)
{
status = PdoHandleQueryInstanceId(DeviceObject, Irp);
break;
}
else if (ioStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
{
status = PdoHandleQueryCompatibleId(DeviceObject, Irp);
break;
}
// fallthrough
}
default:
{
// do nothing
status = Irp->IoStatus.Status;
}
}
if (status != STATUS_PENDING)
{
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
}

View file

@ -0,0 +1,41 @@
/*
* PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: PnP power handlers
* COPYRIGHT: Copyright 2016 Thomas Faber <thomas.faber@reactos.org>
*/
#include "scsiport.h"
NTSTATUS
NTAPI
ScsiPortDispatchPower(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_COMMON_EXTENSION comExt = DeviceObject->DeviceExtension;
if (comExt->IsFDO)
{
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(comExt->LowerDevice, Irp);
}
else
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
switch (ioStack->MinorFunction)
{
case IRP_MN_SET_POWER:
case IRP_MN_QUERY_POWER:
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
}
NTSTATUS status = Irp->IoStatus.Status;
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
}

View file

@ -4,9 +4,11 @@
* PURPOSE: Registry operations
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
* Aleksey Bragin (aleksey@reactos.org)
* 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
#include "scsiport.h"
#include "scsitypes.h"
#define NDEBUG
#include <debug.h>
@ -15,26 +17,28 @@
VOID
SpiInitOpenKeys(
_Inout_ PCONFIGURATION_INFO ConfigInfo,
_In_ PUNICODE_STRING RegistryPath)
_In_ PSCSI_PORT_DRIVER_EXTENSION DriverExtension)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
NTSTATUS Status;
HANDLE parametersKey;
DriverExtension->IsLegacyDriver = TRUE;
/* Open the service key */
InitializeObjectAttributes(&ObjectAttributes,
RegistryPath,
OBJ_CASE_INSENSITIVE,
&DriverExtension->RegistryPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwOpenKey(&ConfigInfo->ServiceKey,
KEY_READ,
&ObjectAttributes);
Status = ZwOpenKey(&ConfigInfo->ServiceKey, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n",
DriverExtension->RegistryPath, Status);
ConfigInfo->ServiceKey = NULL;
}
@ -44,14 +48,12 @@ SpiInitOpenKeys(
RtlInitUnicodeString(&KeyName, L"Parameters");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
ConfigInfo->ServiceKey,
(PSECURITY_DESCRIPTOR) NULL);
NULL);
/* Try to open it */
Status = ZwOpenKey(&ConfigInfo->DeviceKey,
KEY_READ,
&ObjectAttributes);
Status = ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
@ -69,14 +71,32 @@ SpiInitOpenKeys(
RtlInitUnicodeString(&KeyName, L"Device");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
ConfigInfo->ServiceKey,
NULL);
/* We don't check for failure here - not needed */
ZwOpenKey(&ConfigInfo->DeviceKey,
KEY_READ,
&ObjectAttributes);
ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes);
// Detect the driver PnP capabilities via its Parameters\PnpInterface key
// for example: HKLM\SYSTEM\CurrentControlSet\Services\UNIATA\Parameters\PnpInterface
RtlInitUnicodeString(&KeyName, L"PnpInterface");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
ConfigInfo->ServiceKey,
NULL);
Status = ZwOpenKey(&parametersKey, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
// if the key exists, it's enough for us for now
// (the proper check should iterate over INTERFACE_TYPE values)
DriverExtension->IsLegacyDriver = FALSE;
ZwClose(parametersKey);
}
}
}
@ -104,34 +124,24 @@ SpiInitOpenKeys(
*/
NTSTATUS
SpiBuildDeviceMap(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ PUNICODE_STRING RegistryPath)
RegistryInitAdapterKey(
_Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{
PSCSI_PORT_LUN_EXTENSION LunExtension;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
WCHAR NameBuffer[64];
ULONG Disposition;
HANDLE ScsiKey;
HANDLE ScsiPortKey = NULL;
HANDLE ScsiBusKey = NULL;
HANDLE ScsiInitiatorKey = NULL;
HANDLE ScsiTargetKey = NULL;
HANDLE ScsiLunKey = NULL;
ULONG BusNumber;
ULONG Target;
ULONG CurrentTarget;
ULONG Lun;
PWCHAR DriverName;
ULONG UlongData;
PWCHAR TypeName;
NTSTATUS Status;
DPRINT("SpiBuildDeviceMap() called\n");
if (DeviceExtension == NULL || RegistryPath == NULL)
if (DeviceExtension == NULL)
{
DPRINT1("Invalid parameter\n");
return STATUS_INVALID_PARAMETER;
@ -151,7 +161,7 @@ SpiBuildDeviceMap(
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
@ -165,18 +175,14 @@ SpiBuildDeviceMap(
L"Scsi Port %lu",
DeviceExtension->PortNumber);
RtlInitUnicodeString(&KeyName, NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_KERNEL_HANDLE,
ScsiKey,
NULL);
InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_KERNEL_HANDLE, ScsiKey, NULL);
Status = ZwCreateKey(&ScsiPortKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
NULL);
ZwClose(ScsiKey);
if (!NT_SUCCESS(Status))
{
@ -206,14 +212,29 @@ SpiBuildDeviceMap(
}
/* Set 'Driver' (REG_SZ) value */
DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
PUNICODE_STRING driverNameU = &DeviceExtension->Common.DeviceObject->DriverObject->DriverName;
PWCHAR driverName = ExAllocatePoolWithTag(PagedPool,
driverNameU->Length + sizeof(UNICODE_NULL),
TAG_SCSIPORT);
if (!driverName)
{
DPRINT("Failed to allocate driverName!\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(driverName, driverNameU->Buffer, driverNameU->Length);
driverName[driverNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
RtlInitUnicodeString(&ValueName, L"Driver");
Status = ZwSetValueKey(ScsiPortKey,
&ValueName,
0,
REG_SZ,
DriverName,
(ULONG)((wcslen(DriverName) + 1) * sizeof(WCHAR)));
driverName,
driverNameU->Length + sizeof(UNICODE_NULL));
ExFreePoolWithTag(driverName, TAG_SCSIPORT);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
@ -256,7 +277,7 @@ SpiBuildDeviceMap(
}
/* Enumerate buses */
for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
for (BusNumber = 0; BusNumber < DeviceExtension->NumberOfBuses; BusNumber++)
{
/* Create 'Scsi Bus X' key */
DPRINT(" Scsi Bus %lu\n", BusNumber);
@ -266,7 +287,7 @@ SpiBuildDeviceMap(
RtlInitUnicodeString(&KeyName, NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
0,
OBJ_KERNEL_HANDLE,
ScsiPortKey,
NULL);
Status = ZwCreateKey(&ScsiBusKey,
@ -275,7 +296,7 @@ SpiBuildDeviceMap(
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
@ -291,7 +312,7 @@ SpiBuildDeviceMap(
RtlInitUnicodeString(&KeyName, NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
0,
OBJ_KERNEL_HANDLE,
ScsiBusKey,
NULL);
Status = ZwCreateKey(&ScsiInitiatorKey,
@ -300,7 +321,7 @@ SpiBuildDeviceMap(
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
@ -312,202 +333,14 @@ SpiBuildDeviceMap(
ZwClose(ScsiInitiatorKey);
ScsiInitiatorKey = NULL;
/* Enumerate targets */
CurrentTarget = (ULONG)-1;
ScsiTargetKey = NULL;
for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
{
for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
{
LunExtension = SpiGetLunExtension(DeviceExtension,
(UCHAR)BusNumber,
(UCHAR)Target,
(UCHAR)Lun);
if (LunExtension == NULL)
continue;
if (Target != CurrentTarget)
{
/* Close old target key */
if (ScsiTargetKey != NULL)
{
ZwClose(ScsiTargetKey);
ScsiTargetKey = NULL;
}
/* Create 'Target Id X' key */
DPRINT(" Target Id %lu\n", Target);
swprintf(NameBuffer,
L"Target Id %lu",
Target);
RtlInitUnicodeString(&KeyName, NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
0,
ScsiBusKey,
NULL);
Status = ZwCreateKey(&ScsiTargetKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
goto ByeBye;
}
CurrentTarget = Target;
}
/* Create 'Logical Unit Id X' key */
DPRINT(" Logical Unit Id %lu\n", Lun);
swprintf(NameBuffer,
L"Logical Unit Id %lu",
Lun);
RtlInitUnicodeString(&KeyName, NameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
0,
ScsiTargetKey,
NULL);
Status = ZwCreateKey(&ScsiLunKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
goto ByeBye;
}
/* Set 'Identifier' (REG_SZ) value */
swprintf(NameBuffer,
L"%.8S%.16S%.4S",
LunExtension->InquiryData.VendorId,
LunExtension->InquiryData.ProductId,
LunExtension->InquiryData.ProductRevisionLevel);
DPRINT(" Identifier = '%S'\n", NameBuffer);
RtlInitUnicodeString(&ValueName, L"Identifier");
Status = ZwSetValueKey(ScsiLunKey,
&ValueName,
0,
REG_SZ,
NameBuffer,
(ULONG)((wcslen(NameBuffer) + 1) * sizeof(WCHAR)));
if (!NT_SUCCESS(Status))
{
DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
goto ByeBye;
}
/* Set 'Type' (REG_SZ) value */
/*
* See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices
* and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices
* for a list of types with their human-readable forms.
*/
switch (LunExtension->InquiryData.DeviceType)
{
case 0:
TypeName = L"DiskPeripheral";
break;
case 1:
TypeName = L"TapePeripheral";
break;
case 2:
TypeName = L"PrinterPeripheral";
break;
// case 3: "ProcessorPeripheral", classified as 'other': fall back to default case.
case 4:
TypeName = L"WormPeripheral";
break;
case 5:
TypeName = L"CdRomPeripheral";
break;
case 6:
TypeName = L"ScannerPeripheral";
break;
case 7:
TypeName = L"OpticalDiskPeripheral";
break;
case 8:
TypeName = L"MediumChangerPeripheral";
break;
case 9:
TypeName = L"CommunicationsPeripheral";
break;
/* New peripheral types (SCSI only) */
case 10: case 11:
TypeName = L"ASCPrePressGraphicsPeripheral";
break;
case 12:
TypeName = L"ArrayPeripheral";
break;
case 13:
TypeName = L"EnclosurePeripheral";
break;
case 14:
TypeName = L"RBCPeripheral";
break;
case 15:
TypeName = L"CardReaderPeripheral";
break;
case 16:
TypeName = L"BridgePeripheral";
break;
default:
TypeName = L"OtherPeripheral";
break;
}
DPRINT(" Type = '%S'\n", TypeName);
RtlInitUnicodeString(&ValueName, L"Type");
Status = ZwSetValueKey(ScsiLunKey,
&ValueName,
0,
REG_SZ,
TypeName,
(ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR)));
if (!NT_SUCCESS(Status))
{
DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
goto ByeBye;
}
ZwClose(ScsiLunKey);
ScsiLunKey = NULL;
}
/* Close old target key */
if (ScsiTargetKey != NULL)
{
ZwClose(ScsiTargetKey);
ScsiTargetKey = NULL;
}
}
ZwClose(ScsiBusKey);
DeviceExtension->Buses[BusNumber].RegistryMapKey = ScsiBusKey;
ScsiBusKey = NULL;
}
ByeBye:
if (ScsiLunKey != NULL)
ZwClose(ScsiLunKey);
if (ScsiInitiatorKey != NULL)
ZwClose(ScsiInitiatorKey);
if (ScsiTargetKey != NULL)
ZwClose(ScsiTargetKey);
if (ScsiBusKey != NULL)
ZwClose(ScsiBusKey);
@ -518,3 +351,109 @@ ByeBye:
return Status;
}
NTSTATUS
RegistryInitLunKey(
_Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension)
{
WCHAR nameBuffer[64];
UNICODE_STRING keyName;
UNICODE_STRING valueName;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE targetKey;
NTSTATUS status;
// get the LUN's bus key
PSCSI_PORT_DEVICE_EXTENSION portExt = LunExtension->Common.LowerDevice->DeviceExtension;
HANDLE busKey = portExt->Buses[LunExtension->PathId].RegistryMapKey;
// create/open 'Target Id X' key
swprintf(nameBuffer, L"Target Id %lu", LunExtension->TargetId);
RtlInitUnicodeString(&keyName, nameBuffer);
InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, busKey, NULL);
status = ZwCreateKey(&targetKey,
KEY_ALL_ACCESS,
&objectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL);
if (!NT_SUCCESS(status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", status);
return status;
}
// Create 'Logical Unit Id X' key
swprintf(nameBuffer, L"Logical Unit Id %lu", LunExtension->Lun);
RtlInitUnicodeString(&keyName, nameBuffer);
InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, targetKey, NULL);
status = ZwCreateKey(&LunExtension->RegistryMapKey,
KEY_ALL_ACCESS,
&objectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL);
if (!NT_SUCCESS(status))
{
DPRINT("ZwCreateKey() failed (Status %lx)\n", status);
goto ByeBye;
}
// Set 'Identifier' (REG_SZ) value
swprintf(nameBuffer,
L"%.8S%.16S%.4S",
LunExtension->InquiryData.VendorId,
LunExtension->InquiryData.ProductId,
LunExtension->InquiryData.ProductRevisionLevel);
RtlInitUnicodeString(&valueName, L"Identifier");
status = ZwSetValueKey(LunExtension->RegistryMapKey,
&valueName,
0,
REG_SZ,
nameBuffer,
(wcslen(nameBuffer) + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(status))
{
DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", status);
goto ByeBye;
}
// Set 'Type' (REG_SZ) value
PWCHAR typeName = (PWCHAR)GetPeripheralTypeW(&LunExtension->InquiryData);
DPRINT(" Type = '%S'\n", typeName);
RtlInitUnicodeString(&valueName, L"Type");
status = ZwSetValueKey(LunExtension->RegistryMapKey,
&valueName,
0,
REG_SZ,
typeName,
(wcslen(typeName) + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(status))
{
DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", status);
goto ByeBye;
}
// Set 'InquiryData' (REG_BINARY) value
RtlInitUnicodeString(&valueName, L"InquiryData");
status = ZwSetValueKey(LunExtension->RegistryMapKey,
&valueName,
0,
REG_BINARY,
&LunExtension->InquiryData,
INQUIRYDATABUFFERSIZE);
if (!NT_SUCCESS(status))
{
DPRINT("ZwSetValueKey('InquiryData') failed (Status %lx)\n", status);
goto ByeBye;
}
ByeBye:
ZwClose(targetKey);
// TODO: maybe we will need it in future
ZwClose(LunExtension->RegistryMapKey);
return status;
}

View file

@ -50,47 +50,17 @@ SpiStatusSrbToNt(
static
NTSTATUS
SpiHandleAttachRelease(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,
_Inout_ PIRP Irp)
{
PSCSI_LUN_INFO LunInfo;
PIO_STACK_LOCATION IrpStack;
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension =
LunExtension->Common.LowerDevice->DeviceExtension;
PDEVICE_OBJECT DeviceObject;
PSCSI_REQUEST_BLOCK Srb;
KIRQL Irql;
/* Get pointer to the SRB */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
/* Check if PathId matches number of buses */
if (DeviceExtension->BusesConfig == NULL ||
DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
{
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
return STATUS_DEVICE_DOES_NOT_EXIST;
}
/* Get pointer to LunInfo */
LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
/* Find matching LunInfo */
while (LunInfo)
{
if (LunInfo->PathId == Srb->PathId &&
LunInfo->TargetId == Srb->TargetId &&
LunInfo->Lun == Srb->Lun)
{
break;
}
LunInfo = LunInfo->Next;
}
/* If we couldn't find it - exit */
if (LunInfo == NULL)
return STATUS_DEVICE_DOES_NOT_EXIST;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PSCSI_REQUEST_BLOCK Srb = IrpStack->Parameters.Scsi.Srb;
/* Get spinlock */
KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
@ -98,7 +68,7 @@ SpiHandleAttachRelease(
/* Release, if asked */
if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
{
LunInfo->DeviceClaimed = FALSE;
LunExtension->DeviceClaimed = FALSE;
KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
Srb->SrbStatus = SRB_STATUS_SUCCESS;
@ -106,7 +76,7 @@ SpiHandleAttachRelease(
}
/* Attach, if not already claimed */
if (LunInfo->DeviceClaimed)
if (LunExtension->DeviceClaimed)
{
KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
Srb->SrbStatus = SRB_STATUS_BUSY;
@ -115,13 +85,13 @@ SpiHandleAttachRelease(
}
/* Save the device object */
DeviceObject = LunInfo->DeviceObject;
DeviceObject = LunExtension->Common.DeviceObject;
if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
LunInfo->DeviceClaimed = TRUE;
LunExtension->DeviceClaimed = TRUE;
if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
LunInfo->DeviceObject = Srb->DataBuffer;
LunExtension->Common.DeviceObject = Srb->DataBuffer;
Srb->DataBuffer = DeviceObject;
@ -154,8 +124,8 @@ ScsiPortDispatchScsi(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PSCSI_PORT_LUN_EXTENSION LunExtension;
PSCSI_PORT_DEVICE_EXTENSION portExt;
PSCSI_PORT_LUN_EXTENSION lunExt;
PIO_STACK_LOCATION Stack;
PSCSI_REQUEST_BLOCK Srb;
KIRQL Irql;
@ -165,10 +135,12 @@ ScsiPortDispatchScsi(
DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
DeviceExtension = DeviceObject->DeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp);
Srb = Stack->Parameters.Scsi.Srb;
lunExt = DeviceObject->DeviceExtension;
ASSERT(!lunExt->Common.IsFDO);
portExt = lunExt->Common.LowerDevice->DeviceExtension;
if (Srb == NULL)
{
DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
@ -179,15 +151,16 @@ ScsiPortDispatchScsi(
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return (Status);
return Status;
}
DPRINT("Srb: %p\n", Srb);
DPRINT("Srb->Function: %lu\n", Srb->Function);
DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
DPRINT("Srb: %p, Srb->Function: %lu\n", Srb, Srb->Function);
LunExtension = SpiGetLunExtension(DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun);
if (LunExtension == NULL)
Srb->PathId = lunExt->PathId;
Srb->TargetId = lunExt->TargetId;
Srb->Lun = lunExt->Lun;
if (lunExt == NULL)
{
DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
Status = STATUS_NO_SUCH_DEVICE;
@ -198,7 +171,7 @@ ScsiPortDispatchScsi(
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return (Status);
return Status;
}
switch (Srb->Function)
@ -206,7 +179,7 @@ ScsiPortDispatchScsi(
case SRB_FUNCTION_SHUTDOWN:
case SRB_FUNCTION_FLUSH:
DPRINT(" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
if (DeviceExtension->CachesData == FALSE)
if (portExt->CachesData == FALSE)
{
/* All success here */
Srb->SrbStatus = SRB_STATUS_SUCCESS;
@ -225,7 +198,7 @@ ScsiPortDispatchScsi(
if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
{
/* Start IO directly */
IoStartPacket(DeviceObject, Irp, NULL, NULL);
IoStartPacket(portExt->Common.DeviceObject, Irp, NULL, NULL);
}
else
{
@ -235,13 +208,12 @@ ScsiPortDispatchScsi(
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
/* Insert IRP into the queue */
if (!KeInsertByKeyDeviceQueue(
&LunExtension->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry,
Srb->QueueSortKey))
if (!KeInsertByKeyDeviceQueue(&lunExt->DeviceQueue,
&Irp->Tail.Overlay.DeviceQueueEntry,
Srb->QueueSortKey))
{
/* It means the queue is empty, and we just start this request */
IoStartPacket(DeviceObject, Irp, NULL, NULL);
IoStartPacket(portExt->Common.DeviceObject, Irp, NULL, NULL);
}
/* Back to the old IRQL */
@ -254,39 +226,40 @@ ScsiPortDispatchScsi(
DPRINT(" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
/* Reference device object and keep the device object */
Status = SpiHandleAttachRelease(DeviceExtension, Irp);
Status = SpiHandleAttachRelease(lunExt, Irp);
break;
case SRB_FUNCTION_RELEASE_DEVICE:
DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
/* Dereference device object and clear the device object */
Status = SpiHandleAttachRelease(DeviceExtension, Irp);
Status = SpiHandleAttachRelease(lunExt, Irp);
break;
case SRB_FUNCTION_RELEASE_QUEUE:
DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
/* Guard with the spinlock */
KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
KeAcquireSpinLock(&portExt->SpinLock, &Irql);
if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
if (!(lunExt->Flags & LUNEX_FROZEN_QUEUE))
{
DPRINT("Queue is not frozen really\n");
KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
KeReleaseSpinLock(&portExt->SpinLock, Irql);
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Status = STATUS_SUCCESS;
break;
}
/* Unfreeze the queue */
LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
lunExt->Flags &= ~LUNEX_FROZEN_QUEUE;
if (LunExtension->SrbInfo.Srb == NULL)
if (lunExt->SrbInfo.Srb == NULL)
{
/* Get next logical unit request */
SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
SpiGetNextRequestFromLun(portExt, lunExt);
/* SpiGetNextRequestFromLun() releases the spinlock */
KeLowerIrql(Irql);
@ -294,7 +267,7 @@ ScsiPortDispatchScsi(
else
{
DPRINT("The queue has active request\n");
KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
KeReleaseSpinLock(&portExt->SpinLock, Irql);
}
Srb->SrbStatus = SRB_STATUS_SUCCESS;
@ -305,23 +278,23 @@ ScsiPortDispatchScsi(
DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
/* Guard with the spinlock */
KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
KeAcquireSpinLock(&portExt->SpinLock, &Irql);
if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
if (!(lunExt->Flags & LUNEX_FROZEN_QUEUE))
{
DPRINT("Queue is not frozen really\n");
KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
KeReleaseSpinLock(&portExt->SpinLock, Irql);
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
/* Make sure there is no active request */
ASSERT(LunExtension->SrbInfo.Srb == NULL);
ASSERT(lunExt->SrbInfo.Srb == NULL);
/* Compile a list from the device queue */
IrpList = NULL;
while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
while ((Entry = KeRemoveDeviceQueue(&lunExt->DeviceQueue)) != NULL)
{
NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
@ -339,10 +312,10 @@ ScsiPortDispatchScsi(
}
/* Unfreeze the queue */
LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
lunExt->Flags &= ~LUNEX_FROZEN_QUEUE;
/* Release the spinlock */
KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
KeReleaseSpinLock(&portExt->SpinLock, Irql);
/* Complete those requests */
while (IrpList)
@ -415,7 +388,7 @@ SpiGetNextRequestFromLun(
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
/* Start the next pending request */
IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
IoStartPacket(DeviceExtension->Common.DeviceObject, NextIrp, (PULONG)NULL, NULL);
return;
}
@ -454,7 +427,7 @@ SpiGetNextRequestFromLun(
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
/* Start the next pending request */
IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
IoStartPacket(DeviceExtension->Common.DeviceObject, NextIrp, (PULONG)NULL, NULL);
}
else
{
@ -525,7 +498,7 @@ SpiSenseCompletionRoutine(
static
VOID
SpiSendRequestSense(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,
_In_ PSCSI_REQUEST_BLOCK InitialSrb)
{
PSCSI_REQUEST_BLOCK Srb;
@ -544,7 +517,7 @@ SpiSendRequestSense(
/* Allocate IRP */
LargeInt.QuadPart = (LONGLONG) 1;
Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
DeviceExtension->DeviceObject,
LunExtension->Common.DeviceObject,
InitialSrb->SenseInfoBuffer,
InitialSrb->SenseInfoBufferLength,
&LargeInt,
@ -621,7 +594,7 @@ SpiSendRequestSense(
Srb->NextSrb = 0;
/* Call the driver */
(VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
(VOID)IoCallDriver(LunExtension->Common.DeviceObject, Irp);
DPRINT("SpiSendRequestSense() done\n");
}
@ -642,12 +615,11 @@ SpiProcessCompletedRequest(
Srb = SrbInfo->Srb;
Irp = Srb->OriginalRequest;
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
/* Get Lun extension */
LunExtension = SpiGetLunExtension(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun);
LunExtension = IoStack->DeviceObject->DeviceExtension;
ASSERT(LunExtension && !LunExtension->Common.IsFDO);
if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
DeviceExtension->MapBuffers &&
@ -697,7 +669,7 @@ SpiProcessCompletedRequest(
!(*NeedToCallStartIo))
{
/* We're not busy, but we have a request pending */
IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE);
}
}
@ -931,7 +903,7 @@ Error:
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
/* Send RequestSense */
SpiSendRequestSense(DeviceExtension, Srb);
SpiSendRequestSense(LunExtension, Srb);
/* Exit */
return;
@ -950,10 +922,11 @@ NTAPI
ScsiPortStartPacket(
_In_ PVOID Context)
{
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack;
PSCSI_REQUEST_BLOCK Srb;
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
PSCSI_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension;
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PSCSI_PORT_LUN_EXTENSION LunExtension;
PSCSI_REQUEST_BLOCK_INFO SrbInfo;
BOOLEAN Result;
@ -961,16 +934,20 @@ ScsiPortStartPacket(
DPRINT("ScsiPortStartPacket() called\n");
DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
Srb = IrpStack->Parameters.Scsi.Srb;
/* Get LUN extension */
LunExtension = SpiGetLunExtension(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun);
if (CommonExtension->IsFDO) // IsFDO
{
DeviceExtension = DeviceObject->DeviceExtension;
LunExtension = IrpStack->DeviceObject->DeviceExtension;
ASSERT(LunExtension && !LunExtension->Common.IsFDO);
}
else
{
LunExtension = DeviceObject->DeviceExtension;
DeviceExtension = LunExtension->Common.LowerDevice->DeviceExtension;
}
/* Check if we are in a reset state */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
@ -1006,11 +983,7 @@ ScsiPortStartPacket(
if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
{
/* Get pointer to SRB info structure */
SrbInfo = SpiGetSrbData(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun,
Srb->QueueTag);
SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
/* Check if the request is still "active" */
if (SrbInfo == NULL ||
@ -1036,7 +1009,7 @@ ScsiPortStartPacket(
DeviceExtension->MiniPortDeviceExtension);
/* They might ask for some work, so queue the DPC for them */
IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
/* We're done in this branch */
return TRUE;
@ -1096,7 +1069,7 @@ ScsiPortStartPacket(
/* If notification is needed, then request a DPC */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
return Result;
}
@ -1140,10 +1113,9 @@ SpiSaveInterruptData(IN PVOID Context)
/* Get SRB and LunExtension */
Srb = SrbInfo->Srb;
LunExtension = SpiGetLunExtension(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun);
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
LunExtension = IoStack->DeviceObject->DeviceExtension;
ASSERT(LunExtension && !LunExtension->Common.IsFDO);
/* We have to check special cases if request is unsuccessful*/
if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
@ -1359,7 +1331,7 @@ TryAgain:
/* If we ready for next packet, start it */
if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE);
NeedToStartIo = FALSE;
@ -1456,11 +1428,7 @@ SpiAllocateSrbStructures(
/* Treat the abort request in a special way */
if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
{
SrbInfo = SpiGetSrbData(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun,
Srb->QueueTag);
SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
}
else if (Srb->SrbFlags &
(SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
@ -1606,20 +1574,18 @@ ScsiPortStartIo(
DeviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
LunExtension = IrpStack->DeviceObject->DeviceExtension;
DPRINT("DeviceExtension %p\n", DeviceExtension);
ASSERT(DeviceExtension->Common.IsFDO);
ASSERT(!LunExtension->Common.IsFDO);
DPRINT("LunExtension %p DeviceExtension %p\n", LunExtension, DeviceExtension);
Srb = IrpStack->Parameters.Scsi.Srb;
/* Apply "default" flags */
Srb->SrbFlags |= DeviceExtension->SrbFlags;
/* Get LUN extension */
LunExtension = SpiGetLunExtension(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun);
if (DeviceExtension->NeedSrbDataAlloc ||
DeviceExtension->NeedSrbExtensionAlloc)
{
@ -1699,7 +1665,7 @@ ScsiPortStartIo(
/* Allocate adapter channel */
Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
DeviceExtension->DeviceObject,
DeviceExtension->Common.DeviceObject,
SrbInfo->NumberOfMapRegisters,
SpiAdapterControl,
SrbInfo);
@ -1717,7 +1683,7 @@ ScsiPortStartIo(
DeviceExtension + 1);
/* Request DPC for that work */
IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
}
/* Control goes to SpiAdapterControl */

View file

@ -4,6 +4,7 @@
* PURPOSE: Main and exported functions
* COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
* Aleksey Bragin (aleksey@reactos.org)
* 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -112,8 +113,43 @@ NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DPRINT("ScsiPort Driver %s\n", VERSION);
return(STATUS_SUCCESS);
return STATUS_SUCCESS;
}
VOID
NTAPI
ScsiPortUnload(
_In_ PDRIVER_OBJECT DriverObject)
{
// no-op
}
NTSTATUS
NTAPI
ScsiPortDispatchPnp(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
if (((PSCSI_PORT_COMMON_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
{
return FdoDispatchPnp(DeviceObject, Irp);
}
else
{
return PdoDispatchPnp(DeviceObject, Irp);
}
}
NTSTATUS
NTAPI
ScsiPortAddDevice(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
{
DPRINT("AddDevice no-op DriverObj: %p, PDO: %p\n", DriverObject, PhysicalDeviceObject);
return STATUS_SUCCESS;
}
@ -202,8 +238,6 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
PSCSI_PORT_LUN_EXTENSION LunExtension;
PSCSI_REQUEST_BLOCK_INFO SrbInfo;
PLIST_ENTRY ListEntry;
ULONG BusNumber;
ULONG Target;
DPRINT("ScsiPortCompleteRequest() called\n");
@ -212,60 +246,56 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
MiniPortDeviceExtension);
/* Go through all buses */
for (BusNumber = 0; BusNumber < 8; BusNumber++)
for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
{
/* Go through all targets */
for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
/* Go through all logical units */
for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
lunEntry != &bus->LunsListHead;
lunEntry = lunEntry->Flink)
{
/* Get logical unit list head */
LunExtension = DeviceExtension->LunExtensionList[Target % 8];
LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
/* Go through all logical units */
while (LunExtension)
/* Now match what caller asked with what we are at now */
if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
(TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
(Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
{
/* Now match what caller asked with what we are at now */
if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
(TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
(Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
/* Yes, that's what caller asked for. Complete abort requests */
if (LunExtension->CompletedAbortRequests)
{
/* Yes, that's what caller asked for. Complete abort requests */
if (LunExtension->CompletedAbortRequests)
{
/* TODO: Save SrbStatus in this request */
DPRINT1("Completing abort request without setting SrbStatus!\n");
/* TODO: Save SrbStatus in this request */
DPRINT1("Completing abort request without setting SrbStatus!\n");
/* Issue a notification request */
ScsiPortNotification(RequestComplete,
HwDeviceExtension,
LunExtension->CompletedAbortRequests);
}
/* Complete the request using our helper */
SpiCompleteRequest(HwDeviceExtension,
&LunExtension->SrbInfo,
SrbStatus);
/* Go through the queue and complete everything there too */
ListEntry = LunExtension->SrbInfo.Requests.Flink;
while (ListEntry != &LunExtension->SrbInfo.Requests)
{
/* Get the actual SRB info entry */
SrbInfo = CONTAINING_RECORD(ListEntry,
SCSI_REQUEST_BLOCK_INFO,
Requests);
/* Complete it */
SpiCompleteRequest(HwDeviceExtension,
SrbInfo,
SrbStatus);
/* Advance to the next request in queue */
ListEntry = SrbInfo->Requests.Flink;
}
/* Issue a notification request */
ScsiPortNotification(RequestComplete,
HwDeviceExtension,
LunExtension->CompletedAbortRequests);
}
/* Advance to the next one */
LunExtension = LunExtension->Next;
/* Complete the request using our helper */
SpiCompleteRequest(HwDeviceExtension,
&LunExtension->SrbInfo,
SrbStatus);
/* Go through the queue and complete everything there too */
ListEntry = LunExtension->SrbInfo.Requests.Flink;
while (ListEntry != &LunExtension->SrbInfo.Requests)
{
/* Get the actual SRB info entry */
SrbInfo = CONTAINING_RECORD(ListEntry,
SCSI_REQUEST_BLOCK_INFO,
Requests);
/* Complete it */
SpiCompleteRequest(HwDeviceExtension,
SrbInfo,
SrbStatus);
/* Advance to the next request in queue */
ListEntry = SrbInfo->Requests.Flink;
}
}
}
}
@ -468,10 +498,8 @@ ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
return NULL;
}
LunExtension = SpiGetLunExtension(DeviceExtension,
PathId,
TargetId,
Lun);
LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
/* Check that the logical unit exists */
if (!LunExtension)
{
@ -517,12 +545,12 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
}
else if (DeviceExtension->MapRegisters)
{
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
ASSERT(LunExtension && !LunExtension->Common.IsFDO);
/* Scatter-gather list must be used */
SrbInfo = SpiGetSrbData(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun,
Srb->QueueTag);
SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
SGList = SrbInfo->ScatterGather;
@ -816,7 +844,6 @@ ScsiPortInitialize(
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
PCONFIGURATION_INFORMATION SystemConfig;
PPORT_CONFIGURATION_INFORMATION PortConfig;
PORT_CONFIGURATION_INFORMATION InitialPortConfig;
CONFIGURATION_INFO ConfigInfo;
ULONG DeviceExtensionSize;
ULONG PortConfigSize;
@ -829,16 +856,10 @@ ScsiPortInitialize(
PCI_SLOT_NUMBER SlotNumber;
PDEVICE_OBJECT PortDeviceObject;
WCHAR NameBuffer[80];
UNICODE_STRING DeviceName;
WCHAR DosNameBuffer[80];
UNICODE_STRING DosDeviceName;
PIO_SCSI_CAPABILITIES PortCapabilities;
PCM_RESOURCE_LIST ResourceList;
BOOLEAN Conflict;
SIZE_T BusConfigSize;
DPRINT ("ScsiPortInitialize() called!\n");
@ -849,15 +870,46 @@ ScsiPortInitialize(
(HwInitializationData->HwFindAdapter == NULL) ||
(HwInitializationData->HwResetBus == NULL))
{
return STATUS_INVALID_PARAMETER;
return STATUS_REVISION_MISMATCH;
}
PSCSI_PORT_DRIVER_EXTENSION driverExtension;
// ScsiPortInitialize may be called multiple times by the same driver
driverExtension = IoGetDriverObjectExtension(DriverObject, HwInitializationData->HwInitialize);
if (!driverExtension)
{
Status = IoAllocateDriverObjectExtension(DriverObject,
HwInitializationData->HwInitialize,
sizeof(SCSI_PORT_DRIVER_EXTENSION),
(PVOID *)&driverExtension);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate the driver extension! Status 0x%x\n", Status);
return Status;
}
}
// set up the driver extension
driverExtension->RegistryPath.Buffer =
ExAllocatePoolWithTag(PagedPool, RegistryPath->MaximumLength, TAG_SCSIPORT);
driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
RtlCopyUnicodeString(&driverExtension->RegistryPath, RegistryPath);
driverExtension->DriverObject = DriverObject;
/* Set handlers */
DriverObject->DriverUnload = ScsiPortUnload;
DriverObject->DriverStartIo = ScsiPortStartIo;
DriverObject->DriverExtension->AddDevice = ScsiPortAddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiPortDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = ScsiPortDispatchPower;
/* Obtain configuration information */
SystemConfig = IoGetConfigurationInformation();
@ -880,8 +932,11 @@ ScsiPortInitialize(
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Open registry keys */
SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
/* Open registry keys and fill the driverExtension */
SpiInitOpenKeys(&ConfigInfo, driverExtension);
// FIXME: PnP miniports are not supported
ASSERT(driverExtension->IsLegacyDriver);
/* Last adapter number = not known */
ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
@ -895,11 +950,18 @@ ScsiPortInitialize(
while (TRUE)
{
WCHAR NameBuffer[27];
/* Create a unicode device name */
swprintf(NameBuffer,
L"\\Device\\ScsiPort%lu",
SystemConfig->ScsiPortCount);
RtlInitUnicodeString(&DeviceName, NameBuffer);
if (!RtlCreateUnicodeString(&DeviceName, NameBuffer))
{
DPRINT1("Failed to allocate memory for device name!\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
PortDeviceObject = NULL;
break;
}
DPRINT("Creating device: %wZ\n", &DeviceName);
@ -908,7 +970,7 @@ ScsiPortInitialize(
DeviceExtensionSize,
&DeviceName,
FILE_DEVICE_CONTROLLER,
0,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&PortDeviceObject);
@ -919,7 +981,7 @@ ScsiPortInitialize(
break;
}
DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
DPRINT1("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
/* Set the buffering strategy here... */
PortDeviceObject->Flags |= DO_DIRECT_IO;
@ -928,9 +990,11 @@ ScsiPortInitialize(
/* Fill Device Extension */
DeviceExtension = PortDeviceObject->DeviceExtension;
RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
DeviceExtension->Common.DeviceObject = PortDeviceObject;
DeviceExtension->Common.IsFDO = TRUE;
DeviceExtension->Length = DeviceExtensionSize;
DeviceExtension->DeviceObject = PortDeviceObject;
DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
DeviceExtension->DeviceName = DeviceName;
/* Driver's routines... */
DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
@ -941,13 +1005,10 @@ ScsiPortInitialize(
/* Extensions sizes */
DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
/* Round Srb extension size to the quadword */
DeviceExtension->LunExtensionSize =
ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64);
DeviceExtension->SrbExtensionSize =
~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
sizeof(LONGLONG) - 1);
ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64);
/* Fill some numbers (bus count, lun count, etc) */
DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
@ -975,22 +1036,10 @@ ScsiPortInitialize(
CreatePortConfig:
Status = SpiCreatePortConfig(DeviceExtension,
HwInitializationData,
&ConfigInfo,
&InitialPortConfig,
FirstConfigCall);
if (!NT_SUCCESS(Status))
{
DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
break;
}
/* Allocate and initialize port configuration info */
PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
HwInitializationData->NumberOfAccessRanges *
sizeof(ACCESS_RANGE) + 7) & ~7;
PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
PortConfigSize = ALIGN_UP(PortConfigSize, INT64);
DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
/* Fail if failed */
@ -1000,14 +1049,20 @@ CreatePortConfig:
break;
}
Status = SpiCreatePortConfig(DeviceExtension,
HwInitializationData,
&ConfigInfo,
DeviceExtension->PortConfig,
FirstConfigCall);
if (!NT_SUCCESS(Status))
{
DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
break;
}
PortConfig = DeviceExtension->PortConfig;
/* Copy information here */
RtlCopyMemory(PortConfig,
&InitialPortConfig,
sizeof(PORT_CONFIGURATION_INFORMATION));
/* Copy extension sizes into the PortConfig */
PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
@ -1015,11 +1070,7 @@ CreatePortConfig:
/* Initialize Access ranges */
if (HwInitializationData->NumberOfAccessRanges != 0)
{
PortConfig->AccessRanges = (PVOID)(PortConfig+1);
/* Align to LONGLONG */
PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64);
/* Copy the data */
RtlCopyMemory(PortConfig->AccessRanges,
@ -1113,54 +1164,44 @@ CreatePortConfig:
(PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
{
/* Set it (rounding to LONGLONG again) */
DeviceExtension->SrbExtensionSize =
(PortConfig->SrbExtensionSize + sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64);
}
/* The same with LUN extension size */
if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
(HwInitializationData->VendorIdLength > 0) &&
(HwInitializationData->VendorId != NULL) &&
(HwInitializationData->DeviceIdLength > 0) &&
(HwInitializationData->DeviceId != NULL)))
/* Construct a resource list */
ResourceList = SpiConfigToResource(DeviceExtension, PortConfig);
PDEVICE_OBJECT LowerPDO = NULL;
Status = IoReportDetectedDevice(DriverObject,
HwInitializationData->AdapterInterfaceType,
ConfigInfo.BusNumber,
PortConfig->SlotNumber,
ResourceList,
NULL,
TRUE,
&LowerPDO);
if (!NT_SUCCESS(Status))
{
/* Construct a resource list */
ResourceList = SpiConfigToResource(DeviceExtension, PortConfig);
if (ResourceList)
{
UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
DPRINT("Reporting resources\n");
Status = IoReportResourceUsage(&UnicodeString,
DriverObject,
NULL,
0,
PortDeviceObject,
ResourceList,
FIELD_OFFSET(CM_RESOURCE_LIST,
List[0].PartialResourceList.PartialDescriptors) +
ResourceList->List[0].PartialResourceList.Count *
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
FALSE,
&Conflict);
ExFreePool(ResourceList);
/* In case of a failure or a conflict, break */
if (Conflict || (!NT_SUCCESS(Status)))
{
if (Conflict)
Status = STATUS_CONFLICTING_ADDRESSES;
break;
}
}
DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status);
__debugbreak();
break;
}
/* Reset the Conflict var */
Conflict = FALSE;
DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(PortDeviceObject, LowerPDO);
ASSERT(DeviceExtension->Common.LowerDevice);
PortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
if (ResourceList)
{
ExFreePoolWithTag(ResourceList, TAG_SCSIPORT);
}
/* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
@ -1168,12 +1209,30 @@ CreatePortConfig:
else
DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
DeviceExtension->BusNum = PortConfig->NumberOfBuses;
DeviceExtension->NumberOfBuses = PortConfig->NumberOfBuses;
DeviceExtension->CachesData = PortConfig->CachesData;
DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
/* Initialize bus scanning information */
size_t BusConfigSize = DeviceExtension->NumberOfBuses * sizeof(*DeviceExtension->Buses);
DeviceExtension->Buses = ExAllocatePoolZero(NonPagedPool, BusConfigSize, TAG_SCSIPORT);
if (!DeviceExtension->Buses)
{
DPRINT1("Out of resources!\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
// initialize bus data
for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
{
DeviceExtension->Buses[pathId].BusIdentifier =
DeviceExtension->PortConfig->InitiatorBusId[pathId];
InitializeListHead(&DeviceExtension->Buses[pathId].LunsListHead);
}
/* If something was disabled via registry - apply it */
if (ConfigInfo.DisableMultipleLun)
DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
@ -1283,43 +1342,18 @@ CreatePortConfig:
}
}
CallHWInitialize(DeviceExtension);
FdoCallHWInitialize(DeviceExtension);
/* Start our timer */
IoStartTimer(PortDeviceObject);
Status = FdoStartAdapter(DeviceExtension);
/* Initialize bus scanning information */
BusConfigSize = FIELD_OFFSET(
BUSES_CONFIGURATION_INFORMATION,
BusScanInfo[DeviceExtension->PortConfig->NumberOfBuses]);
DeviceExtension->BusesConfig =
ExAllocatePoolWithTag(PagedPool, BusConfigSize, TAG_SCSIPORT);
if (!DeviceExtension->BusesConfig)
if (!NT_SUCCESS(Status))
{
DPRINT1("Out of resources!\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status);
break;
}
/* Zero it */
RtlZeroMemory(DeviceExtension->BusesConfig, BusConfigSize);
FdoScanAdapter(DeviceExtension);
/* Store number of buses there */
DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
/* Scan the adapter for devices */
SpiScanAdapter(DeviceExtension);
/* Build the registry device map */
SpiBuildDeviceMap(DeviceExtension, (PUNICODE_STRING)Argument2);
/* Create the dos device link */
swprintf(DosNameBuffer, L"\\??\\Scsi%lu:", SystemConfig->ScsiPortCount);
RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
/* Increase the port count */
SystemConfig->ScsiPortCount++;
FirstConfigCall = FALSE;
/* Increase adapter number and bus number respectively */
@ -1334,7 +1368,10 @@ CreatePortConfig:
}
/* Clean up the mess */
SpiCleanupAfterInit(DeviceExtension);
if (!NT_SUCCESS(Status) && PortDeviceObject)
{
FdoRemoveAdapter(DeviceExtension);
}
/* Close registry keys */
if (ConfigInfo.ServiceKey != NULL)
@ -1461,9 +1498,12 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDevi
}
else
{
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
ASSERT(LunExtension && !LunExtension->Common.IsFDO);
/* Get the SRB data */
SrbData = SpiGetSrbData(
DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun, Srb->QueueTag);
SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
/* Make sure there are no CompletedRequests and there is a Srb */
ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
@ -1504,7 +1544,7 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDevi
DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
/* Get the LUN extension */
LunExtension = SpiGetLunExtension(DeviceExtension, PathId, TargetId, Lun);
LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
/* If returned LunExtension is NULL, break out */
if (!LunExtension)
@ -2104,7 +2144,7 @@ ScsiPortIsr(
/* If flag of notification is set - queue a DPC */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
{
IoRequestDpc(DeviceExtension->DeviceObject,
IoRequestDpc(DeviceExtension->Common.DeviceObject,
DeviceExtension->CurrentIrp,
DeviceExtension);
}
@ -2140,7 +2180,7 @@ SpiProcessTimeout(PVOID ServiceContext)
{
DPRINT("Resetting the bus\n");
for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++)
{
DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
@ -2151,7 +2191,7 @@ SpiProcessTimeout(PVOID ServiceContext)
/* If miniport requested - request a dpc for it */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
}
return TRUE;
@ -2176,7 +2216,7 @@ SpiResetBus(PVOID ServiceContext)
/* If miniport requested - give him a DPC */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
return TRUE;
}
@ -2198,7 +2238,6 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
{
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PSCSI_PORT_LUN_EXTENSION LunExtension;
ULONG Lun;
PIRP Irp;
DPRINT("ScsiPortIoTimer()\n");
@ -2219,7 +2258,7 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
/* Timeout, process it */
if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
SpiProcessTimeout,
DeviceExtension->DeviceObject))
DeviceExtension->Common.DeviceObject))
{
DPRINT("Error happened during processing timeout, but nothing critical\n");
}
@ -2232,12 +2271,16 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
}
/* Per-Lun scanning of timeouts is needed... */
for (Lun = 0; Lun < LUS_NUMBER; Lun++)
for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
{
LunExtension = DeviceExtension->LunExtensionList[Lun];
PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
while (LunExtension)
for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
lunEntry != &bus->LunsListHead;
lunEntry = lunEntry->Flink)
{
LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
if (LunExtension->Flags & LUNEX_BUSY)
{
if (!(LunExtension->Flags &
@ -2283,8 +2326,6 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
/* Decrement the timeout counter */
LunExtension->RequestTimeout--;
}
LunExtension = LunExtension->Next;
}
}
@ -2320,7 +2361,7 @@ SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
{
ScsiPortDpcForIsr(NULL,
DeviceExtension->DeviceObject,
DeviceExtension->Common.DeviceObject,
NULL,
NULL);
}
@ -2398,8 +2439,8 @@ TryNextAd:
{
/* Open registry key for HW database */
InitializeObjectAttributes(&ObjectAttributes,
DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
OBJ_CASE_INSENSITIVE,
DeviceExtension->Common.DeviceObject->DriverObject->HardwareDatabase,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
@ -2418,7 +2459,7 @@ TryNextAd:
/* Open device key */
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
RootKey,
NULL);
@ -2479,7 +2520,7 @@ TryNextAd:
/* Open the service key */
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
InternalConfigInfo->ServiceKey,
NULL);
@ -3012,5 +3053,3 @@ ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
return(Address.u.LowPart);
}
/* EOF */

View file

@ -7,15 +7,16 @@
#pragma once
#include <wdm.h>
#include <ntddk.h>
#include <ntifs.h>
#include <stdio.h>
#include <scsi.h>
#include <ntddscsi.h>
#include <ntdddisk.h>
#include <mountdev.h>
#define VERSION "0.0.3"
#ifdef DBG
#include <debug/driverdbg.h>
#endif
#define TAG_SCSIPORT 'ISCS'
@ -25,29 +26,29 @@
#define MAX_SG_LIST 17
/* Flags */
#define SCSI_PORT_DEVICE_BUSY 0x0001
#define SCSI_PORT_LU_ACTIVE 0x0002
#define SCSI_PORT_NOTIFICATION_NEEDED 0x0004
#define SCSI_PORT_NEXT_REQUEST_READY 0x0008
#define SCSI_PORT_FLUSH_ADAPTERS 0x0010
#define SCSI_PORT_MAP_TRANSFER 0x0020
#define SCSI_PORT_RESET 0x0080
#define SCSI_PORT_RESET_REQUEST 0x0100
#define SCSI_PORT_RESET_REPORTED 0x0200
#define SCSI_PORT_REQUEST_PENDING 0x0800
#define SCSI_PORT_DISCONNECT_ALLOWED 0x1000
#define SCSI_PORT_DISABLE_INT_REQUESET 0x2000
#define SCSI_PORT_DISABLE_INTERRUPTS 0x4000
#define SCSI_PORT_ENABLE_INT_REQUEST 0x8000
#define SCSI_PORT_TIMER_NEEDED 0x10000
#define SCSI_PORT_DEVICE_BUSY 0x00001
#define SCSI_PORT_LU_ACTIVE 0x00002
#define SCSI_PORT_NOTIFICATION_NEEDED 0x00004
#define SCSI_PORT_NEXT_REQUEST_READY 0x00008
#define SCSI_PORT_FLUSH_ADAPTERS 0x00010
#define SCSI_PORT_MAP_TRANSFER 0x00020
#define SCSI_PORT_RESET 0x00080
#define SCSI_PORT_RESET_REQUEST 0x00100
#define SCSI_PORT_RESET_REPORTED 0x00200
#define SCSI_PORT_REQUEST_PENDING 0x00800
#define SCSI_PORT_DISCONNECT_ALLOWED 0x01000
#define SCSI_PORT_DISABLE_INT_REQUESET 0x02000
#define SCSI_PORT_DISABLE_INTERRUPTS 0x04000
#define SCSI_PORT_ENABLE_INT_REQUEST 0x08000
#define SCSI_PORT_TIMER_NEEDED 0x10000
/* LUN Extension flags*/
#define LUNEX_FROZEN_QUEUE 0x0001
#define LUNEX_NEED_REQUEST_SENSE 0x0004
#define LUNEX_BUSY 0x0008
#define LUNEX_FULL_QUEUE 0x0010
#define LUNEX_REQUEST_PENDING 0x0020
#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000
#define LUNEX_FROZEN_QUEUE 0x0001
#define LUNEX_NEED_REQUEST_SENSE 0x0004
#define LUNEX_BUSY 0x0008
#define LUNEX_FULL_QUEUE 0x0010
#define LUNEX_REQUEST_PENDING 0x0020
#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000
typedef enum _SCSI_PORT_TIMER_STATES
@ -115,18 +116,27 @@ typedef struct _SCSI_REQUEST_BLOCK_INFO
SCSI_SG_ADDRESS ScatterGatherList[MAX_SG_LIST];
} SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO;
typedef struct _SCSI_PORT_COMMON_EXTENSION
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT LowerDevice;
BOOLEAN IsFDO;
} SCSI_PORT_COMMON_EXTENSION, *PSCSI_PORT_COMMON_EXTENSION;
// PDO device
typedef struct _SCSI_PORT_LUN_EXTENSION
{
SCSI_PORT_COMMON_EXTENSION Common;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
ULONG Flags;
struct _SCSI_PORT_LUN_EXTENSION *Next;
LIST_ENTRY LunEntry;
BOOLEAN DeviceClaimed;
PDEVICE_OBJECT DeviceObject;
INQUIRYDATA InquiryData;
@ -146,6 +156,8 @@ typedef struct _SCSI_PORT_LUN_EXTENSION
SCSI_REQUEST_BLOCK_INFO SrbInfo;
HANDLE RegistryMapKey;
/* More data? */
UCHAR MiniportLunExtension[1]; /* must be the last entry */
@ -153,31 +165,14 @@ typedef struct _SCSI_PORT_LUN_EXTENSION
/* Structures for inquiries support */
typedef struct _SCSI_LUN_INFO
typedef struct _SCSI_BUS_INFO
{
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
BOOLEAN DeviceClaimed;
PVOID DeviceObject;
struct _SCSI_LUN_INFO *Next;
UCHAR InquiryData[INQUIRYDATABUFFERSIZE];
} SCSI_LUN_INFO, *PSCSI_LUN_INFO;
typedef struct _SCSI_BUS_SCAN_INFO
{
USHORT Length;
LIST_ENTRY LunsListHead;
UCHAR LogicalUnitsCount;
UCHAR TargetsCount;
UCHAR BusIdentifier;
PSCSI_LUN_INFO LunInfo;
} SCSI_BUS_SCAN_INFO, *PSCSI_BUS_SCAN_INFO;
typedef struct _BUSES_CONFIGURATION_INFORMATION
{
UCHAR NumberOfBuses;
PSCSI_BUS_SCAN_INFO BusScanInfo[1];
} BUSES_CONFIGURATION_INFORMATION, *PBUSES_CONFIGURATION_INFORMATION;
HANDLE RegistryMapKey;
} SCSI_BUS_INFO, *PSCSI_BUS_INFO;
typedef struct _SCSI_PORT_INTERRUPT_DATA
{
@ -201,16 +196,19 @@ typedef struct _SCSI_PORT_SAVE_INTERRUPT
* SCSI_PORT_DEVICE_EXTENSION
*
* DESCRIPTION
* First part of the port objects device extension. The second
* part is the miniport-specific device extension.
* First part of the port objects device extension. The second
* part is the miniport-specific device extension.
*/
// FDO
typedef struct _SCSI_PORT_DEVICE_EXTENSION
{
SCSI_PORT_COMMON_EXTENSION Common;
ULONG Length;
ULONG MiniPortExtensionSize;
PPORT_CONFIGURATION_INFORMATION PortConfig;
PBUSES_CONFIGURATION_INFORMATION BusesConfig;
PSCSI_BUS_INFO Buses; // children LUNs are stored here
PVOID NonCachedExtension;
ULONG PortNumber;
@ -218,7 +216,7 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
ULONG SrbFlags;
ULONG Flags;
ULONG BusNum;
UCHAR NumberOfBuses;
ULONG MaxTargedIds;
ULONG MaxLunCount;
@ -238,7 +236,6 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
PMAPPED_ADDRESS MappedAddressList;
ULONG LunExtensionSize;
PSCSI_PORT_LUN_EXTENSION LunExtensionList[LUS_NUMBER];
SCSI_PORT_INTERRUPT_DATA InterruptData;
@ -254,7 +251,6 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
IO_SCSI_CAPABILITIES PortCapabilities;
PDEVICE_OBJECT DeviceObject;
PCONTROLLER_OBJECT ControllerObject;
PHW_INITIALIZE HwInitialize;
@ -294,6 +290,11 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
ULONG InterruptCount;
UNICODE_STRING DeviceName;
UNICODE_STRING InterfaceName;
BOOLEAN DeviceStarted;
UINT8 TotalLUCount;
UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
} SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
@ -303,6 +304,42 @@ typedef struct _RESETBUS_PARAMS
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
} RESETBUS_PARAMS, *PRESETBUS_PARAMS;
typedef struct _SCSIPORT_DRIVER_EXTENSION
{
PDRIVER_OBJECT DriverObject;
UNICODE_STRING RegistryPath;
BOOLEAN IsLegacyDriver;
} SCSI_PORT_DRIVER_EXTENSION, *PSCSI_PORT_DRIVER_EXTENSION;
FORCEINLINE
BOOLEAN
VerifyIrpOutBufferSize(
_In_ PIRP Irp,
_In_ SIZE_T Size)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
{
Irp->IoStatus.Information = Size;
return FALSE;
}
return TRUE;
}
FORCEINLINE
BOOLEAN
VerifyIrpInBufferSize(
_In_ PIRP Irp,
_In_ SIZE_T Size)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
if (ioStack->Parameters.DeviceIoControl.InputBufferLength < Size)
{
Irp->IoStatus.Information = Size;
return FALSE;
}
return TRUE;
}
// ioctl.c
@ -315,25 +352,34 @@ ScsiPortDeviceControl(
// fdo.c
VOID
SpiScanAdapter(
FdoScanAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
NTSTATUS
CallHWInitialize(
FdoCallHWInitialize(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
VOID
SpiCleanupAfterInit(
NTSTATUS
FdoRemoveAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
NTSTATUS
FdoStartAdapter(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
NTSTATUS
FdoDispatchPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp);
// pdo.c
PSCSI_PORT_LUN_EXTENSION
SpiAllocateLunExtension(
PDEVICE_OBJECT
PdoCreateLunDevice(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
PSCSI_PORT_LUN_EXTENSION
SpiGetLunExtension(
GetLunByPath(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ UCHAR PathId,
_In_ UCHAR TargetId,
@ -342,22 +388,32 @@ SpiGetLunExtension(
PSCSI_REQUEST_BLOCK_INFO
SpiGetSrbData(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ UCHAR PathId,
_In_ UCHAR TargetId,
_In_ UCHAR Lun,
_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,
_In_ UCHAR QueueTag);
NTSTATUS
PdoDispatchPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp);
// power.c
DRIVER_DISPATCH ScsiPortDispatchPower;
// registry.c
VOID
SpiInitOpenKeys(
_Inout_ PCONFIGURATION_INFO ConfigInfo,
_In_ PUNICODE_STRING RegistryPath);
_In_ PSCSI_PORT_DRIVER_EXTENSION DriverExtension);
NTSTATUS
SpiBuildDeviceMap(
_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
_In_ PUNICODE_STRING RegistryPath);
RegistryInitAdapterKey(
_Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
NTSTATUS
RegistryInitLunKey(
_Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension);
// scsi.c

View file

@ -0,0 +1,124 @@
// see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices
// and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices
FORCEINLINE
PCSTR
GetDeviceType(
_In_ PINQUIRYDATA InquiryData)
{
switch (InquiryData->DeviceType)
{
case DIRECT_ACCESS_DEVICE:
return "Disk";
case SEQUENTIAL_ACCESS_DEVICE:
return "Sequential";
case PRINTER_DEVICE:
return "Printer";
case PROCESSOR_DEVICE:
return "Processor";
case WRITE_ONCE_READ_MULTIPLE_DEVICE:
return "Worm";
case READ_ONLY_DIRECT_ACCESS_DEVICE:
return "CdRom";
case SCANNER_DEVICE:
return "Scanner";
case OPTICAL_DEVICE:
return "Optical";
case MEDIUM_CHANGER:
return "Changer";
case COMMUNICATION_DEVICE:
return "Net";
case ARRAY_CONTROLLER_DEVICE:
return "Array";
case SCSI_ENCLOSURE_DEVICE:
return "Enclosure";
case REDUCED_BLOCK_DEVICE:
return "RBC";
case OPTICAL_CARD_READER_WRITER_DEVICE:
return "CardReader";
case BRIDGE_CONTROLLER_DEVICE:
return "Bridge";
default:
return "Other";
}
}
FORCEINLINE
PCSTR
GetGenericType(
_In_ PINQUIRYDATA InquiryData)
{
switch (InquiryData->DeviceType)
{
case DIRECT_ACCESS_DEVICE:
return "GenDisk";
case PRINTER_DEVICE:
return "GenPrinter";
case WRITE_ONCE_READ_MULTIPLE_DEVICE:
return "GenWorm";
case READ_ONLY_DIRECT_ACCESS_DEVICE:
return "GenCdRom";
case SCANNER_DEVICE:
return "GenScanner";
case OPTICAL_DEVICE:
return "GenOptical";
case MEDIUM_CHANGER:
return "ScsiChanger";
case COMMUNICATION_DEVICE:
return "ScsiNet";
case ARRAY_CONTROLLER_DEVICE:
return "ScsiArray";
case SCSI_ENCLOSURE_DEVICE:
return "ScsiEnclosure";
case REDUCED_BLOCK_DEVICE:
return "ScsiRBC";
case OPTICAL_CARD_READER_WRITER_DEVICE:
return "ScsiCardReader";
case BRIDGE_CONTROLLER_DEVICE:
return "ScsiBridge";
default:
return "ScsiOther";
}
}
FORCEINLINE
PCWSTR
GetPeripheralTypeW(
_In_ PINQUIRYDATA InquiryData)
{
switch (InquiryData->DeviceType)
{
case DIRECT_ACCESS_DEVICE:
return L"DiskPeripheral";
case SEQUENTIAL_ACCESS_DEVICE:
return L"TapePeripheral";
case PRINTER_DEVICE:
return L"PrinterPeripheral";
// case 3: "ProcessorPeripheral", classified as 'other': fall back to default case.
case WRITE_ONCE_READ_MULTIPLE_DEVICE:
return L"WormPeripheral";
case READ_ONLY_DIRECT_ACCESS_DEVICE:
return L"CdRomPeripheral";
case SCANNER_DEVICE:
return L"ScannerPeripheral";
case OPTICAL_DEVICE:
return L"OpticalDiskPeripheral";
case MEDIUM_CHANGER:
return L"MediumChangerPeripheral";
case COMMUNICATION_DEVICE:
return L"CommunicationsPeripheral";
case ARRAY_CONTROLLER_DEVICE:
return L"ArrayPeripheral";
case SCSI_ENCLOSURE_DEVICE:
return L"EnclosurePeripheral";
case REDUCED_BLOCK_DEVICE:
return L"RBCPeripheral";
case OPTICAL_CARD_READER_WRITER_DEVICE:
return L"CardReaderPeripheral";
case BRIDGE_CONTROLLER_DEVICE:
return L"BridgePeripheral";
default:
return L"OtherPeripheral";
}
}