- 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)