From bfde26a3f6da24b5cefd0f1557891f793642dc3b Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Wed, 7 Apr 2004 09:21:01 +0000 Subject: [PATCH] - Rewrote the code which handles processing of irp's and notifications from miniport driver. - Implemented support for srb extensions (very simple). svn path=/trunk/; revision=8999 --- reactos/drivers/storage/scsiport/scsiport.c | 718 +++++++++++------- .../drivers/storage/scsiport/scsiport_int.h | 21 +- 2 files changed, 460 insertions(+), 279 deletions(-) diff --git a/reactos/drivers/storage/scsiport/scsiport.c b/reactos/drivers/storage/scsiport/scsiport.c index 5f748eabd7a..af6653d5def 100644 --- a/reactos/drivers/storage/scsiport/scsiport.c +++ b/reactos/drivers/storage/scsiport/scsiport.c @@ -16,13 +16,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: scsiport.c,v 1.52 2004/04/02 15:43:01 hbirr Exp $ +/* $Id: scsiport.c,v 1.53 2004/04/07 09:21:01 hbirr Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: services/storage/scsiport/scsiport.c * PURPOSE: SCSI port driver * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + * Hartmut Birr */ /* INCLUDES *****************************************************************/ @@ -41,17 +42,24 @@ #include "scsiport_int.h" -/* #define USE_DEVICE_QUEUES */ - /* TYPES *********************************************************************/ #define IRP_FLAG_COMPLETE 0x00000001 #define IRP_FLAG_NEXT 0x00000002 #define IRP_FLAG_NEXT_LU 0x00000004 +#define MAX_SRB_EXTENSIONS 32 /* GLOBALS *******************************************************************/ +static VOID +SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + PIRP NextIrp); + +static VOID +SpiStartIo(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + PIRP Irp); + static BOOLEAN SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData, IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, @@ -70,10 +78,6 @@ static NTSTATUS STDCALL ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); -static VOID STDCALL -ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp); - static BOOLEAN STDCALL ScsiPortStartPacket(IN OUT PVOID Context); @@ -119,16 +123,20 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, PVOID Context); static PSCSI_REQUEST_BLOCK -ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - PSCSI_REQUEST_BLOCK OriginalSrb); - -static VOID -ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); +ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb); static NTSTATUS SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, PUNICODE_STRING RegistryPath); +static VOID +SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + PSCSI_REQUEST_BLOCK Srb); + +static VOID +SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + PSCSI_REQUEST_BLOCK Srb); + /* FUNCTIONS *****************************************************************/ @@ -568,12 +576,13 @@ ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension, /* Allocate a common DMA buffer */ DeviceExtension->CommonBufferLength = - NumberOfBytes + DeviceExtension->SrbExtensionSize; + NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * MAX_SRB_EXTENSIONS); DeviceExtension->VirtualAddress = HalAllocateCommonBuffer(DeviceExtension->AdapterObject, DeviceExtension->CommonBufferLength, &DeviceExtension->PhysicalAddress, FALSE); + DeviceExtension->VirtualAddressMap = 0; if (DeviceExtension->VirtualAddress == NULL) { DPRINT1("HalAllocateCommonBuffer() failed!\n"); @@ -582,7 +591,7 @@ ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension, } return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + - DeviceExtension->SrbExtensionSize); + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * MAX_SRB_EXTENSIONS)); } @@ -685,7 +694,7 @@ ScsiPortInitialize(IN PVOID Argument1, (HwInitializationData->HwResetBus == NULL)) return(STATUS_INVALID_PARAMETER); - DriverObject->DriverStartIo = ScsiPortStartIo; + DriverObject->DriverStartIo = NULL; DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl; @@ -738,6 +747,7 @@ ScsiPortInitialize(IN PVOID Argument1, PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; DeviceExtension = PortDeviceObject->DeviceExtension; + RtlZeroMemory(DeviceExtension, DeviceExtensionSize); DeviceExtension->Length = DeviceExtensionSize; DeviceExtension->DeviceObject = PortDeviceObject; DeviceExtension->PortNumber = SystemConfig->ScsiPortCount; @@ -759,6 +769,12 @@ ScsiPortInitialize(IN PVOID Argument1, /* Initialize the device base list */ InitializeListHead (&DeviceExtension->DeviceBaseListHead); + /* Initialize the irp lists */ + InitializeListHead (&DeviceExtension->PendingIrpListHead); + InitializeListHead (&DeviceExtension->ActiveIrpListHead); + DeviceExtension->PendingIrpCount = 0; + DeviceExtension->ActiveIrpCount = 0; + /* Initialize LUN-Extension list */ InitializeListHead (&DeviceExtension->LunExtensionListHead); @@ -826,6 +842,9 @@ ScsiPortInitialize(IN PVOID Argument1, PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS; // PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS; + PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize; + PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize; + PortConfig->SlotNumber = SlotNumber.u.AsULONG; PortConfig->AccessRanges = (PACCESS_RANGE)(PortConfig + 1); @@ -870,13 +889,35 @@ ScsiPortInitialize(IN PVOID Argument1, { DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector); + + if (DeviceExtension->VirtualAddress == NULL && DeviceExtension->SrbExtensionSize) + { + ScsiPortGetUncachedExtension(&DeviceExtension->MiniPortDeviceExtension, + PortConfig, + 0); + } + /* Register an interrupt handler for this device */ MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber, PortConfig->BusInterruptLevel, +#if 1 +/* + * FIXME: + * Something is wrong in our interrupt conecting code. + * The promise Ultra100TX driver returns 0 for BusInterruptVector + * and a nonzero value for BusInterruptLevel. The driver does only + * work with this fix. + */ + PortConfig->BusInterruptLevel, +#else PortConfig->BusInterruptVector, +#endif &Dirql, &Affinity); + DPRINT("AdapterInterfaceType %x, SystemIoBusNumber %x, BusInterruptLevel %x, BusInterruptVector %x\n", + PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber, + PortConfig->BusInterruptLevel, PortConfig->BusInterruptVector); Status = IoConnectInterrupt(&DeviceExtension->Interrupt, ScsiPortIsr, DeviceExtension, @@ -1089,12 +1130,15 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, DPRINT("Notify: RequestComplete (Srb %p)\n", Srb); DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE; + Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE; + InterlockedIncrement((PLONG)&DeviceExtension->CompleteRequestCount); } break; case NextRequest: DPRINT("Notify: NextRequest\n"); DeviceExtension->IrpFlags |= IRP_FLAG_NEXT; + InterlockedIncrement((PLONG)&DeviceExtension->NextRequestCount); break; case NextLuRequest: @@ -1102,20 +1146,25 @@ ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, UCHAR PathId; UCHAR TargetId; UCHAR Lun; + PSCSI_PORT_LUN_EXTENSION LunExtension; PathId = (UCHAR) va_arg (ap, int); TargetId = (UCHAR) va_arg (ap, int); Lun = (UCHAR) va_arg (ap, int); - DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n", + DPRINT ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n", PathId, TargetId, Lun); - /* FIXME: Implement it! */ - DeviceExtension->IrpFlags |= IRP_FLAG_NEXT; -// DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU; - - /* Hack! */ - DeviceExtension->IrpFlags |= IRP_FLAG_NEXT; + LunExtension = SpiGetLunExtension(DeviceExtension, + PathId, + TargetId, + Lun); + if (LunExtension) + { + DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU; + InterlockedIncrement((PLONG)&LunExtension->NextLuRequestCount); + InterlockedIncrement((PLONG)&DeviceExtension->NextLuRequestCount); + } } break; @@ -1425,34 +1474,10 @@ ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject, { case SRB_FUNCTION_EXECUTE_SCSI: case SRB_FUNCTION_IO_CONTROL: -#ifdef USE_DEVICE_QUEUES - if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) - { - IoMarkIrpPending(Irp); - IoStartPacket (DeviceObject, Irp, NULL, NULL); - } - else - { - KIRQL oldIrql; - - KeRaiseIrql (DISPATCH_LEVEL, - &oldIrql); - - if (!KeInsertByKeyDeviceQueue (&LunExtension->DeviceQueue, - &Irp->Tail.Overlay.DeviceQueueEntry, - Srb->QueueSortKey)) - { - Srb->SrbStatus = SRB_STATUS_SUCCESS; - IoMarkIrpPending(Irp); - IoStartPacket (DeviceObject, Irp, NULL, NULL); - } - - KeLowerIrql (oldIrql); - } -#else IoMarkIrpPending(Irp); - IoStartPacket (DeviceObject, Irp, NULL, NULL); -#endif + Srb->OriginalRequest = LunExtension; + Irp->Tail.Overlay.DriverContext[3] = Srb; + SpiProcessRequests(DeviceExtension, Irp); return(STATUS_PENDING); case SRB_FUNCTION_SHUTDOWN: @@ -1460,7 +1485,9 @@ ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject, if (DeviceExtension->PortConfig->CachesData == TRUE) { IoMarkIrpPending(Irp); - IoStartPacket(DeviceObject, Irp, NULL, NULL); + Srb->OriginalRequest = LunExtension; + Irp->Tail.Overlay.DriverContext[3] = Srb; + SpiProcessRequests(DeviceExtension, Irp); return(STATUS_PENDING); } break; @@ -1581,130 +1608,49 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject, return(STATUS_SUCCESS); } - -static VOID STDCALL -ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) +static VOID +SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + PSCSI_REQUEST_BLOCK Srb) { - PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - PSCSI_PORT_LUN_EXTENSION LunExtension; - PIO_STACK_LOCATION IrpStack; - PSCSI_REQUEST_BLOCK Srb; - KIRQL oldIrql; + ULONG i; + ULONG mask; - DPRINT("ScsiPortStartIo() called!\n"); + DPRINT("SpiAllocateSrbExtension\n"); - DeviceExtension = DeviceObject->DeviceExtension; - IrpStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n", + DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize); - DPRINT("DeviceExtension %p\n", DeviceExtension); - - oldIrql = KeGetCurrentIrql(); - - if (IrpStack->MajorFunction != IRP_MJ_SCSI) + if (DeviceExtension->VirtualAddress != NULL && + DeviceExtension->SrbExtensionSize > 0) { - DPRINT("No IRP_MJ_SCSI!\n"); - Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, - IO_NO_INCREMENT); - if (oldIrql < DISPATCH_LEVEL) - { - KeRaiseIrql (DISPATCH_LEVEL, - &oldIrql); - IoStartNextPacket (DeviceObject, - FALSE); - KeLowerIrql (oldIrql); - } - else - { - IoStartNextPacket (DeviceObject, - FALSE); - } - return; - } - - Srb = IrpStack->Parameters.Scsi.Srb; - - LunExtension = SpiGetLunExtension(DeviceExtension, - Srb->PathId, - Srb->TargetId, - Srb->Lun); - if (LunExtension == NULL) - { - DPRINT("Can't get LunExtension!\n"); - Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; - Irp->IoStatus.Information = 0; - IoCompleteRequest (Irp, - IO_NO_INCREMENT); - if (oldIrql < DISPATCH_LEVEL) - { - KeRaiseIrql (DISPATCH_LEVEL, - &oldIrql); - IoStartNextPacket (DeviceObject, - FALSE); - KeLowerIrql (oldIrql); - } - else - { - IoStartNextPacket (DeviceObject, - FALSE); - } - return; - } - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = Srb->DataTransferLength; - - DeviceExtension->CurrentIrp = Irp; - - if (!KeSynchronizeExecution(DeviceExtension->Interrupt, - ScsiPortStartPacket, - DeviceExtension)) - { - DPRINT("Synchronization failed!\n"); - - Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, - IO_NO_INCREMENT); - if (oldIrql < DISPATCH_LEVEL) - { - KeRaiseIrql (DISPATCH_LEVEL, - &oldIrql); - IoStartNextPacket (DeviceObject, - FALSE); - KeLowerIrql (oldIrql); - } - else - { - IoStartNextPacket (DeviceObject, - FALSE); + for (i = 0, mask = 1; i < MAX_SRB_EXTENSIONS; i++, mask <<= 1) + { + if (!(DeviceExtension->VirtualAddressMap & mask)) + { + DeviceExtension->VirtualAddressMap |= mask; + Srb->SrbExtension = DeviceExtension->VirtualAddress + i * DeviceExtension->SrbExtensionSize; + DPRINT("%x\n", Srb->SrbExtension); + return; + } } } + Srb->SrbExtension = NULL; +} - KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql); - if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE) - { - DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE; - IoCompleteRequest(Irp, - IO_NO_INCREMENT); - } +static VOID +SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + PSCSI_REQUEST_BLOCK Srb) +{ + ULONG i; - if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT) + if (DeviceExtension->VirtualAddress != NULL && + DeviceExtension->SrbExtensionSize > 0 && + Srb->SrbExtension != NULL) { - DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT; - KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); - IoStartNextPacket(DeviceObject, - FALSE); - KeLowerIrql(oldIrql); + i = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize; + DeviceExtension->VirtualAddressMap &= ~(1 << i); } - else - { - KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql); - } - - DPRINT("ScsiPortStartIo() done\n"); + Srb->SrbExtension = NULL; } @@ -1712,21 +1658,16 @@ static BOOLEAN STDCALL ScsiPortStartPacket(IN OUT PVOID Context) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - PIO_STACK_LOCATION IrpStack; PSCSI_REQUEST_BLOCK Srb; + PIRP Irp; + PIO_STACK_LOCATION IrpStack; DPRINT("ScsiPortStartPacket() called\n"); - - DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context; - - IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp); - Srb = IrpStack->Parameters.Scsi.Srb; - - /* Allocte SRB extension */ - if (DeviceExtension->SrbExtensionSize != 0) - { - Srb->SrbExtension = DeviceExtension->VirtualAddress; - } + + Srb = (PSCSI_REQUEST_BLOCK)Context; + Irp = (PIRP)Srb->OriginalRequest; + IrpStack = IoGetCurrentIrpStackLocation(Irp); + DeviceExtension = IrpStack->DeviceObject->DeviceExtension; return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension, Srb)); @@ -1766,7 +1707,8 @@ SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, LunExtension->TargetId = TargetId; LunExtension->Lun = Lun; - KeInitializeDeviceQueue (&LunExtension->DeviceQueue); + LunExtension->PendingIrpCount = 0; + LunExtension->ActiveIrpCount = 0; return LunExtension; } @@ -2064,7 +2006,7 @@ ScsiPortIsr(IN PKINTERRUPT Interrupt, if (DeviceExtension->IrpFlags) { IoRequestDpc(DeviceExtension->DeviceObject, - DeviceExtension->CurrentIrp, + NULL, DeviceExtension); } @@ -2090,96 +2032,13 @@ ScsiPortDpcForIsr(IN PKDPC Dpc, IN PVOID DpcContext) { PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; - PIO_STACK_LOCATION IrpStack; - PSCSI_REQUEST_BLOCK Srb; DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n", Dpc, DpcDeviceObject, DpcIrp, DpcContext); DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext; - KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock); - if (DeviceExtension->IrpFlags) - { - IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp); - Srb = IrpStack->Parameters.Scsi.Srb; - - if (DeviceExtension->OriginalSrb != NULL) - { - DPRINT("Got sense data!\n"); - - DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid); - DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode); - DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey); - DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode); - - /* Copy sense data */ - if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0) - { - RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer, - &DeviceExtension->InternalSenseData, - sizeof(SENSE_DATA)); - DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; - } - - /* Clear current sense data */ - RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA)); - - IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb; - ScsiPortFreeSenseRequestSrb (DeviceExtension); - } - else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) && - (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION)) - { - DPRINT("SCSIOP_REQUEST_SENSE required!\n"); - - DeviceExtension->OriginalSrb = Srb; - IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension, - Srb); - KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); - if (!KeSynchronizeExecution(DeviceExtension->Interrupt, - ScsiPortStartPacket, - DeviceExtension)) - { - DPRINT1("Synchronization failed!\n"); - - DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; - DpcIrp->IoStatus.Information = 0; - IoCompleteRequest(DpcIrp, - IO_NO_INCREMENT); - IoStartNextPacket(DpcDeviceObject, - FALSE); - } - - return; - } - - DeviceExtension->CurrentIrp = NULL; - -// DpcIrp->IoStatus.Information = 0; -// DpcIrp->IoStatus.Status = STATUS_SUCCESS; - - if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE) - { - DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE; - IoCompleteRequest(DpcIrp, IO_NO_INCREMENT); - } - - if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT) - { - DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT; - KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); - IoStartNextPacket(DpcDeviceObject, FALSE); - } - else - { - KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); - } - } - else - { - KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); - } + SpiProcessRequests(DeviceExtension, NULL); DPRINT("ScsiPortDpcForIsr() done\n"); } @@ -2205,27 +2064,29 @@ ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, static PSCSI_REQUEST_BLOCK -ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, - PSCSI_REQUEST_BLOCK OriginalSrb) +ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb) { PSCSI_REQUEST_BLOCK Srb; PCDB Cdb; - Srb = &DeviceExtension->InternalSrb; + Srb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA), + TAG('S', 'S', 'r', 'b')); RtlZeroMemory(Srb, - sizeof(SCSI_REQUEST_BLOCK)); + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA)); Srb->PathId = OriginalSrb->PathId; Srb->TargetId = OriginalSrb->TargetId; Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; Srb->Length = sizeof(SCSI_REQUEST_BLOCK); Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + Srb->OriginalRequest = OriginalSrb->OriginalRequest; Srb->TimeOutValue = 4; Srb->CdbLength = 6; - Srb->DataBuffer = &DeviceExtension->InternalSenseData; + Srb->DataBuffer = Srb + 1; Srb->DataTransferLength = sizeof(SENSE_DATA); Cdb = (PCDB)Srb->Cdb; @@ -2235,14 +2096,6 @@ ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, return(Srb); } - -static VOID -ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) -{ - DeviceExtension->OriginalSrb = NULL; -} - - /********************************************************************** * NAME INTERNAL * SpiBuildDeviceMap @@ -2666,4 +2519,321 @@ ByeBye: return Status; } +static VOID +SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + IN PIRP NextIrp) +{ + /* + * Using of some fields from Srb and Irp while processing requests: + * + * NextIrp on entry: + * Srb->OriginalRequest -> LunExtension + * Irp->Tail.Overlay.DriverContext[3] -> original Srb + * IoStack->Parameters.Scsi.Srb -> original Srb + * + * Irp is within the pending irp list: + * Srb->OriginalRequest -> LunExtension + * Irp->Tail.Overlay.DriverContext[0] and DriverContext[1] -> ListEntry for queue + * Irp->Tail.Overlay.DriverContext[2] -> sort key (from Srb->QueueSortKey) + * Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request) + * IoStack->Parameters.Scsi.Srb -> original Srb + * + * Irp is within the active irp list or while other processing: + * Srb->OriginalRequest -> Irp + * Irp->Tail.Overlay.DriverContext[0] and DriverContext[1] -> ListEntry for queue + * Irp->Tail.Overlay.DriverContext[2] -> LunExtension + * Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request) + * IoStack->Parameters.Scsi.Srb -> original Srb + */ + PIO_STACK_LOCATION IrpStack; + PSCSI_PORT_LUN_EXTENSION LunExtension; + PLIST_ENTRY ListEntry; + KIRQL oldIrql; + PIRP Irp; + LIST_ENTRY NextIrpListHead; + LIST_ENTRY CompleteIrpListHead; + PSCSI_REQUEST_BLOCK Srb; + PSCSI_REQUEST_BLOCK OriginalSrb; + + DPRINT("SpiProcessRequests() called\n"); + + InitializeListHead(&NextIrpListHead); + InitializeListHead(&CompleteIrpListHead); + + KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql); + + if (NextIrp) + { + Srb = NextIrp->Tail.Overlay.DriverContext[3]; + NextIrp->Tail.Overlay.DriverContext[2] = (PVOID)Srb->QueueSortKey; + + ListEntry = DeviceExtension->PendingIrpListHead.Flink; + while (ListEntry != DeviceExtension->PendingIrpListHead.Flink) + { + Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]); + if ((ULONG)Irp->Tail.Overlay.DriverContext[2] > Srb->QueueSortKey) + { + break; + } + ListEntry = ListEntry->Flink; + } + InsertTailList(ListEntry, (PLIST_ENTRY)&NextIrp->Tail.Overlay.DriverContext[0]); + } + + while (DeviceExtension->CompleteRequestCount || + ((DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->ActiveIrpCount < MAX_SRB_EXTENSIONS) && !IsListEmpty(&DeviceExtension->PendingIrpListHead) && + (DeviceExtension->NextRequestCount || DeviceExtension->NextLuRequestCount || IsListEmpty(&DeviceExtension->ActiveIrpListHead)))) + { + DPRINT("CompleteRequestCount %d, NextRequestCount %d, NextLuRequestCount %d, PendingIrpList is %s, ActiveIrpList is %s\n", + DeviceExtension->CompleteRequestCount, + DeviceExtension->NextRequestCount, + DeviceExtension->NextLuRequestCount, + IsListEmpty(&DeviceExtension->PendingIrpListHead) ? "EMPTY" : "NOT empty", + IsListEmpty(&DeviceExtension->ActiveIrpListHead) ? "EMPTY" : "NOT empty"); + + if (DeviceExtension->CompleteRequestCount > 0) + { + DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE; + ListEntry = DeviceExtension->ActiveIrpListHead.Flink; + while (ListEntry != &DeviceExtension->ActiveIrpListHead) + { + Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]); + ListEntry = ListEntry->Flink; + Srb = Irp->Tail.Overlay.DriverContext[3]; + if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) + { + BOOLEAN CompleteThisRequest; + InterlockedDecrement((PLONG)&DeviceExtension->CompleteRequestCount); + LunExtension = Irp->Tail.Overlay.DriverContext[2]; + IrpStack = IoGetCurrentIrpStackLocation(Irp); + OriginalSrb = IrpStack->Parameters.Scsi.Srb; + + if (OriginalSrb != Srb) + { + SENSE_DATA* SenseInfoBuffer; + + SenseInfoBuffer = Srb->DataBuffer; + + DPRINT("Got sense data!\n"); + + DPRINT("Valid: %x\n", SenseInfoBuffer->Valid); + DPRINT("ErrorCode: %x\n", SenseInfoBuffer->ErrorCode); + DPRINT("SenseKey: %x\n", SenseInfoBuffer->SenseKey); + DPRINT("SenseCode: %x\n", SenseInfoBuffer->AdditionalSenseCode); + + /* Copy sense data */ + if (OriginalSrb->SenseInfoBufferLength != 0) + { + RtlCopyMemory(OriginalSrb->SenseInfoBuffer, + SenseInfoBuffer, + sizeof(SENSE_DATA)); + OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + ExFreePool(Srb); + CompleteThisRequest = TRUE; + } + else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) && + (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION)) + { + DPRINT("SCSIOP_REQUEST_SENSE required!\n"); + + Srb = ScsiPortInitSenseRequestSrb(OriginalSrb); + + if (Srb) + { + CompleteThisRequest = FALSE; + Irp->Tail.Overlay.DriverContext[3] = Srb; + RemoveEntryList((PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + SpiFreeSrbExtension(DeviceExtension, Srb); + LunExtension->ActiveIrpCount--; + DeviceExtension->ActiveIrpCount--; + + Srb->OriginalRequest = LunExtension; + Irp->Tail.Overlay.DriverContext[2] = 0; + + InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + DeviceExtension->PendingIrpCount++; + LunExtension->PendingIrpCount++; + } + else + { + CompleteThisRequest = TRUE; + } + } + else + { + DPRINT("Complete Request\n"); + CompleteThisRequest = TRUE; + } + if (CompleteThisRequest) + { + RemoveEntryList((PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + InsertHeadList(&CompleteIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + SpiFreeSrbExtension(DeviceExtension, OriginalSrb); + LunExtension->ActiveIrpCount--; + DeviceExtension->ActiveIrpCount--; + } + } + } + } + if (DeviceExtension->NextLuRequestCount || + DeviceExtension->NextRequestCount) + { + BOOLEAN StartThisRequest; + DeviceExtension->IrpFlags &= ~(IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU); + ListEntry = DeviceExtension->PendingIrpListHead.Flink; + while (ListEntry != &DeviceExtension->PendingIrpListHead) + { + Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]); + ListEntry = ListEntry->Flink; + Srb = Irp->Tail.Overlay.DriverContext[3]; + LunExtension = Srb->OriginalRequest; + if (DeviceExtension->SrbExtensionSize > 0 && + DeviceExtension->ActiveIrpCount >= MAX_SRB_EXTENSIONS) + { + break; + } + if (LunExtension->NextLuRequestCount > 0) + { + StartThisRequest = TRUE; + InterlockedDecrement((PLONG)&LunExtension->NextLuRequestCount); + InterlockedDecrement((PLONG)&DeviceExtension->NextLuRequestCount); + } + else if (DeviceExtension->NextRequestCount > 0 && + LunExtension->ActiveIrpCount == 0) + { + InterlockedDecrement((PLONG)&DeviceExtension->NextRequestCount); + StartThisRequest = TRUE; + } + else + { + StartThisRequest = FALSE; + } + if (StartThisRequest) + { + LunExtension->PendingIrpCount--; + DeviceExtension->PendingIrpCount--; + RemoveEntryList((PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + LunExtension->ActiveIrpCount++; + DeviceExtension->ActiveIrpCount++; + SpiAllocateSrbExtension(DeviceExtension, Srb); + + Irp->Tail.Overlay.DriverContext[2] = LunExtension; + Srb->OriginalRequest = Irp; + + InsertHeadList(&NextIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + } + } + } + + if (!IsListEmpty(&NextIrpListHead)) + { + while (!IsListEmpty(&NextIrpListHead)) + { + ListEntry = RemoveTailList(&NextIrpListHead); + Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]); + InsertHeadList(&DeviceExtension->ActiveIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); + + // Start this Irp + SpiStartIo(DeviceExtension, Irp); + KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock); + } + } + + if (!IsListEmpty(&DeviceExtension->PendingIrpListHead) && + IsListEmpty(&DeviceExtension->ActiveIrpListHead) && + (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->ActiveIrpCount < MAX_SRB_EXTENSIONS)) + { + ListEntry = RemoveHeadList(&DeviceExtension->PendingIrpListHead); + Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]); + Srb = Irp->Tail.Overlay.DriverContext[3]; + LunExtension = Srb->OriginalRequest; + + LunExtension->PendingIrpCount--; + DeviceExtension->PendingIrpCount--; + InsertHeadList(&DeviceExtension->ActiveIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]); + LunExtension->ActiveIrpCount++; + DeviceExtension->ActiveIrpCount++; + SpiAllocateSrbExtension(DeviceExtension, Srb); + + Irp->Tail.Overlay.DriverContext[2] = LunExtension; + Srb->OriginalRequest = Irp; + + KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); + + // Start this irp + SpiStartIo(DeviceExtension, Irp); + KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock); + } + + if (!IsListEmpty(&CompleteIrpListHead)) + { + KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); + while (!IsListEmpty(&CompleteIrpListHead)) + { + ListEntry = RemoveTailList(&CompleteIrpListHead); + Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock); + } + } + KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql); + + DPRINT("SpiProcessRequests() done\n"); + } + +static VOID +SpiStartIo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, + IN PIRP Irp) +{ + PSCSI_PORT_LUN_EXTENSION LunExtension; + PSCSI_REQUEST_BLOCK Srb; + PIO_STACK_LOCATION IrpStack; + + DPRINT("SpiStartIo() called!\n"); + + assert(KeGetCurrentIrql() == DISPATCH_LEVEL); + + Srb = Irp->Tail.Overlay.DriverContext[3]; + LunExtension = Irp->Tail.Overlay.DriverContext[2]; + + Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = Srb->DataTransferLength; + + if (!KeSynchronizeExecution(DeviceExtension->Interrupt, + ScsiPortStartPacket, + Srb)) + { + DPRINT1("Synchronization failed!\n"); + + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + Irp->IoStatus.Information = 0; + + KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock); + + RemoveEntryList((PLIST_ENTRY)Irp->Tail.Overlay.DriverContext[0]); + LunExtension = Irp->Tail.Overlay.DriverContext[2]; + LunExtension->ActiveIrpCount--; + SpiFreeSrbExtension(DeviceExtension, Srb); + IrpStack = IoGetCurrentIrpStackLocation(Irp); + if (IrpStack->Parameters.Scsi.Srb != Srb) + { + ExFreePool(Srb); + } + DeviceExtension->ActiveIrpCount--; + + KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + } + + DPRINT("SpiStartIo() done\n"); +} + + + /* EOF */ diff --git a/reactos/drivers/storage/scsiport/scsiport_int.h b/reactos/drivers/storage/scsiport/scsiport_int.h index 1f0012c8918..a81275d5470 100644 --- a/reactos/drivers/storage/scsiport/scsiport_int.h +++ b/reactos/drivers/storage/scsiport/scsiport_int.h @@ -37,7 +37,9 @@ typedef struct _SCSI_PORT_LUN_EXTENSION INQUIRYDATA InquiryData; - KDEVICE_QUEUE DeviceQueue; + ULONG PendingIrpCount; + ULONG ActiveIrpCount; + ULONG NextLuRequestCount; /* More data? */ @@ -63,7 +65,6 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION KSPIN_LOCK IrpLock; KSPIN_LOCK SpinLock; PKINTERRUPT Interrupt; - PIRP CurrentIrp; ULONG IrpFlags; SCSI_PORT_TIMER_STATES TimerState; @@ -84,9 +85,6 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION PHW_STARTIO HwStartIo; PHW_INTERRUPT HwInterrupt; - PSCSI_REQUEST_BLOCK OriginalSrb; - SCSI_REQUEST_BLOCK InternalSrb; - SENSE_DATA InternalSenseData; /* DMA related stuff */ PADAPTER_OBJECT AdapterObject; @@ -94,7 +92,20 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION PHYSICAL_ADDRESS PhysicalAddress; PVOID VirtualAddress; + ULONG VirtualAddressMap; ULONG CommonBufferLength; + LIST_ENTRY PendingIrpListHead; + LIST_ENTRY ActiveIrpListHead; + ULONG PendingIrpCount; + ULONG ActiveIrpCount; + + ULONG CompleteRequestCount; + ULONG NextRequestCount; + ULONG NextLuRequestCount; + UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */ } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION; + + +