summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/dtc/dtc329x.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/miniport/dtc/dtc329x.c')
-rw-r--r--private/ntos/miniport/dtc/dtc329x.c2588
1 files changed, 2588 insertions, 0 deletions
diff --git a/private/ntos/miniport/dtc/dtc329x.c b/private/ntos/miniport/dtc/dtc329x.c
new file mode 100644
index 000000000..4be0fdeb7
--- /dev/null
+++ b/private/ntos/miniport/dtc/dtc329x.c
@@ -0,0 +1,2588 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dtc329x.c
+
+Abstract:
+
+ This is the port driver for the DTC 3290 and DTC 3292
+ EISA SCSI Adapter. This code is based on Microsoft NT aha154x.c
+ modified. ALL modifications can be turned off by setting DTC329X
+ to 0 in dtc3290.h file. Also all the names starting aha154x and a154x
+ have been changed to dtc329x and d329x.
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "dtc329x.h" // includes scsi.h
+
+//
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//
+
+CONST ULONG AdapterAddresses[] = {0X330, 0X334, 0X234, 0X134, 0X130, 0X230, 0};
+
+
+#ifdef DTC329X
+#define DTC_MAILBOX_INITIALIZATION 0x42
+CONST ULONG DTC3290IOAddresses[] = {0X330, 0X334, 0X230, 0X234, 0X130, 0X134, 0};
+CONST ULONG DTC3292IOAddresses[] = {0,0,0X130, 0X134, 0X230, 0X234, 0X330, 0X334, 0};
+#endif
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Physical base address of mailboxes
+ //
+
+ ULONG MailboxPA;
+
+ //
+ // Mailboxes
+ //
+
+ MBO Mbo[MB_COUNT];
+ MBI Mbi[MB_COUNT];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // NonCached extension
+ //
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+
+ //
+ // Adapter parameters
+ //
+
+ PBASE_REGISTER BaseIoAddress;
+
+ //
+ // Host Target id.
+ //
+
+ UCHAR HostTargetId;
+
+ BOOLEAN Dtc3290;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+//
+// Logical unit extension
+//
+
+typedef struct _HW_LU_EXTENSION {
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
+
+
+
+#ifdef DTC329X
+
+// Following algorithm provides the way to detect
+// DTC 3x90 or DTC3x92 presented in the system by
+// scanning EISA slot and check DTC controller ID
+// pattern
+
+
+#define ID_DTC_BYTE0 0x12
+#define ID_DTC_BYTE1 0x83
+#define ID_DTC_3x90_BYTE2 0x31
+#define ID_DTC_3x92_BYTE2 0x39
+#define D3292_IO_MASK 0x7
+#define D3290_IO_MASK 0xf
+
+
+
+#define DTC_GET_CONFIG_CMD 0x41
+#define DTC_ENABLE_INT_CMD 0x1
+#define DTC_CLR_INT_CMD 0x1
+#define DTC_RESET_CONFIG_CMD 0x0
+
+
+
+#define PROD_ID_REG 0xc80
+#define D3292_IO_REG 0xc9f
+#define D3290_IO_REG 0xc91
+
+#define D3290_CONFIG_IO_REG 0xc90
+#define D3290_DOOR_BELL_REG 0xc8d
+#define D3290_CLR_INT_IO_REG 0xc8f
+
+#define TOTAL_EISA_SLOT 0x10
+
+#endif
+
+
+//
+// Function declarations
+//
+// Functions that start with 'D329X' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+D329XEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+D329XDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+D329XFindAdapter (
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+D329XHwInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+D329XStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+D329XInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+D329XResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from D329XStartIo.
+//
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildCcb.
+//
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from D329XInitialize.
+//
+
+BOOLEAN
+AdapterPresent(
+ IN PVOID HwDeviceExtension
+ );
+
+//
+// This function is called from D329XInterrupt.
+//
+
+UCHAR
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ );
+
+BOOLEAN
+ReadCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR DataByte
+ );
+
+BOOLEAN
+WriteCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR AdapterCommand
+ );
+
+
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG adapterCount;
+ ULONG i;
+
+ DebugPrint((1,"\n\nSCSI DTC 329X MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = D329XHwInitialize;
+ hwInitializationData.HwResetBus = D329XResetBus;
+ hwInitializationData.HwStartIo = D329XStartIo;
+ hwInitializationData.HwInterrupt = D329XInterrupt;
+ hwInitializationData.HwFindAdapter = D329XFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.NumberOfAccessRanges = 1;
+
+ //
+ // Ask for SRB extensions for CCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(CCB);
+
+ //
+ // The adapter count is used by the find adapter routine to track how
+ // which adapter addresses have been tested.
+ //
+
+ adapterCount = 0;
+ return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount);
+} // end D329XEntry()
+
+
+ULONG
+D329XFindAdapter (
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Register base address
+ ConfigInfo - Configuration information structure describing HBA
+ This structure is defined in PORT.H.
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG status;
+ UCHAR adapterTid;
+ UCHAR dmaChannel;
+ UCHAR irq;
+ UCHAR bit;
+
+ //
+ // Determine if there are any adapters installed. Determine installed
+ // will initialize the BaseIoAddress if an adapter is found.
+ //
+
+ status = D329XDetermineInstalled(deviceExtension,
+ ConfigInfo,
+ Context,
+ Again);
+
+ //
+ // If there are not adapter's found then return.
+ //
+
+ if (status != SP_RETURN_FOUND) {
+ return(status);
+ }
+
+#if 0
+ //
+ // Set up device extension pointer to 154x mailboxes
+ // in noncached extension.
+ //
+
+ deviceExtension->NoncachedExtension = 0;
+
+ //
+ // Convert virtual to physical mailbox address.
+ //
+
+ deviceExtension->NoncachedExtension->MailboxPA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->Mbo,
+ &length));
+
+ //
+ // Assume that physical address is below 16M
+ //
+
+ ASSERT(deviceExtension->NoncachedExtension->MailboxPA < 0x1000000);
+
+ //
+ // Reset the DTC329X.
+ //
+
+ if (!D329XResetBus(deviceExtension, 0)) {
+ DebugPrint((1,"D329XFindAdapter: Reset SCSI bus failed\n"));
+ return FALSE;
+ }
+
+ DebugPrint((1,"D329XFindAdapter: Reset completed\n"));
+#endif
+
+ //
+ // Issue adapter command to get IRQ.
+ //
+ // Returns 3 data bytes:
+ //
+ // Byte 0 Dma Channel
+ //
+ // Byte 1 Interrupt Channel
+ //
+ // Byte 2 Adapter SCSI ID
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ AC_RET_CONFIGURATION_DATA)) {
+ DebugPrint((1,"D329XFindAdapter: Get configuration data command failed\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Determine DMA channel.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&dmaChannel)) {
+ DebugPrint((1,"D329XFindAdapter: Couldn't read dma channel\n"));
+ return SP_RETURN_ERROR;
+ }
+
+#if 0 // Commented out because EISA should not do this: 4/18/94
+ WHICH_BIT(dmaChannel,bit);
+
+ ConfigInfo->DmaChannel = bit;
+
+ DebugPrint((2,"D329XFindAdapter: DMA channel is %x\n",
+ ConfigInfo->DmaChannel));
+#endif
+
+ //
+ // Determine hardware interrupt vector.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&irq)) {
+ DebugPrint((1,"D329XFindAdapter: Couldn't read adapter irq\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ WHICH_BIT(irq, bit);
+
+ ConfigInfo->BusInterruptLevel = (UCHAR) 9 + bit;
+
+ //
+ // Determine what SCSI bus id the adapter is on.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&adapterTid)) {
+ DebugPrint((1,"D329XFindAdapter: Couldn't read adapter SCSI id\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Set number of buses.
+ //
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = adapterTid;
+ deviceExtension->HostTargetId = adapterTid;
+
+ ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS - 1;
+
+ //
+ // Allocate a Noncached Extension to use for mail boxes.
+ //
+
+ deviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
+ deviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (deviceExtension->NoncachedExtension == NULL) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 6 << 16
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Convert virtual to physical mailbox address.
+ //
+
+ deviceExtension->NoncachedExtension->MailboxPA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->Mbo,
+ &length));
+
+ //
+ // Assume that physical address is below 16M
+ //
+
+ ASSERT(deviceExtension->NoncachedExtension->MailboxPA < 0x1000000);
+
+#if 0
+ //
+ // Reset the DTC329X.
+ //
+
+ if (!D329XResetBus(deviceExtension, 0)) {
+ DebugPrint((1,"D329XFindAdapter: Reset SCSI bus failed\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ DebugPrint((1,"D329XFindAdapter: Reset completed\n"));
+#endif
+
+ DebugPrint((3,"D329XFindAdapter: Configuration completed\n"));
+
+ return SP_RETURN_FOUND;
+
+} // end D329XFindAdapter()
+
+
+ULONG
+D329XDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if DTC 329X SCSI adapter is installed in system
+ by reading the status register as each base I/O address
+ and looking for a DTC EISA pattern. If an adapter is found,
+ the BaseIoAddres is initialized.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the known configuraiton information.
+
+ AdapterCount - Supplies the count of adapter slots which have been tested.
+
+ Again - Returns whehter the OS specific driver should call again.
+
+Return Value:
+
+ Returns a status indicating whether a driver is present or not.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress;
+ PUCHAR ioSpace;
+ PUCHAR slotSpace;
+ UCHAR portValue; // 03-27-93
+ BOOLEAN dtc3290; // 04-09-93, = true if dtc3290 else false
+ UCHAR status;
+
+#ifdef DTC329X
+ ULONG adapterio;
+ ULONG i;
+ ULONG j;
+ UCHAR loid;
+ UCHAR miid;
+ UCHAR hiid;
+ ULONG tempioindex;
+#endif
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ ioSpace = ScsiPortGetDeviceBase(
+ HwDeviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(0),
+ 0x400, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ //
+ // Scan though the adapter address looking for adapters.
+ //
+
+ while (AdapterAddresses[*AdapterCount] != 0) {
+
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ baseIoAddress = (PBASE_REGISTER)(ioSpace +
+ AdapterAddresses[*AdapterCount]);
+
+#ifdef DTC329X
+ adapterio = AdapterAddresses[*AdapterCount];
+#endif
+
+
+ //
+ // Update the adapter count.
+ //
+
+ (*AdapterCount)++;
+
+ portValue = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ //
+ // Check for Adaptec adapter.
+ // The mask (0x29) are bits that may or may not be set.
+ // The bit 0x10 (IOP_SCSI_HBA_IDLE) should be set.
+ //
+
+ if (!((portValue & ~0x29) == IOP_SCSI_HBA_IDLE)) {
+
+ //
+ // Board in funky state. Reset it.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ DebugPrint((2,"ResetBus: Wait done\n"));
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+
+ //
+ // The DTC sometimes needs a soft reset to recover.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->BaseIoAddress->StatusRegister, IOP_SOFT_RESET);
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(5);
+
+ status = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ }
+ }
+
+ portValue = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ if ((portValue & ~0x29) == IOP_SCSI_HBA_IDLE) { /* 03-27-93 */
+
+#ifdef DTC329X
+
+ // following code will make sure that only dtc3292 or dtc3290 board
+ // is recoginzed by this driver by checking current dtc board IO
+ // address (get from EISA config reg).
+
+
+ for (i= 0x1000; i< TOTAL_EISA_SLOT * 0x1000; i=i+0x1000) {
+
+ slotSpace = ScsiPortGetDeviceBase(
+ HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(i),
+ 0x1000,
+ TRUE);
+ loid = ScsiPortReadPortUchar(slotSpace + PROD_ID_REG);
+ miid = ScsiPortReadPortUchar(slotSpace + PROD_ID_REG + 1);
+ hiid = ScsiPortReadPortUchar(slotSpace + PROD_ID_REG + 2);
+
+ if (loid == ID_DTC_BYTE0 && miid == ID_DTC_BYTE1 ) {
+
+ switch (hiid ) {
+ case ID_DTC_3x90_BYTE2:
+ ScsiPortReadPortUchar(slotSpace+D3290_CONFIG_IO_REG); // dummy read
+ ScsiPortWritePortUchar(slotSpace+D3290_CONFIG_IO_REG,DTC_GET_CONFIG_CMD);
+ ScsiPortWritePortUchar(slotSpace+D3290_DOOR_BELL_REG,DTC_ENABLE_INT_CMD);
+ for (j = 0; j < 2000000; j++) {
+ ScsiPortStallExecution(1);
+ if (ScsiPortReadPortUchar(slotSpace+D3290_CONFIG_IO_REG) & 0x80)
+ break;
+ }
+
+ tempioindex = ScsiPortReadPortUchar(slotSpace+D3290_IO_REG);
+ ScsiPortWritePortUchar(slotSpace+D3290_CLR_INT_IO_REG,DTC_CLR_INT_CMD);
+ ScsiPortWritePortUchar(slotSpace+D3290_CONFIG_IO_REG,DTC_RESET_CONFIG_CMD);
+
+ ScsiPortStallExecution(4000 * 1000); /* 03-27-93 */
+
+ if (adapterio == DTC3290IOAddresses[tempioindex & D3290_IO_MASK])
+ {
+ dtc3290 = TRUE;
+ goto find_dtc;
+ }
+ else
+ break;
+
+ case ID_DTC_3x92_BYTE2:
+ tempioindex = ScsiPortReadPortUchar(slotSpace+D3292_IO_REG);
+ if (adapterio == DTC3292IOAddresses[tempioindex & D3292_IO_MASK])
+ {
+ dtc3290 = FALSE;
+ goto find_dtc;
+ }
+ else
+ break;
+
+ default:
+ break;
+ }
+ }
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ (PVOID) slotSpace);
+ }
+
+ if (i == TOTAL_EISA_SLOT * 0x1000 )
+ continue;
+
+ find_dtc:
+#endif
+
+
+ DebugPrint((1,"D329X: Base IO address is %x\n", baseIoAddress));
+
+ //
+ // An adapter has been found. Set the base address in the device
+ // extension, and request another call.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET); /* 03-27-93 */
+ ScsiPortStallExecution(3000*1000);
+ HwDeviceExtension->BaseIoAddress = baseIoAddress;
+ *Again = TRUE;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ AdapterAddresses[*AdapterCount - 1]);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 4;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ deviceExtension->Dtc3290 = dtc3290;
+
+ if (dtc3290) ConfigInfo->CachesData = TRUE; // 04-09-93
+ else ConfigInfo->CachesData = FALSE;
+
+ return SP_RETURN_FOUND;
+ }
+ }
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // There is no need to call again and the device base can now be freed.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *(AdapterCount) = 0;
+
+ ScsiPortFreeDeviceBase(
+ HwDeviceExtension,
+ ioSpace
+ );
+
+ return SP_RETURN_NOT_FOUND;
+
+} // end D329XDetermineInstalled()
+
+
+BOOLEAN
+D329XHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a required entry point.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+
+ DebugPrint((2,"D329XHwInitialize: Reset DTC329X and SCSI bus\n"));
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET);
+
+ ScsiPortStallExecution(2000*1000); /* 03-27-93 */
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+ }
+
+ //
+ // Inform the port driver that the bus has been reset.
+ //
+
+ ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
+
+ //
+ // Check if reset failed or succeeded.
+ //
+
+ if (!(status & IOP_SCSI_HBA_IDLE) || !(status & IOP_MAILBOX_INIT_REQUIRED)) {
+
+ DebugPrint((1, "D329XHwInitialize: Soft reset failed.\n"));
+
+ //
+ // If the soft reset does not work, try a hard reset.
+ //
+
+ if (!D329XResetBus(HwDeviceExtension, 0)) {
+ DebugPrint((1,"D329XHwInitialize: Reset SCSI bus failed\n"));
+ return FALSE;
+ }
+
+ DebugPrint((1,"D329XHwInitialize: Reset completed\n"));
+
+ return TRUE;
+ }
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+ mailboxOut = &noncachedExtension->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ DebugPrint((3,"ResetBus: Initialize mailbox\n"));
+
+#ifndef DTC329X
+ if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the middle byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+#else
+
+ if (!WriteCommandRegister(deviceExtension,DTC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+
+ for (i=0; i < 250000; i++)
+ ScsiPortStallExecution(1);
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 2nd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 3rd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte3)) {
+ return FALSE;
+ }
+
+#endif
+
+ DebugPrint((3,"ResetBus: Initialize mailbox done\n"));
+ return TRUE;
+
+} // end D329XHwInitialize()
+
+
+BOOLEAN
+D329XStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel. The mailboxes are scanned for an empty one and
+ the CCB is written to it. Then the doorbell is rung and the
+ OS port driver is notified that the adapter can take
+ another request, if any are available.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PMBO mailboxOut;
+ PCCB ccb;
+ PHW_LU_EXTENSION luExtension;
+ ULONG physicalCcb;
+ ULONG length;
+ ULONG i = 0;
+
+ DebugPrint((3,"D329XStartIo: Enter routine\n"));
+
+ //
+ // Check if command is an ABORT request.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (!luExtension->CurrentSrb) {
+
+ DebugPrint((1, "D329XStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get CCB to abort.
+ //
+
+ ccb = Srb->NextSrb->SrbExtension;
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ ccb->AbortSrb = Srb;
+
+ } else {
+
+ ccb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in CCB.
+ //
+
+ ccb->SrbAddress = Srb;
+ }
+
+ //
+ // Get CCB physical address.
+ //
+
+ physicalCcb = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, ccb, &length));
+
+ //
+ // Assume physical address is contiguous for size of CCB.
+ //
+
+ ASSERT(length >= sizeof(CCB));
+
+ //
+ // Find free mailboxOut.
+ //
+
+ do {
+
+ mailboxOut = &noncachedExtension->Mbo[i % MB_COUNT];
+ i++;
+
+ } while (mailboxOut->Command != MBO_FREE);
+
+ DebugPrint((3,"D329XStartIo: MBO address %lx, Loop count = %d\n", mailboxOut, i));
+
+ //
+ // Write CCB to mailbox.
+ //
+
+#ifndef DTC329X
+
+ FOUR_TO_THREE(&mailboxOut->Address,
+ (PFOUR_BYTE)&physicalCcb);
+#else
+
+ FOUR_TO_FOUR(&mailboxOut->Address,(PFOUR_BYTE)&physicalCcb);
+
+#endif
+
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "D329XStartIo: Abort request received\n"));
+
+ //
+ // NOTE: Race condition if aborts occur
+ // (what if CCB to be aborted
+ // completes after setting new SrbAddress?)
+ //
+
+ mailboxOut->Command = MBO_ABORT;
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset DTC329X and SCSI bus.
+ //
+
+ DebugPrint((1, "D329XStartIo: Reset bus request received\n"));
+
+ if (!D329XResetBus(
+ deviceExtension,
+ Srb->PathId
+ )) {
+
+ DebugPrint((1,"D329XStartIo: Reset bus failed\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ return TRUE;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Move SRB to logical unit extension.
+ //
+
+ luExtension->CurrentSrb = Srb;
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(deviceExtension, Srb);
+
+ mailboxOut->Command = MBO_START;
+
+ break;
+
+ case SRB_FUNCTION_SHUTDOWN:
+ case SRB_FUNCTION_FLUSH: // 04-09-93, implement flush cache
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Move SRB to logical unit extension.
+ //
+
+ luExtension->CurrentSrb = Srb;
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(deviceExtension, Srb);
+
+ ccb->Cdb[0] = REZERO_UNIT_CMD; // re-zero will force F/W to
+ // flush cache
+ ccb->Cdb[1] = 0; // LU
+ ccb->Cdb[2] = 0; // reserved
+ ccb->Cdb[3] = 0; // reserved
+ ccb->Cdb[4] = 0; // reserved
+ ccb->Cdb[5] = 0; // control byte
+ ccb->CdbLength = 6;
+
+ mailboxOut->Command = MBO_START;
+
+ DebugPrint((1, "D329XStartIo: Flush cache sent\n"));
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DebugPrint((1,"D329XStartIo: Reset device not supported\n"));
+
+ //
+ // Drop through to default.
+ //
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Tell 154xb a CCB is available now.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,AC_START_SCSI_COMMAND)) {
+
+ //
+ // Let request time out and fail.
+ //
+
+ DebugPrint((1,"D329XStartIo: Can't write command to adapter\n"));
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end D329XStartIo()
+
+
+BOOLEAN
+D329XInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the adaptec 154x SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the CCB is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PCCB ccb;
+ PSCSI_REQUEST_BLOCK srb;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ PMBI mailboxIn;
+ ULONG physicalCcb;
+ PHW_LU_EXTENSION luExtension;
+ ULONG i;
+
+ UCHAR InterruptFlags;
+
+ InterruptFlags = ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister);
+
+ //
+ // Determine cause of interrupt.
+ //
+
+ if (InterruptFlags & IOP_COMMAND_COMPLETE) {
+
+ //
+ // Adapter command completed.
+ //
+
+ DebugPrint((2,"D329XInterrupt: Adapter Command complete\n"));
+ DebugPrint((3,"D329XInterrupt: Interrupt flags %x\n", InterruptFlags));
+ DebugPrint((3,"D329XInterrupt: Status %x\n",
+ ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ return TRUE;
+
+ } else if (InterruptFlags & IOP_MBI_FULL) {
+
+ DebugPrint((3,"D329XInterrupt: MBI Full\n"));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ } else if (InterruptFlags & IOP_SCSI_RESET_DETECTED) {
+
+ DebugPrint((1,"D329XInterrupt: SCSI Reset detected\n"));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ //
+ // Notify of reset.
+ //
+
+ ScsiPortNotification(ResetDetected,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint((4,"D329XInterrupt: Spurious interrupt\n"));
+
+ return FALSE;
+ }
+
+ //
+ // Determine which MailboxIn location contains the CCB.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+
+ //
+ // Look for a mailbox entry with a legitimate status.
+ //
+
+ if ((mailboxIn->Status == MBI_SUCCESS) ||
+ (mailboxIn->Status == MBI_ERROR) ||
+ (mailboxIn->Status == MBI_ABORT) ||
+ (mailboxIn->Status == MBI_NOT_FOUND)) {
+
+ //
+ // MBI found.
+ //
+
+ DebugPrint((3,"D329XInterrupt: MBI address %lx\n", mailboxIn));
+ break;
+ }
+ }
+
+ if (i == MB_COUNT) {
+
+ //
+ // No mail. Indicate interrupt was not serviced.
+ //
+
+ DebugPrint((1, "D329XInterrupt: No CCB in mailboxes\n"));
+
+ return TRUE;
+ }
+
+ //
+ // Convert CCB to big endian.
+ //
+
+#ifndef DTC329X
+
+ THREE_TO_FOUR((PFOUR_BYTE)&physicalCcb,
+ &mailboxIn->Address);
+#else
+
+ FOUR_TO_FOUR((PFOUR_BYTE)&physicalCcb, &mailboxIn->Address);
+
+#endif
+
+ DebugPrint((3, "D329XInterrupt: Physical CCB %lx\n", physicalCcb));
+
+ //
+ // Check if physical CCB is zero.
+ // This is done to cover for hardware errors.
+ //
+
+ if (!physicalCcb) {
+
+ DebugPrint((1,"D329XInterrupt: Physical CCB address is 0\n"));
+ return TRUE;
+ }
+
+ //
+ // Convert Physical CCB to Virtual.
+ //
+
+ ccb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
+
+
+ DebugPrint((3, "D329XInterrupt: Virtual CCB %lx\n", ccb));
+
+ //
+ // Make sure the virtual address was found.
+ //
+
+ if (ccb == NULL) {
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5 << 8
+ );
+
+ return(TRUE);
+
+ }
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun);
+
+ //
+ // Make sure the luExtension was found and it has a current request.
+ //
+
+ if (luExtension == NULL || (luExtension->CurrentSrb == NULL &&
+ mailboxIn->Status != MBI_NOT_FOUND)) {
+
+
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (6 << 8) | mailboxIn->Status
+ );
+
+ return(TRUE);
+
+ }
+
+ //
+ // Check MBI status.
+ //
+
+ switch (mailboxIn->Status) {
+
+ case MBI_SUCCESS:
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ASSERT(luExtension->CurrentSrb);
+
+ luExtension->CurrentSrb = NULL;
+
+ break;
+
+ case MBI_NOT_FOUND:
+
+ DebugPrint((1, "D329XInterrupt: CCB abort failed %lx\n", ccb));
+
+ srb = ccb->AbortSrb;
+
+ srb->ScsiStatus = SRB_STATUS_ABORT_FAILED;
+
+ //
+ // Check if SRB still outstanding.
+ //
+
+ if (luExtension->CurrentSrb) {
+
+ //
+ // Complete this SRB.
+ //
+
+ luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ luExtension->CurrentSrb);
+
+ luExtension->CurrentSrb = NULL;
+ }
+
+ break;
+
+ case MBI_ABORT:
+
+ DebugPrint((1, "D329XInterrupt: CCB aborted\n"));
+
+ //
+ // Update target status in aborted SRB.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ABORTED;
+
+ //
+ // Call notification routine for the aborted SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ luExtension->CurrentSrb = NULL;
+
+ //
+ // Get the abort SRB from CCB.
+ //
+
+ srb = ccb->AbortSrb;
+
+ //
+ // Set status for completing abort request.
+ //
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case MBI_ERROR:
+
+ DebugPrint((2, "D329XInterrupt: Error occurred\n"));
+
+ srb->SrbStatus = MapError(deviceExtension, srb, ccb);
+
+ DebugPrint((2, "D329XInterrupt: SrbStatus = %x\n",srb->SrbStatus));
+ //
+ // Check if ABORT command.
+ //
+
+ if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Check if SRB still outstanding.
+ //
+
+ if (luExtension->CurrentSrb) {
+
+ //
+ // Complete this SRB.
+ //
+
+ luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ luExtension->CurrentSrb);
+
+ }
+
+ DebugPrint((1,"D329XInterrupt: Abort command failed\n"));
+ }
+
+ luExtension->CurrentSrb = NULL;
+
+ break;
+
+ default:
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (1 << 8) | mailboxIn->Status
+ );
+
+ DebugPrint((1, "D329XInterrupt: Unrecognized mailbox status\n"));
+
+ mailboxIn->Status = MBI_FREE;
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Indicate MBI is available.
+ //
+
+ mailboxIn->Status = MBI_FREE;
+
+ DebugPrint((2, "D329XInterrupt: SCSI Status %x\n", srb->ScsiStatus));
+
+ DebugPrint((2, "D329XInterrupt: Adapter Status %x\n", ccb->HostStatus));
+
+ //
+ // Update target status in SRB.
+ //
+
+ srb->ScsiStatus = ccb->TargetStatus;
+
+ DebugPrint((2, "D329XInterrupt: Target Status %x\n", ccb->TargetStatus));
+
+ //
+ // Signal request completion.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return TRUE;
+
+} // end D329XInterrupt()
+
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build CCB for 154x.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PCCB ccb = Srb->SrbExtension;
+
+ DebugPrint((3,"BuildCcb: Enter routine\n"));
+
+ //
+ // Set CCB Operation Code.
+ //
+
+ ccb->OperationCode = SCATTER_GATHER_COMMAND;
+
+ //
+ // Set target id and LUN.
+ //
+
+ ccb->ControlByte = (UCHAR)(Srb->TargetId << 5) | Srb->Lun;
+
+ //
+ // Set transfer direction bit.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ ccb->ControlByte |= CCB_DATA_XFER_OUT;
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ccb->ControlByte |= CCB_DATA_XFER_IN;
+ }
+
+ //
+ // 01h disables auto request sense.
+ //
+
+ ccb->RequestSenseLength = 1;
+
+ //
+ // Set CDB length and copy to CCB.
+ //
+
+ ccb->CdbLength = (UCHAR)Srb->CdbLength;
+
+ ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, ccb->CdbLength);
+
+ //
+ // Set reserved bytes to zero.
+ //
+
+ ccb->Reserved[0] = 0;
+ ccb->Reserved[1] = 0;
+
+ ccb->LinkIdentifier = 0;
+
+ //
+ // Zero link pointer.
+ //
+
+
+#ifdef DTC329X
+ ccb->LinkPointer.Byte0 = 0;
+ ccb->LinkPointer.Byte1 = 0;
+ ccb->LinkPointer.Byte2 = 0;
+ ccb->LinkPointer.Byte3 = 0;
+#else
+ ccb->LinkPointer.Lsb= 0;
+ ccb->LinkPointer.Msb = 0;
+ ccb->LinkPointer.Mid = 0;
+#endif
+
+ //
+ // Build SDL in CCB if data transfer.
+ //
+ if (Srb->DataTransferLength > 0) {
+
+ BuildSdl(DeviceExtension, Srb);
+
+ } else {
+ FOUR_TO_FOUR(&ccb->DataLength, (PFOUR_BYTE)&Srb->DataTransferLength);
+ FOUR_TO_FOUR(&ccb->DataPointer, (PFOUR_BYTE)&Srb->DataTransferLength);
+ ccb->OperationCode = SCSI_INITIATOR_COMMAND;
+
+ }
+
+ ccb->TargetStatus = 0;
+ ccb->HostStatus = 0;
+
+ return;
+
+} // end BuildCcb()
+
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the CCB.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PCCB ccb = Srb->SrbExtension;
+ PSDL sdl = &ccb->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG four;
+ ULONG i = 0;
+
+ DebugPrint((3,"BuildSdl: Enter routine\n"));
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SDL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "BuildSdl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSdl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "BuildSdl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSdl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ four = length;
+
+#ifndef DTC329X
+
+ //
+ // Convert length to 3-byte big endian format.
+ //
+
+ three = &sdl->Sgd[i].Length;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+#else
+ //
+ // Keep original little endian format
+ //
+ FOUR_TO_FOUR(&sdl->Sgd[i].Length,(PFOUR_BYTE)&four);
+
+#endif
+
+ four = (ULONG)physicalAddress;
+
+#ifndef DTC329X
+
+ //
+ // Convert physical address to 3-byte big endian format.
+ //
+
+ three = &sdl->Sgd[i].Address;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+#else
+ //
+ // Keep original little endian format
+ //
+ FOUR_TO_FOUR(&sdl->Sgd[i].Address,(PFOUR_BYTE)&four);
+
+#endif
+ i++;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+
+ } while (bytesLeft);
+
+ //
+ // Write SDL length to CCB.
+ //
+
+ four = i * sizeof(SGD);
+
+#ifndef DTC329X
+
+ three = &ccb->DataLength;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+#else
+
+ FOUR_TO_FOUR(&ccb->DataLength, (PFOUR_BYTE)&four);
+
+#endif
+
+ DebugPrint((3,"BuildSdl: SDL length is %d\n", four));
+
+ //
+ // Write SDL address to CCB.
+ //
+
+#ifndef DTC329X
+
+ FOUR_TO_THREE(&ccb->DataPointer,
+ (PFOUR_BYTE)&physicalSdl);
+#else
+
+ FOUR_TO_FOUR(&ccb->DataPointer,(PFOUR_BYTE)&physicalSdl);
+
+#endif
+
+
+ DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
+
+ DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
+
+ return;
+
+} // end BuildSdl()
+
+
+BOOLEAN
+D329XResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset Adaptec 154X SCSI adapter and SCSI bus.
+ Initialize adpater mailbox.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+
+ DebugPrint((2,"ResetBus: Reset DTC329X and SCSI bus\n"));
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)PathId,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ DebugPrint((2,"ResetBus: Wait done\n"));
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+
+ //
+ // The DTC sometimes needs a soft reset to recover.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->BaseIoAddress->StatusRegister, IOP_SOFT_RESET);
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(5);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ }
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+ return(FALSE);
+ }
+
+ DebugPrint((2,"ResetBus: Hardreset OK\n"));
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+ mailboxOut = &noncachedExtension->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ DebugPrint((3,"D329XResetBus: Initialize mailbox\n"));
+
+#ifndef DTC329X
+ if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the middle byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+#else
+
+
+ if (!WriteCommandRegister(deviceExtension,DTC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+
+ for (i=0; i < 250000; i++)
+ ScsiPortStallExecution(1);
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 2nd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 3rd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte3)) {
+ return FALSE;
+ }
+
+#endif
+
+
+
+ DebugPrint((3,"D329XResetBus: Initialize mailbox ok\n"));
+
+
+
+ return TRUE;
+
+} // end D329XResetBus()
+
+
+UCHAR
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate D329X error to SRB error, and log an error if necessary.
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+ Srb - The failing Srb.
+
+ Ccb - Command Control Block contains error.
+
+Return Value:
+
+ SRB Error
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR status;
+ ULONG logError;
+
+ switch (Ccb->HostStatus) {
+
+
+#ifdef DTC329X
+
+ case CCB_SELECTION_TIMEOUT:
+ return SRB_STATUS_SELECTION_TIMEOUT;
+
+ case CCB_COMPLETE:
+ if (Ccb->TargetStatus != SCSISTAT_GOOD) {
+ return SRB_STATUS_ERROR;
+ } else if (!deviceExtension->Dtc3290) {
+
+ //
+ // The DTC 3292 does not update the scsi bus status assume the
+ // scsi bus status is a check condition.
+ //
+
+ Ccb->TargetStatus = SCSISTAT_CHECK_CONDITION;
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // Fall through to the under run case.
+ //
+
+#else
+ case CCB_COMPLETE:
+ case CCB_SELECTION_TIMEOUT:
+ return SRB_STATUS_ERROR;
+#endif
+
+ case CCB_DATA_OVER_UNDER_RUN:
+ return SRB_STATUS_DATA_OVERRUN;
+
+ case CCB_UNEXPECTED_BUS_FREE:
+ status = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ logError = SP_UNEXPECTED_DISCONNECT;
+ break;
+
+ case CCB_PHASE_SEQUENCE_FAIL:
+ case CCB_INVALID_DIRECTION:
+ status = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ logError = SP_PROTOCOL_ERROR;
+ break;
+
+ case CCB_BAD_MBO_COMMAND:
+ case CCB_INVALID_OP_CODE:
+ case CCB_BAD_LINKED_LUN:
+ case CCB_DUPLICATE_CCB:
+ case CCB_INVALID_CCB:
+ status = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+
+ default:
+ status = SRB_STATUS_ERROR;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+ }
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ (2 << 8) | Ccb->HostStatus
+ );
+
+ return(status);
+
+} // end MapError()
+
+
+BOOLEAN
+ReadCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR DataByte
+ )
+
+/*++
+
+Routine Description:
+
+ Read command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapder extension
+ DataByte - Byte read from register
+
+Return Value:
+
+ TRUE if command register read.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+#ifndef DTC329X
+
+ for (i=0; i<500; i++) {
+
+#else
+
+ for (i=0; i<5000; i++) { /* 03-27-93 */
+
+#endif
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_DATA_IN_PORT_FULL) {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+#ifndef DTC329X
+ if (i==500) {
+#else
+ if (i==5000) { /* 03-27-93 */
+#endif
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 8
+ );
+
+ DebugPrint((1, "DTC329X:ReadCommandRegister: Read command timed out\n"));
+ return FALSE;
+ }
+
+ *DataByte = ScsiPortReadPortUchar(&baseIoAddress->CommandRegister);
+
+ return TRUE;
+
+} // end ReadCommandRegister()
+
+
+BOOLEAN
+WriteCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR AdapterCommand
+ )
+
+/*++
+
+Routine Description:
+
+ Write operation code to command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapter extension
+ AdapterCommand - Value to be written to register
+
+Return Value:
+
+ TRUE if command sent.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+#ifndef DTC329X
+
+ for (i=0; i<500; i++) {
+
+#else
+
+ for (i=0; i<5000; i++) { /* 03-27-93 */
+#endif
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_COMMAND_DATA_OUT_FULL) {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+ }
+ }
+
+#ifndef DTC329X
+ if (i==500) {
+#else
+ if (i==5000) { /* 03-27-93 */
+#endif
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 8
+ );
+
+ DebugPrint((1, "DTC329X:WriteCommandRegister: Write command timed out\n"));
+ return FALSE;
+ }
+
+ DebugPrint((3,"AdapterCommand = %x \n", AdapterCommand));
+
+ ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, AdapterCommand);
+
+ return TRUE;
+
+} // end WriteCommandRegister()