https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1b45d9ee4b66768e569a1…
commit 1b45d9ee4b66768e569a1f3e06f92897c0957f01
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Sat Oct 17 04:06:36 2020 +0300
Commit: Victor Perevertkin <victor.perevertkin(a)reactos.org>
CommitDate: Sat Oct 17 04:06:36 2020 +0300
[SCSIPORT] Split scsiport.c file into several ones, prepare for the refactoring
CORE-17132
---
drivers/storage/port/scsiport/CMakeLists.txt | 5 +
drivers/storage/port/scsiport/fdo.c | 694 +++++
drivers/storage/port/scsiport/ioctl.c | 255 ++
drivers/storage/port/scsiport/pdo.c | 124 +
drivers/storage/port/scsiport/registry.c | 520 ++++
drivers/storage/port/scsiport/scsi.c | 1768 +++++++++++++
drivers/storage/port/scsiport/scsiport.c | 3539 +-------------------------
drivers/storage/port/scsiport/scsiport.h | 96 +-
8 files changed, 3541 insertions(+), 3460 deletions(-)
diff --git a/drivers/storage/port/scsiport/CMakeLists.txt
b/drivers/storage/port/scsiport/CMakeLists.txt
index 74304049d99..13c4407e4d9 100644
--- a/drivers/storage/port/scsiport/CMakeLists.txt
+++ b/drivers/storage/port/scsiport/CMakeLists.txt
@@ -2,6 +2,11 @@
spec2def(scsiport.sys scsiport.spec ADD_IMPORTLIB)
list(APPEND SOURCE
+ fdo.c
+ ioctl.c
+ pdo.c
+ registry.c
+ scsi.c
scsiport.c
stubs.c)
diff --git a/drivers/storage/port/scsiport/fdo.c b/drivers/storage/port/scsiport/fdo.c
new file mode 100644
index 00000000000..95a0f3b4ed5
--- /dev/null
+++ b/drivers/storage/port/scsiport/fdo.c
@@ -0,0 +1,694 @@
+/*
+ * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Adapter device object (FDO) support routines
+ * COPYRIGHT: Eric Kohl (eric.kohl(a)reactos.org)
+ * Aleksey Bragin (aleksey(a)reactos.org)
+ */
+
+#include "scsiport.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+static
+NTSTATUS
+SpiSendInquiry(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PSCSI_LUN_INFO LunInfo)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIO_STACK_LOCATION IrpStack;
+ KEVENT Event;
+ KIRQL Irql;
+ PIRP Irp;
+ NTSTATUS Status;
+ PINQUIRYDATA InquiryBuffer;
+ PSENSE_DATA SenseBuffer;
+ BOOLEAN KeepTrying = TRUE;
+ ULONG RetryCount = 0;
+ SCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+
+ DPRINT("SpiSendInquiry() called\n");
+
+ DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE,
TAG_SCSIPORT);
+ if (InquiryBuffer == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
+ if (SenseBuffer == NULL)
+ {
+ ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ while (KeepTrying)
+ {
+ /* Initialize event for waiting */
+ KeInitializeEvent(&Event,
+ NotificationEvent,
+ FALSE);
+
+ /* Create an IRP */
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
+ DeviceObject,
+ NULL,
+ 0,
+ InquiryBuffer,
+ INQUIRYDATABUFFERSIZE,
+ TRUE,
+ &Event,
+ &IoStatusBlock);
+ if (Irp == NULL)
+ {
+ DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+
+ /* Quit the loop */
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ KeepTrying = FALSE;
+ continue;
+ }
+
+ /* Prepare SRB */
+ RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
+ Srb.OriginalRequest = Irp;
+ Srb.PathId = LunInfo->PathId;
+ Srb.TargetId = LunInfo->TargetId;
+ Srb.Lun = LunInfo->Lun;
+ Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
+ Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ Srb.TimeOutValue = 4;
+ Srb.CdbLength = 6;
+
+ Srb.SenseInfoBuffer = SenseBuffer;
+ Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ Srb.DataBuffer = InquiryBuffer;
+ Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+ /* Attach Srb to the Irp */
+ IrpStack = IoGetNextIrpStackLocation (Irp);
+ IrpStack->Parameters.Scsi.Srb = &Srb;
+
+ /* Fill in CDB */
+ Cdb = (PCDB)Srb.Cdb;
+ Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+ Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+ Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+ /* Call the driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ /* Wait for it to complete */
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT("SpiSendInquiry(): Waiting for the driver to process
request...\n");
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ DPRINT("SpiSendInquiry(): 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,
+ InquiryBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ /* Quit the loop */
+ Status = STATUS_SUCCESS;
+ KeepTrying = FALSE;
+ continue;
+ }
+
+ DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
+
+ /* Check if the queue is frozen */
+ if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
+ {
+ /* 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);
+
+ /* Clear frozen flag */
+ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+ /* Acquire the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ /* Process the request */
+ SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
+
+ /* SpiGetNextRequestFromLun() releases the spinlock,
+ so we just lower irql back to what it was before */
+ KeLowerIrql(Irql);
+ }
+
+ /* Check if data overrun happened */
+ if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
+ {
+ DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
+
+ /* Nothing dramatic, just copy data, but limiting the size */
+ RtlCopyMemory(LunInfo->InquiryData,
+ InquiryBuffer,
+ (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
+ INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
+
+ /* Quit the loop */
+ Status = STATUS_SUCCESS;
+ KeepTrying = FALSE;
+ }
+ else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
+ {
+ /* LUN is not valid, but some device responds there.
+ Mark it as invalid anyway */
+
+ /* Quit the loop */
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ KeepTrying = FALSE;
+ }
+ else
+ {
+ /* Retry a couple of times if no timeout happened */
+ if ((RetryCount < 2) &&
+ (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
+ (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
+ {
+ RetryCount++;
+ KeepTrying = TRUE;
+ }
+ else
+ {
+ /* That's all, quit the loop */
+ KeepTrying = FALSE;
+
+ /* Set status according to SRB status */
+ if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
+ SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
+ {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else
+ {
+ Status = STATUS_IO_DEVICE_ERROR;
+ }
+ }
+ }
+ }
+
+ /* Free buffers */
+ ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
+ ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
+
+ DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
+
+ return Status;
+}
+
+/* Scans all SCSI buses */
+VOID
+SpiScanAdapter(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ 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;
+
+ DPRINT("SpiScanAdapter() called\n");
+
+ /* Scan all buses */
+ for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+ {
+ DPRINT(" Scanning bus %d\n", Bus);
+ DevicesFound = 0;
+
+ /* 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);
+
+ /* And send INQUIRY to every target */
+ for (Target = 0; Target <
DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+ {
+ /* 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)
+ continue;
+
+ /* Scan all logical units */
+ for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+ {
+ if ((!LunExtension) || (!LunInfo))
+ break;
+
+ /* 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)
+ {
+ RtlZeroMemory(LunExtension + 1,
+ DeviceExtension->LunExtensionSize);
+ }
+
+ /* Finally send the inquiry command */
+ Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Let's see if we really found a device */
+ PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
+
+ /* Check if this device is unsupported */
+ if (InquiryData->DeviceTypeQualifier ==
DEVICE_QUALIFIER_NOT_SUPPORTED)
+ {
+ DeviceExtension->LunExtensionList[Hint] =
+ DeviceExtension->LunExtensionList[Hint]->Next;
+
+ continue;
+ }
+
+ /* Clear the "in scan" flag */
+ LunExtension->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);
+
+ /*
+ * 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);
+
+ /* Add this info to the linked list */
+ LunInfo->Next = NULL;
+ if (LastLunInfo)
+ LastLunInfo->Next = LunInfo;
+ else
+ BusScanInfo->LunInfo = LunInfo;
+
+ /* 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++;
+ }
+ 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)
+ continue;
+ else
+ break;
+ }
+ }
+ }
+
+ /* 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");
+}
+
+/**
+ * @brief Calls HwInitialize routine of the miniport and sets up interrupts
+ * Should be called inside ScsiPortInitialize (for legacy drivers)
+ * or inside IRP_MN_START_DEVICE for pnp drivers
+ *
+ * @param[in] DeviceExtension The device extension
+ *
+ * @return NTSTATUS of the operation
+ */
+NTSTATUS
+CallHWInitialize(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PPORT_CONFIGURATION_INFORMATION PortConfig = DeviceExtension->PortConfig;
+ NTSTATUS Status = STATUS_SUCCESS;
+ KIRQL OldIrql;
+
+ /* Deal with interrupts */
+ if (DeviceExtension->HwInterrupt == NULL ||
+ (PortConfig->BusInterruptLevel == 0 &&
PortConfig->BusInterruptVector == 0))
+ {
+ /* No interrupts */
+ DeviceExtension->InterruptCount = 0;
+
+ DPRINT1("Interrupt Count: 0\n");
+
+ UNIMPLEMENTED;
+
+ /* This code path will ALWAYS crash so stop it now */
+ __debugbreak();
+ }
+ else
+ {
+ BOOLEAN InterruptShareable;
+ KINTERRUPT_MODE InterruptMode[2];
+ ULONG InterruptVector[2], i, MappedIrq[2];
+ KIRQL Dirql[2], MaxDirql;
+ KAFFINITY Affinity[2];
+
+ DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
+ DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
+
+ InterruptVector[0] = PortConfig->BusInterruptVector;
+ InterruptVector[1] = PortConfig->BusInterruptVector2;
+
+ InterruptMode[0] = PortConfig->InterruptMode;
+ InterruptMode[1] = PortConfig->InterruptMode2;
+
+ DeviceExtension->InterruptCount =
+ (PortConfig->BusInterruptLevel2 != 0 ||
+ PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
+
+ for (i = 0; i < DeviceExtension->InterruptCount; i++)
+ {
+ /* Register an interrupt handler for this device */
+ MappedIrq[i] = HalGetInterruptVector(
+ PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber,
+ DeviceExtension->InterruptLevel[i], InterruptVector[i],
&Dirql[i],
+ &Affinity[i]);
+ }
+
+ if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
+ MaxDirql = Dirql[0];
+ else
+ MaxDirql = Dirql[1];
+
+ for (i = 0; i < DeviceExtension->InterruptCount; i++)
+ {
+ /* Determine IRQ sharability as usual */
+ if (PortConfig->AdapterInterfaceType == MicroChannel ||
+ InterruptMode[i] == LevelSensitive)
+ {
+ InterruptShareable = TRUE;
+ }
+ else
+ {
+ InterruptShareable = FALSE;
+ }
+
+ Status = IoConnectInterrupt(
+ &DeviceExtension->Interrupt[i], (PKSERVICE_ROUTINE)ScsiPortIsr,
DeviceExtension,
+ &DeviceExtension->IrqLock, MappedIrq[i], Dirql[i], MaxDirql,
InterruptMode[i],
+ InterruptShareable, Affinity[i], FALSE);
+
+ if (!(NT_SUCCESS(Status)))
+ {
+ DPRINT1("Could not connect interrupt %d\n",
InterruptVector[i]);
+ DeviceExtension->Interrupt[i] = NULL;
+ return Status;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ return Status;
+ }
+
+ /* Save IoAddress (from access ranges) */
+ if (PortConfig->NumberOfAccessRanges != 0)
+ {
+ DeviceExtension->IoAddress =
((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
+
+ DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
+ }
+
+ /* Set flag that it's allowed to disconnect during this command */
+ DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
+
+ /* Initialize counter of active requests (-1 means there are none) */
+ DeviceExtension->ActiveRequestCounter = -1;
+
+ /* Analyze what we have about DMA */
+ if (DeviceExtension->AdapterObject != NULL && PortConfig->Master
&&
+ PortConfig->NeedPhysicalAddresses)
+ {
+ DeviceExtension->MapRegisters = TRUE;
+ }
+ else
+ {
+ DeviceExtension->MapRegisters = FALSE;
+ }
+
+ /* Call HwInitialize at DISPATCH_LEVEL */
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ if (!KeSynchronizeExecution(
+ DeviceExtension->Interrupt[0], DeviceExtension->HwInitialize,
+ DeviceExtension->MiniPortDeviceExtension))
+ {
+ DPRINT1("HwInitialize() failed!\n");
+ KeLowerIrql(OldIrql);
+ return STATUS_ADAPTER_HARDWARE_ERROR;
+ }
+
+ /* Check if a notification is needed */
+ 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);
+ }
+
+ /* Lower irql back to what it was */
+ KeLowerIrql(OldIrql);
+
+ return Status;
+}
+
+VOID
+SpiCleanupAfterInit(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PSCSI_LUN_INFO LunInfo;
+ PVOID Ptr;
+ ULONG Bus, Lun;
+
+ /* Check if we have something to clean up */
+ if (DeviceExtension == NULL)
+ return;
+
+ /* Stop the timer */
+ IoStopTimer(DeviceExtension->DeviceObject);
+
+ /* Disconnect the interrupts */
+ while (DeviceExtension->InterruptCount)
+ {
+ if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
+
IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
+ }
+
+ /* Delete ConfigInfo */
+ if (DeviceExtension->BusesConfig)
+ {
+ for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
+ {
+ if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
+ continue;
+
+ LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+
+ while (LunInfo)
+ {
+ /* Free current, but save pointer to the next one */
+ Ptr = LunInfo->Next;
+ ExFreePool(LunInfo);
+ LunInfo = Ptr;
+ }
+
+ ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
+ }
+
+ ExFreePool(DeviceExtension->BusesConfig);
+ }
+
+ /* 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);
+ }
+ }
+
+ /* Free common buffer (if it exists) */
+ if (DeviceExtension->SrbExtensionBuffer != NULL &&
+ DeviceExtension->CommonBufferLength != 0)
+ {
+ if (!DeviceExtension->AdapterObject)
+ {
+ ExFreePool(DeviceExtension->SrbExtensionBuffer);
+ }
+ else
+ {
+ HalFreeCommonBuffer(DeviceExtension->AdapterObject,
+ DeviceExtension->CommonBufferLength,
+ DeviceExtension->PhysicalAddress,
+ DeviceExtension->SrbExtensionBuffer,
+ FALSE);
+ }
+ }
+
+ /* Free SRB info */
+ if (DeviceExtension->SrbInfo != NULL)
+ ExFreePool(DeviceExtension->SrbInfo);
+
+ /* Unmap mapped addresses */
+ while (DeviceExtension->MappedAddressList != NULL)
+ {
+ MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
+ DeviceExtension->MappedAddressList->NumberOfBytes);
+
+ Ptr = DeviceExtension->MappedAddressList;
+ DeviceExtension->MappedAddressList =
DeviceExtension->MappedAddressList->NextMappedAddress;
+
+ ExFreePool(Ptr);
+ }
+
+ /* Finally delete the device object */
+ DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
+ IoDeleteDevice(DeviceExtension->DeviceObject);
+}
diff --git a/drivers/storage/port/scsiport/ioctl.c
b/drivers/storage/port/scsiport/ioctl.c
new file mode 100644
index 00000000000..08de2260961
--- /dev/null
+++ b/drivers/storage/port/scsiport/ioctl.c
@@ -0,0 +1,255 @@
+/*
+ * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: IOCTL handlers
+ * COPYRIGHT: Eric Kohl (eric.kohl(a)reactos.org)
+ * Aleksey Bragin (aleksey(a)reactos.org)
+ */
+
+#include "scsiport.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+static
+NTSTATUS
+SpiGetInquiryData(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _In_ PIRP Irp)
+{
+ ULONG InquiryDataSize;
+ PSCSI_LUN_INFO LunInfo;
+ ULONG BusCount, LunCount, 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");
+
+ /* Get pointer to the buffer */
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+ 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;
+
+ /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
+ InquiryDataSize =
+ ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
+ sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
+
+ /* Calculate data size */
+ Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA);
+
+ Length += InquiryDataSize * LunCount;
+
+ /* Check, if all data is going to fit into provided buffer */
+ if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
+ {
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Store data size in the IRP */
+ Irp->IoStatus.Information = Length;
+
+ DPRINT("Data size: %lu\n", Length);
+
+ AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
+
+ AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
+
+ /* Point InquiryData to the corresponding place inside Buffer */
+ InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
+ (BusCount - 1) * sizeof(SCSI_BUS_DATA));
+
+ /* Loop each bus */
+ for (Bus = 0; Bus < BusCount; Bus++)
+ {
+ BusData = &AdapterBusInfo->BusData[Bus];
+
+ /* 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;
+
+ /* Store LUN count */
+ BusData->NumberOfLogicalUnits =
+ DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+ /* Loop all LUNs */
+ while (LunInfo != NULL)
+ {
+ DPRINT("(Bus %lu Target %lu Lun %lu)\n",
+ Bus, LunInfo->TargetId, LunInfo->Lun);
+
+ /* Fill InquiryData with values */
+ InquiryData->PathId = LunInfo->PathId;
+ InquiryData->TargetId = LunInfo->TargetId;
+ InquiryData->Lun = LunInfo->Lun;
+ InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
+ InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
+ InquiryData->NextInquiryDataOffset =
+ (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
+
+ /* Copy data in it */
+ RtlCopyMemory(InquiryData->InquiryData,
+ LunInfo->InquiryData,
+ INQUIRYDATABUFFERSIZE);
+
+ /* Move to the next LUN */
+ LunInfo = LunInfo->Next;
+ InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
+ }
+
+ /* Either mark the end, or set offset to 0 */
+ if (BusData->NumberOfLogicalUnits != 0)
+ ((PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData -
InquiryDataSize))->NextInquiryDataOffset = 0;
+ else
+ BusData->InquiryDataOffset = 0;
+ }
+
+ /* Finish with success */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * NAME INTERNAL
+ * ScsiPortDeviceControl
+ *
+ * DESCRIPTION
+ * Answer requests for device control calls
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * Standard dispatch arguments
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+NTSTATUS
+NTAPI
+ScsiPortDeviceControl(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PDUMP_POINTERS DumpPointers;
+ 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))
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
+ break;
+ }
+
+ 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)
+ {
+ 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);
+ break;
+ }
+ } else {
+ DPRINT1(" unknown ioctl code: 0x%lX\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
+ }
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ /* Complete the request with the given status */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
diff --git a/drivers/storage/port/scsiport/pdo.c b/drivers/storage/port/scsiport/pdo.c
new file mode 100644
index 00000000000..7365f42e443
--- /dev/null
+++ b/drivers/storage/port/scsiport/pdo.c
@@ -0,0 +1,124 @@
+/*
+ * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Logical Unit (PDO) functions
+ * COPYRIGHT: Eric Kohl (eric.kohl(a)reactos.org)
+ * Aleksey Bragin (aleksey(a)reactos.org)
+ */
+
+#include "scsiport.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+PSCSI_PORT_LUN_EXTENSION
+SpiAllocateLunExtension(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ ULONG LunExtensionSize;
+
+ DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension);
+
+ /* Round LunExtensionSize first to the sizeof LONGLONG */
+ LunExtensionSize = (DeviceExtension->LunExtensionSize +
+ sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
+
+ LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
+ DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
+
+ LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
+ if (LunExtension == NULL)
+ {
+ DPRINT1("Out of resources!\n");
+ return NULL;
+ }
+
+ /* Zero everything */
+ RtlZeroMemory(LunExtension, LunExtensionSize);
+
+ /* Initialize a list of requests */
+ InitializeListHead(&LunExtension->SrbInfo.Requests);
+
+ /* Initialize timeout counter */
+ LunExtension->RequestTimeout = -1;
+
+ /* Set maximum queue size */
+ LunExtension->MaxQueueCount = 256;
+
+ /* Initialize request queue */
+ KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
+
+ return LunExtension;
+}
+
+PSCSI_PORT_LUN_EXTENSION
+SpiGetLunExtension(
+ _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 (LunExtension->TargetId == TargetId &&
+ LunExtension->Lun == Lun &&
+ LunExtension->PathId == PathId)
+ {
+ /* All matches, return */
+ return LunExtension;
+ }
+
+ /* Advance to the next item */
+ LunExtension = LunExtension->Next;
+ }
+
+ /* We did not find anything */
+ DPRINT("Nothing found\n");
+ return NULL;
+}
+
+PSCSI_REQUEST_BLOCK_INFO
+SpiGetSrbData(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _In_ UCHAR PathId,
+ _In_ UCHAR TargetId,
+ _In_ UCHAR Lun,
+ _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;
+ }
+ else
+ {
+ /* Make sure the tag is valid, if it is - return the data */
+ if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
+ return NULL;
+ else
+ return &DeviceExtension->SrbInfo[QueueTag -1];
+ }
+}
diff --git a/drivers/storage/port/scsiport/registry.c
b/drivers/storage/port/scsiport/registry.c
new file mode 100644
index 00000000000..5deaf85c8e9
--- /dev/null
+++ b/drivers/storage/port/scsiport/registry.c
@@ -0,0 +1,520 @@
+/*
+ * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Registry operations
+ * COPYRIGHT: Eric Kohl (eric.kohl(a)reactos.org)
+ * Aleksey Bragin (aleksey(a)reactos.org)
+ */
+
+#include "scsiport.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+VOID
+SpiInitOpenKeys(
+ _Inout_ PCONFIGURATION_INFO ConfigInfo,
+ _In_ PUNICODE_STRING RegistryPath)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING KeyName;
+ NTSTATUS Status;
+
+ /* Open the service key */
+ InitializeObjectAttributes(&ObjectAttributes,
+ RegistryPath,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ 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);
+ ConfigInfo->ServiceKey = NULL;
+ }
+
+ /* If we could open driver's service key, then proceed to the Parameters key */
+ if (ConfigInfo->ServiceKey != NULL)
+ {
+ RtlInitUnicodeString(&KeyName, L"Parameters");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ ConfigInfo->ServiceKey,
+ (PSECURITY_DESCRIPTOR) NULL);
+
+ /* Try to open it */
+ Status = ZwOpenKey(&ConfigInfo->DeviceKey,
+ KEY_READ,
+ &ObjectAttributes);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Yes, Parameters key exist, and it must be used instead of
+ the Service key */
+ ZwClose(ConfigInfo->ServiceKey);
+ ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
+ ConfigInfo->DeviceKey = NULL;
+ }
+ }
+
+ if (ConfigInfo->ServiceKey != NULL)
+ {
+ /* Open the Device key */
+ RtlInitUnicodeString(&KeyName, L"Device");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ ConfigInfo->ServiceKey,
+ NULL);
+
+ /* We don't check for failure here - not needed */
+ ZwOpenKey(&ConfigInfo->DeviceKey,
+ KEY_READ,
+ &ObjectAttributes);
+ }
+}
+
+/**********************************************************************
+ * NAME INTERNAL
+ * SpiBuildDeviceMap
+ *
+ * DESCRIPTION
+ * Builds the registry device map of all device which are attached
+ * to the given SCSI HBA port. The device map is located at:
+ * \Registry\Machine\DeviceMap\Scsi
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * DeviceExtension
+ * ...
+ *
+ * RegistryPath
+ * Name of registry driver service key.
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+NTSTATUS
+SpiBuildDeviceMap(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _In_ PUNICODE_STRING RegistryPath)
+{
+ 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)
+ {
+ DPRINT1("Invalid parameter\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Open or create the 'Scsi' subkey */
+ RtlInitUnicodeString(&KeyName,
+ L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
+ 0,
+ NULL);
+ Status = ZwCreateKey(&ScsiKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ return Status;
+ }
+
+ /* Create new 'Scsi Port X' subkey */
+ DPRINT("Scsi Port %lu\n", DeviceExtension->PortNumber);
+
+ swprintf(NameBuffer,
+ L"Scsi Port %lu",
+ DeviceExtension->PortNumber);
+ RtlInitUnicodeString(&KeyName, NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_KERNEL_HANDLE,
+ ScsiKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiPortKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ ZwClose(ScsiKey);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ return Status;
+ }
+
+ /*
+ * Create port-specific values
+ */
+
+ /* Set 'DMA Enabled' (REG_DWORD) value */
+ UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
+ DPRINT(" DMA Enabled = %s\n", UlongData ? "TRUE" :
"FALSE");
+ RtlInitUnicodeString(&ValueName, L"DMA Enabled");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &UlongData,
+ sizeof(UlongData));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n",
Status);
+ ZwClose(ScsiPortKey);
+ return Status;
+ }
+
+ /* Set 'Driver' (REG_SZ) value */
+ DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
+ RtlInitUnicodeString(&ValueName, L"Driver");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_SZ,
+ DriverName,
+ (ULONG)((wcslen(DriverName) + 1) * sizeof(WCHAR)));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n",
Status);
+ ZwClose(ScsiPortKey);
+ return Status;
+ }
+
+ /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
+ UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
+ DPRINT(" Interrupt = %lu\n", UlongData);
+ RtlInitUnicodeString(&ValueName, L"Interrupt");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &UlongData,
+ sizeof(UlongData));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n",
Status);
+ ZwClose(ScsiPortKey);
+ return Status;
+ }
+
+ /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
+ UlongData =
ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
+ DPRINT(" IOAddress = %lx\n", UlongData);
+ RtlInitUnicodeString(&ValueName, L"IOAddress");
+ Status = ZwSetValueKey(ScsiPortKey,
+ &ValueName,
+ 0,
+ REG_DWORD,
+ &UlongData,
+ sizeof(UlongData));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n",
Status);
+ ZwClose(ScsiPortKey);
+ return Status;
+ }
+
+ /* Enumerate buses */
+ for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses;
BusNumber++)
+ {
+ /* Create 'Scsi Bus X' key */
+ DPRINT(" Scsi Bus %lu\n", BusNumber);
+ swprintf(NameBuffer,
+ L"Scsi Bus %lu",
+ BusNumber);
+ RtlInitUnicodeString(&KeyName, NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiPortKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiBusKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ /* Create 'Initiator Id X' key */
+ DPRINT(" Initiator Id %lu\n",
+ DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
+ swprintf(NameBuffer,
+ L"Initiator Id %lu",
+
(ULONG)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
+ RtlInitUnicodeString(&KeyName, NameBuffer);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ 0,
+ ScsiBusKey,
+ NULL);
+ Status = ZwCreateKey(&ScsiInitiatorKey,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_VOLATILE,
+ &Disposition);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
+ goto ByeBye;
+ }
+
+ /* FIXME: Are there any initiator values (??) */
+
+ 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/identifie…
+ * and
https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifie…
+ * 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);
+ ScsiBusKey = NULL;
+ }
+
+ByeBye:
+ if (ScsiLunKey != NULL)
+ ZwClose(ScsiLunKey);
+
+ if (ScsiInitiatorKey != NULL)
+ ZwClose(ScsiInitiatorKey);
+
+ if (ScsiTargetKey != NULL)
+ ZwClose(ScsiTargetKey);
+
+ if (ScsiBusKey != NULL)
+ ZwClose(ScsiBusKey);
+
+ if (ScsiPortKey != NULL)
+ ZwClose(ScsiPortKey);
+
+ DPRINT("SpiBuildDeviceMap() done\n");
+
+ return Status;
+}
diff --git a/drivers/storage/port/scsiport/scsi.c b/drivers/storage/port/scsiport/scsi.c
new file mode 100644
index 00000000000..7feb6da5cdf
--- /dev/null
+++ b/drivers/storage/port/scsiport/scsi.c
@@ -0,0 +1,1768 @@
+/*
+ * PROJECT: ReactOS Storage Stack
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: SCSI Port driver SCSI requests handling
+ * COPYRIGHT: Eric Kohl (eric.kohl(a)reactos.org)
+ * Aleksey Bragin (aleksey(a)reactos.org)
+ * 2020 Victor Perevertkin (victor.perevertkin(a)reactos.org)
+ */
+
+#include "scsiport.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+static
+NTSTATUS
+SpiStatusSrbToNt(
+ _In_ UCHAR SrbStatus)
+{
+ switch (SRB_STATUS(SrbStatus))
+ {
+ case SRB_STATUS_TIMEOUT:
+ case SRB_STATUS_COMMAND_TIMEOUT:
+ return STATUS_IO_TIMEOUT;
+
+ case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+ case SRB_STATUS_BAD_FUNCTION:
+ return STATUS_INVALID_DEVICE_REQUEST;
+
+ case SRB_STATUS_NO_DEVICE:
+ case SRB_STATUS_INVALID_LUN:
+ case SRB_STATUS_INVALID_TARGET_ID:
+ case SRB_STATUS_NO_HBA:
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ case SRB_STATUS_DATA_OVERRUN:
+ return STATUS_BUFFER_OVERFLOW;
+
+ case SRB_STATUS_SELECTION_TIMEOUT:
+ return STATUS_DEVICE_NOT_CONNECTED;
+
+ default:
+ return STATUS_IO_DEVICE_ERROR;
+ }
+
+ return STATUS_IO_DEVICE_ERROR;
+}
+
+static
+NTSTATUS
+SpiHandleAttachRelease(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _Inout_ PIRP Irp)
+{
+ PSCSI_LUN_INFO LunInfo;
+ PIO_STACK_LOCATION IrpStack;
+ 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;
+
+
+ /* Get spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ /* Release, if asked */
+ if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
+ {
+ LunInfo->DeviceClaimed = FALSE;
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Attach, if not already claimed */
+ if (LunInfo->DeviceClaimed)
+ {
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+
+ return STATUS_DEVICE_BUSY;
+ }
+
+ /* Save the device object */
+ DeviceObject = LunInfo->DeviceObject;
+
+ if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
+ LunInfo->DeviceClaimed = TRUE;
+
+ if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
+ LunInfo->DeviceObject = Srb->DataBuffer;
+
+ Srb->DataBuffer = DeviceObject;
+
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * NAME INTERNAL
+ * ScsiPortDispatchScsi
+ *
+ * DESCRIPTION
+ * Answer requests for SCSI calls
+ *
+ * RUN LEVEL
+ * PASSIVE_LEVEL
+ *
+ * ARGUMENTS
+ * Standard dispatch arguments
+ *
+ * RETURNS
+ * NTSTATUS
+ */
+
+NTSTATUS
+NTAPI
+ScsiPortDispatchScsi(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PIO_STACK_LOCATION Stack;
+ PSCSI_REQUEST_BLOCK Srb;
+ KIRQL Irql;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIRP NextIrp, IrpList;
+ PKDEVICE_QUEUE_ENTRY Entry;
+
+ DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n", DeviceObject,
Irp);
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ Srb = Stack->Parameters.Scsi.Srb;
+ if (Srb == NULL)
+ {
+ DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
+ Status = STATUS_UNSUCCESSFUL;
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ 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);
+
+ LunExtension = SpiGetLunExtension(DeviceExtension, Srb->PathId, Srb->TargetId,
Srb->Lun);
+ if (LunExtension == NULL)
+ {
+ DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
+ Status = STATUS_NO_SUCH_DEVICE;
+
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return (Status);
+ }
+
+ switch (Srb->Function)
+ {
+ case SRB_FUNCTION_SHUTDOWN:
+ case SRB_FUNCTION_FLUSH:
+ DPRINT(" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
+ if (DeviceExtension->CachesData == FALSE)
+ {
+ /* All success here */
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+ /* Fall through to a usual execute operation */
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+ case SRB_FUNCTION_IO_CONTROL:
+ DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or
SRB_FUNCTION_IO_CONTROL\n");
+ /* Mark IRP as pending in all cases */
+ IoMarkIrpPending(Irp);
+
+ if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ {
+ /* Start IO directly */
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+ else
+ {
+ KIRQL oldIrql;
+
+ /* We need to be at DISPATCH_LEVEL */
+ KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
+
+ /* Insert IRP into the queue */
+ if (!KeInsertByKeyDeviceQueue(
+ &LunExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ /* It means the queue is empty, and we just start this request */
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+
+ /* Back to the old IRQL */
+ KeLowerIrql(oldIrql);
+ }
+ return STATUS_PENDING;
+
+ case SRB_FUNCTION_CLAIM_DEVICE:
+ case SRB_FUNCTION_ATTACH_DEVICE:
+ DPRINT(" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
+
+ /* Reference device object and keep the device object */
+ Status = SpiHandleAttachRelease(DeviceExtension, 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);
+ break;
+
+ case SRB_FUNCTION_RELEASE_QUEUE:
+ DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
+
+ /* Guard with the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
+ {
+ DPRINT("Queue is not frozen really\n");
+
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ /* Unfreeze the queue */
+ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+ if (LunExtension->SrbInfo.Srb == NULL)
+ {
+ /* Get next logical unit request */
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+
+ /* SpiGetNextRequestFromLun() releases the spinlock */
+ KeLowerIrql(Irql);
+ }
+ else
+ {
+ DPRINT("The queue has active request\n");
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ }
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Status = STATUS_SUCCESS;
+ break;
+
+ case SRB_FUNCTION_FLUSH_QUEUE:
+ DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
+
+ /* Guard with the spinlock */
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+
+ if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
+ {
+ DPRINT("Queue is not frozen really\n");
+
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ /* Make sure there is no active request */
+ ASSERT(LunExtension->SrbInfo.Srb == NULL);
+
+ /* Compile a list from the device queue */
+ IrpList = NULL;
+ while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) !=
NULL)
+ {
+ NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
+
+ /* Get the Srb */
+ Stack = IoGetCurrentIrpStackLocation(NextIrp);
+ Srb = Stack->Parameters.Scsi.Srb;
+
+ /* Set statuse */
+ Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
+ NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ /* Add then to the list */
+ NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
+ IrpList = NextIrp;
+ }
+
+ /* Unfreeze the queue */
+ LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
+
+ /* Release the spinlock */
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
+
+ /* Complete those requests */
+ while (IrpList)
+ {
+ NextIrp = IrpList;
+ IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
+
+ IoCompleteRequest(NextIrp, 0);
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ DPRINT1("SRB function not implemented (Function %lu)\n",
Srb->Function);
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+VOID
+SpiGetNextRequestFromLun(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension)
+{
+ PIO_STACK_LOCATION IrpStack;
+ PIRP NextIrp;
+ PKDEVICE_QUEUE_ENTRY Entry;
+ PSCSI_REQUEST_BLOCK Srb;
+
+
+ /* If LUN is not active or queue is more than maximum allowed */
+ if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
+ !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
+ {
+ /* Release the spinlock and exit */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return;
+ }
+
+ /* Check if we can get a next request */
+ if (LunExtension->Flags &
+ (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
+ LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
+ {
+ /* Pending requests can only be started if the queue is empty */
+ if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
+ !(LunExtension->Flags &
+ (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE |
LUNEX_NEED_REQUEST_SENSE)))
+ {
+ /* Make sure we have SRB */
+ ASSERT(LunExtension->SrbInfo.Srb == NULL);
+
+ /* Clear active and pending flags */
+ LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING |
SCSI_PORT_LU_ACTIVE);
+
+ /* Get next Irp, and clear pending requests list */
+ NextIrp = LunExtension->PendingRequest;
+ LunExtension->PendingRequest = NULL;
+
+ /* Set attempt counter to zero */
+ LunExtension->AttemptCount = 0;
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Start the next pending request */
+ IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL,
NULL);
+
+ return;
+ }
+ else
+ {
+ /* Release the spinlock, without clearing any flags and exit */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ return;
+ }
+ }
+
+ /* Reset active flag */
+ LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
+
+ /* Set attempt counter to zero */
+ LunExtension->AttemptCount = 0;
+
+ /* Remove packet from the device queue */
+ Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue,
LunExtension->SortKey);
+
+ if (Entry != NULL)
+ {
+ /* Get pointer to the next irp */
+ NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
+
+ /* Get point to the SRB */
+ IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
+ Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
+
+ /* Set new key*/
+ LunExtension->SortKey = Srb->QueueSortKey;
+ LunExtension->SortKey++;
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Start the next pending request */
+ IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
+ }
+ else
+ {
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+}
+
+IO_COMPLETION_ROUTINE SpiSenseCompletionRoutine;
+
+NTSTATUS
+NTAPI
+SpiSenseCompletionRoutine(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _In_opt_ PVOID Context)
+{
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
+ PSCSI_REQUEST_BLOCK InitialSrb;
+ PIRP InitialIrp;
+
+ DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
+
+ if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
+ (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
+ {
+ /* Deallocate SRB and IRP and exit */
+ ExFreePool(Srb);
+ IoFreeIrp(Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ /* Get a pointer to the SRB and IRP which were initially sent */
+ InitialSrb = *((PVOID *)(Srb+1));
+ InitialIrp = InitialSrb->OriginalRequest;
+
+ if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
+ (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
+ {
+ /* Sense data is OK */
+ InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+
+ /* Set length to be the same */
+ InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
+ }
+
+ /* Make sure initial SRB's queue is frozen */
+ ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
+
+ /* Complete this request */
+ IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
+
+ /* Deallocate everything (internal) */
+ ExFreePool(Srb);
+
+ if (Irp->MdlAddress != NULL)
+ {
+ MmUnlockPages(Irp->MdlAddress);
+ IoFreeMdl(Irp->MdlAddress);
+ Irp->MdlAddress = NULL;
+ }
+
+ IoFreeIrp(Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static
+VOID
+SpiSendRequestSense(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _In_ PSCSI_REQUEST_BLOCK InitialSrb)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpStack;
+ LARGE_INTEGER LargeInt;
+ PVOID *Ptr;
+
+ DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
+
+ /* Allocate Srb */
+ Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID),
TAG_SCSIPORT);
+ RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ /* Allocate IRP */
+ LargeInt.QuadPart = (LONGLONG) 1;
+ Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
+ DeviceExtension->DeviceObject,
+ InitialSrb->SenseInfoBuffer,
+ InitialSrb->SenseInfoBufferLength,
+ &LargeInt,
+ NULL);
+
+ IoSetCompletionRoutine(Irp,
+ SpiSenseCompletionRoutine,
+ Srb,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ if (!Srb)
+ {
+ DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
+ return;
+ }
+
+ IrpStack = IoGetNextIrpStackLocation(Irp);
+ IrpStack->MajorFunction = IRP_MJ_SCSI;
+
+ /* Put Srb address into Irp... */
+ IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ /* ...and vice versa */
+ Srb->OriginalRequest = Irp;
+
+ /* Save Srb */
+ Ptr = (PVOID *)(Srb+1);
+ *Ptr = InitialSrb;
+
+ /* Build CDB for REQUEST SENSE */
+ Srb->CdbLength = 6;
+ Cdb = (PCDB)Srb->Cdb;
+
+ Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+ Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
+ Cdb->CDB6INQUIRY.Reserved1 = 0;
+ Cdb->CDB6INQUIRY.PageCode = 0;
+ Cdb->CDB6INQUIRY.IReserved = 0;
+ Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
+ Cdb->CDB6INQUIRY.Control = 0;
+
+ /* Set address */
+ Srb->TargetId = InitialSrb->TargetId;
+ Srb->Lun = InitialSrb->Lun;
+ Srb->PathId = InitialSrb->PathId;
+
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+
+ /* Timeout will be 2 seconds */
+ Srb->TimeOutValue = 2;
+
+ /* No auto request sense */
+ Srb->SenseInfoBufferLength = 0;
+ Srb->SenseInfoBuffer = NULL;
+
+ /* Set necessary flags */
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
+ SRB_FLAGS_DISABLE_DISCONNECT;
+
+ /* Transfer disable synch transfer flag */
+ if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
+ Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
+
+ /* Fill the transfer length */
+ Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
+
+ /* Clear statuses */
+ Srb->ScsiStatus = Srb->SrbStatus = 0;
+ Srb->NextSrb = 0;
+
+ /* Call the driver */
+ (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
+
+ DPRINT("SpiSendRequestSense() done\n");
+}
+
+
+static
+VOID
+SpiProcessCompletedRequest(
+ _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _Inout_ PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+ _Out_ PBOOLEAN NeedToCallStartIo)
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ LONG Result;
+ PIRP Irp;
+ //ULONG SequenceNumber;
+
+ Srb = SrbInfo->Srb;
+ Irp = Srb->OriginalRequest;
+
+ /* Get Lun extension */
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
+ DeviceExtension->MapBuffers &&
+ Irp->MdlAddress)
+ {
+ /* MDL is shared if transfer is broken into smaller parts */
+ Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
+ ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
+
+ /* In case of data going in, flush the buffers */
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ {
+ KeFlushIoBuffers(Irp->MdlAddress,
+ TRUE,
+ FALSE);
+ }
+ }
+
+ /* Flush adapter if needed */
+ if (SrbInfo->BaseOfMapRegister)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* Clear the request */
+ SrbInfo->Srb = NULL;
+
+ /* If disconnect is disabled... */
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ /* Acquire the spinlock since we mess with flags */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Set corresponding flag */
+ DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
+
+ /* Clear the timer if needed */
+ if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
+ DeviceExtension->TimerCount = -1;
+
+ /* Spinlock is not needed anymore */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
+ !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
+ !(*NeedToCallStartIo))
+ {
+ /* We're not busy, but we have a request pending */
+ IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
+ }
+ }
+
+ /* Scatter/gather */
+ if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* Acquire spinlock (we're freeing SrbExtension) */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Free it (if needed) */
+ if (Srb->SrbExtension)
+ {
+ if (Srb->SenseInfoBuffer != NULL &&
DeviceExtension->SupportsAutoSense)
+ {
+ ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest !=
NULL);
+
+ if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
+ {
+ /* Copy sense data to the buffer */
+ RtlCopyMemory(SrbInfo->SaveSenseRequest,
+ Srb->SenseInfoBuffer,
+ Srb->SenseInfoBufferLength);
+ }
+
+ /* And restore the pointer */
+ Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
+ }
+
+ /* Put it into the free srb extensions list */
+ *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
+ DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
+ }
+
+ /* Save transfer length in the IRP */
+ Irp->IoStatus.Information = Srb->DataTransferLength;
+
+ //SequenceNumber = SrbInfo->SequenceNumber;
+ SrbInfo->SequenceNumber = 0;
+
+ /* Decrement the queue count */
+ LunExtension->QueueCount--;
+
+ /* Free Srb, if needed*/
+ if (Srb->QueueTag != SP_UNTAGGED)
+ {
+ /* Put it into the free list */
+ SrbInfo->Requests.Blink = NULL;
+ SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
+ DeviceExtension->FreeSrbInfo = SrbInfo;
+ }
+
+ /* SrbInfo is not used anymore */
+ SrbInfo = NULL;
+
+ if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
+ {
+ /* Clear the flag */
+ DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
+
+ /* Note the caller about StartIo */
+ *NeedToCallStartIo = TRUE;
+ }
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
+ {
+ /* Start the packet */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
+ LunExtension->RequestTimeout == -1)
+ {
+ /* Start the next packet */
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+ }
+ else
+ {
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+ DPRINT("IoCompleting request IRP 0x%p\n", Irp);
+
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ /* Decrement number of active requests, and analyze the result */
+ Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
+
+ if (Result < 0 &&
+ !DeviceExtension->MapRegisters &&
+ DeviceExtension->AdapterObject != NULL)
+ {
+ /* Nullify map registers */
+ DeviceExtension->MapRegisterBase = NULL;
+ IoFreeAdapterChannel(DeviceExtension->AdapterObject);
+ }
+
+ /* Exit, we're done */
+ return;
+ }
+
+ /* Decrement number of active requests, and analyze the result */
+ Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
+
+ if (Result < 0 &&
+ !DeviceExtension->MapRegisters &&
+ DeviceExtension->AdapterObject != NULL)
+ {
+ /* Result is negative, so this is a slave, free map registers */
+ DeviceExtension->MapRegisterBase = NULL;
+ IoFreeAdapterChannel(DeviceExtension->AdapterObject);
+ }
+
+ /* Convert status */
+ Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
+
+ /* It's not a bypass, it's busy or the queue is full? */
+ if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
+ Srb->SrbStatus == SRB_STATUS_BUSY ||
+ Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
+ !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
+ {
+
+ DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
+
+ /* Requeue, if needed */
+ if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
+ {
+ DPRINT("it's being requeued\n");
+
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+ Srb->ScsiStatus = 0;
+
+ if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+ &Irp->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ /* It's a big f.ck up if we got here */
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_BUSY;
+
+ ASSERT(FALSE);
+ goto Error;
+ }
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ }
+ else if (LunExtension->AttemptCount++ < 20)
+ {
+ /* LUN is still busy */
+ Srb->ScsiStatus = 0;
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+
+ LunExtension->BusyRequest = Irp;
+ LunExtension->Flags |= LUNEX_BUSY;
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+ else
+ {
+Error:
+ /* Freeze the queue*/
+ Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
+ LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
+
+ /* "Unfull" the queue */
+ LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Return status that the device is not ready */
+ Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ }
+
+ return;
+ }
+
+ /* Start the next request, if LUN is idle, and this is sense request */
+ if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
+ (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
+ !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
+ && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
+ {
+ if (LunExtension->RequestTimeout == -1)
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+ else
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+ else
+ {
+ /* Freeze the queue */
+ Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
+ LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
+
+ /* Do we need a request sense? */
+ if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
+ {
+ /* If LUN is busy, we have to requeue it in order to allow request sense */
+ if (LunExtension->Flags & LUNEX_BUSY)
+ {
+ DPRINT("Requeuing busy request to allow request sense\n");
+
+ if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
+ &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
+ Srb->QueueSortKey))
+ {
+ /* We should never get here */
+ ASSERT(FALSE);
+
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+ return;
+
+ }
+
+ /* Clear busy flags */
+ LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
+ }
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Send RequestSense */
+ SpiSendRequestSense(DeviceExtension, Srb);
+
+ /* Exit */
+ return;
+ }
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+ /* Complete the request */
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+}
+
+BOOLEAN
+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_LUN_EXTENSION LunExtension;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ BOOLEAN Result;
+ BOOLEAN StartTimer;
+
+ 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);
+
+ /* Check if we are in a reset state */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
+ {
+ /* Mark the we've got requests while being in the reset state */
+ DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
+ return TRUE;
+ }
+
+ /* Set the time out value */
+ DeviceExtension->TimerCount = Srb->TimeOutValue;
+
+ /* We are busy */
+ DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
+
+ if (LunExtension->RequestTimeout != -1)
+ {
+ /* Timer already active */
+ StartTimer = FALSE;
+ }
+ else
+ {
+ /* It hasn't been initialized yet */
+ LunExtension->RequestTimeout = Srb->TimeOutValue;
+ StartTimer = TRUE;
+ }
+
+ if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ {
+ /* Handle bypass-requests */
+
+ /* Is this an abort request? */
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+ {
+ /* Get pointer to SRB info structure */
+ SrbInfo = SpiGetSrbData(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ /* Check if the request is still "active" */
+ if (SrbInfo == NULL ||
+ SrbInfo->Srb == NULL ||
+ !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
+ {
+ /* It's not, mark it as active then */
+ Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+
+ if (StartTimer)
+ LunExtension->RequestTimeout = -1;
+
+ DPRINT("Request has been already completed, but abort request
came\n");
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ /* Notify about request complete */
+ ScsiPortNotification(RequestComplete,
+ DeviceExtension->MiniPortDeviceExtension,
+ Srb);
+
+ /* and about readiness for the next request */
+ ScsiPortNotification(NextRequest,
+ DeviceExtension->MiniPortDeviceExtension);
+
+ /* They might ask for some work, so queue the DPC for them */
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+
+ /* We're done in this branch */
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* Add number of queued requests */
+ LunExtension->QueueCount++;
+ }
+
+ /* Bypass requests don't need request sense */
+ LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
+
+ /* Is disconnect disabled for this request? */
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ /* Set the corresponding flag */
+ DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
+ }
+
+ /* Transfer timeout value from Srb to Lun */
+ LunExtension->RequestTimeout = Srb->TimeOutValue;
+ }
+ else
+ {
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ /* It's a disconnect, so no more requests can go */
+ DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
+ }
+
+ LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
+
+ /* Increment queue count */
+ LunExtension->QueueCount++;
+
+ /* If it's tagged - special thing */
+ if (Srb->QueueTag != SP_UNTAGGED)
+ {
+ SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
+
+ /* Chek for consistency */
+ ASSERT(SrbInfo->Requests.Blink == NULL);
+
+ /* Insert it into the list of requests */
+ InsertTailList(&LunExtension->SrbInfo.Requests,
&SrbInfo->Requests);
+ }
+ }
+
+ /* Mark this Srb active */
+ Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
+
+ /* Call HwStartIo routine */
+ Result =
DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
+ Srb);
+
+ /* If notification is needed, then request a DPC */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+
+ return Result;
+}
+
+BOOLEAN
+NTAPI
+SpiSaveInterruptData(IN PVOID Context)
+{
+ PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ BOOLEAN IsTimed;
+
+ /* Get pointer to the device extension */
+ DeviceExtension = InterruptContext->DeviceExtension;
+
+ /* If we don't have anything pending - return */
+ if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
+ return FALSE;
+
+ /* Actually save the interrupt data */
+ *InterruptContext->InterruptData = DeviceExtension->InterruptData;
+
+ /* Clear the data stored in the device extension */
+ DeviceExtension->InterruptData.Flags &=
+ (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
+ DeviceExtension->InterruptData.CompletedAbort = NULL;
+ DeviceExtension->InterruptData.ReadyLun = NULL;
+ DeviceExtension->InterruptData.CompletedRequests = NULL;
+
+ /* Loop through the list of completed requests */
+ SrbInfo = InterruptContext->InterruptData->CompletedRequests;
+
+ while (SrbInfo)
+ {
+ /* Make sure we have SRV */
+ ASSERT(SrbInfo->Srb);
+
+ /* Get SRB and LunExtension */
+ Srb = SrbInfo->Srb;
+
+ LunExtension = SpiGetLunExtension(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ /* We have to check special cases if request is unsuccessful*/
+ if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
+ {
+ /* Check if we need request sense by a few conditions */
+ if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength
&&
+ Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
+ {
+ if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
+ {
+ /* It means: we tried to send REQUEST SENSE, but failed */
+
+ Srb->ScsiStatus = 0;
+ Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
+ }
+ else
+ {
+ /* Set the corresponding flag, so that REQUEST SENSE
+ will be sent */
+ LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
+ }
+
+ }
+
+ /* Check for a full queue */
+ if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
+ {
+ /* TODO: Implement when it's encountered */
+ ASSERT(FALSE);
+ }
+ }
+
+ /* Let's decide if we need to watch timeout or not */
+ if (Srb->QueueTag == SP_UNTAGGED)
+ {
+ IsTimed = TRUE;
+ }
+ else
+ {
+ if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
+ IsTimed = TRUE;
+ else
+ IsTimed = FALSE;
+
+ /* Remove it from the queue */
+ RemoveEntryList(&SrbInfo->Requests);
+ }
+
+ if (IsTimed)
+ {
+ /* We have to maintain timeout counter */
+ if (IsListEmpty(&LunExtension->SrbInfo.Requests))
+ {
+ LunExtension->RequestTimeout = -1;
+ }
+ else
+ {
+ NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
+ SCSI_REQUEST_BLOCK_INFO,
+ Requests);
+
+ Srb = NextSrbInfo->Srb;
+
+ /* Update timeout counter */
+ LunExtension->RequestTimeout = Srb->TimeOutValue;
+ }
+ }
+
+ SrbInfo = SrbInfo->CompletedRequests;
+ }
+
+ return TRUE;
+}
+
+VOID
+NTAPI
+ScsiPortDpcForIsr(
+ _In_ PKDPC Dpc,
+ _In_ PDEVICE_OBJECT DpcDeviceObject,
+ _Inout_ PIRP DpcIrp,
+ _In_opt_ PVOID DpcContext)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
+ SCSI_PORT_INTERRUPT_DATA InterruptData;
+ SCSI_PORT_SAVE_INTERRUPT Context;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ BOOLEAN NeedToStartIo;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ LARGE_INTEGER TimerValue;
+
+ DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext
%p)\n",
+ Dpc, DpcDeviceObject, DpcIrp, DpcContext);
+
+ /* We need to acquire spinlock */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
+
+TryAgain:
+
+ /* Interrupt structure must be snapshotted, and only then analyzed */
+ Context.InterruptData = &InterruptData;
+ Context.DeviceExtension = DeviceExtension;
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
+ SpiSaveInterruptData,
+ &Context))
+ {
+ /* Nothing - just return (don't forget to release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ DPRINT("ScsiPortDpcForIsr() done\n");
+ return;
+ }
+
+ /* If flush of adapters is needed - do it */
+ if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* Check for IoMapTransfer */
+ if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* Check if timer is needed */
+ if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
+ {
+ /* Save the timer routine */
+ DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
+
+ if (InterruptData.MiniportTimerValue == 0)
+ {
+ /* Cancel the timer */
+ KeCancelTimer(&DeviceExtension->MiniportTimer);
+ }
+ else
+ {
+ /* Convert timer value */
+ TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
+
+ /* Set the timer */
+ KeSetTimer(&DeviceExtension->MiniportTimer,
+ TimerValue,
+ &DeviceExtension->MiniportTimerDpc);
+ }
+ }
+
+ /* If it's ready for the next request */
+ if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
+ {
+ /* Check for a duplicate request (NextRequest+NextLuRequest) */
+ if ((DeviceExtension->Flags &
+ (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
+ (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
+ {
+ /* Clear busy flag set by ScsiPortStartPacket() */
+ DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
+
+ if (!(InterruptData.Flags & SCSI_PORT_RESET))
+ {
+ /* Ready for next, and no reset is happening */
+ DeviceExtension->TimerCount = -1;
+ }
+ }
+ else
+ {
+ /* Not busy, but not ready for the next request */
+ DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
+ InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
+ }
+ }
+
+ /* Any resets? */
+ if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
+ {
+ /* Hold for a bit */
+ DeviceExtension->TimerCount = 4;
+ }
+
+ /* Any ready LUN? */
+ if (InterruptData.ReadyLun != NULL)
+ {
+
+ /* Process all LUNs from the list*/
+ while (TRUE)
+ {
+ /* Remove it from the list first (as processed) */
+ LunExtension = InterruptData.ReadyLun;
+ InterruptData.ReadyLun = LunExtension->ReadyLun;
+ LunExtension->ReadyLun = NULL;
+
+ /* Get next request for this LUN */
+ SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
+
+ /* Still ready requests exist?
+ If yes - get spinlock, if no - stop here */
+ if (InterruptData.ReadyLun != NULL)
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+ else
+ break;
+ }
+ }
+ else
+ {
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+ /* If we ready for next packet, start it */
+ if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
+ IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
+
+ NeedToStartIo = FALSE;
+
+ /* Loop the completed request list */
+ while (InterruptData.CompletedRequests)
+ {
+ /* Remove the request */
+ SrbInfo = InterruptData.CompletedRequests;
+ InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
+ SrbInfo->CompletedRequests = NULL;
+
+ /* Process it */
+ SpiProcessCompletedRequest(DeviceExtension,
+ SrbInfo,
+ &NeedToStartIo);
+ }
+
+ /* Loop abort request list */
+ while (InterruptData.CompletedAbort)
+ {
+ LunExtension = InterruptData.CompletedAbort;
+
+ /* Remove the request */
+ InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
+
+ /* Get spinlock since we're going to change flags */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* TODO: Put SrbExtension to the list of free extensions */
+ ASSERT(FALSE);
+ }
+
+ /* If we need - call StartIo routine */
+ if (NeedToStartIo)
+ {
+ /* Make sure CurrentIrp is not null! */
+ ASSERT(DpcDeviceObject->CurrentIrp != NULL);
+ ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
+ }
+
+ /* Everything has been done, check */
+ if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
+ {
+ /* Synchronize using spinlock */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Request an interrupt */
+ DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
+
+ ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
+
+ /* Should interrupts be enabled again? */
+ if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
+ {
+ /* Clear this flag */
+ DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
+
+ /* Call a special routine to do this */
+ ASSERT(FALSE);
+#if 0
+ KeSynchronizeExecution(DeviceExtension->Interrupt,
+ SpiEnableInterrupts,
+ DeviceExtension);
+#endif
+ }
+
+ /* If we need a notification again - loop */
+ if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
+ goto TryAgain;
+
+ /* Release the spinlock */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+ DPRINT("ScsiPortDpcForIsr() done\n");
+}
+
+static
+PSCSI_REQUEST_BLOCK_INFO
+SpiAllocateSrbStructures(
+ _Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension,
+ _Inout_ PSCSI_REQUEST_BLOCK Srb)
+{
+ PCHAR SrbExtension;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+
+ /* Spinlock must be held while this function executes */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ /* Allocate SRB data structure */
+ if (DeviceExtension->NeedSrbDataAlloc)
+ {
+ /* 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);
+ }
+ else if (Srb->SrbFlags &
+ (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
+ !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ )
+ {
+ /* Do not process tagged commands if need request sense is set */
+ if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
+ {
+ ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
+
+ LunExtension->PendingRequest = Srb->OriginalRequest;
+ LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
+
+ /* Release the spinlock and return */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return NULL;
+ }
+
+ ASSERT(LunExtension->SrbInfo.Srb == NULL);
+ SrbInfo = DeviceExtension->FreeSrbInfo;
+
+ if (SrbInfo == NULL)
+ {
+ /* No SRB structures left in the list. We have to leave
+ and wait while we are called again */
+
+ DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return NULL;
+ }
+
+ DeviceExtension->FreeSrbInfo =
(PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
+
+ /* QueueTag must never be 0, so +1 to it */
+ Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
+ }
+ else
+ {
+ /* Usual untagged command */
+ if (
+ (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
+ LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
+ !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
+ )
+ {
+ /* Mark it as pending and leave */
+ ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
+ LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
+ LunExtension->PendingRequest = Srb->OriginalRequest;
+
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return(NULL);
+ }
+
+ Srb->QueueTag = SP_UNTAGGED;
+ SrbInfo = &LunExtension->SrbInfo;
+ }
+ }
+ else
+ {
+ Srb->QueueTag = SP_UNTAGGED;
+ SrbInfo = &LunExtension->SrbInfo;
+ }
+
+ /* Allocate SRB extension structure */
+ if (DeviceExtension->NeedSrbExtensionAlloc)
+ {
+ /* Check the list of free extensions */
+ SrbExtension = DeviceExtension->FreeSrbExtensions;
+
+ /* If no free extensions... */
+ if (SrbExtension == NULL)
+ {
+ /* Free SRB data */
+ if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
+ Srb->QueueTag != SP_UNTAGGED)
+ {
+ SrbInfo->Requests.Blink = NULL;
+ SrbInfo->Requests.Flink =
(PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
+ DeviceExtension->FreeSrbInfo = SrbInfo;
+ }
+
+ /* Return, in order to be called again later */
+ DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ return NULL;
+ }
+
+ /* Remove that free SRB extension from the list (since
+ we're going to use it) */
+ DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
+
+ /* Spinlock can be released now */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ Srb->SrbExtension = SrbExtension;
+
+ if (Srb->SenseInfoBuffer != NULL &&
+ DeviceExtension->SupportsAutoSense)
+ {
+ /* Store pointer to the SenseInfo buffer */
+ SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
+
+ /* Does data fit the buffer? */
+ if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
+ {
+ /* No, disabling autosense at all */
+ Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
+ }
+ else
+ {
+ /* Yes, update the buffer pointer */
+ Srb->SenseInfoBuffer = SrbExtension +
DeviceExtension->SrbExtensionSize;
+ }
+ }
+ }
+ else
+ {
+ /* Cleanup... */
+ Srb->SrbExtension = NULL;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+ return SrbInfo;
+}
+
+VOID
+NTAPI
+ScsiPortStartIo(
+ _Inout_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp)
+{
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PSCSI_PORT_LUN_EXTENSION LunExtension;
+ PIO_STACK_LOCATION IrpStack;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ LONG CounterResult;
+ NTSTATUS Status;
+
+ DPRINT("ScsiPortStartIo() called!\n");
+
+ DeviceExtension = DeviceObject->DeviceExtension;
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ DPRINT("DeviceExtension %p\n", 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)
+ {
+ /* Allocate them */
+ SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
+ LunExtension,
+ Srb);
+
+ /* Couldn't alloc one or both data structures, return */
+ if (SrbInfo == NULL)
+ {
+ /* We have to call IoStartNextPacket, because this request
+ was not started */
+ if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
+ IoStartNextPacket(DeviceObject, FALSE);
+
+ return;
+ }
+ }
+ else
+ {
+ /* No allocations are needed */
+ SrbInfo = &LunExtension->SrbInfo;
+ Srb->SrbExtension = NULL;
+ Srb->QueueTag = SP_UNTAGGED;
+ }
+
+ /* Increase sequence number of SRB */
+ if (!SrbInfo->SequenceNumber)
+ {
+ /* Increase global sequence number */
+ DeviceExtension->SequenceNumber++;
+
+ /* Assign it */
+ SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
+ }
+
+ /* Check some special SRBs */
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
+ {
+ /* Some special handling */
+ DPRINT1("Abort command! Unimplemented now\n");
+ }
+ else
+ {
+ SrbInfo->Srb = Srb;
+ }
+
+ if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
+ {
+ // Store the MDL virtual address in SrbInfo structure
+ SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
+
+ if (DeviceExtension->MapBuffers)
+ {
+ /* Calculate offset within DataBuffer */
+ SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
+ Srb->DataBuffer = SrbInfo->DataOffset +
+ (ULONG)((PUCHAR)Srb->DataBuffer -
+ (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
+ }
+
+ if (DeviceExtension->AdapterObject)
+ {
+ /* Flush buffers */
+ KeFlushIoBuffers(Irp->MdlAddress,
+ Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
+ TRUE);
+ }
+
+ if (DeviceExtension->MapRegisters)
+ {
+ /* Calculate number of needed map registers */
+ SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ Srb->DataBuffer,
+ Srb->DataTransferLength);
+
+ /* Allocate adapter channel */
+ Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
+ DeviceExtension->DeviceObject,
+ SrbInfo->NumberOfMapRegisters,
+ SpiAdapterControl,
+ SrbInfo);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IoAllocateAdapterChannel() failed!\n");
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ DeviceExtension + 1,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension + 1);
+
+ /* Request DPC for that work */
+ IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
+ }
+
+ /* Control goes to SpiAdapterControl */
+ return;
+ }
+ }
+
+ /* Increase active request counter */
+ CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
+
+ if (CounterResult == 0 &&
+ DeviceExtension->AdapterObject != NULL &&
+ !DeviceExtension->MapRegisters)
+ {
+ IoAllocateAdapterChannel(
+ DeviceExtension->AdapterObject,
+ DeviceObject,
+ DeviceExtension->PortCapabilities.MaximumPhysicalPages,
+ ScsiPortAllocateAdapterChannel,
+ LunExtension
+ );
+
+ return;
+ }
+
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
+ ScsiPortStartPacket,
+ DeviceObject))
+ {
+ DPRINT("Synchronization failed!\n");
+
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ Irp->IoStatus.Information = 0;
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ /* Release the spinlock only */
+ KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
+ }
+
+
+ DPRINT("ScsiPortStartIo() done\n");
+}
diff --git a/drivers/storage/port/scsiport/scsiport.c
b/drivers/storage/port/scsiport/scsiport.c
index 2155a2c069d..1f527947d25 100644
--- a/drivers/storage/port/scsiport/scsiport.c
+++ b/drivers/storage/port/scsiport/scsiport.c
@@ -1,7 +1,7 @@
/*
- * PROJECT: ReactOS Storage Stack
+ * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
* LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE: SCSI Port driver SCSI requests handling
+ * PURPOSE: Main and exported functions
* COPYRIGHT: Eric Kohl (eric.kohl(a)reactos.org)
* Aleksey Bragin (aleksey(a)reactos.org)
*/
@@ -32,108 +32,10 @@ static NTSTATUS NTAPI
ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
-static DRIVER_DISPATCH ScsiPortDispatchScsi;
-static NTSTATUS NTAPI
-ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
-
-static NTSTATUS NTAPI
-ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
-
-static DRIVER_STARTIO ScsiPortStartIo;
-static VOID NTAPI
-ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp);
-
-static BOOLEAN NTAPI
-ScsiPortStartPacket(IN OUT PVOID Context);
-
-IO_ALLOCATION_ACTION
-NTAPI
-SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
- PVOID MapRegisterBase, PVOID Context);
-
-static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
-
-static PSCSI_PORT_LUN_EXTENSION
-SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN UCHAR PathId,
- IN UCHAR TargetId,
- IN UCHAR Lun);
-
-static PSCSI_REQUEST_BLOCK_INFO
-SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PSCSI_PORT_LUN_EXTENSION LunExtension,
- PSCSI_REQUEST_BLOCK Srb);
-
-static NTSTATUS
-SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject,
- IN OUT PSCSI_LUN_INFO LunInfo);
-
-static VOID
-SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
-
-static NTSTATUS
-SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PIRP Irp);
-
-static PSCSI_REQUEST_BLOCK_INFO
-SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN UCHAR PathId,
- IN UCHAR TargetId,
- IN UCHAR Lun,
- IN UCHAR QueueTag);
-
-static BOOLEAN NTAPI
-ScsiPortIsr(IN PKINTERRUPT Interrupt,
- IN PVOID ServiceContext);
-
-static VOID NTAPI
-ScsiPortDpcForIsr(IN PKDPC Dpc,
- IN PDEVICE_OBJECT DpcDeviceObject,
- IN PIRP DpcIrp,
- IN PVOID DpcContext);
-
static VOID NTAPI
ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
PVOID Context);
-IO_ALLOCATION_ACTION
-NTAPI
-ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID MapRegisterBase,
- IN PVOID Context);
-
-static NTSTATUS
-SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PUNICODE_STRING RegistryPath);
-
-static NTSTATUS
-SpiStatusSrbToNt(UCHAR SrbStatus);
-
-static VOID
-SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PSCSI_REQUEST_BLOCK Srb);
-
-static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
-NTSTATUS NTAPI
-SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PVOID Context);
-
-static VOID
-NTAPI
-SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
- OUT PBOOLEAN NeedToCallStartIo);
-
-VOID NTAPI
-SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- IN PSCSI_PORT_LUN_EXTENSION LunExtension);
-
VOID NTAPI
SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
IN PVOID DeviceObject,
@@ -176,13 +78,6 @@ static PCM_RESOURCE_LIST
SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
PPORT_CONFIGURATION_INFORMATION PortConfig);
-static VOID
-SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
-
-static NTSTATUS
-SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PIRP Irp);
-
static NTSTATUS
SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG
NonCachedSize);
@@ -880,73 +775,6 @@ ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
}
-static VOID
-SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
-{
- OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING KeyName;
- NTSTATUS Status;
-
- /* Open the service key */
- InitializeObjectAttributes(&ObjectAttributes,
- RegistryPath,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- 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);
- ConfigInfo->ServiceKey = NULL;
- }
-
- /* If we could open driver's service key, then proceed to the Parameters key */
- if (ConfigInfo->ServiceKey != NULL)
- {
- RtlInitUnicodeString(&KeyName, L"Parameters");
- InitializeObjectAttributes(&ObjectAttributes,
- &KeyName,
- OBJ_CASE_INSENSITIVE,
- ConfigInfo->ServiceKey,
- (PSECURITY_DESCRIPTOR) NULL);
-
- /* Try to open it */
- Status = ZwOpenKey(&ConfigInfo->DeviceKey,
- KEY_READ,
- &ObjectAttributes);
-
- if (NT_SUCCESS(Status))
- {
- /* Yes, Parameters key exist, and it must be used instead of
- the Service key */
- ZwClose(ConfigInfo->ServiceKey);
- ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
- ConfigInfo->DeviceKey = NULL;
- }
- }
-
- if (ConfigInfo->ServiceKey != NULL)
- {
- /* Open the Device key */
- RtlInitUnicodeString(&KeyName, L"Device");
- InitializeObjectAttributes(&ObjectAttributes,
- &KeyName,
- OBJ_CASE_INSENSITIVE,
- ConfigInfo->ServiceKey,
- NULL);
-
- /* We don't check for failure here - not needed */
- ZwOpenKey(&ConfigInfo->DeviceKey,
- KEY_READ,
- &ObjectAttributes);
- }
-}
-
-
/**********************************************************************
* NAME EXPORTED
* ScsiPortInitialize
@@ -1007,7 +835,6 @@ ScsiPortInitialize(
UNICODE_STRING DosDeviceName;
PIO_SCSI_CAPABILITIES PortCapabilities;
- KIRQL OldIrql;
PCM_RESOURCE_LIST ResourceList;
BOOLEAN Conflict;
SIZE_T BusConfigSize;
@@ -1456,132 +1283,7 @@ CreatePortConfig:
}
}
- /* Deal with interrupts */
- if (DeviceExtension->HwInterrupt == NULL ||
- (PortConfig->BusInterruptLevel == 0 &&
PortConfig->BusInterruptVector == 0))
- {
- /* No interrupts */
- DeviceExtension->InterruptCount = 0;
-
- DPRINT1("Interrupt Count: 0\n");
-
- UNIMPLEMENTED;
-
- /* This code path will ALWAYS crash so stop it now */
- while (TRUE);
- }
- else
- {
- BOOLEAN InterruptShareable;
- KINTERRUPT_MODE InterruptMode[2];
- ULONG InterruptVector[2], i, MappedIrq[2];
- KIRQL Dirql[2], MaxDirql;
- KAFFINITY Affinity[2];
-
- DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
- DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
-
- InterruptVector[0] = PortConfig->BusInterruptVector;
- InterruptVector[1] = PortConfig->BusInterruptVector2;
-
- InterruptMode[0] = PortConfig->InterruptMode;
- InterruptMode[1] = PortConfig->InterruptMode2;
-
- DeviceExtension->InterruptCount =
- (PortConfig->BusInterruptLevel2 != 0 ||
- PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
-
- for (i = 0; i < DeviceExtension->InterruptCount; i++)
- {
- /* Register an interrupt handler for this device */
- MappedIrq[i] = HalGetInterruptVector(
- PortConfig->AdapterInterfaceType,
PortConfig->SystemIoBusNumber,
- DeviceExtension->InterruptLevel[i], InterruptVector[i],
&Dirql[i],
- &Affinity[i]);
- }
-
- if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
- MaxDirql = Dirql[0];
- else
- MaxDirql = Dirql[1];
-
- for (i = 0; i < DeviceExtension->InterruptCount; i++)
- {
- /* Determine IRQ sharability as usual */
- if (PortConfig->AdapterInterfaceType == MicroChannel ||
- InterruptMode[i] == LevelSensitive)
- {
- InterruptShareable = TRUE;
- }
- else
- {
- InterruptShareable = FALSE;
- }
-
- Status = IoConnectInterrupt(
- &DeviceExtension->Interrupt[i],
(PKSERVICE_ROUTINE)ScsiPortIsr, DeviceExtension,
- &DeviceExtension->IrqLock, MappedIrq[i], Dirql[i], MaxDirql,
InterruptMode[i],
- InterruptShareable, Affinity[i], FALSE);
-
- if (!(NT_SUCCESS(Status)))
- {
- DPRINT1("Could not connect interrupt %d\n",
InterruptVector[i]);
- DeviceExtension->Interrupt[i] = NULL;
- break;
- }
- }
-
- if (!NT_SUCCESS(Status))
- break;
- }
-
- /* Save IoAddress (from access ranges) */
- if (HwInitializationData->NumberOfAccessRanges != 0)
- {
- DeviceExtension->IoAddress =
((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
-
- DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
- }
-
- /* Set flag that it's allowed to disconnect during this command */
- DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
-
- /* Initialize counter of active requests (-1 means there are none) */
- DeviceExtension->ActiveRequestCounter = -1;
-
- /* Analyze what we have about DMA */
- if (DeviceExtension->AdapterObject != NULL && PortConfig->Master
&&
- PortConfig->NeedPhysicalAddresses)
- {
- DeviceExtension->MapRegisters = TRUE;
- }
- else
- {
- DeviceExtension->MapRegisters = FALSE;
- }
-
- /* Call HwInitialize at DISPATCH_LEVEL */
- KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
-
- if (!KeSynchronizeExecution(
- DeviceExtension->Interrupt[0], DeviceExtension->HwInitialize,
- DeviceExtension->MiniPortDeviceExtension))
- {
- DPRINT1("HwInitialize() failed!\n");
- KeLowerIrql(OldIrql);
- Status = STATUS_ADAPTER_HARDWARE_ERROR;
- break;
- }
-
- /* Check if a notification is needed */
- 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);
- }
-
- /* Lower irql back to what it was */
- KeLowerIrql(OldIrql);
+ CallHWInitialize(DeviceExtension);
/* Start our timer */
IoStartTimer(PortDeviceObject);
@@ -1656,106 +1358,6 @@ CreatePortConfig:
return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
}
-static VOID
-SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
- PSCSI_LUN_INFO LunInfo;
- PVOID Ptr;
- ULONG Bus, Lun;
-
- /* Check if we have something to clean up */
- if (DeviceExtension == NULL)
- return;
-
- /* Stop the timer */
- IoStopTimer(DeviceExtension->DeviceObject);
-
- /* Disconnect the interrupts */
- while (DeviceExtension->InterruptCount)
- {
- if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
-
IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
- }
-
- /* Delete ConfigInfo */
- if (DeviceExtension->BusesConfig)
- {
- for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
- {
- if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
- continue;
-
- LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
-
- while (LunInfo)
- {
- /* Free current, but save pointer to the next one */
- Ptr = LunInfo->Next;
- ExFreePool(LunInfo);
- LunInfo = Ptr;
- }
-
- ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
- }
-
- ExFreePool(DeviceExtension->BusesConfig);
- }
-
- /* 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);
- }
- }
-
- /* Free common buffer (if it exists) */
- if (DeviceExtension->SrbExtensionBuffer != NULL &&
- DeviceExtension->CommonBufferLength != 0)
- {
- if (!DeviceExtension->AdapterObject)
- {
- ExFreePool(DeviceExtension->SrbExtensionBuffer);
- }
- else
- {
- HalFreeCommonBuffer(DeviceExtension->AdapterObject,
- DeviceExtension->CommonBufferLength,
- DeviceExtension->PhysicalAddress,
- DeviceExtension->SrbExtensionBuffer,
- FALSE);
- }
- }
-
- /* Free SRB info */
- if (DeviceExtension->SrbInfo != NULL)
- ExFreePool(DeviceExtension->SrbInfo);
-
- /* Unmap mapped addresses */
- while (DeviceExtension->MappedAddressList != NULL)
- {
- MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
- DeviceExtension->MappedAddressList->NumberOfBytes);
-
- Ptr = DeviceExtension->MappedAddressList;
- DeviceExtension->MappedAddressList =
DeviceExtension->MappedAddressList->NextMappedAddress;
-
- ExFreePool(Ptr);
- }
-
- /* Finally delete the device object */
- DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
- IoDeleteDevice(DeviceExtension->DeviceObject);
-}
-
/*
* @unimplemented
*/
@@ -2392,2619 +1994,122 @@ ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
return STATUS_SUCCESS;
}
-static NTSTATUS
-SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PIRP Irp)
+IO_ALLOCATION_ACTION
+NTAPI
+SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID MapRegisterBase,
+ PVOID Context)
{
- PSCSI_LUN_INFO LunInfo;
- PIO_STACK_LOCATION IrpStack;
- PDEVICE_OBJECT DeviceObject;
PSCSI_REQUEST_BLOCK Srb;
- KIRQL Irql;
+ PSCSI_SG_ADDRESS ScatterGatherList;
+ KIRQL CurrentIrql;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG TotalLength = 0;
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+ PUCHAR DataVA;
+ BOOLEAN WriteToDevice;
+
+ /* Get pointers to SrbInfo and DeviceExtension */
+ SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
+ DeviceExtension = DeviceObject->DeviceExtension;
- /* Get pointer to the SRB */
+ /* Get pointer to 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)
+ /* Depending on the map registers number, we allocate
+ either from NonPagedPool, or from our static list */
+ if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
{
- Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
+ SrbInfo->ScatterGather = ExAllocatePoolWithTag(
+ NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS),
TAG_SCSIPORT);
- /* Get pointer to LunInfo */
- LunInfo =
DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
+ if (SrbInfo->ScatterGather == NULL)
+ ASSERT(FALSE);
- /* Find matching LunInfo */
- while (LunInfo)
+ Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
+ }
+ else
{
- if (LunInfo->PathId == Srb->PathId &&
- LunInfo->TargetId == Srb->TargetId &&
- LunInfo->Lun == Srb->Lun)
- {
- break;
- }
-
- LunInfo = LunInfo->Next;
+ SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
}
- /* If we couldn't find it - exit */
- if (LunInfo == NULL)
- return STATUS_DEVICE_DOES_NOT_EXIST;
-
+ /* Use chosen SG list source */
+ ScatterGatherList = SrbInfo->ScatterGather;
- /* Get spinlock */
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
+ /* Save map registers base */
+ SrbInfo->BaseOfMapRegister = MapRegisterBase;
- /* Release, if asked */
- if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
- {
- LunInfo->DeviceClaimed = FALSE;
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ /* Determine WriteToDevice flag */
+ WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
- return STATUS_SUCCESS;
- }
+ /* Get virtual address of the data buffer */
+ DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
+ ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
- /* Attach, if not already claimed */
- if (LunInfo->DeviceClaimed)
+ /* Build the actual SG list */
+ while (TotalLength < Srb->DataTransferLength)
{
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- Srb->SrbStatus = SRB_STATUS_BUSY;
-
- return STATUS_DEVICE_BUSY;
- }
+ if (!ScatterGatherList)
+ break;
- /* Save the device object */
- DeviceObject = LunInfo->DeviceObject;
+ ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
+ ScatterGatherList->PhysicalAddress =
IoMapTransfer(DeviceExtension->AdapterObject,
+ Irp->MdlAddress,
+ MapRegisterBase,
+ DataVA + TotalLength,
+
&ScatterGatherList->Length,
+ WriteToDevice);
- if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
- LunInfo->DeviceClaimed = TRUE;
+ TotalLength += ScatterGatherList->Length;
+ ScatterGatherList++;
+ }
- if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
- LunInfo->DeviceObject = Srb->DataBuffer;
+ /* Schedule an active request */
+ InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
+ KeSynchronizeExecution(DeviceExtension->Interrupt[0],
+ ScsiPortStartPacket,
+ DeviceObject);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
- Srb->DataBuffer = DeviceObject;
+ return DeallocateObjectKeepRegisters;
+}
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
-
- return STATUS_SUCCESS;
-}
-
-
-/**********************************************************************
- * NAME INTERNAL
- * ScsiPortDispatchScsi
- *
- * DESCRIPTION
- * Answer requests for SCSI calls
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * Standard dispatch arguments
- *
- * RETURNS
- * NTSTATUS
- */
-
-static NTSTATUS NTAPI
-ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
-{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PIO_STACK_LOCATION Stack;
- PSCSI_REQUEST_BLOCK Srb;
- KIRQL Irql;
- NTSTATUS Status = STATUS_SUCCESS;
- PIRP NextIrp, IrpList;
- PKDEVICE_QUEUE_ENTRY Entry;
-
- DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n", DeviceObject,
Irp);
-
- DeviceExtension = DeviceObject->DeviceExtension;
- Stack = IoGetCurrentIrpStackLocation(Irp);
-
- Srb = Stack->Parameters.Scsi.Srb;
- if (Srb == NULL)
- {
- DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
- Status = STATUS_UNSUCCESSFUL;
-
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
-
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- 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);
-
- LunExtension = SpiGetLunExtension(DeviceExtension, Srb->PathId, Srb->TargetId,
Srb->Lun);
- if (LunExtension == NULL)
- {
- DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
- Status = STATUS_NO_SUCH_DEVICE;
-
- Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
-
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return (Status);
- }
-
- switch (Srb->Function)
- {
- case SRB_FUNCTION_SHUTDOWN:
- case SRB_FUNCTION_FLUSH:
- DPRINT(" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
- if (DeviceExtension->CachesData == FALSE)
- {
- /* All success here */
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
- }
- /* Fall through to a usual execute operation */
-
- case SRB_FUNCTION_EXECUTE_SCSI:
- case SRB_FUNCTION_IO_CONTROL:
- DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or
SRB_FUNCTION_IO_CONTROL\n");
- /* Mark IRP as pending in all cases */
- IoMarkIrpPending(Irp);
-
- if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
- {
- /* Start IO directly */
- IoStartPacket(DeviceObject, Irp, NULL, NULL);
- }
- else
- {
- KIRQL oldIrql;
-
- /* We need to be at DISPATCH_LEVEL */
- KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
-
- /* Insert IRP into the queue */
- if (!KeInsertByKeyDeviceQueue(
- &LunExtension->DeviceQueue,
- &Irp->Tail.Overlay.DeviceQueueEntry,
- Srb->QueueSortKey))
- {
- /* It means the queue is empty, and we just start this request */
- IoStartPacket(DeviceObject, Irp, NULL, NULL);
- }
-
- /* Back to the old IRQL */
- KeLowerIrql(oldIrql);
- }
- return STATUS_PENDING;
-
- case SRB_FUNCTION_CLAIM_DEVICE:
- case SRB_FUNCTION_ATTACH_DEVICE:
- DPRINT(" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
-
- /* Reference device object and keep the device object */
- Status = SpiHandleAttachRelease(DeviceExtension, 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);
- break;
-
- case SRB_FUNCTION_RELEASE_QUEUE:
- DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
-
- /* Guard with the spinlock */
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
-
- if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
- {
- DPRINT("Queue is not frozen really\n");
-
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- Status = STATUS_SUCCESS;
- break;
- }
-
- /* Unfreeze the queue */
- LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
-
- if (LunExtension->SrbInfo.Srb == NULL)
- {
- /* Get next logical unit request */
- SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
-
- /* SpiGetNextRequestFromLun() releases the spinlock */
- KeLowerIrql(Irql);
- }
- else
- {
- DPRINT("The queue has active request\n");
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- }
-
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- Status = STATUS_SUCCESS;
- break;
-
- case SRB_FUNCTION_FLUSH_QUEUE:
- DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
-
- /* Guard with the spinlock */
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
-
- if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
- {
- DPRINT("Queue is not frozen really\n");
-
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
- }
-
- /* Make sure there is no active request */
- ASSERT(LunExtension->SrbInfo.Srb == NULL);
-
- /* Compile a list from the device queue */
- IrpList = NULL;
- while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) !=
NULL)
- {
- NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
-
- /* Get the Srb */
- Stack = IoGetCurrentIrpStackLocation(NextIrp);
- Srb = Stack->Parameters.Scsi.Srb;
-
- /* Set statuse */
- Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
- NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
-
- /* Add then to the list */
- NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
- IrpList = NextIrp;
- }
-
- /* Unfreeze the queue */
- LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
-
- /* Release the spinlock */
- KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
-
- /* Complete those requests */
- while (IrpList)
- {
- NextIrp = IrpList;
- IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
-
- IoCompleteRequest(NextIrp, 0);
- }
-
- Status = STATUS_SUCCESS;
- break;
-
- default:
- DPRINT1("SRB function not implemented (Function %lu)\n",
Srb->Function);
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- }
-
- Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return Status;
-}
-
-
-/**********************************************************************
- * NAME INTERNAL
- * ScsiPortDeviceControl
- *
- * DESCRIPTION
- * Answer requests for device control calls
- *
- * RUN LEVEL
- * PASSIVE_LEVEL
- *
- * ARGUMENTS
- * Standard dispatch arguments
- *
- * RETURNS
- * NTSTATUS
- */
-
-static NTSTATUS NTAPI
-ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PIO_STACK_LOCATION Stack;
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PDUMP_POINTERS DumpPointers;
- 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))
- {
- Status = STATUS_BUFFER_OVERFLOW;
- Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
- break;
- }
-
- 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)
- {
- 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);
- break;
- }
- } else {
- DPRINT1(" unknown ioctl code: 0x%lX\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
- }
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- }
-
- /* Complete the request with the given status */
- Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return Status;
-}
-
-
-static VOID NTAPI
-ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PIO_STACK_LOCATION IrpStack;
- PSCSI_REQUEST_BLOCK Srb;
- PSCSI_REQUEST_BLOCK_INFO SrbInfo;
- LONG CounterResult;
- NTSTATUS Status;
-
- DPRINT("ScsiPortStartIo() called!\n");
-
- DeviceExtension = DeviceObject->DeviceExtension;
- IrpStack = IoGetCurrentIrpStackLocation(Irp);
-
- DPRINT("DeviceExtension %p\n", 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)
- {
- /* Allocate them */
- SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
- LunExtension,
- Srb);
-
- /* Couldn't alloc one or both data structures, return */
- if (SrbInfo == NULL)
- {
- /* We have to call IoStartNextPacket, because this request
- was not started */
- if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
- IoStartNextPacket(DeviceObject, FALSE);
-
- return;
- }
- }
- else
- {
- /* No allocations are needed */
- SrbInfo = &LunExtension->SrbInfo;
- Srb->SrbExtension = NULL;
- Srb->QueueTag = SP_UNTAGGED;
- }
-
- /* Increase sequence number of SRB */
- if (!SrbInfo->SequenceNumber)
- {
- /* Increase global sequence number */
- DeviceExtension->SequenceNumber++;
-
- /* Assign it */
- SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
- }
-
- /* Check some special SRBs */
- if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
- {
- /* Some special handling */
- DPRINT1("Abort command! Unimplemented now\n");
- }
- else
- {
- SrbInfo->Srb = Srb;
- }
-
- if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
- {
- // Store the MDL virtual address in SrbInfo structure
- SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
-
- if (DeviceExtension->MapBuffers)
- {
- /* Calculate offset within DataBuffer */
- SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
- Srb->DataBuffer = SrbInfo->DataOffset +
- (ULONG)((PUCHAR)Srb->DataBuffer -
- (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
- }
-
- if (DeviceExtension->AdapterObject)
- {
- /* Flush buffers */
- KeFlushIoBuffers(Irp->MdlAddress,
- Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
- TRUE);
- }
-
- if (DeviceExtension->MapRegisters)
- {
- /* Calculate number of needed map registers */
- SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
- Srb->DataBuffer,
- Srb->DataTransferLength);
-
- /* Allocate adapter channel */
- Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
- DeviceExtension->DeviceObject,
- SrbInfo->NumberOfMapRegisters,
- SpiAdapterControl,
- SrbInfo);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IoAllocateAdapterChannel() failed!\n");
-
- Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
- ScsiPortNotification(RequestComplete,
- DeviceExtension + 1,
- Srb);
-
- ScsiPortNotification(NextRequest,
- DeviceExtension + 1);
-
- /* Request DPC for that work */
- IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
- }
-
- /* Control goes to SpiAdapterControl */
- return;
- }
- }
-
- /* Increase active request counter */
- CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
-
- if (CounterResult == 0 &&
- DeviceExtension->AdapterObject != NULL &&
- !DeviceExtension->MapRegisters)
- {
- IoAllocateAdapterChannel(
- DeviceExtension->AdapterObject,
- DeviceObject,
- DeviceExtension->PortCapabilities.MaximumPhysicalPages,
- ScsiPortAllocateAdapterChannel,
- LunExtension
- );
-
- return;
- }
-
- KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
-
- if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
- ScsiPortStartPacket,
- DeviceObject))
- {
- DPRINT("Synchronization failed!\n");
-
- Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- Irp->IoStatus.Information = 0;
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
-
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- }
- else
- {
- /* Release the spinlock only */
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- }
-
-
- DPRINT("ScsiPortStartIo() done\n");
-}
-
-
-static BOOLEAN NTAPI
-ScsiPortStartPacket(IN OUT PVOID Context)
-{
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PIO_STACK_LOCATION IrpStack;
- PSCSI_REQUEST_BLOCK Srb;
- PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- PSCSI_REQUEST_BLOCK_INFO SrbInfo;
- BOOLEAN Result;
- BOOLEAN StartTimer;
-
- 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);
-
- /* Check if we are in a reset state */
- if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
- {
- /* Mark the we've got requests while being in the reset state */
- DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
- return TRUE;
- }
-
- /* Set the time out value */
- DeviceExtension->TimerCount = Srb->TimeOutValue;
-
- /* We are busy */
- DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
-
- if (LunExtension->RequestTimeout != -1)
- {
- /* Timer already active */
- StartTimer = FALSE;
- }
- else
- {
- /* It hasn't been initialized yet */
- LunExtension->RequestTimeout = Srb->TimeOutValue;
- StartTimer = TRUE;
- }
-
- if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
- {
- /* Handle bypass-requests */
-
- /* Is this an abort request? */
- if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
- {
- /* Get pointer to SRB info structure */
- SrbInfo = SpiGetSrbData(DeviceExtension,
- Srb->PathId,
- Srb->TargetId,
- Srb->Lun,
- Srb->QueueTag);
-
- /* Check if the request is still "active" */
- if (SrbInfo == NULL ||
- SrbInfo->Srb == NULL ||
- !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
- {
- /* It's not, mark it as active then */
- Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
-
- if (StartTimer)
- LunExtension->RequestTimeout = -1;
-
- DPRINT("Request has been already completed, but abort request
came\n");
- Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
-
- /* Notify about request complete */
- ScsiPortNotification(RequestComplete,
- DeviceExtension->MiniPortDeviceExtension,
- Srb);
-
- /* and about readiness for the next request */
- ScsiPortNotification(NextRequest,
- DeviceExtension->MiniPortDeviceExtension);
-
- /* They might ask for some work, so queue the DPC for them */
- IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
-
- /* We're done in this branch */
- return TRUE;
- }
- }
- else
- {
- /* Add number of queued requests */
- LunExtension->QueueCount++;
- }
-
- /* Bypass requests don't need request sense */
- LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
-
- /* Is disconnect disabled for this request? */
- if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
- {
- /* Set the corresponding flag */
- DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
- }
-
- /* Transfer timeout value from Srb to Lun */
- LunExtension->RequestTimeout = Srb->TimeOutValue;
- }
- else
- {
- if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
- {
- /* It's a disconnect, so no more requests can go */
- DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
- }
-
- LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
-
- /* Increment queue count */
- LunExtension->QueueCount++;
-
- /* If it's tagged - special thing */
- if (Srb->QueueTag != SP_UNTAGGED)
- {
- SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
-
- /* Chek for consistency */
- ASSERT(SrbInfo->Requests.Blink == NULL);
-
- /* Insert it into the list of requests */
- InsertTailList(&LunExtension->SrbInfo.Requests,
&SrbInfo->Requests);
- }
- }
-
- /* Mark this Srb active */
- Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
-
- /* Call HwStartIo routine */
- Result =
DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
- Srb);
-
- /* If notification is needed, then request a DPC */
- if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
- IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
-
- return Result;
-}
-
-IO_ALLOCATION_ACTION
-NTAPI
-SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PVOID MapRegisterBase,
- PVOID Context)
-{
- PSCSI_REQUEST_BLOCK Srb;
- PSCSI_SG_ADDRESS ScatterGatherList;
- KIRQL CurrentIrql;
- PIO_STACK_LOCATION IrpStack;
- ULONG TotalLength = 0;
- PSCSI_REQUEST_BLOCK_INFO SrbInfo;
- PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
- PUCHAR DataVA;
- BOOLEAN WriteToDevice;
-
- /* Get pointers to SrbInfo and DeviceExtension */
- SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
- DeviceExtension = DeviceObject->DeviceExtension;
-
- /* Get pointer to SRB */
- IrpStack = IoGetCurrentIrpStackLocation(Irp);
- Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
-
- /* Depending on the map registers number, we allocate
- either from NonPagedPool, or from our static list */
- if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
- {
- SrbInfo->ScatterGather = ExAllocatePoolWithTag(
- NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS),
TAG_SCSIPORT);
-
- if (SrbInfo->ScatterGather == NULL)
- ASSERT(FALSE);
-
- Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
- }
- else
- {
- SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
- }
-
- /* Use chosen SG list source */
- ScatterGatherList = SrbInfo->ScatterGather;
-
- /* Save map registers base */
- SrbInfo->BaseOfMapRegister = MapRegisterBase;
-
- /* Determine WriteToDevice flag */
- WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
-
- /* Get virtual address of the data buffer */
- DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
- ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
-
- /* Build the actual SG list */
- while (TotalLength < Srb->DataTransferLength)
- {
- if (!ScatterGatherList)
- break;
-
- ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
- ScatterGatherList->PhysicalAddress =
IoMapTransfer(DeviceExtension->AdapterObject,
- Irp->MdlAddress,
- MapRegisterBase,
- DataVA + TotalLength,
-
&ScatterGatherList->Length,
- WriteToDevice);
-
- TotalLength += ScatterGatherList->Length;
- ScatterGatherList++;
- }
-
- /* Schedule an active request */
- InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
- KeSynchronizeExecution(DeviceExtension->Interrupt[0],
- ScsiPortStartPacket,
- DeviceObject);
- KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
-
- return DeallocateObjectKeepRegisters;
-}
-
-static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
- PSCSI_PORT_LUN_EXTENSION LunExtension;
- ULONG LunExtensionSize;
-
- DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension);
-
- /* Round LunExtensionSize first to the sizeof LONGLONG */
- LunExtensionSize = (DeviceExtension->LunExtensionSize +
- sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
-
- LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
- DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
-
- LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
- if (LunExtension == NULL)
- {
- DPRINT1("Out of resources!\n");
- return NULL;
- }
-
- /* Zero everything */
- RtlZeroMemory(LunExtension, LunExtensionSize);
-
- /* Initialize a list of requests */
- InitializeListHead(&LunExtension->SrbInfo.Requests);
-
- /* Initialize timeout counter */
- LunExtension->RequestTimeout = -1;
-
- /* Set maximum queue size */
- LunExtension->MaxQueueCount = 256;
-
- /* Initialize request queue */
- KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
-
- return LunExtension;
-}
-
-static PSCSI_PORT_LUN_EXTENSION
-SpiGetLunExtension (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 (LunExtension->TargetId == TargetId &&
- LunExtension->Lun == Lun &&
- LunExtension->PathId == PathId)
- {
- /* All matches, return */
- return LunExtension;
- }
-
- /* Advance to the next item */
- LunExtension = LunExtension->Next;
- }
-
- /* We did not find anything */
- DPRINT("Nothing found\n");
- return NULL;
-}
-
-static PSCSI_REQUEST_BLOCK_INFO
-SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
- PSCSI_PORT_LUN_EXTENSION LunExtension,
- PSCSI_REQUEST_BLOCK Srb)
-{
- PCHAR SrbExtension;
- PSCSI_REQUEST_BLOCK_INFO SrbInfo;
-
- /* Spinlock must be held while this function executes */
- KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
-
- /* Allocate SRB data structure */
- if (DeviceExtension->NeedSrbDataAlloc)
- {
- /* 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);
- }
- else if (Srb->SrbFlags &
- (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
- !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
- )
- {
- /* Do not process tagged commands if need request sense is set */
- if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
- {
- ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
-
- LunExtension->PendingRequest = Srb->OriginalRequest;
- LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
-
- /* Release the spinlock and return */
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- return NULL;
- }
-
- ASSERT(LunExtension->SrbInfo.Srb == NULL);
- SrbInfo = DeviceExtension->FreeSrbInfo;
-
- if (SrbInfo == NULL)
- {
- /* No SRB structures left in the list. We have to leave
- and wait while we are called again */
-
- DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- return NULL;
- }
-
- DeviceExtension->FreeSrbInfo =
(PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
-
- /* QueueTag must never be 0, so +1 to it */
- Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
- }
- else
- {
- /* Usual untagged command */
- if (
- (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
- LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
- !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
- )
- {
- /* Mark it as pending and leave */
- ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
- LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
- LunExtension->PendingRequest = Srb->OriginalRequest;
-
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- return(NULL);
- }
-
- Srb->QueueTag = SP_UNTAGGED;
- SrbInfo = &LunExtension->SrbInfo;
- }
- }
- else
- {
- Srb->QueueTag = SP_UNTAGGED;
- SrbInfo = &LunExtension->SrbInfo;
- }
-
- /* Allocate SRB extension structure */
- if (DeviceExtension->NeedSrbExtensionAlloc)
- {
- /* Check the list of free extensions */
- SrbExtension = DeviceExtension->FreeSrbExtensions;
-
- /* If no free extensions... */
- if (SrbExtension == NULL)
- {
- /* Free SRB data */
- if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
- Srb->QueueTag != SP_UNTAGGED)
- {
- SrbInfo->Requests.Blink = NULL;
- SrbInfo->Requests.Flink =
(PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
- DeviceExtension->FreeSrbInfo = SrbInfo;
- }
-
- /* Return, in order to be called again later */
- DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
- KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
- return NULL;
- }
-
- /* Remove that free SRB extension from the list (since
- we're going to use it) */
- DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
... 2187 lines suppressed ...