- Rearrange code inside ScsiPortStartIo() routine (some code for dma-support added, but currently disabled), also change time when spinlock is being held.

- Respective changes in ScsiPortStartPacket(), also some code is missing for rare kind of requests.
- Add flags check into ScsiPortIsr(), so that we skip unwanted interrupts (and change to usage of the new interrupt flags structure instead of a strange and unclear "IrpFlags" field).

svn path=/trunk/; revision=26196
This commit is contained in:
Aleksey Bragin 2007-03-28 18:29:15 +00:00
parent d7f6674119
commit d8175ef0a6
2 changed files with 262 additions and 129 deletions

View file

@ -885,6 +885,9 @@ ScsiPortInitialize(IN PVOID Argument1,
goto ByeBye; goto ByeBye;
} }
/* Initialize counter of active requests (-1 means there are none) */
DeviceExtension->ActiveRequestCounter = -1;
if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension)) if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension))
{ {
DbgPrint("HwInitialize() failed!"); DbgPrint("HwInitialize() failed!");
@ -1642,152 +1645,253 @@ static VOID STDCALL
ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject, ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp) IN PIRP Irp)
{ {
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PSCSI_PORT_LUN_EXTENSION LunExtension; PSCSI_PORT_LUN_EXTENSION LunExtension;
PIO_STACK_LOCATION IrpStack; PIO_STACK_LOCATION IrpStack;
PSCSI_REQUEST_BLOCK Srb; PSCSI_REQUEST_BLOCK Srb;
KIRQL oldIrql; PSCSI_REQUEST_BLOCK_INFO SrbInfo;
LONG CounterResult;
DPRINT("ScsiPortStartIo() called!\n"); DPRINT("ScsiPortStartIo() called!\n");
DeviceExtension = DeviceObject->DeviceExtension; DeviceExtension = DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(Irp); IrpStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT("DeviceExtension %p\n", DeviceExtension); DPRINT("DeviceExtension %p\n", DeviceExtension);
oldIrql = KeGetCurrentIrql(); Srb = IrpStack->Parameters.Scsi.Srb;
if (IrpStack->MajorFunction != IRP_MJ_SCSI) /* FIXME: Apply standard flags to Srb->SrbFlags ? */
/* Get LUN extension */
LunExtension = SpiGetLunExtension(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun);
if (DeviceExtension->NeedSrbDataAlloc ||
DeviceExtension->NeedSrbExtensionAlloc)
{ {
DPRINT("No IRP_MJ_SCSI!\n"); /* TODO: Implement */
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; ASSERT(FALSE);
Irp->IoStatus.Information = 0; SrbInfo = NULL;
IoCompleteRequest (Irp, }
IO_NO_INCREMENT); else
if (oldIrql < DISPATCH_LEVEL) {
{ /* No allocations are needed */
KeRaiseIrql (DISPATCH_LEVEL, SrbInfo = &LunExtension->SrbInfo;
&oldIrql); Srb->SrbExtension = NULL;
IoStartNextPacket (DeviceObject, Srb->QueueTag = SP_UNTAGGED;
FALSE);
KeLowerIrql (oldIrql);
}
else
{
IoStartNextPacket (DeviceObject,
FALSE);
}
return;
} }
Srb = IrpStack->Parameters.Scsi.Srb; /* FIXME: Increase sequence number here of SRB, if it's ever needed */
LunExtension = SpiGetLunExtension(DeviceExtension, /* Check some special SRBs */
Srb->PathId, if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
Srb->TargetId,
Srb->Lun);
if (LunExtension == NULL)
{ {
DPRINT("Can't get LunExtension!\n"); /* Some special handling */
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; DPRINT1("Abort command! Unimplemented now\n");
Irp->IoStatus.Information = 0; }
IoCompleteRequest (Irp, else
IO_NO_INCREMENT); {
if (oldIrql < DISPATCH_LEVEL) SrbInfo->Srb = Srb;
{
KeRaiseIrql (DISPATCH_LEVEL,
&oldIrql);
IoStartNextPacket (DeviceObject,
FALSE);
KeLowerIrql (oldIrql);
}
else
{
IoStartNextPacket (DeviceObject,
FALSE);
}
return;
} }
Irp->IoStatus.Status = STATUS_SUCCESS; if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
Irp->IoStatus.Information = Srb->DataTransferLength;
DeviceExtension->CurrentIrp = Irp;
if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
ScsiPortStartPacket,
DeviceExtension))
{ {
DPRINT("Synchronization failed!\n"); // Store the MDL virtual address in SrbInfo structure
SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; if (DeviceExtension->MapBuffers && Irp->MdlAddress)
Irp->IoStatus.Information = 0; {
IoCompleteRequest(Irp, /* Calculate offset within DataBuffer */
IO_NO_INCREMENT); SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
if (oldIrql < DISPATCH_LEVEL) Srb->DataBuffer = SrbInfo->DataOffset +
{ (ULONG)((PUCHAR)Srb->DataBuffer -
KeRaiseIrql (DISPATCH_LEVEL, (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
&oldIrql); }
IoStartNextPacket (DeviceObject,
FALSE); if (DeviceExtension->AdapterObject)
KeLowerIrql (oldIrql); {
} /* Flush buffers */
else KeFlushIoBuffers(Irp->MdlAddress,
{ Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
IoStartNextPacket (DeviceObject, TRUE);
FALSE); }
}
if (DeviceExtension->MapRegisters)
{
#if 0
/* 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;
#else
ASSERT(FALSE);
#endif
}
} }
KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql); /* Increase active request counter */
if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE) CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
if (CounterResult == 0 &&
DeviceExtension->AdapterObject != NULL &&
!DeviceExtension->MapRegisters)
{ {
DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE; #if 0
IoCompleteRequest(Irp, IoAllocateAdapterChannel(
IO_NO_INCREMENT); DeviceExtension->AdapterObject,
DeviceObject,
DeviceExtension->PortCapabilities.MaximumPhysicalPages,
ScsiPortAllocationRoutine,
LunExtension
);
return;
#else
/* TODO: DMA is not implemented yet */
ASSERT(FALSE);
#endif
} }
if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->IrpLock);
if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
ScsiPortStartPacket,
DeviceObject))
{ {
DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT; DPRINT("Synchronization failed!\n");
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
IoStartNextPacket(DeviceObject, Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
FALSE); Irp->IoStatus.Information = 0;
KeLowerIrql(oldIrql); KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
}
else IoCompleteRequest(Irp, IO_NO_INCREMENT);
{
KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
} }
DPRINT("ScsiPortStartIo() done\n"); KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
DPRINT("ScsiPortStartIo() done\n");
} }
static BOOLEAN STDCALL static BOOLEAN STDCALL
ScsiPortStartPacket(IN OUT PVOID Context) ScsiPortStartPacket(IN OUT PVOID Context)
{ {
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IrpStack; PIO_STACK_LOCATION IrpStack;
PSCSI_REQUEST_BLOCK Srb; PSCSI_REQUEST_BLOCK Srb;
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
PSCSI_PORT_LUN_EXTENSION LunExtension;
BOOLEAN Result;
BOOLEAN StartTimer;
DPRINT("ScsiPortStartPacket() called\n"); DPRINT("ScsiPortStartPacket() called\n");
DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context; DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp); IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
Srb = IrpStack->Parameters.Scsi.Srb; Srb = IrpStack->Parameters.Scsi.Srb;
/* Allocte SRB extension */ /* Get LUN extension */
if (DeviceExtension->SrbExtensionSize != 0) LunExtension = SpiGetLunExtension(DeviceExtension,
Srb->PathId,
Srb->TargetId,
Srb->Lun);
/* Check if we are in a reset state */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
{ {
Srb->SrbExtension = DeviceExtension->VirtualAddress; /* Mark the we've got requests while being in the reset state */
DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
return TRUE;
} }
return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension, /* Set the time out value */
Srb)); DeviceExtension->TimeOutCount = 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)
{
/* TODO: Handle bypass-requests */
ASSERT(FALSE);
}
else
{
if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
{
/* It's a disconnect, so no more requests can go */
DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_IN_PROGRESS;
}
LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
/* Increment queue count */
LunExtension->QueueCount++;
/* If it's tagged - special thing */
if (Srb->QueueTag != SP_UNTAGGED)
{
/* TODO: Support tagged requests */
ASSERT(FALSE);
}
}
/* 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;
}
static PSCSI_PORT_LUN_EXTENSION static PSCSI_PORT_LUN_EXTENSION
SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
@ -1818,6 +1922,9 @@ SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
/* Initialize a list of requests */ /* Initialize a list of requests */
InitializeListHead(&LunExtension->SrbInfo.Requests); InitializeListHead(&LunExtension->SrbInfo.Requests);
/* Initialize timeout counter */
LunExtension->RequestTimeout = -1;
/* TODO: Initialize other fields */ /* TODO: Initialize other fields */
/* Initialize request queue */ /* Initialize request queue */
@ -2390,29 +2497,31 @@ SpiGetSrbData(IN PVOID DeviceExtension,
static BOOLEAN STDCALL static BOOLEAN STDCALL
ScsiPortIsr(IN PKINTERRUPT Interrupt, ScsiPortIsr(IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext) IN PVOID ServiceContext)
{ {
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
BOOLEAN Result; BOOLEAN Result;
DPRINT("ScsiPortIsr() called!\n"); DPRINT("ScsiPortIsr() called!\n");
DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext; DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension); /* If interrupts are disabled - we don't expect any */
if (Result == FALSE) if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
return FALSE;
/* Call miniport's HwInterrupt routine */
Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
/* If flag of notification is set - queue a DPC */
if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
{ {
return(FALSE); IoRequestDpc(DeviceExtension->DeviceObject,
DeviceExtension->CurrentIrp,
DeviceExtension);
} }
if (DeviceExtension->IrpFlags) return TRUE;
{
IoRequestDpc(DeviceExtension->DeviceObject,
DeviceExtension->CurrentIrp,
DeviceExtension);
}
return(TRUE);
} }
@ -2483,7 +2592,7 @@ ScsiPortDpcForIsr(IN PKDPC Dpc,
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock); KeReleaseSpinLockFromDpcLevel(&DeviceExtension->IrpLock);
if (!KeSynchronizeExecution(DeviceExtension->Interrupt, if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
ScsiPortStartPacket, ScsiPortStartPacket,
DeviceExtension)) DpcDeviceObject))
{ {
DPRINT1("Synchronization failed!\n"); DPRINT1("Synchronization failed!\n");

View file

@ -20,8 +20,19 @@
#define LUS_NUMBER 8 #define LUS_NUMBER 8
/* Flags */ /* Flags */
#define SCSI_PORT_NEXT_REQUEST_READY 0x0008 #define SCSI_PORT_DEVICE_BUSY 0x0001
#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000 #define SCSI_PORT_LU_ACTIVE 0x0002
#define SCSI_PORT_NOTIFICATION_NEEDED 0x0004
#define SCSI_PORT_NEXT_REQUEST_READY 0x0008
#define SCSI_PORT_RESET 0x0080
#define SCSI_PORT_RESET_REQUEST 0x0100
#define SCSI_PORT_DISCONNECT_IN_PROGRESS 0x1000
#define SCSI_PORT_DISABLE_INTERRUPTS 0x4000
#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000
typedef enum _SCSI_PORT_TIMER_STATES typedef enum _SCSI_PORT_TIMER_STATES
{ {
@ -46,6 +57,7 @@ typedef struct _SCSI_REQUEST_BLOCK_INFO
{ {
LIST_ENTRY Requests; LIST_ENTRY Requests;
PSCSI_REQUEST_BLOCK Srb; PSCSI_REQUEST_BLOCK Srb;
PCHAR DataOffset;
struct _SCSI_REQUEST_BLOCK_INFO *CompletedRequests; struct _SCSI_REQUEST_BLOCK_INFO *CompletedRequests;
} SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO; } SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO;
@ -65,6 +77,9 @@ typedef struct _SCSI_PORT_LUN_EXTENSION
INQUIRYDATA InquiryData; INQUIRYDATA InquiryData;
KDEVICE_QUEUE DeviceQueue; KDEVICE_QUEUE DeviceQueue;
ULONG QueueCount;
LONG RequestTimeout;
SCSI_REQUEST_BLOCK_INFO SrbInfo; SCSI_REQUEST_BLOCK_INFO SrbInfo;
@ -125,6 +140,10 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
PBUSES_CONFIGURATION_INFORMATION BusesConfig; PBUSES_CONFIGURATION_INFORMATION BusesConfig;
ULONG PortNumber; ULONG PortNumber;
LONG ActiveRequestCounter;
ULONG Flags;
LONG TimeOutCount;
KSPIN_LOCK IrpLock; KSPIN_LOCK IrpLock;
KSPIN_LOCK SpinLock; KSPIN_LOCK SpinLock;
PKINTERRUPT Interrupt; PKINTERRUPT Interrupt;
@ -158,10 +177,15 @@ typedef struct _SCSI_PORT_DEVICE_EXTENSION
/* DMA related stuff */ /* DMA related stuff */
PADAPTER_OBJECT AdapterObject; PADAPTER_OBJECT AdapterObject;
ULONG MapRegisterCount; ULONG MapRegisterCount;
BOOLEAN MapBuffers;
BOOLEAN MapRegisters;
PHYSICAL_ADDRESS PhysicalAddress; PHYSICAL_ADDRESS PhysicalAddress;
PVOID VirtualAddress; PVOID VirtualAddress;
ULONG CommonBufferLength; ULONG CommonBufferLength;
BOOLEAN NeedSrbExtensionAlloc;
BOOLEAN NeedSrbDataAlloc;
UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */ UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
} SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION; } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;