- Enable DMA support, this time properly.

- Fix ScsiPortGetPhysicalAddress() function to use scatter-gather list, if needed.
- Now BusLogic initializes succesfully, but BSODs later.

svn path=/trunk/; revision=27470
This commit is contained in:
Aleksey Bragin 2007-07-08 12:21:18 +00:00
parent 081ca81b64
commit ad9fd2687e
2 changed files with 313 additions and 81 deletions

View file

@ -85,6 +85,10 @@ ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
static BOOLEAN STDCALL static BOOLEAN STDCALL
ScsiPortStartPacket(IN OUT PVOID Context); ScsiPortStartPacket(IN OUT PVOID Context);
IO_ALLOCATION_ACTION
STDCALL
SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
PVOID MapRegisterBase, PVOID Context);
static PSCSI_PORT_LUN_EXTENSION static PSCSI_PORT_LUN_EXTENSION
SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
@ -95,6 +99,11 @@ SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR TargetId, IN UCHAR TargetId,
IN UCHAR Lun); IN UCHAR Lun);
static PSCSI_REQUEST_BLOCK_INFO
SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
PSCSI_PORT_LUN_EXTENSION LunExtension,
PSCSI_REQUEST_BLOCK Srb);
static NTSTATUS static NTSTATUS
SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject, SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
IN PSCSI_LUN_INFO LunInfo); IN PSCSI_LUN_INFO LunInfo);
@ -490,92 +499,64 @@ ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
*/ */
SCSI_PHYSICAL_ADDRESS STDCALL SCSI_PHYSICAL_ADDRESS STDCALL
ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension, ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
IN PVOID VirtualAddress, IN PVOID VirtualAddress,
OUT ULONG *Length) OUT ULONG *Length)
{ {
PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
SCSI_PHYSICAL_ADDRESS PhysicalAddress; SCSI_PHYSICAL_ADDRESS PhysicalAddress;
SCSI_PHYSICAL_ADDRESS NextPhysicalAddress; ULONG BufferLength = 0;
ULONG BufferLength = 0; ULONG Offset;
ULONG Offset; PSCSI_SG_ADDRESS SGList;
PVOID EndAddress; PSCSI_REQUEST_BLOCK_INFO SrbInfo;
DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n", DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
HwDeviceExtension, Srb, VirtualAddress, Length); HwDeviceExtension, Srb, VirtualAddress, Length);
DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
SCSI_PORT_DEVICE_EXTENSION, SCSI_PORT_DEVICE_EXTENSION,
MiniPortDeviceExtension); MiniPortDeviceExtension);
*Length = 0; if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
if (Srb == NULL)
{ {
if ((ULONG_PTR)DeviceExtension->VirtualAddress > (ULONG_PTR)VirtualAddress) /* Simply look it up in the allocated common buffer */
{ Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
PhysicalAddress.QuadPart = 0ULL;
return PhysicalAddress;
}
Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress; BufferLength = DeviceExtension->CommonBufferSize - Offset;
if (Offset >= DeviceExtension->CommonBufferLength) PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
{
PhysicalAddress.QuadPart = 0ULL;
return PhysicalAddress;
}
PhysicalAddress.QuadPart =
DeviceExtension->PhysicalAddress.QuadPart + (ULONGLONG)Offset;
BufferLength = DeviceExtension->CommonBufferLength - Offset;
} }
else else if (DeviceExtension->MapRegisters)
{ {
EndAddress = (PVOID)((ULONG_PTR)Srb->DataBuffer + Srb->DataTransferLength); /* Scatter-gather list must be used */
if (VirtualAddress == NULL) SrbInfo = SpiGetSrbData(DeviceExtension,
{ Srb->PathId,
VirtualAddress = Srb->DataBuffer; Srb->TargetId,
} Srb->Lun,
else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress) Srb->QueueTag);
{
PhysicalAddress.QuadPart = 0LL;
return PhysicalAddress;
}
PhysicalAddress = MmGetPhysicalAddress(VirtualAddress); SGList = SrbInfo->ScatterGather;
if (PhysicalAddress.QuadPart == 0LL)
{
return PhysicalAddress;
}
Offset = (ULONG_PTR)VirtualAddress & (PAGE_SIZE - 1); /* Find needed item in the SG list */
#if 1 Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
/* while (Offset >= SGList->Length)
* FIXME: {
* MmGetPhysicalAddress doesn't return the offset within the page. Offset -= SGList->Length;
* We must set the correct offset. SGList++;
*/ }
PhysicalAddress.u.LowPart = (PhysicalAddress.u.LowPart & ~(PAGE_SIZE - 1)) + Offset;
#endif /* We're done, store length and physical address */
BufferLength += PAGE_SIZE - Offset; BufferLength = SGList->Length - Offset;
while ((ULONG_PTR)VirtualAddress + BufferLength < (ULONG_PTR)EndAddress) PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
{ }
NextPhysicalAddress = MmGetPhysicalAddress((PVOID)((ULONG_PTR)VirtualAddress + BufferLength)); else
if (PhysicalAddress.QuadPart + (ULONGLONG)BufferLength != NextPhysicalAddress.QuadPart) {
{ /* Nothing */
break; *Length = 0;
} PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
BufferLength += PAGE_SIZE;
}
if ((ULONG_PTR)VirtualAddress + BufferLength >= (ULONG_PTR)EndAddress)
{
BufferLength = (ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress;
}
} }
*Length = BufferLength; *Length = BufferLength;
return PhysicalAddress;
return PhysicalAddress;
} }
@ -2727,6 +2708,7 @@ ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
PSCSI_REQUEST_BLOCK Srb; PSCSI_REQUEST_BLOCK Srb;
PSCSI_REQUEST_BLOCK_INFO SrbInfo; PSCSI_REQUEST_BLOCK_INFO SrbInfo;
LONG CounterResult; LONG CounterResult;
NTSTATUS Status;
DPRINT("ScsiPortStartIo() called!\n"); DPRINT("ScsiPortStartIo() called!\n");
@ -2749,9 +2731,21 @@ ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
if (DeviceExtension->NeedSrbDataAlloc || if (DeviceExtension->NeedSrbDataAlloc ||
DeviceExtension->NeedSrbExtensionAlloc) DeviceExtension->NeedSrbExtensionAlloc)
{ {
/* TODO: Implement */ /* Allocate them */
ASSERT(FALSE); SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
SrbInfo = NULL; 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 else
{ {
@ -2806,7 +2800,6 @@ ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
if (DeviceExtension->MapRegisters) if (DeviceExtension->MapRegisters)
{ {
#if 0
/* Calculate number of needed map registers */ /* Calculate number of needed map registers */
SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
Srb->DataBuffer, Srb->DataBuffer,
@ -2837,9 +2830,6 @@ ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
/* Control goes to SpiAdapterControl */ /* Control goes to SpiAdapterControl */
return; return;
#else
ASSERT(FALSE);
#endif
} }
} }
@ -3038,6 +3028,87 @@ ScsiPortStartPacket(IN OUT PVOID Context)
return Result; return Result;
} }
IO_ALLOCATION_ACTION
STDCALL
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 = ExAllocatePool(
NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS));
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)
{
ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
ScatterGatherList->PhysicalAddress = IoMapTransfer(NULL,
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,
ScsiPortStartPacket,
DeviceObject);
KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
return DeallocateObjectKeepRegisters;
}
static PSCSI_PORT_LUN_EXTENSION static PSCSI_PORT_LUN_EXTENSION
SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{ {
@ -3113,6 +3184,155 @@ SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
return NULL; 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;
/* Relese 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 static NTSTATUS
SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject, SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,

View file

@ -20,6 +20,8 @@
/* Defines how many logical unit arrays will be in a device extension */ /* Defines how many logical unit arrays will be in a device extension */
#define LUS_NUMBER 8 #define LUS_NUMBER 8
#define MAX_SG_LIST 17
/* Flags */ /* Flags */
#define SCSI_PORT_DEVICE_BUSY 0x0001 #define SCSI_PORT_DEVICE_BUSY 0x0001
#define SCSI_PORT_LU_ACTIVE 0x0002 #define SCSI_PORT_LU_ACTIVE 0x0002
@ -85,6 +87,12 @@ typedef struct _SCSI_PORT_DEVICE_BASE
ULONG SystemIoBusNumber; ULONG SystemIoBusNumber;
} SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE; } SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE;
typedef struct _SCSI_SG_ADDRESS
{
PHYSICAL_ADDRESS PhysicalAddress;
ULONG Length;
} SCSI_SG_ADDRESS, *PSCSI_SG_ADDRESS;
typedef struct _SCSI_REQUEST_BLOCK_INFO typedef struct _SCSI_REQUEST_BLOCK_INFO
{ {
LIST_ENTRY Requests; LIST_ENTRY Requests;
@ -99,6 +107,10 @@ typedef struct _SCSI_REQUEST_BLOCK_INFO
ULONG NumberOfMapRegisters; ULONG NumberOfMapRegisters;
struct _SCSI_REQUEST_BLOCK_INFO *CompletedRequests; struct _SCSI_REQUEST_BLOCK_INFO *CompletedRequests;
/* Scatter-gather list */
PSCSI_SG_ADDRESS ScatterGather;
SCSI_SG_ADDRESS ScatterGatherList[MAX_SG_LIST];
} SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO; } SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO;
typedef struct _SCSI_PORT_LUN_EXTENSION typedef struct _SCSI_PORT_LUN_EXTENSION