mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2588 lines
56 KiB
2588 lines
56 KiB
/*++
|
|
|
|
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()
|