Author: fireball
Date: Fri Mar 30 01:05:41 2007
New Revision: 26199
URL:
http://svn.reactos.org/svn/reactos?rev=26199&view=rev
Log:
- Massive changes due to a rewrite of the core logic related to ISR, DPC, IRP completion
and commands delivery. Fixes a lot of race conditions which existed in hbirr-scsiport.
- Add some helper functions, and fields inside device extension structures.
- Reorganize flags a little, dividing them into flags for scsi port device extension and
logical unit device extension. (however some of the flags are still messed up)
- This gets us further, but still not enough / bugs may exist.
Modified:
trunk/reactos/drivers/storage/scsiport-new/scsiport.c
trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h
Modified: trunk/reactos/drivers/storage/scsiport-new/scsiport.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/storage/scsiport-n…
==============================================================================
--- trunk/reactos/drivers/storage/scsiport-new/scsiport.c (original)
+++ trunk/reactos/drivers/storage/scsiport-new/scsiport.c Fri Mar 30 01:05:41 2007
@@ -117,16 +117,41 @@
ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
PVOID Context);
+#if 0
static PSCSI_REQUEST_BLOCK
ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
PSCSI_REQUEST_BLOCK OriginalSrb);
static VOID
ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
+#endif
static NTSTATUS
SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
PUNICODE_STRING RegistryPath);
+
+static NTSTATUS
+SpiStatusSrbToNt(UCHAR SrbStatus);
+
+static VOID
+SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb);
+
+NTSTATUS STDCALL
+SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context);
+
+static VOID
+STDCALL
+SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
+ OUT PBOOLEAN NeedToCallStartIo);
+
+VOID
+STDCALL
+SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_PORT_LUN_EXTENSION LunExtension);
/* FUNCTIONS *****************************************************************/
@@ -2086,7 +2111,7 @@
}
else
{
- /* Check if queue is frozen */
+ /* Check if the queue is frozen */
if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
{
/* Something weird happeend */
@@ -2512,6 +2537,480 @@
}
}
+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\n");
+
+ /* Allocate Srb */
+ Srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID));
+ 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);
+
+ 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 = Srb;
+
+ /* 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
+STDCALL
+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%08X", 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);
+
+ /* Requeu, 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("Requeueing 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
+STDCALL
+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 STDCALL
ScsiPortIsr(IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext)
@@ -2540,6 +3039,220 @@
return TRUE;
}
+
+BOOLEAN
+STDCALL
+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 unsuccessfull*/
+ 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
+STDCALL
+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
@@ -2559,99 +3272,195 @@
IN PIRP DpcIrp,
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,
- DpcDeviceObject))
- {
- 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);
- }
-
- DPRINT("ScsiPortDpcForIsr() done\n");
+ 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;
+
+ DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext
%p)\n",
+ Dpc, DpcDeviceObject, DpcIrp, DpcContext);
+
+ /* We need to acquire spinlock */
+ KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
+
+TryAgain:
+
+ /* Interrupt structure must be snapshotted, and only then analyzed */
+ Context.InterruptData = &InterruptData;
+ Context.DeviceExtension = DeviceExtension;
+
+ if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
+ 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 & SCIS_PORT_TIMER_NEEDED)
+ {
+ /* TODO: Implement */
+ ASSERT(FALSE);
+ }
+
+ /* 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");
}
@@ -2673,7 +3482,7 @@
DPRINT1("ScsiPortIoTimer()\n");
}
-
+#if 0
static PSCSI_REQUEST_BLOCK
ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
PSCSI_REQUEST_BLOCK OriginalSrb)
@@ -2711,7 +3520,7 @@
{
DeviceExtension->OriginalSrb = NULL;
}
-
+#endif
/**********************************************************************
* NAME INTERNAL
@@ -3136,6 +3945,39 @@
return Status;
}
+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
/*
Modified: trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/storage/scsiport-n…
==============================================================================
--- trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h (original)
+++ trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h Fri Mar 30 01:05:41 2007
@@ -24,13 +24,25 @@
#define SCSI_PORT_LU_ACTIVE 0x0002
#define SCSI_PORT_NOTIFICATION_NEEDED 0x0004
#define SCSI_PORT_NEXT_REQUEST_READY 0x0008
+#define SCSI_PORT_FLUSH_ADAPTERS 0x0010
+#define SCSI_PORT_MAP_TRANSFER 0x0020
#define SCSI_PORT_RESET 0x0080
#define SCSI_PORT_RESET_REQUEST 0x0100
+#define SCSI_PORT_RESET_REPORTED 0x0200
+#define SCSI_PORT_REQUEST_PENDING 0x0800
#define SCSI_PORT_DISCONNECT_ALLOWED 0x1000
+#define SCSI_PORT_DISABLE_INT_REQUESET 0x2000
#define SCSI_PORT_DISABLE_INTERRUPTS 0x4000
+#define SCSI_PORT_ENABLE_INT_REQUEST 0x8000
+#define SCIS_PORT_TIMER_NEEDED 0x10000
+
+/* LUN Extension flags*/
+#define LUNEX_FROZEN_QUEUE 0x0001
+#define LUNEX_NEED_REQUEST_SENSE 0x0004
+#define LUNEX_BUSY 0x0008
+#define LUNEX_FULL_QUEUE 0x0010
+#define LUNEX_REQUEST_PENDING 0x0020
#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000
-
-
@@ -58,6 +70,14 @@
LIST_ENTRY Requests;
PSCSI_REQUEST_BLOCK Srb;
PCHAR DataOffset;
+ PVOID SaveSenseRequest;
+
+ ULONG SequenceNumber;
+
+ /* DMA stuff */
+ PVOID BaseOfMapRegister;
+ ULONG NumberOfMapRegisters;
+
struct _SCSI_REQUEST_BLOCK_INFO *CompletedRequests;
} SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO;
@@ -77,9 +97,18 @@
INQUIRYDATA InquiryData;
KDEVICE_QUEUE DeviceQueue;
+ ULONG SortKey;
ULONG QueueCount;
-
+ ULONG MaxQueueCount;
+
+ ULONG AttemptCount;
LONG RequestTimeout;
+
+ PIRP BusyRequest;
+ PIRP PendingRequest;
+
+ struct _SCSI_PORT_LUN_EXTENSION *ReadyLun;
+ struct _SCSI_PORT_LUN_EXTENSION *CompletedAbortRequests;
SCSI_REQUEST_BLOCK_INFO SrbInfo;
@@ -120,9 +149,17 @@
{
ULONG Flags; /* Interrupt-time flags */
PSCSI_REQUEST_BLOCK_INFO CompletedRequests; /* Linked list of Srb info data */
-
+ PSCSI_PORT_LUN_EXTENSION CompletedAbort;
+ PSCSI_PORT_LUN_EXTENSION ReadyLun;
} SCSI_PORT_INTERRUPT_DATA, *PSCSI_PORT_INTERRUPT_DATA;
+
+/* Only for interrupt data saving function */
+typedef struct _SCSI_PORT_SAVE_INTERRUPT
+{
+ PSCSI_PORT_INTERRUPT_DATA InterruptData;
+ struct _SCSI_PORT_DEVICE_EXTENSION *DeviceExtension;
+} SCSI_PORT_SAVE_INTERRUPT, *PSCSI_PORT_SAVE_INTERRUPT;
/*
* SCSI_PORT_DEVICE_EXTENSION
@@ -159,7 +196,14 @@
SCSI_PORT_INTERRUPT_DATA InterruptData;
+ /* SRB extension stuff*/
ULONG SrbExtensionSize;
+ PVOID SrbExtensionBuffer;
+ PVOID FreeSrbExtensions;
+
+ /* SRB information */
+ PSCSI_REQUEST_BLOCK_INFO SrbInfo;
+ PSCSI_REQUEST_BLOCK_INFO FreeSrbInfo;
PIO_SCSI_CAPABILITIES PortCapabilities;
@@ -178,6 +222,12 @@
ULONG MapRegisterCount;
BOOLEAN MapBuffers;
BOOLEAN MapRegisters;
+ PVOID MapRegisterBase;
+
+ /* Features */
+ BOOLEAN SupportsTaggedQueuing;
+ BOOLEAN SupportsAutoSense;
+
PHYSICAL_ADDRESS PhysicalAddress;
PVOID VirtualAddress;