summaryrefslogtreecommitdiffstats
path: root/private/ntos/fw/mips/scsiport.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/fw/mips/scsiport.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/fw/mips/scsiport.c')
-rw-r--r--private/ntos/fw/mips/scsiport.c4927
1 files changed, 4927 insertions, 0 deletions
diff --git a/private/ntos/fw/mips/scsiport.c b/private/ntos/fw/mips/scsiport.c
new file mode 100644
index 000000000..670b329af
--- /dev/null
+++ b/private/ntos/fw/mips/scsiport.c
@@ -0,0 +1,4927 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ scsiboot.c
+
+Abstract:
+
+ This is the NT SCSI port driver.
+
+Author:
+
+ Mike Glass
+ Jeff Havens
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+ This module is linked into the kernel.
+
+Revision History:
+
+--*/
+
+#if !defined(DECSTATION)
+
+#include "stdarg.h"
+#include "stdio.h"
+#ifdef MIPS
+#include "..\fw\mips\fwp.h"
+#elif defined(ALPHA)
+#include "..\fw\alpha\fwp.h"
+#else
+#include "boot.h"
+#endif
+#include "scsi.h"
+#include "scsiboot.h"
+
+ULONG ScsiPortCount;
+ULONG ScsiDebug = 0;
+PDEVICE_OBJECT ScsiPortDeviceObject[10];
+PINQUIRYDATA InquiryDataBuffer;
+FULL_SCSI_REQUEST_BLOCK PrimarySrb;
+FULL_SCSI_REQUEST_BLOCK RequestSenseSrb;
+FULL_SCSI_REQUEST_BLOCK AbortSrb;
+
+//
+// Function declarations
+//
+VOID
+IopAllocateCommonBuffer(
+ IN PVOID NonCachedExtension,
+ IN ULONG NonCachedExtensionSize,
+ OUT PPHYSICAL_ADDRESS LogicalAddress
+ );
+
+ARC_STATUS
+ScsiPortDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiPortStartIo (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+BOOLEAN
+ScsiPortInterrupt(
+ IN PKINTERRUPT InterruptObject,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+VOID
+ScsiPortCompletionDpc(
+ IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+VOID
+ScsiPortTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ );
+
+IO_ALLOCATION_ACTION
+ScsiPortAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+ARC_STATUS
+IssueInquiry(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PLUNINFO LunInfo
+ );
+
+VOID
+IssueRequestSense(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK FailingSrb
+ );
+
+VOID
+ScsiPortInternalCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ );
+
+PSCSI_BUS_SCAN_DATA
+ScsiBusScan(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ScsiBus,
+ IN UCHAR InitiatorBusId
+ );
+
+PLOGICAL_UNIT_EXTENSION
+CreateLogicalUnitExtension(
+ IN PDEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+SpStartIoSynchronized (
+ PVOID ServiceContext
+ );
+
+VOID
+IssueAbortRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP FailingIrp
+ );
+
+IO_ALLOCATION_ACTION
+SpBuildScatterGather(
+ IN struct _DEVICE_OBJECT *DeviceObject,
+ IN struct _IRP *Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+BOOLEAN
+SpGetInterruptState(
+ IN PVOID ServiceContext
+ );
+
+VOID
+SpTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+PLOGICAL_UNIT_EXTENSION
+GetLogicalUnitExtension(
+ PDEVICE_EXTENSION DeviceExtension,
+ UCHAR TargetId
+ );
+
+NTSTATUS
+SpInitializeConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PHW_INITIALIZATION_DATA HwInitData,
+ OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN BOOLEAN InitialCall
+ );
+
+NTSTATUS
+SpGetCommonBuffer(
+ PDEVICE_EXTENSION DeviceExtension,
+ ULONG NonCachedExtensionSize
+ );
+
+#ifdef i386
+ULONG
+HalpGetCmosData(
+ IN ULONG SourceLocation,
+ IN ULONG SourceAddress,
+ IN PVOID ReturnBuffer,
+ IN ULONG ByteCount
+ );
+#endif
+
+//
+// Routines start
+//
+
+ULONG
+ScsiPortInitialize(
+ IN PVOID Argument1,
+ IN PVOID Argument2,
+ IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+ IN PVOID HwContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the port driver.
+
+Arguments:
+
+ Argument1 - Pointer to driver object created by system
+ HwInitializationData - Miniport initialization structure
+ HwContext - Value passed to miniport driver's config routine
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PDEVICE_OBJECT DeviceObject;
+ PORT_CONFIGURATION_INFORMATION configInfo;
+ KEVENT allocateAdapterEvent;
+ ULONG ExtensionAllocationSize;
+ ULONG j;
+ UCHAR scsiBus;
+ PULONG scsiPortNumber;
+ ULONG numberOfPageBreaks;
+ PIO_SCSI_CAPABILITIES capabilities;
+ BOOLEAN callAgain;
+ DEVICE_DESCRIPTION deviceDescription;
+ ARC_CODES status;
+ BOOLEAN foundOne = FALSE;
+
+ UNREFERENCED_PARAMETER(Argument1);
+ UNREFERENCED_PARAMETER(Argument2);
+
+ if (HwInitializationData->HwInitializationDataSize != sizeof(HW_INITIALIZATION_DATA)) {
+
+ DebugPrint((0,"ScsiPortInitialize: Miniport driver wrong version\n"));
+
+ return EBADF;
+ }
+
+ //
+ // Check that each required entry is not NULL.
+ //
+
+ if ((!HwInitializationData->HwInitialize) ||
+ (!HwInitializationData->HwFindAdapter) ||
+ (!HwInitializationData->HwResetBus)) {
+
+ DebugPrint((0,
+ "ScsiPortInitialize: Miniport driver missing required entry\n"));
+
+ return EBADF;
+ }
+
+CallAgain:
+
+ //
+ // Get the configuration information
+ //
+
+ scsiPortNumber = &ScsiPortCount;
+
+ //
+ // Determine size of extensions.
+ //
+
+ ExtensionAllocationSize = DEVICE_EXTENSION_SIZE +
+ HwInitializationData->DeviceExtensionSize + sizeof(DEVICE_OBJECT);
+
+ DeviceObject = ExAllocatePool(NonPagedPool, ExtensionAllocationSize);
+
+ if (DeviceObject == NULL) {
+ return ENOMEM;
+ }
+
+ RtlZeroMemory(DeviceObject, ExtensionAllocationSize);
+
+ //
+ // Set up device extension pointers
+ //
+
+ deviceExtension = DeviceObject->DeviceExtension = (PVOID) (DeviceObject + 1);
+ deviceExtension->DeviceObject = DeviceObject;
+
+ //
+ // Save the dependent driver routines in the device extension.
+ //
+
+ deviceExtension->HwInitialize = HwInitializationData->HwInitialize;
+ deviceExtension->HwStartIo = HwInitializationData->HwStartIo;
+ deviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
+ deviceExtension->HwReset = HwInitializationData->HwResetBus;
+ deviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
+ deviceExtension->HwLogicalUnitExtensionSize =
+ HwInitializationData->SpecificLuExtensionSize;
+
+ deviceExtension->HwDeviceExtension =
+ (PVOID)(deviceExtension + 1);
+
+ //
+ // Set indicater as to whether adapter needs kernel mapped buffers.
+ //
+
+ deviceExtension->MapBuffers = HwInitializationData->MapBuffers;
+
+ //
+ // Mark this object as supporting direct I/O so that I/O system
+ // will supply mdls in irps.
+ //
+
+ DeviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Check if miniport driver requires any noncached memory.
+ // SRB extensions will come from zoned memory. A page is
+ // allocated as it is the smallest unit of noncached memory
+ // allocation.
+ //
+
+ deviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+
+ //
+ // Get the miniport configuration information.
+ //
+
+ capabilities = &deviceExtension->Capabilities;
+
+ capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+
+ callAgain = FALSE;
+
+
+ if (!NT_SUCCESS(SpInitializeConfiguration(
+ deviceExtension,
+ HwInitializationData,
+ &configInfo,
+ TRUE
+ ))) {
+
+ DebugPrint((2, "ScsiPortInitialize: no Configuration info found\n"));
+ return(ENODEV);
+ }
+
+ configInfo.NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
+
+ configInfo.AccessRanges = ExAllocatePool(
+ NonPagedPool,
+ sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges
+ );
+
+ if (configInfo.AccessRanges == NULL) {
+ return ENOMEM;
+ }
+
+ if (HwInitializationData->HwFindAdapter(
+ deviceExtension->HwDeviceExtension, // DeviceExtension
+ HwContext, // HwContext
+ NULL, // BusInformation
+ NULL, // ArgumentString
+ &configInfo, // ConfigurationInformation
+ &callAgain // Again
+ ) != SP_RETURN_FOUND) {
+
+ return foundOne ? ESUCCESS : EIO;
+ }
+
+ ScsiDebugPrint(1,"ScsiPortInitialize: SCSI adapter IRQ is %d\n",
+ configInfo.BusInterruptLevel);
+
+ ScsiDebugPrint(1,"ScsiPortInitialize: SCSI adapter ID is %d\n",
+ configInfo.InitiatorBusId[0]);
+
+ deviceExtension->NumberOfBuses = configInfo.NumberOfBuses;
+
+ //
+ // Free the pointer to the bus data at map register base. This was
+ // allocated by ScsiPortGetBusData.
+ //
+
+ if (deviceExtension->MapRegisterBase != NULL) {
+ ExFreePool(deviceExtension->MapRegisterBase);
+ }
+
+ //
+ // Allocate memory for the non cached extension if it has not already been
+ // allocated.
+ //
+
+ if (deviceExtension->SrbExtensionSize != 0 &&
+ deviceExtension->SrbExtensionZonePool == NULL) {
+
+ status = SpGetCommonBuffer(deviceExtension, 0);
+
+ if (status != ESUCCESS) {
+
+ return(status);
+ }
+ }
+
+ //
+ // Get the adapter object for this card.
+ //
+
+ if ((configInfo.Master || configInfo.DmaChannel != 0xFFFFFFFF)) {
+
+ deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ deviceDescription.DmaChannel = configInfo.DmaChannel;
+ deviceDescription.InterfaceType = configInfo.AdapterInterfaceType;
+ deviceDescription.BusNumber = configInfo.SystemIoBusNumber;
+ deviceDescription.DmaWidth = configInfo.DmaWidth;
+ deviceDescription.DmaSpeed = configInfo.DmaSpeed;
+ deviceDescription.DmaPort = configInfo.DmaPort;
+ deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
+ deviceDescription.ScatterGather = configInfo.ScatterGather;
+ deviceDescription.Master = configInfo.Master;
+ deviceDescription.AutoInitialize = FALSE;
+ deviceDescription.DemandMode = FALSE;
+
+ // BugBug: Make the 0x11000 a define when there is one.
+ if (configInfo.MaximumTransferLength > 0x11000) {
+
+ deviceDescription.MaximumLength = 0x11000;
+
+ } else {
+
+ deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
+
+ }
+
+ deviceExtension->DmaAdapterObject = HalGetAdapter(
+ &deviceDescription,
+ &numberOfPageBreaks
+ );
+
+ //
+ // Set maximum number of page breaks.
+ //
+
+ if (numberOfPageBreaks > configInfo.NumberOfPhysicalBreaks) {
+ capabilities->MaximumPhysicalPages = configInfo.NumberOfPhysicalBreaks;
+ } else {
+ capabilities->MaximumPhysicalPages = numberOfPageBreaks;
+ }
+
+ }
+
+ capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+ capabilities->MaximumTransferLength = configInfo.MaximumTransferLength;
+ ScsiDebugPrint(1, "Maximum physical page breaks = %d. Maximum transfer length = %x\n", capabilities->MaximumPhysicalPages, capabilities->MaximumTransferLength);
+
+ if (HwInitializationData->ReceiveEvent) {
+ capabilities->SupportedAsynchronousEvents |=
+ SRBEV_SCSI_ASYNC_NOTIFICATION;
+ }
+
+ capabilities->TaggedQueuing = HwInitializationData->TaggedQueuing;
+ capabilities->AdapterScansDown = configInfo.AdapterScansDown;
+
+ //
+ // Make sure maximum nuber of pages is set to a reasonable value.
+ // This occurs for mini-ports with no Dma adapter.
+ //
+
+ if (capabilities->MaximumPhysicalPages == 0) {
+
+ capabilities->MaximumPhysicalPages =
+ ROUND_TO_PAGES(capabilities->MaximumTransferLength) + 1;
+
+ //
+ // Honor any limit requested by the mini-port.
+ //
+
+ if (configInfo.NumberOfPhysicalBreaks < capabilities->MaximumPhysicalPages) {
+
+ capabilities->MaximumPhysicalPages =
+ configInfo.NumberOfPhysicalBreaks;
+ }
+ }
+
+
+ if (deviceExtension->DmaAdapterObject != NULL &&
+ !HwInitializationData->NeedPhysicalAddresses) {
+
+ //
+ // Allocate the adapter object. For the port driver the adapter object
+ // and map registers are permentently allocated and used shared between
+ // all logical units. The adapter is allocated by initializing an event,
+ // calling IoAllocateAdapterChannel and waiting on the event. When the
+ // adapter and map registers are available, ScsiPortAllocationRoutine is
+ // called which set the event. In reality, all this takes zero time since
+ // the stuff is available immediately.
+ //
+ // Allocate the AdapterObject. The number of registers is equal to the
+ // maximum transfer length supported by the adapter + 1. This insures
+ // that there will always be a sufficient number of registers.
+ //
+ /* TODO: Fix this for the case when there is no maximum transfer length. */
+
+ IoAllocateAdapterChannel(
+ deviceExtension->DmaAdapterObject,
+ DeviceObject,
+// configInfo.NumberOfPhysicalBreaks,
+ capabilities->MaximumPhysicalPages,
+ ScsiPortAllocationRoutine,
+ &allocateAdapterEvent
+ );
+
+ //
+ // Wait for adapter object.
+ //
+
+ ASSERT(deviceExtension->MapRegisterBase);
+
+ deviceExtension->MasterWithAdapter = FALSE;
+
+ } else if (deviceExtension->DmaAdapterObject != NULL) {
+
+ //
+ // This SCSI adapter is a master with an adapter so a scatter/gather
+ // list needs to be allocated for each transfer.
+ //
+
+ deviceExtension->MasterWithAdapter = TRUE;
+
+ } else {
+
+ deviceExtension->MasterWithAdapter = FALSE;
+
+ } // end if (deviceExtension->DmaAdapterObject != NULL)
+
+ //
+ // Call the hardware dependent driver to do its initialization.
+ //
+
+ if (!KeSynchronizeExecution(
+ deviceExtension->InterruptObject,
+ deviceExtension->HwInitialize,
+ deviceExtension->HwDeviceExtension
+ )) {
+
+ ScsiDebugPrint(1,"ScsiPortInitialize: initialization failed\n");
+
+ return ENODEV;
+ }
+
+ //
+ // Allocate properly aligned INQUIRY buffer.
+ //
+
+ InquiryDataBuffer = ExAllocatePool(NonPagedPool, INQUIRYDATABUFFERSIZE);
+
+ if (InquiryDataBuffer == NULL) {
+ return(ENOMEM);
+ }
+
+ //
+ // Reset the scsi bus.
+ //
+
+ if (!deviceExtension->HwReset(
+ deviceExtension->HwDeviceExtension,
+ 0)){
+
+ ScsiDebugPrint(1,"Reset SCSI bus failed\n");
+ }
+
+ //
+ // Call the interupt handler for a few microseconds to clear any reset
+ // interrupts.
+ //
+
+ for (j = 0; j < 1000 * 100; j++) {
+
+ FwStallExecution(10);
+ if (deviceExtension->HwInterrupt != NULL) {
+ deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension);
+ }
+
+
+ }
+
+ //
+ // Wait 2 seconds for the devices to recover after the reset.
+ //
+
+ //FwStallExecution(2 * 1000 * 1000);
+ FwStallExecution(2 * 1000 * 100);
+
+ //
+ // Find devices on each SCSI bus.
+ //
+
+ //
+ // Allocate buffer for SCSI bus scan information.
+ //
+
+ deviceExtension->ScsiInfo = ExAllocatePool(NonPagedPool,
+ deviceExtension->NumberOfBuses * sizeof(PSCSI_BUS_SCAN_DATA) +
+ 4);
+
+ if (deviceExtension->ScsiInfo) {
+
+ deviceExtension->ScsiInfo->NumberOfBuses = deviceExtension->NumberOfBuses;
+
+ //
+ // Find devices on each SCSI bus.
+ //
+
+ for (scsiBus = 0; scsiBus < deviceExtension->NumberOfBuses; scsiBus++) {
+ deviceExtension->ScsiInfo->BusScanData[scsiBus] =
+ ScsiBusScan(deviceExtension,
+ scsiBus,
+ configInfo.InitiatorBusId[scsiBus]);
+ }
+ }
+
+ //
+ // Save the device object for use by the driver.
+ //
+
+ ScsiPortDeviceObject[*scsiPortNumber] = DeviceObject;
+
+ //
+ // Bump SCSI host bus adapters count.
+ //
+
+ (*scsiPortNumber)++;
+
+ foundOne = TRUE;
+
+ //
+ // If the adapter wants to be called again with the same configuration data
+ // then start over from the begining again.
+ //
+
+ if (callAgain) {
+ goto CallAgain;
+
+ }
+
+ return ESUCCESS;
+
+} // end ScsiPortInitialize()
+
+IO_ALLOCATION_ACTION
+ScsiPortAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by IoAllocateAdapterChannel when sufficent resources
+ are available to the driver. This routine saves the MapRegisterBase in the
+ device object and set the event pointed to by the context parameter.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object to which the adapter is being
+ allocated.
+
+ Irp - Unused.
+
+ MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer.
+
+ Context - Supplies a pointer to an event which is set to indicate the
+ AdapterObject has been allocated.
+
+Return Value:
+
+ KeepObject - Indicates the adapter and mapregisters should remain allocated
+ after return.
+
+--*/
+
+{
+ ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->MapRegisterBase =
+ MapRegisterBase;
+
+ UNREFERENCED_PARAMETER(Irp);
+ UNREFERENCED_PARAMETER(Context);
+
+ return(KeepObject);
+}
+
+IO_ALLOCATION_ACTION
+SpBuildScatterGather(
+ IN struct _DEVICE_OBJECT *DeviceObject,
+ IN struct _IRP *Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the I/O system when an adapter object and map
+ registers have been allocated. This routine then builds a scatter/gather
+ list for use by the mini-port driver. Next it sets the timeout and
+ the current Irp for the logical unit. Finally it calls the mini-port
+ StartIo routine. Once that routines complete, this routine will return
+ requesting that the adapter be freed and but the registers remain allocated.
+ The registers will be freed the request completes.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the port driver device object.
+
+ Irp - Supplies a pointer to the current Irp.
+
+ MapRegisterBase - Supplies a context pointer to be used with calls the
+ adapter object routines.
+
+ Context - Supplies a pointer to the logical unit structure.
+
+Return Value:
+
+ Returns DeallocateObjectKeepRegisters so that the adapter object can be
+ used by other logical units.
+
+--*/
+
+{
+ BOOLEAN writeToDevice;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PSCSI_REQUEST_BLOCK srb;
+ PSRB_SCATTER_GATHER scatterList;
+ ULONG totalLength;
+
+ logicalUnit = Context;
+ srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ scatterList = logicalUnit->ScatterGather;
+ totalLength = 0;
+
+ //
+ // Save the MapRegisterBase for later use to deallocate the map registers.
+ //
+
+ logicalUnit->MapRegisterBase = MapRegisterBase;
+
+ //
+ // Build the scatter/gather list by looping throught the transfer calling
+ // I/O map transfer.
+ //
+
+ writeToDevice = srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
+
+ while (totalLength < srb->DataTransferLength) {
+
+ //
+ // Request that the rest of the transfer be mapped.
+ //
+
+ scatterList->Length = srb->DataTransferLength - totalLength;
+
+ //
+ // Since we are a master call I/O map transfer with a NULL adapter.
+ //
+
+ scatterList->PhysicalAddress = IoMapTransfer(
+ NULL,
+ Irp->MdlAddress,
+ MapRegisterBase,
+ (PCCHAR) srb->DataBuffer + totalLength,
+ &scatterList->Length,
+ writeToDevice
+ ).LowPart;
+
+ totalLength += scatterList->Length;
+ scatterList++;
+ }
+
+ //
+ // Set request timeout value from Srb SCSI extension in Irp.
+ //
+
+ logicalUnit->RequestTimeoutCounter = srb->TimeOutValue;
+
+ //
+ // Set current request for this logical unit.
+ //
+
+ logicalUnit->CurrentRequest = Irp;
+
+ /* TODO: Check the return value. */
+ KeSynchronizeExecution(
+ ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->InterruptObject,
+ SpStartIoSynchronized,
+ DeviceObject
+ );
+
+ return(DeallocateObjectKeepRegisters);
+
+}
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the start I/O routine an waits for the request to
+ complete. During the wait for complete the interrupt routine is called,
+ also the timer routines are called at the appropriate times. After the
+ request completes a check is made to determine if an request sense needs
+ to be issued.
+
+Arguments:
+
+ DeviceObject - Supplies pointer to Adapter device object.
+
+ Irp - Supplies a pointer to an IRP.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ ULONG milliSecondTime;
+ ULONG secondTime;
+ ULONG completionDelay;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ PVOID logicalUnit;
+
+ deviceExtension = DeviceObject->DeviceExtension;
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
+
+ if (logicalUnit == NULL) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ return;
+ }
+
+ //
+ // Mark IRP as pending.
+ //
+
+ Irp->PendingReturned = TRUE;
+
+ //
+ // Start the request.
+ //
+
+ ScsiPortStartIo( DeviceObject, Irp);
+
+ //
+ // The completion delay controls how long interrupts are serviced after
+ // a request has been completed. This allows interrupts which occur after
+ // a completion to be serviced.
+ //
+
+ completionDelay = COMPLETION_DELAY;
+
+ //
+ // Wait for the IRP to complete.
+ //
+
+ while (Irp->PendingReturned && completionDelay) {
+
+ //
+ // Wait 1 second then call the scsi port timer routine.
+ //
+
+ for (secondTime = 0; secondTime < 1000/ 500; secondTime++) {
+
+ for (milliSecondTime = 0; milliSecondTime < (250 * 1000 / PD_INTERLOOP_STALL); milliSecondTime++) {
+
+ ScsiPortInterrupt(NULL, DeviceObject);
+
+ if (!Irp->PendingReturned) {
+ if (completionDelay-- == 0) {
+ goto done;
+ }
+ }
+
+ if (deviceExtension->Flags & PD_ENABLE_CALL_REQUEST) {
+
+ //
+ // Call the mini-port requested routine.
+ //
+
+ deviceExtension->Flags &= ~PD_ENABLE_CALL_REQUEST;
+ deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
+
+ if (deviceExtension->Flags & PD_DISABLE_CALL_REQUEST) {
+
+ deviceExtension->Flags &= ~(PD_DISABLE_INTERRUPTS | PD_DISABLE_CALL_REQUEST);
+ deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
+
+ }
+ }
+
+ FwStallExecution(PD_INTERLOOP_STALL);
+
+ //
+ // Check the miniport timer.
+ //
+
+ if (deviceExtension->TimerValue != 0) {
+
+ deviceExtension->TimerValue--;
+
+ if (deviceExtension->TimerValue == 0) {
+
+ //
+ // The timer timed out so called requested timer routine.
+ //
+
+ deviceExtension->HwTimerRequest(deviceExtension->HwDeviceExtension);
+ }
+ }
+ }
+
+ }
+
+ ScsiPortTickHandler(DeviceObject, NULL);
+ }
+
+done:
+
+ if (!NT_SUCCESS(Irp->IoStatus.Status)) {
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Determine if a REQUEST SENSE command needs to be done.
+ // Check that a CHECK_CONDITION was received, an autosense has not
+ // been done already, and that autosense has been requested.
+ //
+
+ if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ srb->SenseInfoBuffer) {
+
+ //
+ // Call IssueRequestSense and it will complete the request after
+ // the REQUEST SENSE completes.
+ //
+
+ IssueRequestSense(deviceExtension, Srb);
+ }
+ }
+}
+
+VOID
+ScsiPortStartIo (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ DeviceObject - Supplies pointer to Adapter device object.
+ Irp - Supplies a pointer to an IRP.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PFULL_SCSI_REQUEST_BLOCK FullSrb;
+ NTSTATUS status;
+
+ ScsiDebugPrint(3,"ScsiPortStartIo: Enter routine\n");
+
+ FullSrb = CONTAINING_RECORD(Srb, FULL_SCSI_REQUEST_BLOCK, Srb);
+
+ if (deviceExtension->SrbExtensionZonePool && (Srb->SrbExtension == NULL
+ || deviceExtension->SrbExtensionSize > FullSrb->SrbExtensionSize)) {
+
+ //
+ // Allocate SRB extension from zone.
+ //
+
+ Srb->SrbExtension = deviceExtension->SrbExtensionPointer;
+
+ (PCCHAR) deviceExtension->SrbExtensionPointer +=
+ deviceExtension->SrbExtensionSize;
+
+ FullSrb->SrbExtensionSize = deviceExtension->SrbExtensionSize;
+
+ if ((ULONG) deviceExtension->SrbExtensionPointer >
+ (ULONG) deviceExtension->NonCachedExtension) {
+ ScsiDebugPrint(0, "NtLdr: ScsiPortStartIo: Srb extension overflow. Too many srb extension allocated.\n");
+ }
+
+ ScsiDebugPrint(3,"ExInterlockedAllocateFromZone: %lx\n",
+ Srb->SrbExtension);
+
+ ScsiDebugPrint(3,"Srb %lx\n",Srb);
+
+
+ }
+
+ //
+ // Get logical unit extension.
+ //
+
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
+
+ //
+ // Flush the data buffer if necessary.
+ //
+
+ if (Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) {
+
+ if (Srb->DataTransferLength > deviceExtension->Capabilities.MaximumTransferLength) {
+
+ ScsiDebugPrint(1, "Scsiboot: ScsiPortStartIo Length Exceeds limit %x, %x\n Hit any key\n",
+ Srb->DataTransferLength,
+ deviceExtension->Capabilities.MaximumTransferLength
+ );
+
+ }
+
+ KeFlushIoBuffers(
+ Irp->MdlAddress,
+ Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
+ TRUE
+ );
+
+ //
+ // Determine if this adapter needs map registers
+ //
+
+ if (deviceExtension->MasterWithAdapter) {
+
+ //
+ // Calculate the number of map registers needed for this transfer.
+ //
+
+ logicalUnit->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ Srb->DataBuffer,
+ Srb->DataTransferLength
+ );
+
+ //
+ // Allocate the adapter channel with sufficient map registers
+ // for the transfer.
+ //
+
+ status = IoAllocateAdapterChannel(
+ deviceExtension->DmaAdapterObject, // AdapterObject
+ DeviceObject, // DeviceObject.
+ logicalUnit->NumberOfMapRegisters, // NumberOfMapRegisters
+ SpBuildScatterGather, // ExecutionRoutine
+ logicalUnit // Context
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ ;
+ }
+
+ //
+ // The execution routine called by IoAllocateChannel will do the
+ // rest of the work so just return.
+ //
+
+ return;
+ }
+ }
+
+ //
+ // Set request timeout value from Srb SCSI extension in Irp.
+ //
+
+ logicalUnit->RequestTimeoutCounter = Srb->TimeOutValue;
+
+ //
+ // Set current request for this logical unit.
+ //
+
+ logicalUnit->CurrentRequest = Irp;
+
+ /* TODO: Check the return value. */
+ KeSynchronizeExecution(
+ deviceExtension->InterruptObject,
+ SpStartIoSynchronized,
+ DeviceObject
+ );
+
+ return;
+
+} // end ScsiPortStartIO()
+
+
+BOOLEAN
+SpStartIoSynchronized (
+ PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the dependent driver start io routine.
+
+Arguments:
+
+ ServiceContext - Supplies the pointer to the device object.
+
+Return Value:
+
+ Returns the value returned by the dependent start I/O routine.
+
+
+--*/
+
+{
+ PDEVICE_OBJECT DeviceObject = ServiceContext;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpstack;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ ScsiDebugPrint(3, "ScsiPortStartIoSynchronized: Enter routine\n");
+
+ irpstack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ ScsiDebugPrint(3, "SpPortStartIoSynchronized: SRB %lx\n",
+ Srb);
+
+ ScsiDebugPrint(3, "SpPortStartIoSynchronized: IRP %lx\n",
+ DeviceObject->CurrentIrp);
+
+ //
+ // Disable all synchronous transfers.
+ //
+
+ Srb->SrbFlags |=
+ (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT | SRB_FLAGS_DISABLE_AUTOSENSE);
+
+ return deviceExtension->HwStartIo(
+ deviceExtension->HwDeviceExtension,
+ Srb
+ );
+
+} // end SpStartIoSynchronized()
+
+
+BOOLEAN
+ScsiPortInterrupt(
+ IN PKINTERRUPT Interrupt,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Interrupt
+
+ Device Object
+
+Return Value:
+
+ Returns TRUE if interrupt expected.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ if (deviceExtension->HwInterrupt != NULL) {
+
+ if (deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+ }
+
+ return(FALSE);
+
+} // end ScsiPortInterrupt()
+
+
+VOID
+ScsiPortCompletionDpc(
+ IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Dpc
+ DeviceObject
+ Irp - not used
+ Context - not used
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpstack;
+ PSCSI_REQUEST_BLOCK Srb;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Context);
+
+ ScsiDebugPrint(3, "ScsiPortCompletionDpc Entered\n");
+
+ //
+ // Acquire the spinlock to protect the flags structure and the saved
+ // interrupt context.
+ //
+
+ KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
+
+ //
+ // Check for a flush DMA adapter object request.
+ //
+
+ if (deviceExtension->InterruptFlags & PD_FLUSH_ADAPTER_BUFFERS) {
+
+ //
+ // Call IoFlushAdapterBuffers using the parameters saved from the last
+ // IoMapTransfer call.
+ //
+
+ IoFlushAdapterBuffers(
+ deviceExtension->DmaAdapterObject,
+ ((PIRP)deviceExtension->FlushAdapterParameters.Srb->OriginalRequest)
+ ->MdlAddress,
+ deviceExtension->MapRegisterBase,
+ deviceExtension->FlushAdapterParameters.LogicalAddress,
+ deviceExtension->FlushAdapterParameters.Length,
+ (BOOLEAN)(deviceExtension->FlushAdapterParameters.Srb->SrbFlags
+ & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ }
+
+ //
+ // Check for an IoMapTransfer DMA request.
+ //
+
+ if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
+
+ //
+ // Call IoMapTransfer using the parameters saved from the
+ // interrupt level.
+ //
+
+ IoMapTransfer(
+ deviceExtension->DmaAdapterObject,
+ ((PIRP)deviceExtension->MapTransferParameters.Srb->OriginalRequest)
+ ->MdlAddress,
+ deviceExtension->MapRegisterBase,
+ deviceExtension->MapTransferParameters.LogicalAddress,
+ &deviceExtension->MapTransferParameters.Length,
+ (BOOLEAN)(deviceExtension->MapTransferParameters.Srb->SrbFlags
+ & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ //
+ // Save the paramters for IoFlushAdapterBuffers.
+ //
+
+ deviceExtension->FlushAdapterParameters =
+ deviceExtension->MapTransferParameters;
+
+ //
+ // If necessary notify the mini-port driver that the DMA has been
+ // started.
+ //
+
+ if (deviceExtension->HwDmaStarted) {
+ KeSynchronizeExecution(
+ &deviceExtension->InterruptObject,
+ (PKSYNCHRONIZE_ROUTINE) deviceExtension->HwDmaStarted,
+ deviceExtension->HwDeviceExtension
+ );
+ }
+
+ }
+
+ //
+ // Process any completed requests.
+ //
+
+ while (deviceExtension->CompletedRequests != NULL) {
+
+ Irp = deviceExtension->CompletedRequests;
+ irpstack = IoGetCurrentIrpStackLocation(Irp);
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ luExtension =
+ GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
+
+ ScsiDebugPrint(3, "ScsiPortCompletionDpc: SRB %lx\n", Srb);
+ ScsiDebugPrint(3, "ScsiPortCompletionDpc: IRP %lx\n", Irp);
+
+ //
+ // Remove the request from the linked-list.
+ //
+
+ deviceExtension->CompletedRequests =
+ irpstack->Parameters.Others.Argument3;
+
+ //
+ // Reset request timeout counter.
+ //
+
+ luExtension->RequestTimeoutCounter = -1;
+
+ //
+ // Flush the adapter buffers if necessary.
+ //
+
+ if (luExtension->MapRegisterBase) {
+
+ //
+ // Since we are a master call I/O flush adapter buffers with a NULL
+ // adapter.
+ //
+
+ IoFlushAdapterBuffers(
+ NULL,
+ Irp->MdlAddress,
+ luExtension->MapRegisterBase,
+ Srb->DataBuffer,
+ Srb->DataTransferLength,
+ (BOOLEAN) (Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ //
+ // Free the map registers.
+ //
+
+ IoFreeMapRegisters(
+ deviceExtension->DmaAdapterObject,
+ luExtension->MapRegisterBase,
+ luExtension->NumberOfMapRegisters
+ );
+
+ //
+ // Clear the MapRegisterBase.
+ //
+
+ luExtension->MapRegisterBase = NULL;
+
+ }
+
+ //
+ // Set IRP status. Class drivers will reset IRP status based
+ // on request sense if error.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Move bytes transfered to IRP.
+ //
+
+ Irp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // If success then start next packet.
+ // Not starting packet effectively
+ // freezes the queue.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
+
+ ScsiDebugPrint(
+ 2,
+ "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
+ Irp
+ );
+
+ IoCompleteRequest(Irp, 2);
+
+ } else {
+
+ if ( Srb->ScsiStatus == SCSISTAT_BUSY &&
+ (luExtension->RetryCount++ < 2)) {
+ //
+ // If busy status is returned, then indicate that the logical
+ // unit is busy. The timeout code will restart the request
+ // when it fires. Reset the status to pending.
+ //
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+ luExtension->CurrentRequest = Irp;
+ luExtension->Flags |= PD_LOGICAL_UNIT_IS_BUSY;
+ } else {
+
+
+ ScsiDebugPrint(
+ 3,
+ "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
+ Irp
+ );
+
+ IoCompleteRequest(Irp, 2);
+ }
+ }
+ }
+
+ //
+ // Release the spinlock.
+ //
+
+ KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
+
+ return;
+
+} // end ScsiPortCompletionDpc()
+
+
+ARC_STATUS
+IssueInquiry(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PLUNINFO LunInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Build IRP, SRB and CDB for SCSI INQUIRY command.
+
+Arguments:
+
+ DeviceExtension - address of adapter's device object extension.
+ LunInfo - address of buffer for INQUIRY information.
+
+Return Value:
+
+ ARC_STATUS
+
+--*/
+
+{
+ PIRP irp;
+ PIO_STACK_LOCATION irpstack;
+ PCDB cdb;
+ PSCSI_REQUEST_BLOCK srb;
+ ARC_STATUS status;
+ ULONG retryCount = 0;
+
+ ScsiDebugPrint(3,"IssueInquiry: Enter routine\n");
+
+ if (InquiryDataBuffer == NULL) {
+ return ENOMEM;
+ }
+
+inquiryRetry:
+
+ //
+ // Build IRP for this request.
+ //
+
+ irp = InitializeIrp(
+ &PrimarySrb,
+ IRP_MJ_SCSI,
+ DeviceExtension->DeviceObject,
+ (PVOID)InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE
+ );
+
+ irpstack = IoGetNextIrpStackLocation(irp);
+
+ //
+ // Set major and minor codes.
+ //
+
+ irpstack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Fill in SRB fields.
+ //
+
+ irpstack->Parameters.Others.Argument1 = &PrimarySrb;
+ srb = &PrimarySrb.Srb;
+
+ srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+ 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_FLAGS_DISABLE_DISCONNECT;
+
+ srb->SrbStatus = srb->ScsiStatus = 0;
+
+ srb->OriginalRequest = irp;
+
+ srb->NextSrb = 0;
+
+ //
+ // Set timeout to 5 seconds.
+ //
+
+ srb->TimeOutValue = 5;
+
+ srb->CdbLength = 6;
+
+ srb->SenseInfoBufferLength = 0;
+ srb->SenseInfoBuffer = 0;
+
+ srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
+ srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+ cdb = (PCDB)srb->Cdb;
+
+ //
+ // Set CDB operation code.
+ //
+
+ cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+
+ //
+ // Set CDB LUN.
+ //
+
+ cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+ cdb->CDB6INQUIRY.Reserved1 = 0;
+
+ //
+ // Set allocation length to inquiry data buffer size.
+ //
+
+ cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+ //
+ // Zero reserve field and
+ // Set EVPD Page Code to zero.
+ // Set Control field to zero.
+ // (See SCSI-II Specification.)
+ //
+
+ cdb->CDB6INQUIRY.PageCode = 0;
+ cdb->CDB6INQUIRY.IReserved = 0;
+ cdb->CDB6INQUIRY.Control = 0;
+
+ //
+ // Call port driver to handle this request.
+ //
+
+ (VOID)IoCallDriver(DeviceExtension->DeviceObject, irp);
+
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ ScsiDebugPrint(2,"IssueInquiry: Inquiry failed SRB status %x\n",
+ srb->SrbStatus);
+
+ //
+ // NOTE: if INQUIRY fails with a data underrun,
+ // indicate success and let the class drivers
+ // determine whether the inquiry information
+ // is useful.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
+
+ //
+ // Copy INQUIRY buffer to LUNINFO.
+ //
+
+ ScsiDebugPrint(1,"IssueInquiry: Data underrun at TID %d\n",
+ LunInfo->TargetId);
+
+ RtlMoveMemory(LunInfo->InquiryData,
+ InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ status = STATUS_SUCCESS;
+
+ } else if ((SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT) && (retryCount++ < 2)) {
+
+ //
+ // If the selection did not time out then retry the request.
+ //
+
+ ScsiDebugPrint(2,"IssueInquiry: Retry %d\n", retryCount);
+ goto inquiryRetry;
+
+ } else {
+
+ status = EIO;
+
+ }
+
+
+ } else {
+
+ //
+ // Copy INQUIRY buffer to LUNINFO.
+ //
+
+ RtlMoveMemory(LunInfo->InquiryData,
+ InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ status = STATUS_SUCCESS;
+ }
+
+ return status;
+
+} // end IssueInquiry()
+
+
+PSCSI_BUS_SCAN_DATA
+ScsiBusScan(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ScsiBus,
+ IN UCHAR InitiatorBusId
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ DeviceExtension
+ ScsiBus
+
+Return Value:
+
+ SCSI configuration information
+
+
+--*/
+{
+ PSCSI_BUS_SCAN_DATA busScanData;
+ PLUNINFO lunInfo;
+ UCHAR target;
+ UCHAR device = 0;
+ PLOGICAL_UNIT_EXTENSION nextLogicalUnitExtension;
+
+ ScsiDebugPrint(3,"ScsiBusScan: Enter routine\n");
+
+ busScanData = ExAllocatePool(NonPagedPool,
+ sizeof(SCSI_BUS_SCAN_DATA));
+
+ if (busScanData == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return NULL;
+ }
+
+ RtlZeroMemory(busScanData,sizeof(SCSI_BUS_SCAN_DATA));
+
+ busScanData->Length = sizeof(SCSI_CONFIGURATION_INFO);
+
+ //
+ // Create first LUNINFO.
+ //
+
+ lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
+
+ if (lunInfo == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return NULL;
+ }
+
+ RtlZeroMemory(lunInfo, sizeof(LUNINFO));
+
+ //
+ // Create first logical unit extension.
+ //
+
+ nextLogicalUnitExtension = CreateLogicalUnitExtension(DeviceExtension);
+
+ if (nextLogicalUnitExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Link logical unit extension on list.
+ //
+
+ nextLogicalUnitExtension->NextLogicalUnit = DeviceExtension->LogicalUnitList;
+
+ DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
+
+ //
+ // Issue inquiry command to each target id to find devices.
+ //
+ // NOTE: Does not handle multiple logical units per target id.
+ //
+
+ for (target = 8; target > 0; target--) {
+
+ //
+ // This takes a long time so print a dot so the system doesn't look
+ // hung.
+ //
+
+ FwPrint(".");
+
+ if (InitiatorBusId == target-1) {
+ continue;
+ }
+
+ nextLogicalUnitExtension->PathId = lunInfo->PathId = ScsiBus;
+
+ nextLogicalUnitExtension->TargetId = lunInfo->TargetId = target-1;
+
+ nextLogicalUnitExtension->Lun = lunInfo->Lun = 0;
+
+ //
+ // Rezero hardware logigal unit extension if it's being recycled.
+ //
+
+ if (DeviceExtension->HwLogicalUnitExtensionSize) {
+
+ if (nextLogicalUnitExtension->SpecificLuExtension) {
+
+ RtlZeroMemory(nextLogicalUnitExtension->SpecificLuExtension,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+ }
+
+ }
+
+ //
+ // Issue inquiry command.
+ //
+
+ ScsiDebugPrint(3,"ScsiBusScan: LunInfo at %lx\n", lunInfo);
+
+ ScsiDebugPrint(3, "ScsiBusScan: Device extension %lx\n",
+ DeviceExtension);
+
+ ScsiDebugPrint(2,"ScsiBusScan: Try TargetId %d LUN 0\n", target-1);
+
+ if (IssueInquiry(DeviceExtension, lunInfo) == ESUCCESS) {
+
+ ScsiDebugPrint(1,"ScsiBusScan: Found Device %d", device);
+ ScsiDebugPrint(1," at Target Id %d", lunInfo->TargetId);
+ ScsiDebugPrint(1," LUN %d\n", lunInfo->Lun);
+ //
+ // Link LUN information on list.
+ //
+
+ lunInfo->NextLunInfo = busScanData->LunInfoList;
+ busScanData->LunInfoList = lunInfo;
+
+ //
+ // This buffer is used. Get another.
+ //
+
+ lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
+
+ if (lunInfo == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return busScanData;
+ }
+
+ RtlZeroMemory(lunInfo, sizeof(LUNINFO));
+
+ //
+ // Current logical unit extension claimed.
+ // Create next logical unit.
+ //
+
+ nextLogicalUnitExtension =
+ CreateLogicalUnitExtension(DeviceExtension);
+
+ if (nextLogicalUnitExtension == NULL) {
+ return busScanData;
+ }
+
+ //
+ // Link logical unit extension on list.
+ //
+
+ nextLogicalUnitExtension->NextLogicalUnit =
+ DeviceExtension->LogicalUnitList;
+
+ DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
+
+ device++;
+ }
+
+ } // end for (target ...
+
+ //
+ // Remove unused logicalunit extension from list.
+ //
+
+ DeviceExtension->LogicalUnitList =
+ DeviceExtension->LogicalUnitList->NextLogicalUnit;
+
+ ExFreePool(nextLogicalUnitExtension);
+ ExFreePool(lunInfo);
+
+ busScanData->NumberOfLogicalUnits = device;
+ ScsiDebugPrint(1,
+ "ScsiBusScan: Found %d devices on SCSI bus %d\n",
+ device,
+ ScsiBus);
+
+ return busScanData;
+
+} // end ScsiBusScan()
+
+
+PLOGICAL_UNIT_EXTENSION
+CreateLogicalUnitExtension(
+ IN PDEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Create logical unit extension.
+
+Arguments:
+
+ DeviceExtension
+ PathId
+
+Return Value:
+
+ Logical unit extension
+
+
+--*/
+{
+ PLOGICAL_UNIT_EXTENSION logicalUnitExtension;
+
+ //
+ // Create logical unit extension and link in chain.
+ //
+
+ logicalUnitExtension =
+ ExAllocatePool(NonPagedPool, sizeof(LOGICAL_UNIT_EXTENSION));
+
+ if (logicalUnitExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Zero logical unit extension.
+ //
+
+ RtlZeroMemory(logicalUnitExtension, sizeof(LOGICAL_UNIT_EXTENSION));
+
+ //
+ // Allocate miniport driver logical unit extension if necessary.
+ //
+
+ if (DeviceExtension->HwLogicalUnitExtensionSize) {
+
+ logicalUnitExtension->SpecificLuExtension =
+ ExAllocatePool(NonPagedPool,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+
+ if (logicalUnitExtension->SpecificLuExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Zero hardware logical unit extension.
+ //
+
+ RtlZeroMemory(logicalUnitExtension->SpecificLuExtension,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+ }
+
+ //
+ // Set timer counters in LogicalUnits to -1 to indicate no
+ // outstanding requests.
+ //
+
+ logicalUnitExtension->RequestTimeoutCounter = -1;
+
+ //
+ // Clear the current request field.
+ //
+
+ logicalUnitExtension->CurrentRequest = NULL;
+
+ return logicalUnitExtension;
+
+} // end CreateLogicalUnitExtension()
+
+
+//
+// Routines providing service to hardware dependent driver.
+//
+
+SCSI_PHYSICAL_ADDRESS
+ScsiPortGetPhysicalAddress(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID VirtualAddress,
+ OUT ULONG *Length
+)
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PSRB_SCATTER_GATHER scatterList;
+ PIRP irp;
+ PMDL mdl;
+ ULONG byteOffset;
+ ULONG whichPage;
+ PULONG pages;
+ ULONG address;
+
+ if (Srb == NULL) {
+
+ if (deviceExtension->SrbExtensionZonePool) {
+
+ address = (PUCHAR) VirtualAddress - (PUCHAR) deviceExtension->SrbExtensionZonePool +
+ deviceExtension->PhysicalZoneBase;
+
+ } else {
+
+ address = MmGetPhysicalAddress(VirtualAddress).LowPart;
+ }
+
+ //
+ // Return the requested length.
+ //
+
+ } else if (deviceExtension->MasterWithAdapter) {
+
+ //
+ // A scatter/gather list has already been allocated use it to determine
+ // the physical address and length. Get the scatter/gather list.
+ //
+
+ scatterList = GetLogicalUnitExtension(deviceExtension, Srb->TargetId)
+ ->ScatterGather;
+
+ //
+ // Calculate byte offset into the data buffer.
+ //
+
+ byteOffset = (PCHAR) VirtualAddress - (PCHAR) Srb->DataBuffer;
+
+ //
+ // Find the appropirate entry in the scatter/gatter list.
+ //
+
+ while (byteOffset >= scatterList->Length) {
+
+ byteOffset -= scatterList->Length;
+ scatterList++;
+ }
+
+ //
+ // Calculate the physical address and length to be returned.
+ //
+
+ *Length = scatterList->Length - byteOffset;
+ return(ScsiPortConvertUlongToPhysicalAddress(scatterList->PhysicalAddress + byteOffset));
+
+ } else {
+
+ //
+ // Get IRP from SRB.
+ //
+
+ irp = Srb->OriginalRequest;
+
+ //
+ // Get MDL from IRP.
+ //
+
+ mdl = irp->MdlAddress;
+
+ //
+ // Calculate byte offset from
+ // beginning of first physical page.
+ //
+
+ byteOffset = (PCHAR)VirtualAddress - (PCHAR)mdl->StartVa;
+
+ //
+ // Calculate which physical page.
+ //
+
+ whichPage = byteOffset >> PAGE_SHIFT;
+
+ //
+ // Calculate beginning of physical page array.
+ //
+
+ pages = (PULONG)(mdl + 1);
+
+ //
+ // Calculate physical address.
+ //
+
+ address = (pages[whichPage] << PAGE_SHIFT) +
+ BYTE_OFFSET(VirtualAddress);
+
+ //
+ // Assume the buffer is contiguous. Just return the requested length.
+ //
+ }
+
+ return ScsiPortConvertUlongToPhysicalAddress(address);
+
+} // end ScsiPortGetPhysicalAddress()
+
+
+PVOID
+ScsiPortGetVirtualAddress(
+ IN PVOID HwDeviceExtension,
+ IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is returns a virtual address associated with a
+ physical address, if the physical address was obtained by a
+ call to ScsiPortGetPhysicalAddress.
+
+Arguments:
+
+ PhysicalAddress
+
+Return Value:
+
+ Virtual address if physical page hashed.
+ NULL if physical page not found in hash.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PVOID address;
+
+
+
+ address = ScsiPortConvertPhysicalAddressToUlong(PhysicalAddress)
+ - deviceExtension->PhysicalZoneBase +
+ (PUCHAR)deviceExtension->SrbExtensionZonePool;
+
+ return address;
+
+} // end ScsiPortGetVirtualAddress()
+
+
+PVOID
+ScsiPortGetLogicalUnit(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun
+ )
+
+/*++
+
+Routine Description:
+
+ Walk port driver's logical unit extension list searching
+ for entry.
+
+Arguments:
+
+ HwDeviceExtension - The port driver's device extension follows
+ the miniport's device extension and contains a pointer to
+ the logical device extension list.
+
+ PathId, TargetId and Lun - identify which logical unit on the
+ SCSI buses.
+
+Return Value:
+
+ If entry found return miniport driver's logical unit extension.
+ Else, return NULL.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+
+ ScsiDebugPrint(3, "ScsiPortGetLogicalUnit: TargetId %d\n",
+ TargetId);
+
+ //
+ // Get pointer to port driver device extension.
+ //
+
+ deviceExtension = (PDEVICE_EXTENSION)HwDeviceExtension -1;
+
+ //
+ // Get pointer to logical unit list.
+ //
+
+ logicalUnit = deviceExtension->LogicalUnitList;
+
+ //
+ // Walk list looking at target id for requested logical unit extension.
+ //
+
+ while (logicalUnit != NULL) {
+
+ if ((logicalUnit->TargetId == TargetId) &&
+ (logicalUnit->PathId == PathId) &&
+ (logicalUnit->Lun == Lun)) {
+
+ //
+ // Logical unit extension found.
+ // Return specific logical unit extension.
+ //
+
+ return logicalUnit->SpecificLuExtension;
+ }
+
+ //
+ // Get next logical unit.
+ //
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ //
+ // Requested logical unit extension not found.
+ //
+
+ return NULL;
+
+} // end ScsiPortGetLogicalUnit()
+
+VOID
+ScsiPortNotification(
+ IN SCSI_NOTIFICATION_TYPE NotificationType,
+ IN PVOID HwDeviceExtension,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) HwDeviceExtension - 1;
+ PIO_STACK_LOCATION irpstack;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PSCSI_REQUEST_BLOCK srb;
+ va_list(ap);
+
+ va_start(ap, HwDeviceExtension);
+
+ switch (NotificationType) {
+
+ case NextLuRequest:
+ case NextRequest:
+
+ //
+ // Start next packet on adapter's queue.
+ //
+
+ ScsiDebugPrint(3,
+ "ScsiPortNotification: Start next request\n");
+
+ deviceExtension->InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
+ break;
+
+ case RequestComplete:
+
+ ScsiDebugPrint(3,
+ "ScsiPortNotification: Request complete\n");
+
+ srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
+
+ if (srb->SrbStatus == SRB_STATUS_ERROR) {
+ }
+
+ //
+ // Link the completed request into a forward-linked list of IRPs.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(
+ ((PIRP) srb->OriginalRequest)
+ );
+
+ irpstack->Parameters.Others.Argument3 =
+ deviceExtension->CompletedRequests;
+
+ deviceExtension->CompletedRequests = srb->OriginalRequest;
+
+ //
+ // Set logical unit current request to NULL
+ // to prevent race condition.
+ //
+
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
+
+ logicalUnit->CurrentRequest = NULL;
+
+ break;
+
+ case ResetDetected:
+
+ break;
+
+ case CallDisableInterrupts:
+
+ ASSERT(deviceExtension->Flags & PD_DISABLE_INTERRUPTS);
+
+ //
+ // The mini-port wants us to call the specified routine
+ // with interrupts disabled. This is done after the current
+ // HwRequestInterrutp routine completes. Indicate the call is
+ // needed and save the routine to be called.
+ //
+
+ deviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;
+
+ deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
+
+ break;
+
+ case CallEnableInterrupts:
+
+ ASSERT(!(deviceExtension->Flags & PD_DISABLE_INTERRUPTS));
+
+ //
+ // The mini-port wants us to call the specified routine
+ // with interrupts enabled this is done from the DPC.
+ // Disable calls to the interrupt routine, indicate the call is
+ // needed and save the routine to be called.
+ //
+
+ deviceExtension->Flags |= PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;
+
+ deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
+
+ break;
+
+ case RequestTimerCall:
+
+ deviceExtension->HwTimerRequest = va_arg(ap, PHW_INTERRUPT);
+ deviceExtension->TimerValue =
+ (va_arg(ap, ULONG) + PD_INTERLOOP_STALL) / PD_INTERLOOP_STALL;
+ break;
+ }
+
+ va_end(ap);
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+} // end ScsiPortNotification()
+
+
+VOID
+ScsiPortFlushDma(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks to see if the perivious IoMapTransfer has been done
+ started. If it has not, then the PD_MAP_TRANSER flag is cleared, and the
+ routine returns; otherwise, this routine schedules a DPC which will call
+ IoFlushAdapter buffers.
+
+Arguments:
+
+ HwDeviceExtension - Supplies a the hardware device extension for the
+ host bus adapter which will be doing the data transfer.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
+
+ //
+ // The transfer has not been started so just clear the map transfer
+ // flag and return.
+ //
+
+ deviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
+ return;
+ }
+
+ deviceExtension->InterruptFlags |= PD_FLUSH_ADAPTER_BUFFERS;
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+ return;
+
+}
+
+VOID
+ScsiPortIoMapTransfer(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID LogicalAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Saves the parameters for the call to IoMapTransfer and schedules the DPC
+ if necessary.
+
+Arguments:
+
+ HwDeviceExtension - Supplies a the hardware device extension for the
+ host bus adapter which will be doing the data transfer.
+
+ Srb - Supplies the particular request that data transfer is for.
+
+ LogicalAddress - Supplies the logical address where the transfer should
+ begin.
+
+ Length - Supplies the maximum length in bytes of the transfer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ //
+ // Make sure this host bus adapter has an Dma adapter object.
+ //
+
+ if (deviceExtension->DmaAdapterObject == NULL) {
+ //
+ // No DMA adapter, no work.
+ //
+ return;
+ }
+
+ deviceExtension->MapTransferParameters.Srb = Srb;
+ deviceExtension->MapTransferParameters.LogicalAddress = LogicalAddress;
+ deviceExtension->MapTransferParameters.Length = Length;
+
+ deviceExtension->InterruptFlags |= PD_MAP_TRANSFER;
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+} // end ScsiPortIoMapTransfer()
+
+
+VOID
+IssueRequestSense(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK FailingSrb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a REQUEST SENSE request and uses IoCallDriver to
+ renter the driver. The completion routine cleans up the data structures
+ and processes the logical unit queue according to the flags.
+
+ A pointer to failing SRB is stored at the end of the request sense
+ Srb, so that the completion routine can find it.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+ FailingSrb - Supplies a pointer to the request that the request sense
+ is being done for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpstack;
+ PIRP Irp;
+ PSCSI_REQUEST_BLOCK Srb;
+ PCDB cdb;
+ PVOID *Pointer;
+
+ ScsiDebugPrint(3,"IssueRequestSense: Enter routine\n");
+
+ //
+ // Allocate Srb from non-paged pool
+ // plus room for a pointer to the failing IRP.
+ // Since this routine is in an error-handling
+ // path and a shortterm allocation
+ // NonPagedMustSucceed is requested.
+ //
+
+ Srb = &RequestSenseSrb.Srb;
+
+ //
+ // Allocate an IRP to issue the REQUEST SENSE request.
+ //
+
+ Irp = InitializeIrp(
+ &RequestSenseSrb,
+ IRP_MJ_READ,
+ deviceExtension->DeviceObject,
+ FailingSrb->SenseInfoBuffer,
+ FailingSrb->SenseInfoBufferLength
+ );
+
+ irpstack = IoGetNextIrpStackLocation(Irp);
+
+ irpstack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Save the Failing SRB after the request sense Srb.
+ //
+
+ Pointer = (PVOID *) (Srb+1);
+ *Pointer = FailingSrb;
+
+ //
+ // Build the REQUEST SENSE CDB.
+ //
+
+ 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)FailingSrb->SenseInfoBufferLength;
+ cdb->CDB6INQUIRY.Control = 0;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ irpstack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ //
+ // Set up IRP Address.
+ //
+
+ Srb->OriginalRequest = Irp;
+
+ Srb->NextSrb = 0;
+
+ //
+ // Set up SCSI bus address.
+ //
+
+ Srb->TargetId = FailingSrb->TargetId;
+ Srb->Lun = FailingSrb->Lun;
+ Srb->PathId = FailingSrb->PathId;
+ Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ //
+ // Set timeout value to 2 seconds.
+ //
+
+ Srb->TimeOutValue = 2;
+
+ //
+ // Disable auto request sense.
+ //
+
+ Srb->SenseInfoBufferLength = 0;
+
+ //
+ // Sense buffer is in stack.
+ //
+
+ Srb->SenseInfoBuffer = NULL;
+
+ //
+ // Set read and bypass frozen queue bits in flags.
+ //
+
+ //
+ // Set a speical flags to indicate the logical unit queue should be by
+ // passed and that no queue processing should be done when the request
+ // completes.
+ //
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
+
+ Srb->DataBuffer = FailingSrb->SenseInfoBuffer;
+
+ //
+ // Set the transfer length.
+ //
+
+ Srb->DataTransferLength = FailingSrb->SenseInfoBufferLength;
+
+ //
+ // Zero out status.
+ //
+
+ Srb->ScsiStatus = Srb->SrbStatus = 0;
+
+ (VOID)IoCallDriver(deviceExtension->DeviceObject, Irp);
+
+ ScsiPortInternalCompletion(deviceExtension->DeviceObject, Irp, Srb);
+
+ return;
+
+} // end IssueRequestSense()
+
+
+VOID
+ScsiPortInternalCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Device object
+ IRP
+ Context - pointer to SRB
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK failingSrb;
+ PIRP failingIrp;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ ScsiDebugPrint(3,"ScsiPortInternalCompletion: Enter routine\n");
+
+ //
+ // Request sense completed. If successful or data over/underrun
+ // get the failing SRB and indicate that the sense information
+ // is valid. The class driver will check for underrun and determine
+ // if there is enough sense information to be useful.
+ //
+
+ if ((SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
+ (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) {
+
+ //
+ // Get a pointer to failing Irp and Srb.
+ //
+
+ failingSrb = *((PVOID *) (srb+1));
+ failingIrp = failingSrb->OriginalRequest;
+
+ //
+ // Report sense buffer is valid.
+ //
+
+ failingSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+
+ //
+ // Copy bytes transferred to failing SRB
+ // request sense length field to communicate
+ // to the class drivers the number of valid
+ // sense bytes.
+ //
+
+ failingSrb->SenseInfoBufferLength = (UCHAR) srb->DataTransferLength;
+
+ }
+
+} // ScsiPortInternalCompletion()
+
+
+VOID
+ScsiPortTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+
+ UNREFERENCED_PARAMETER(Context);
+
+ logicalUnit = deviceExtension->LogicalUnitList;
+
+ //
+ // NOTE: The use of Current request needs to be synchronized with the
+ // clearing of current request.
+ //
+
+ while (logicalUnit != NULL) {
+
+ //
+ // Check for busy requests.
+ //
+
+ if (logicalUnit->Flags & PD_LOGICAL_UNIT_IS_BUSY) {
+
+ ScsiDebugPrint(1,"ScsiPortTickHandler: Retrying busy status request\n");
+
+ //
+ // Clear the busy flag and retry the request.
+ //
+
+ logicalUnit->Flags &= ~PD_LOGICAL_UNIT_IS_BUSY;
+
+ ScsiPortStartIo(DeviceObject, logicalUnit->CurrentRequest);
+
+ } else if (logicalUnit->RequestTimeoutCounter == 0) {
+
+ //
+ // Request timed out.
+ //
+
+ ScsiDebugPrint(1, "ScsiPortTickHandler: Request timed out\n");
+
+ //
+ // Reset request timeout counter to unused state.
+ //
+
+ logicalUnit->RequestTimeoutCounter = -1;
+
+ //
+ // Build and send request to abort command.
+ //
+
+ IssueAbortRequest(deviceExtension, logicalUnit->CurrentRequest);
+ } else if (logicalUnit->RequestTimeoutCounter != -1) {
+
+ ScsiDebugPrint(1, "ScsiPortTickHandler: Timeout value %lx\n",logicalUnit->RequestTimeoutCounter);
+ logicalUnit->RequestTimeoutCounter--;
+ }
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ return;
+
+} // end ScsiPortTickHandler()
+
+
+VOID
+IssueAbortRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP FailingIrp
+ )
+
+/*++
+
+Routine Description:
+
+ A request timed out and to clear the request at the HBA
+ an ABORT request is issued. But first, if the request
+ that timed out was an ABORT command, then reset the
+ adapter instead.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+ FailingIrp - Supplies a pointer to the request that is to be aborted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG j;
+ ScsiDebugPrint(3,"IssueAbortRequest: Enter routine\n");
+
+
+ //
+ // A request to abort failed.
+ // Need to reset the adapter.
+ //
+
+ ScsiDebugPrint(1,"IssueAbort: Request timed out resetting the bus.\n");
+
+
+ if (!DeviceExtension->HwReset(
+ DeviceExtension->HwDeviceExtension,
+ 0)){
+
+ ScsiDebugPrint(1,"Reset SCSI bus failed\n");
+ }
+
+ //
+ // Call the interupt handler for a few microseconds to clear any reset
+ // interrupts.
+ //
+
+ for (j = 0; j < 1000 * 100; j++) {
+
+ FwStallExecution(10);
+ if (DeviceExtension->HwInterrupt != NULL) {
+ DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
+ }
+
+ }
+
+ //
+ // Wait 2 seconds for the devices to recover after the reset.
+ //
+
+ //FwStallExecution(2 * 1000 * 1000);
+ FwStallExecution(2 * 1000 * 100);
+
+ return;
+
+
+} // end IssueAbortRequest()
+
+
+BOOLEAN
+SpGetInterruptState(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the InterruptFlags, MapTransferParameters and
+ CompletedRequests fields and clears the InterruptFlags.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension for this
+ SCSI port.
+
+Return Value:
+
+ Always returns TRUE.
+
+Notes:
+
+ Called via KeSynchronizeExecution.
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ //
+ // Move the interrupt state to save area.
+ //
+
+ deviceExtension->InterruptFlags = deviceExtension->InterruptFlags;
+ deviceExtension->CompletedRequests = deviceExtension->CompletedRequests;
+ deviceExtension->MapTransferParameters = deviceExtension->MapTransferParameters;
+
+ //
+ // Clear the interrupt state.
+ //
+
+ deviceExtension->InterruptFlags = 0;
+ deviceExtension->CompletedRequests = NULL;
+
+ return(TRUE);
+}
+
+VOID
+ScsiPortLogError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an error log entry, copies the supplied text
+ to it, and requests that it be written to the error log file.
+
+Arguments:
+
+ DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
+
+ TargetId, Lun and PathId - specify device address on a SCSI bus.
+
+ ErrorCode - Supplies an error code indicating the type of error.
+
+ UniqueId - Supplies a unique identifier for the error.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR errorCodeString;
+
+ switch (ErrorCode) {
+ case SP_BUS_PARITY_ERROR:
+ errorCodeString = "SCSI bus partity error";
+ break;
+
+ case SP_UNEXPECTED_DISCONNECT:
+ errorCodeString = "Unexpected disconnect";
+ break;
+
+ case SP_INVALID_RESELECTION:
+ errorCodeString = "Invalid reselection";
+ break;
+
+ case SP_BUS_TIME_OUT:
+ errorCodeString = "SCSI bus time out";
+ break;
+
+ case SP_PROTOCOL_ERROR:
+ errorCodeString = "SCSI protocol error";
+ break;
+
+ case SP_INTERNAL_ADAPTER_ERROR:
+ errorCodeString = "Internal adapter error";
+ break;
+
+ default:
+ errorCodeString = "Unknown error code";
+ break;
+
+ }
+
+ DebugPrint((0,"\n\nLogErrorEntry: Logging SCSI error packet. ErrorCode = %s.\n",
+ errorCodeString
+ ));
+ DebugPrint((0,
+ "PathId = %2x, TargetId = %2x, Lun = %2x, UniqueId = %x.\n\n",
+ PathId,
+ TargetId,
+ Lun,
+ UniqueId
+ ));
+
+
+ return;
+
+} // end ScsiPortLogError()
+
+
+VOID
+ScsiPortCompleteRequest(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR SrbStatus
+ )
+
+/*++
+
+Routine Description:
+
+ Complete all active requests for the specified logical unit.
+
+Arguments:
+
+ DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
+
+ TargetId, Lun and PathId - specify device address on a SCSI bus.
+
+ SrbStatus - Status to be returned in each completed SRB.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK failingSrb;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PIRP nextIrp;
+ PIO_STACK_LOCATION irpstack;
+
+ UNREFERENCED_PARAMETER(PathId);
+ UNREFERENCED_PARAMETER(Lun);
+
+ if (TargetId == (UCHAR)(-1)) {
+
+ //
+ // Complete requests for all units on this bus.
+ //
+
+ luExtension = deviceExtension->LogicalUnitList;
+
+ while (luExtension != NULL) {
+
+ ScsiDebugPrint(2,
+ "ScsiPortCompleteRequest: Complete requests for targetid %d\n",
+ luExtension->TargetId);
+
+ //
+ // Complete requests until queue is empty.
+ //
+
+ if ((nextIrp = luExtension->CurrentRequest) != NULL &&
+ !(luExtension->Flags & PD_LOGICAL_UNIT_IS_BUSY)) {
+
+ ScsiDebugPrint(3,"ScsiPortCompleteRequest: Current request %lx\n",
+ nextIrp);
+
+ //
+ // Get SRB address from current IRP stack.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Just in case this is an abort request,
+ // get pointer to failingSrb.
+ //
+
+ failingSrb = Srb->NextSrb;
+
+ //
+ // Update SRB status.
+ //
+
+ Srb->SrbStatus = SrbStatus;
+
+ //
+ // Indicate no bytes transferred.
+ //
+
+ Srb->DataTransferLength = 0;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ Srb);
+
+ if (failingSrb) {
+
+ //
+ // This was an abort request. The failing
+ // SRB must also be completed.
+ //
+
+ failingSrb->SrbStatus = SrbStatus;
+ failingSrb->DataTransferLength = 0;
+
+ //
+ // Get IRP from SRB.
+ //
+
+ nextIrp = failingSrb->OriginalRequest;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information =
+ failingSrb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ failingSrb);
+ }
+
+ } // end if
+
+ luExtension = luExtension->NextLogicalUnit;
+
+ } // end while
+
+ } else {
+
+ //
+ // Complete all requests for this logical unit.
+ //
+
+ ScsiDebugPrint(2,
+ "ScsiPortCompleteRequest: Complete requests for targetid %d\n",
+ TargetId);
+
+
+ luExtension =
+ GetLogicalUnitExtension(deviceExtension, TargetId);
+
+ //
+ // Complete requests until queue is empty.
+ //
+
+ if ((nextIrp = luExtension->CurrentRequest) != NULL) {
+
+ ScsiDebugPrint(3,"ScsiPortCompleteRequest: Current request %lx\n",
+ nextIrp);
+
+ //
+ // Get SRB address from current IRP stack.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Update SRB status.
+ //
+
+ Srb->SrbStatus = SrbStatus;
+
+ //
+ // Indicate no bytes transferred.
+ //
+
+ Srb->DataTransferLength = 0;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ Srb);
+
+ } // end while
+
+ } // end if ... else
+
+ return;
+
+
+} // end ScsiPortCompleteRequest()
+
+
+VOID
+ScsiPortMoveMemory(
+ IN PVOID WriteBuffer,
+ IN PVOID ReadBuffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from one buffer into another.
+
+Arguments:
+
+ ReadBuffer - source
+ WriteBuffer - destination
+ Length - number of bytes to copy
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
+
+} // end ScsiPortMoveMemory()
+
+
+VOID
+ScsiPortStallExecution(
+ ULONG Delay
+ )
+/*++
+
+Routine Description:
+
+ Wait number of microseconds in tight processor loop.
+
+Arguments:
+
+ Delay - number of microseconds to wait.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FwStallExecution(Delay);
+
+} // end ScsiPortStallExecution()
+
+
+PLOGICAL_UNIT_EXTENSION
+GetLogicalUnitExtension(
+ PDEVICE_EXTENSION deviceExtension,
+ UCHAR TargetId
+ )
+
+/*++
+
+Routine Description:
+
+ Walk logical unit extension list looking for
+ extension with matching target id.
+
+Arguments:
+
+ deviceExtension
+ TargetId
+
+Return Value:
+
+ Requested logical unit extension if found,
+ else NULL.
+
+--*/
+
+{
+ PLOGICAL_UNIT_EXTENSION logicalUnit = deviceExtension->LogicalUnitList;
+
+ while (logicalUnit != NULL) {
+
+ if (logicalUnit->TargetId == TargetId) {
+
+ return logicalUnit;
+ }
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ //
+ // Logical unit extension not found.
+ //
+
+ return (PLOGICAL_UNIT_EXTENSION)NULL;
+
+} // end GetLogicalUnitExtension()
+
+
+VOID
+ScsiDebugPrint(
+ ULONG DebugPrintLevel,
+ PCCHAR DebugMessage,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Debug print for all SCSI drivers
+
+Arguments:
+
+ Debug print level between 0 and 3, with 3 being the most verbose.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ va_list ap;
+
+ va_start( ap, DebugMessage );
+
+ if (DebugPrintLevel <= ScsiDebug) {
+
+ char buffer[128];
+
+ vsprintf(buffer, DebugMessage, ap);
+ DbgPrint(buffer);
+ DbgPrint("\r");
+ }
+
+ va_end(ap);
+}
+
+UCHAR
+ScsiPortReadPortUchar(
+ IN PUCHAR Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_UCHAR(Port));
+
+#else
+
+ return(READ_PORT_UCHAR(Port));
+
+#endif
+}
+
+USHORT
+ScsiPortReadPortUshort(
+ IN PUSHORT Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_USHORT(Port));
+
+#else
+
+ return(READ_PORT_USHORT(Port));
+
+#endif
+}
+
+ULONG
+ScsiPortReadPortUlong(
+ IN PULONG Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_ULONG(Port));
+
+#else
+
+ return(READ_PORT_ULONG(Port));
+
+#endif
+}
+
+UCHAR
+ScsiPortReadRegisterUchar(
+ IN PUCHAR Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_UCHAR(Register));
+
+}
+
+USHORT
+ScsiPortReadRegisterUshort(
+ IN PUSHORT Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_USHORT(Register));
+
+}
+
+ULONG
+ScsiPortReadRegisterUlong(
+ IN PULONG Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_ULONG(Register));
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUchar(
+ IN PUCHAR Register,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned bytes from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUshort(
+ IN PUSHORT Register,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned shorts from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUlong(
+ IN PULONG Register,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned longs from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortUchar(
+ IN PUCHAR Port,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_UCHAR(Port, Value);
+
+#else
+
+ WRITE_PORT_UCHAR(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWritePortUshort(
+ IN PUSHORT Port,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_USHORT(Port, Value);
+
+#else
+
+ WRITE_PORT_USHORT(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWritePortUlong(
+ IN PULONG Port,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_ULONG(Port, Value);
+
+#else
+
+ WRITE_PORT_ULONG(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWriteRegisterUchar(
+ IN PUCHAR Register,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_UCHAR(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterUshort(
+ IN PUSHORT Register,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_USHORT(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterUlong(
+ IN PULONG Register,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_ULONG(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUchar(
+ IN PUCHAR Register,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned bytes from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUshort(
+ IN PUSHORT Register,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned shorts from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUlong(
+ IN PULONG Register,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned longs from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
+
+}
+
+SCSI_PHYSICAL_ADDRESS
+ScsiPortConvertUlongToPhysicalAddress(
+ ULONG UlongAddress
+ )
+
+{
+ SCSI_PHYSICAL_ADDRESS physicalAddress;
+
+ physicalAddress.HighPart = 0;
+ physicalAddress.LowPart = UlongAddress;
+ return(physicalAddress);
+}
+
+#undef ScsiPortConvertPhysicalAddressToUlong
+
+ULONG
+ScsiPortConvertPhysicalAddressToUlong(
+ SCSI_PHYSICAL_ADDRESS Address
+ )
+{
+
+ return(Address.LowPart);
+}
+
+
+
+PIRP
+InitializeIrp(
+ PFULL_SCSI_REQUEST_BLOCK FullSrb,
+ CCHAR MajorFunction,
+ PVOID DeviceObject,
+ PVOID Buffer,
+ ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This funcition builds an IRP for use by the SCSI port driver and builds a
+ MDL list.
+
+Arguments:
+
+ FullSrb - Supplies a pointer to the full srb structure which contains the
+ Irp and Mdl.
+
+ MajorFunction - Supplies the major function code to initialize the Irp
+ entry.
+
+ DeviceObject - Supplies the device Object pointer to initialize the Irp
+ with.
+
+ Buffer - Supplies the virual address of the buffer for which the
+ Mdl should be built.
+
+ Length - Supplies the size of buffer for which the Mdl should be built.
+
+Return Value:
+
+ Returns a pointer to the initialized IRP.
+
+--*/
+
+{
+ PIRP irp;
+ PMDL mdl;
+ PULONG pageFrame;
+ ULONG frameNumber;
+ ULONG index;
+ ULONG numberOfPages;
+
+ irp = &FullSrb->Irp;
+ mdl = &FullSrb->Mdl;
+
+ irp->Tail.Overlay.CurrentStackLocation = &FullSrb->IrpStack[IRP_STACK_SIZE];
+
+ if (Buffer != NULL && Length != 0) {
+
+ //
+ // Build the memory descriptor list.
+ //
+
+ irp->MdlAddress = mdl;
+ mdl->Next = NULL;
+ mdl->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
+ mdl->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ mdl->ByteCount = Length;
+ mdl->ByteOffset = BYTE_OFFSET(Buffer);
+ mdl->MappedSystemVa = Buffer;
+ mdl->MdlFlags = MDL_MAPPED_TO_SYSTEM_VA;
+ pageFrame = (PULONG)(mdl + 1);
+ frameNumber = RtlLargeIntegerShiftRight(
+ MmGetPhysicalAddress(mdl->StartVa), PAGE_SHIFT).LowPart;
+ numberOfPages = (mdl->ByteCount +
+ mdl->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (index = 0; index < numberOfPages; index += 1) {
+ *pageFrame++ = frameNumber++;
+ }
+
+ } else {
+ irp->MdlAddress = NULL;
+ }
+
+ return(irp);
+}
+
+PVOID
+ScsiPortGetDeviceBase(
+ IN PVOID HwDeviceExtension,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG SystemIoBusNumber,
+ SCSI_PHYSICAL_ADDRESS IoAddress,
+ ULONG NumberOfBytes,
+ BOOLEAN InMemorySpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an IO address to system address space.
+ Use ScsiPortFreeDeviceBase to unmap address.
+
+Arguments:
+
+ HwDeviceExtension - used to find port device extension.
+ BusType - what type of bus - eisa, mca, isa
+ SystemIoBusNumber - which IO bus (for machines with multiple buses).
+ IoAddress - base device address to be mapped.
+ NumberOfBytes - number of bytes for which address is valid.
+
+Return Value:
+
+ Mapped address
+
+--*/
+
+{
+ PHYSICAL_ADDRESS cardAddress;
+ ULONG addressSpace = InMemorySpace;
+ PVOID mappedAddress;
+
+ HalTranslateBusAddress(
+ BusType, // AdapterInterfaceType
+ SystemIoBusNumber, // SystemIoBusNumber
+ IoAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &cardAddress // Translated address
+ );
+
+ //
+ // Map the device base address into the virtual address space
+ // if the address is in memory space.
+ //
+
+ if (!addressSpace) {
+
+ mappedAddress = MmMapIoSpace(cardAddress,
+ NumberOfBytes,
+ FALSE);
+
+
+ } else {
+
+ mappedAddress = (PVOID)cardAddress.LowPart;
+ }
+
+ return mappedAddress;
+
+} // end ScsiPortGetDeviceBase()
+
+VOID
+ScsiPortFreeDeviceBase(
+ IN PVOID HwDeviceExtension,
+ IN PVOID MappedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps an IO address that has been previously mapped
+ to system address space using ScsiPortGetDeviceBase().
+
+Arguments:
+
+ HwDeviceExtension - used to find port device extension.
+ MappedAddress - address to unmap.
+ NumberOfBytes - number of bytes mapped.
+ InIoSpace - addresses in IO space don't get mapped.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(HwDeviceExtension);
+ UNREFERENCED_PARAMETER(MappedAddress);
+
+ return;
+
+} // end ScsiPortFreeDeviceBase()
+
+ARC_STATUS
+GetAdapterCapabilities(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PIO_SCSI_CAPABILITIES *PortCapabilities
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ Status is returned.
+
+--*/
+
+{
+ *PortCapabilities = &((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
+ ->Capabilities;
+
+ return(ESUCCESS);
+} // end GetAdapterCapabilities()
+
+
+ARC_STATUS
+GetInquiryData(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PSCSI_CONFIGURATION_INFO *ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a request to a port driver to return
+ configuration information.
+
+Arguments:
+
+ The address of the configuration information is returned in
+ the formal parameter ConfigInfo.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ *ConfigInfo = ((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
+ ->ScsiInfo;
+ return(ESUCCESS);
+} // end GetInquiryData()
+
+NTSTATUS
+SpInitializeConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PHW_INITIALIZATION_DATA HwInitData,
+ OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN BOOLEAN InitialCall
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the port configuration information structure.
+ Any necessary information is extracted from the registery.
+
+Arguments:
+
+ DeviceExtension - Supplies the device extension.
+
+ HwInitializationData - Supplies the initial miniport data.
+
+ ConfigInfo - Supplies the configuration information to be
+ initialized.
+
+ InitialCall - Indicates that this is first call to this function.
+ If InitialCall is FALSE, then the perivous configuration information
+ is used to determine the new information.
+
+Return Value:
+
+ Returns a status indicating the success or fail of the initializaiton.
+
+--*/
+
+{
+#ifdef i386
+ extern ULONG MachineType;
+#endif
+
+ ULONG j;
+
+ //
+ // If this is the initial call then zero the information and set
+ // the structure to the uninitialized values.
+ //
+
+ if (InitialCall) {
+
+ RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
+
+ ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
+ ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->MaximumTransferLength = 0xffffffff;
+ ConfigInfo->NumberOfPhysicalBreaks = 0xffffffff;
+ ConfigInfo->DmaChannel = 0xffffffff;
+ ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
+
+#ifdef MIPS
+ {
+ PCONFIGURATION_COMPONENT Component;
+ PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ sizeof(CM_SCSI_DEVICE_DATA)];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG Count;
+ ULONG ScsiHostId;
+ UCHAR ScsiComponentName[8];
+
+ //
+ // Build the string scsi(n) to get the Arc component info
+ // for the current scsi
+ //
+ sprintf(ScsiComponentName,"scsi(%d)",ScsiPortCount);
+ if (((Component = ArcGetComponent(ScsiComponentName)) != NULL) &&
+ (Component->Class == AdapterClass) && (Component->Type == ScsiAdapter) &&
+ (ArcGetConfigurationData((PVOID)Descriptor, Component) == ESUCCESS) &&
+ ((Count = Descriptor->Count) < 6)) {
+
+ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA)&Descriptor->PartialDescriptors[Count];
+
+ if (ScsiDeviceData->HostIdentifier > 7) {
+ ScsiHostId = 7;
+ } else {
+ ScsiHostId = ScsiDeviceData->HostIdentifier;
+ }
+ } else {
+ ScsiHostId = 7;
+ }
+
+ for (j = 0; j < 8; j++) {
+ ConfigInfo->InitiatorBusId[j] = ScsiHostId;
+ }
+ }
+
+#else
+
+ for (j = 0; j < 8; j++) {
+ ConfigInfo->InitiatorBusId[j] = ~0;
+ }
+
+#endif
+
+#if i386
+ switch (HwInitData->AdapterInterfaceType) {
+ case Isa:
+ if ((MachineType & 0xff) == MACHINE_TYPE_ISA) {
+ return(STATUS_SUCCESS);
+ }
+ case Eisa:
+ if ((MachineType & 0xff) == MACHINE_TYPE_EISA) {
+ return(STATUS_SUCCESS);
+ } else {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+
+ case MicroChannel:
+ if ((MachineType & 0xff) == MACHINE_TYPE_MCA) {
+ return(STATUS_SUCCESS);
+ } else {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+
+ default:
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#elif MIPS
+
+ //
+ // ****** TMP to use the DEMO board only. Eisa can be removed.
+ //
+ if ((HwInitData->AdapterInterfaceType != Internal) &&
+ (HwInitData->AdapterInterfaceType != Isa)) {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#endif
+
+ return(STATUS_SUCCESS);
+
+ } else {
+
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+}
+
+
+NTSTATUS
+SpGetCommonBuffer(
+ PDEVICE_EXTENSION DeviceExtension,
+ ULONG NonCachedExtensionSize
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the required size of the common buffer. Allocates
+ the common buffer and finally sets up the srb extension zone. This routine
+ expects that the adapter object has already been allocated.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension.
+
+ NonCachedExtensionSize - Supplies the size of the noncached device
+ extension for the mini-port driver.
+
+Return Value:
+
+ Returns the status of the allocate operation.
+
+--*/
+
+{
+ PVOID buffer;
+ ULONG length;
+ ULONG blockSize;
+
+ //
+ // Calculate the block size for the zone elements based on the Srb
+ // Extension.
+ //
+
+ blockSize = DeviceExtension->SrbExtensionSize;
+
+ //
+ // Last three bits of blocksize must be zero.
+ // Round blocksize up.
+ //
+
+ blockSize = (blockSize + 7) & ~7;
+
+ length = NonCachedExtensionSize + blockSize * MINIMUM_SRB_EXTENSIONS;
+
+ //
+ // Round the length up to a page size, since HalGetCommonBuffer allocates
+ // in pages anyway.
+ //
+
+ length = ROUND_TO_PAGES(length);
+
+ //
+ // Allocate one page for noncached deviceextension
+ // and srbextension zoned pool.
+ //
+ buffer = MmAllocateNonCachedMemory(length);
+ if (buffer == NULL) {
+
+ ScsiDebugPrint(1,
+ "ScsiPortInitialize: Could not allocate page of noncached pool\n");
+
+ return ENOMEM;
+ }
+
+ //
+ // Determine length and starting address of zone.
+ // If noncached device extension required then
+ // subtract size from page leaving rest for zone.
+ //
+
+ DeviceExtension->NonCachedExtension = (PUCHAR)buffer + length - NonCachedExtensionSize;
+
+ if (DeviceExtension->SrbExtensionSize) {
+
+ //
+ // Get block size.
+ //
+
+ blockSize = DeviceExtension->SrbExtensionSize;
+
+ //
+ // Record starting virtual address of zone.
+ //
+
+ DeviceExtension->SrbExtensionZonePool = buffer;
+ DeviceExtension->SrbExtensionPointer = buffer;
+ DeviceExtension->SrbExtensionSize = blockSize;
+
+ //
+ // Set the IO translation for the common buffer
+ // and store the mapping in PhysicalZoneBase.
+ //
+ IopAllocateCommonBuffer(buffer,
+ length,
+ &DeviceExtension->PhysicalZoneBase
+ );
+
+ } else {
+ DeviceExtension->SrbExtensionZonePool = NULL;
+ }
+
+ return(ESUCCESS);
+}
+
+PVOID
+ScsiPortGetUncachedExtension(
+ IN PVOID HwDeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN ULONG NumberOfBytes
+ )
+/*++
+
+Routine Description:
+
+ This function allocates a common buffer to be used as the uncached device
+ extension for the mini-port driver. This function will also allocate any
+ required SRB extensions. The DmaAdapter is allocated if it has not been
+ allocated previously.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the mini-ports device extension.
+
+ ConfigInfo - Supplies a pointer to the partially initialized configuraiton
+ information. This is used to get an DMA adapter object.
+
+ NumberOfBytes - Supplies the size of the extension which needs to be
+ allocated
+
+Return Value:
+
+ A pointer to the uncached device extension or NULL if the extension could
+ not be allocated or was previously allocated.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ NTSTATUS status;
+
+ //
+ // Make sure that an common buffer has not already been allocated.
+ //
+
+ if (deviceExtension->SrbExtensionZonePool != NULL) {
+ return(NULL);
+ }
+
+ //
+ // Allocate the common buffer.
+ //
+
+ status = SpGetCommonBuffer( deviceExtension, NumberOfBytes);
+
+ if (status != ESUCCESS) {
+ return(NULL);
+ }
+
+ return(deviceExtension->NonCachedExtension);
+}
+
+ULONG
+ScsiPortGetBusData(
+ IN PVOID DeviceExtension,
+ IN ULONG BusDataType,
+ IN ULONG SystemIoBusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the bus data for an adapter slot or CMOS address.
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+
+{
+ ULONG DataLength = 0;
+
+#ifdef i386
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) DeviceExtension - 1;
+
+ //
+ // If the length is non-zero, the the requested data.
+ //
+
+ if (Length != 0) {
+
+ return( HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length
+ ));
+ }
+
+ //
+ // Free any previously allocated data.
+ //
+
+ if (deviceExtension->MapRegisterBase != NULL) {
+ ExFreePool(deviceExtension->MapRegisterBase);
+ }
+
+ if (BusDataType == EisaConfiguration) {
+
+#if 0
+ //
+ // Deteremine the length to allocate based on the number of functions
+ // for the slot.
+ //
+
+ Length = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ &slotInformation,
+ sizeof(CM_EISA_SLOT_INFORMATION));
+
+
+ if (Length < sizeof(CM_EISA_SLOT_INFORMATION)) {
+
+ //
+ // The data is messed up since this should never occur
+ //
+
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Slot information not returned. Length = %d\n", Length);
+#if 0
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+#endif
+ return(0);
+ }
+
+ //
+ // Calculate the required length based on the number of functions.
+ //
+
+ Length = sizeof(CM_EISA_SLOT_INFORMATION) +
+ (sizeof(CM_EISA_FUNCTION_INFORMATION) * slotInformation.NumberFunctions);
+
+#else
+
+ //
+ // Since the loader does not really support freeing data and the EISA
+ // configuration data can be very large. Hal get bus data has be changed
+ // to accept a length of zero for EIAS configuration data.
+ //
+
+ DataLength = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length
+ );
+
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Returning data. Length = %d\n", DataLength);
+#if 0
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+#endif
+
+ return(DataLength);
+#endif
+
+ } else {
+
+ Length = PAGE_SIZE;
+ }
+
+ deviceExtension->MapRegisterBase = ExAllocatePool(NonPagedPool, Length);
+
+ if (deviceExtension->MapRegisterBase == NULL) {
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Memory allocation failed. Length = %d\n", Length);
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+
+ return(0);
+ }
+
+ //
+ // Return the pointer to the mini-port driver.
+ //
+
+ *((PVOID *)Buffer) = deviceExtension->MapRegisterBase;
+
+ DataLength = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ deviceExtension->MapRegisterBase,
+ Length
+ );
+
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Returning data. Length = %d\n", DataLength);
+#if 0
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+#endif
+
+#endif
+ return(DataLength);
+}
+
+PSCSI_REQUEST_BLOCK
+ScsiPortGetSrb(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN LONG QueueTag
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves an active SRB for a particuliar logical unit.
+
+Arguments:
+
+ HwDeviceExtension
+ PathId, TargetId, Lun - identify logical unit on SCSI bus.
+ QueueTag - -1 indicates request is not tagged.
+
+Return Value:
+
+ SRB, if one exists. Otherwise, NULL.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PIRP irp;
+ PIO_STACK_LOCATION irpstack;
+
+
+ luExtension = GetLogicalUnitExtension(deviceExtension, TargetId);
+
+
+ if (luExtension == NULL) {
+ return(NULL);
+ }
+
+ irp = luExtension->CurrentRequest;
+ irpstack = IoGetCurrentIrpStackLocation(irp);
+ return ((PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1);
+
+} // end ScsiPortGetSrb()
+
+
+VOID
+ScsiPortReadPortBufferUchar(
+ IN PUCHAR Port,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned bytes from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadPortBufferUshort(
+ IN PUSHORT Port,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned shorts from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadPortBufferUlong(
+ IN PULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned longs from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUchar(
+ IN PUCHAR Port,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned bytes from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUshort(
+ IN PUSHORT Port,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned shorts from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUlong(
+ IN PULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned longs from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
+
+}
+
+#endif /* DECSTATION */