NT4/private/ntos/miniport/dtc/dtc329x.c
2020-09-30 17:12:29 +02:00

2589 lines
56 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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()