From 1b45d9ee4b66768e569a1f3e06f92897c0957f01 Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Sat, 17 Oct 2020 04:06:36 +0300 Subject: [PATCH] [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(-) create mode 100644 drivers/storage/port/scsiport/fdo.c create mode 100644 drivers/storage/port/scsiport/ioctl.c create mode 100644 drivers/storage/port/scsiport/pdo.c create mode 100644 drivers/storage/port/scsiport/registry.c create mode 100644 drivers/storage/port/scsiport/scsi.c 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@reactos.org) + * Aleksey Bragin (aleksey@reactos.org) + */ + +#include "scsiport.h" + +#define NDEBUG +#include + + +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@reactos.org) + * Aleksey Bragin (aleksey@reactos.org) + */ + +#include "scsiport.h" + +#define NDEBUG +#include + + +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@reactos.org) + * Aleksey Bragin (aleksey@reactos.org) + */ + +#include "scsiport.h" + +#define NDEBUG +#include + + +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@reactos.org) + * Aleksey Bragin (aleksey@reactos.org) + */ + +#include "scsiport.h" + +#define NDEBUG +#include + + +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/identifiers-for-ide-devices + * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices + * for a list of types with their human-readable forms. + */ + switch (LunExtension->InquiryData.DeviceType) + { + case 0: + TypeName = L"DiskPeripheral"; + break; + case 1: + TypeName = L"TapePeripheral"; + break; + case 2: + TypeName = L"PrinterPeripheral"; + break; + // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case. + case 4: + TypeName = L"WormPeripheral"; + break; + case 5: + TypeName = L"CdRomPeripheral"; + break; + case 6: + TypeName = L"ScannerPeripheral"; + break; + case 7: + TypeName = L"OpticalDiskPeripheral"; + break; + case 8: + TypeName = L"MediumChangerPeripheral"; + break; + case 9: + TypeName = L"CommunicationsPeripheral"; + break; + + /* New peripheral types (SCSI only) */ + case 10: case 11: + TypeName = L"ASCPrePressGraphicsPeripheral"; + break; + case 12: + TypeName = L"ArrayPeripheral"; + break; + case 13: + TypeName = L"EnclosurePeripheral"; + break; + case 14: + TypeName = L"RBCPeripheral"; + break; + case 15: + TypeName = L"CardReaderPeripheral"; + break; + case 16: + TypeName = L"BridgePeripheral"; + break; + + default: + TypeName = L"OtherPeripheral"; + break; + } + DPRINT(" Type = '%S'\n", TypeName); + RtlInitUnicodeString(&ValueName, L"Type"); + Status = ZwSetValueKey(ScsiLunKey, + &ValueName, + 0, + REG_SZ, + TypeName, + (ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR))); + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status); + goto ByeBye; + } + + ZwClose(ScsiLunKey); + ScsiLunKey = NULL; + } + + /* Close old target key */ + if (ScsiTargetKey != NULL) + { + ZwClose(ScsiTargetKey); + ScsiTargetKey = NULL; + } + } + + ZwClose(ScsiBusKey); + 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@reactos.org) + * Aleksey Bragin (aleksey@reactos.org) + * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) + */ + +#include "scsiport.h" + +#define NDEBUG +#include + + +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@reactos.org) * Aleksey Bragin (aleksey@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); - - /* 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; -} - - -static NTSTATUS -SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject, - IN OUT 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 */ -static 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"); -} - - -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; -} - -static 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]; - } -} - -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, - (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine, - 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 -NTAPI -SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - IN 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); -} - -NTSTATUS -NTAPI -SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject, - PIRP Irp, - 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 BOOLEAN NTAPI -ScsiPortIsr(IN PKINTERRUPT Interrupt, - IN PVOID ServiceContext) -{ - PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - - DPRINT("ScsiPortIsr() called!\n"); - - DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext; - - /* If interrupts are disabled - we don't expect any */ - if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS) - return FALSE; - - /* Call miniport's HwInterrupt routine */ - if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE) - { - /* This interrupt doesn't belong to us */ - return FALSE; - } - - /* If flag of notification is set - queue a DPC */ - if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) - { - IoRequestDpc(DeviceExtension->DeviceObject, - DeviceExtension->CurrentIrp, - DeviceExtension); - } - - return TRUE; -} - -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 -SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - IN 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); - } -} - - - -// ScsiPortDpcForIsr -// DESCRIPTION: -// -// RUN LEVEL: -// -// ARGUMENTS: -// IN PKDPC Dpc -// IN PDEVICE_OBJECT DpcDeviceObject -// IN PIRP DpcIrp -// IN PVOID DpcContext -// -static VOID NTAPI -ScsiPortDpcForIsr(IN PKDPC Dpc, - IN PDEVICE_OBJECT DpcDeviceObject, - IN PIRP DpcIrp, - IN PVOID DpcContext) +BOOLEAN +NTAPI +ScsiPortIsr( + _In_ PKINTERRUPT Interrupt, + _In_ PVOID ServiceContext) { - 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; + PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - /* Remove the request */ - InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests; + DPRINT("ScsiPortIsr() called!\n"); - /* Get spinlock since we're going to change flags */ - KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); + DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext; - /* TODO: Put SrbExtension to the list of free extensions */ - ASSERT(FALSE); - } + /* If interrupts are disabled - we don't expect any */ + if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS) + return FALSE; - /* If we need - call StartIo routine */ - if (NeedToStartIo) + /* Call miniport's HwInterrupt routine */ + if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE) { - /* Make sure CurrentIrp is not null! */ - ASSERT(DpcDeviceObject->CurrentIrp != NULL); - ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp); + /* This interrupt doesn't belong to us */ + return FALSE; } - /* Everything has been done, check */ - if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST) + /* If flag of notification is set - queue a DPC */ + if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) { - /* 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); + IoRequestDpc(DeviceExtension->DeviceObject, + DeviceExtension->CurrentIrp, + DeviceExtension); } - DPRINT("ScsiPortDpcForIsr() done\n"); + return TRUE; } BOOLEAN @@ -5187,444 +2292,6 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); } -/********************************************************************** - * 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 - */ - -static 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/identifiers-for-ide-devices - * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices - * for a list of types with their human-readable forms. - */ - switch (LunExtension->InquiryData.DeviceType) - { - case 0: - TypeName = L"DiskPeripheral"; - break; - case 1: - TypeName = L"TapePeripheral"; - break; - case 2: - TypeName = L"PrinterPeripheral"; - break; - // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case. - case 4: - TypeName = L"WormPeripheral"; - break; - case 5: - TypeName = L"CdRomPeripheral"; - break; - case 6: - TypeName = L"ScannerPeripheral"; - break; - case 7: - TypeName = L"OpticalDiskPeripheral"; - break; - case 8: - TypeName = L"MediumChangerPeripheral"; - break; - case 9: - TypeName = L"CommunicationsPeripheral"; - break; - - /* New peripheral types (SCSI only) */ - case 10: case 11: - TypeName = L"ASCPrePressGraphicsPeripheral"; - break; - case 12: - TypeName = L"ArrayPeripheral"; - break; - case 13: - TypeName = L"EnclosurePeripheral"; - break; - case 14: - TypeName = L"RBCPeripheral"; - break; - case 15: - TypeName = L"CardReaderPeripheral"; - break; - case 16: - TypeName = L"BridgePeripheral"; - break; - - default: - TypeName = L"OtherPeripheral"; - break; - } - DPRINT(" Type = '%S'\n", TypeName); - RtlInitUnicodeString(&ValueName, L"Type"); - Status = ZwSetValueKey(ScsiLunKey, - &ValueName, - 0, - REG_SZ, - TypeName, - (ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR))); - if (!NT_SUCCESS(Status)) - { - DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status); - goto ByeBye; - } - - ZwClose(ScsiLunKey); - ScsiLunKey = NULL; - } - - /* Close old target key */ - if (ScsiTargetKey != NULL) - { - ZwClose(ScsiTargetKey); - ScsiTargetKey = NULL; - } - } - - ZwClose(ScsiBusKey); - 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; -} - VOID NTAPI SpiMiniportTimerDpc(IN struct _KDPC *Dpc, @@ -6335,40 +3002,6 @@ ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject, return KeepObject; } -static -NTSTATUS -SpiStatusSrbToNt(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; -} - - #undef ScsiPortConvertPhysicalAddressToUlong /* * @implemented diff --git a/drivers/storage/port/scsiport/scsiport.h b/drivers/storage/port/scsiport/scsiport.h index b0076e543a9..73c9a91599b 100644 --- a/drivers/storage/port/scsiport/scsiport.h +++ b/drivers/storage/port/scsiport/scsiport.h @@ -17,13 +17,6 @@ #define VERSION "0.0.3" -#ifndef PAGE_ROUND_UP -#define PAGE_ROUND_UP(x) ( (((ULONG_PTR)x)%PAGE_SIZE) ? ((((ULONG_PTR)x)&(~(PAGE_SIZE-1)))+PAGE_SIZE) : ((ULONG_PTR)x) ) -#endif -#ifndef ROUND_UP -#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) -#endif - #define TAG_SCSIPORT 'ISCS' /* Defines how many logical unit arrays will be in a device extension */ @@ -309,3 +302,92 @@ typedef struct _RESETBUS_PARAMS ULONG PathId; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; } RESETBUS_PARAMS, *PRESETBUS_PARAMS; + + +// ioctl.c + +NTSTATUS +NTAPI +ScsiPortDeviceControl( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp); + +// fdo.c + +VOID +SpiScanAdapter( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); + +NTSTATUS +CallHWInitialize( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); + +VOID +SpiCleanupAfterInit( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); + +// pdo.c + +PSCSI_PORT_LUN_EXTENSION +SpiAllocateLunExtension( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); + +PSCSI_PORT_LUN_EXTENSION +SpiGetLunExtension( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + _In_ UCHAR PathId, + _In_ UCHAR TargetId, + _In_ UCHAR Lun); + +PSCSI_REQUEST_BLOCK_INFO +SpiGetSrbData( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + _In_ UCHAR PathId, + _In_ UCHAR TargetId, + _In_ UCHAR Lun, + _In_ UCHAR QueueTag); + +// registry.c + +VOID +SpiInitOpenKeys( + _Inout_ PCONFIGURATION_INFO ConfigInfo, + _In_ PUNICODE_STRING RegistryPath); + +NTSTATUS +SpiBuildDeviceMap( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + _In_ PUNICODE_STRING RegistryPath); + +// scsi.c + +VOID +SpiGetNextRequestFromLun( + _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension); + +IO_DPC_ROUTINE ScsiPortDpcForIsr; +DRIVER_DISPATCH ScsiPortDispatchScsi; +KSYNCHRONIZE_ROUTINE ScsiPortStartPacket; +DRIVER_STARTIO ScsiPortStartIo; + + +// scsiport.c + +KSERVICE_ROUTINE ScsiPortIsr; + +IO_ALLOCATION_ACTION +NTAPI +SpiAdapterControl( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PVOID MapRegisterBase, + _In_ PVOID Context); + +IO_ALLOCATION_ACTION +NTAPI +ScsiPortAllocateAdapterChannel( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PVOID MapRegisterBase, + _In_ PVOID Context); -- 2.17.1