3182 lines
77 KiB
C
3182 lines
77 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 BusLogic, Inc.
|
||
|
||
Module Name:
|
||
|
||
Buslogic.c
|
||
|
||
Abstract:
|
||
|
||
This is the port driver for the BusLogic SCSI ISA/EISA/MCA Adapters.
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "miniport.h"
|
||
#include "buslogic.h" // includes scsi.h
|
||
|
||
//
|
||
// The following table specifies the ports to be checked when searching for
|
||
// an adapter. A zero entry terminates the search.
|
||
//
|
||
|
||
ULONG AdapterAddresses[] = {0X330, 0X334, 0X234, 0X134, 0X130, 0X230, 0};
|
||
ULONG PciAdapterAddresses[] = {0Xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0}; /* dummy entry for PCI */
|
||
|
||
UCHAR VendorId[4]={'1','0','4','b'};
|
||
UCHAR NewDeviceId[4]={'1','0','4','0'};
|
||
|
||
ULONG InittedEISABoards = 0;
|
||
//
|
||
// Function declarations
|
||
//
|
||
// Functions that start with 'BLogic' are entry points
|
||
// for the OS port driver.
|
||
//
|
||
|
||
ULONG
|
||
DriverEntry(
|
||
IN PVOID DriverObject,
|
||
IN PVOID Argument2
|
||
);
|
||
|
||
ULONG
|
||
BLogicEntry(
|
||
IN PVOID DriverObject,
|
||
IN PVOID Argument2
|
||
);
|
||
|
||
ULONG
|
||
BLogicDetermineInstalled(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
IN OUT PBL_CONTEXT CurrContextPtr,
|
||
OUT PBOOLEAN Again
|
||
);
|
||
|
||
ULONG
|
||
BLogicFindAdapter (
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PVOID Context,
|
||
IN PVOID BusInformation,
|
||
IN PCHAR ArgumentString,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
OUT PBOOLEAN Again
|
||
);
|
||
|
||
BOOLEAN
|
||
BLogicAdapterState(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PVOID Context,
|
||
IN BOOLEAN SaveState
|
||
);
|
||
|
||
BOOLEAN
|
||
BLogicHwInitialize(
|
||
IN PCARD_STRUC CardPtr
|
||
);
|
||
|
||
BOOLEAN
|
||
BLogicStartIo(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
BOOLEAN
|
||
BLogicInterrupt(
|
||
IN PCARD_STRUC CardPtr
|
||
);
|
||
|
||
BOOLEAN
|
||
BLogicResetBus(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN ULONG PathId
|
||
);
|
||
|
||
BOOLEAN
|
||
ResetBus(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN ULONG PathId
|
||
);
|
||
|
||
// Add the following function back in!
|
||
|
||
BOOLEAN
|
||
ReInitializeHBA(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN ULONG PathId
|
||
);
|
||
//
|
||
// This function is called from BLogicStartIo.
|
||
//
|
||
|
||
VOID
|
||
BuildCcb(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
//
|
||
// This function is called from BuildCcb.
|
||
//
|
||
|
||
VOID
|
||
BuildSdl(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
);
|
||
|
||
//
|
||
// This function is called from BLogicInitialize.
|
||
//
|
||
|
||
BOOLEAN
|
||
AdapterPresent(
|
||
IN PCARD_STRUC CardPtr
|
||
);
|
||
|
||
//
|
||
// This function is called from BLogicInterrupt.
|
||
//
|
||
|
||
UCHAR
|
||
MapError(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
IN PCCB Ccb
|
||
);
|
||
|
||
BOOLEAN
|
||
ReadCommandRegister(
|
||
IN PCARD_STRUC CardPtr,
|
||
OUT PUCHAR DataByte
|
||
);
|
||
|
||
BOOLEAN
|
||
WriteCommandRegister(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN UCHAR AdapterCommand
|
||
);
|
||
|
||
BOOLEAN
|
||
AdjustCCBqueue(
|
||
PCCB ccbp,
|
||
IN PDEV_STRUC devptr
|
||
);
|
||
|
||
PMBI
|
||
DoneMbox(
|
||
IN PCARD_STRUC CardPtr
|
||
);
|
||
|
||
BOOLEAN
|
||
SendCCB(
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PDEV_STRUC DevStruc
|
||
);
|
||
|
||
BOOLEAN
|
||
FinishHBACmd(
|
||
IN PCARD_STRUC CardPtr
|
||
);
|
||
|
||
BOOLEAN
|
||
CheckInvalid(
|
||
IN PCARD_STRUC CardPtr
|
||
);
|
||
|
||
ULONG
|
||
FindOurEISAId(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
PBASE_REGISTER baseIoAddress
|
||
);
|
||
|
||
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()
|
||
|
||
--*/
|
||
|
||
{
|
||
return BLogicEntry(DriverObject, Argument2);
|
||
|
||
} // end DriverEntry()
|
||
|
||
|
||
ULONG
|
||
BLogicEntry(
|
||
IN PVOID DriverObject,
|
||
IN PVOID Argument2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called from DriverEntry if this driver is installable
|
||
or directly from the system if the driver is built into the kernel.
|
||
It calls the OS dependent driver which controls the initialization.
|
||
|
||
Arguments:
|
||
|
||
Driver Object
|
||
|
||
Return Value:
|
||
|
||
Status return by scsi port intialize.
|
||
|
||
--*/
|
||
|
||
{
|
||
HW_INITIALIZATION_DATA hwInitializationData;
|
||
BL_CONTEXT CurrContext;
|
||
PBL_CONTEXT CurrContextPtr = &CurrContext;
|
||
ULONG isaStatus;
|
||
ULONG mcaStatus;
|
||
ULONG EisaStatus;
|
||
ULONG i,PCIStatus,LowStatus1,LowStatus2;
|
||
|
||
DebugPrint((1,"\n\nBusLogic SCSI 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 = (PHW_INITIALIZE) BLogicHwInitialize;
|
||
hwInitializationData.HwResetBus = (PHW_RESET_BUS) BLogicResetBus;
|
||
hwInitializationData.HwStartIo = (PHW_STARTIO) BLogicStartIo;
|
||
hwInitializationData.HwInterrupt = (PHW_INTERRUPT) BLogicInterrupt;
|
||
hwInitializationData.HwFindAdapter = (PHW_FIND_ADAPTER) BLogicFindAdapter;
|
||
hwInitializationData.HwAdapterState = BLogicAdapterState;
|
||
|
||
//
|
||
// Indicate no buffer mapping but will need physical addresses.
|
||
//
|
||
|
||
hwInitializationData.NeedPhysicalAddresses = TRUE;
|
||
hwInitializationData.AutoRequestSense = TRUE;
|
||
hwInitializationData.TaggedQueuing = TRUE;
|
||
hwInitializationData.MultipleRequestPerLu = TRUE;
|
||
|
||
//
|
||
// Specify size of extensions.
|
||
//
|
||
|
||
hwInitializationData.DeviceExtensionSize = sizeof(CARD_STRUC);
|
||
hwInitializationData.SpecificLuExtensionSize = sizeof(DEV_STRUC);
|
||
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.
|
||
//
|
||
|
||
CurrContextPtr->AdapterCount = 0;
|
||
CurrContextPtr->PCIDevId = 0x1040;
|
||
|
||
//
|
||
// try to configure for the PCI bus, fully-compliant HBA.
|
||
// Specify the bus type.
|
||
//
|
||
hwInitializationData.AdapterInterfaceType = PCIBus;
|
||
hwInitializationData.VendorId = VendorId;
|
||
hwInitializationData.VendorIdLength = 4;
|
||
hwInitializationData.DeviceId = NewDeviceId;
|
||
hwInitializationData.DeviceIdLength = 4;
|
||
PCIStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
|
||
|
||
//
|
||
// Now try to configure for the EISA bus.
|
||
// Specify the bus type.
|
||
//
|
||
|
||
hwInitializationData.AdapterInterfaceType = Eisa;
|
||
|
||
CurrContextPtr->AdapterCount = 0;
|
||
CurrContextPtr->PCIDevId = 0;
|
||
EisaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
|
||
|
||
|
||
//
|
||
// Now try to configure for the Mca bus.
|
||
// Specifiy the bus type.
|
||
//
|
||
|
||
hwInitializationData.AdapterInterfaceType = MicroChannel;
|
||
|
||
CurrContextPtr->AdapterCount = 0;
|
||
CurrContextPtr->PCIDevId = 0;
|
||
mcaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
|
||
|
||
//
|
||
// Now try to configure for the ISA bus.
|
||
// Specifiy the bus type.
|
||
//
|
||
|
||
hwInitializationData.AdapterInterfaceType = Isa;
|
||
|
||
CurrContextPtr->AdapterCount = 0;
|
||
CurrContextPtr->PCIDevId = 0;
|
||
isaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
|
||
|
||
//
|
||
// Return the smallest status.
|
||
//
|
||
|
||
LowStatus1 = (PCIStatus < EisaStatus ? PCIStatus : EisaStatus);
|
||
LowStatus2 = (mcaStatus < isaStatus ? mcaStatus : isaStatus);
|
||
|
||
return(LowStatus1 < LowStatus2 ? LowStatus1 : LowStatus2);
|
||
|
||
} // end BLogicEntry()
|
||
|
||
|
||
ULONG
|
||
BLogicFindAdapter (
|
||
IN PCARD_STRUC CardPtr,
|
||
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:
|
||
|
||
CardPtr - 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
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG length;
|
||
ULONG status;
|
||
ULONG i;
|
||
UCHAR adapterTid;
|
||
UCHAR dmaChannel;
|
||
UCHAR irq;
|
||
UCHAR bit;
|
||
UCHAR VesaCard = 0;
|
||
UCHAR ThrowAway;
|
||
PBASE_REGISTER baseIoAddress;
|
||
BOOLEAN NoErrorOnWide = TRUE;
|
||
PBL_CONTEXT CurrContextPtr = (PBL_CONTEXT)Context;
|
||
|
||
//
|
||
// Determine if there are any adapters installed. Determine installed
|
||
// will initialize the BaseIoAddress if an adapter is found.
|
||
//
|
||
|
||
status = BLogicDetermineInstalled(CardPtr,
|
||
ConfigInfo,
|
||
(PBL_CONTEXT)CurrContextPtr,
|
||
Again);
|
||
|
||
//
|
||
// If there are not adapter's found then return.
|
||
//
|
||
|
||
if ((status != SP_RETURN_FOUND) && (status != RETURN_FOUND_VESA)) {
|
||
return(status);
|
||
}
|
||
|
||
baseIoAddress = CardPtr->BaseIoAddress;
|
||
|
||
if (status == RETURN_FOUND_VESA) {
|
||
VesaCard = 1;
|
||
}
|
||
|
||
//
|
||
// 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(CardPtr, AC_RET_CONFIGURATION_DATA)) {
|
||
DebugPrint((1,"BLogicFindAdapter: Get configuration data command failed\n"));
|
||
return SP_RETURN_ERROR;
|
||
}
|
||
|
||
//
|
||
// Determine DMA channel.
|
||
//
|
||
|
||
if (!ReadCommandRegister(CardPtr,&dmaChannel)) {
|
||
DebugPrint((1,"BLogicFindAdapter: Couldn't read dma channel\n"));
|
||
return SP_RETURN_ERROR;
|
||
}
|
||
|
||
/* EISA may have DMA channel disabled or MCA byte is not valid */
|
||
/* also, vesa card always returns DMA channel 5 */
|
||
|
||
if ((dmaChannel != 0) && (!VesaCard)
|
||
&& (ConfigInfo->AdapterInterfaceType != PCIBus)){
|
||
WHICH_BIT(dmaChannel,bit);
|
||
ConfigInfo->DmaChannel = bit;
|
||
}
|
||
|
||
DebugPrint((2,"BLogicFindAdapter: DMA channel is %x\n",
|
||
ConfigInfo->DmaChannel));
|
||
|
||
//
|
||
// Determine hardware interrupt vector.
|
||
//
|
||
|
||
if (!ReadCommandRegister(CardPtr,&irq)) {
|
||
DebugPrint((1,"BLogicFindAdapter: Couldn't read adapter irq\n"));
|
||
return SP_RETURN_ERROR;
|
||
}
|
||
|
||
WHICH_BIT(irq, bit);
|
||
|
||
//
|
||
// BusInterruptLevel is already provided for us in the ConfigInfo
|
||
// structure on the fully-compliant 946C boards - otherwise,
|
||
// IRQ assignment from the 0Bh HBA command
|
||
//
|
||
|
||
if (!((ConfigInfo->AdapterInterfaceType == PCIBus) &&
|
||
(CurrContextPtr->PCIDevId == 0x1040)))
|
||
{
|
||
ConfigInfo->BusInterruptLevel = (UCHAR) 9 + bit;
|
||
}
|
||
//
|
||
// Determine what SCSI bus id the adapter is on.
|
||
//
|
||
|
||
if (!ReadCommandRegister(CardPtr,&adapterTid)) {
|
||
DebugPrint((1,"BLogicFindAdapter: Couldn't read adapter SCSI id\n"));
|
||
return SP_RETURN_ERROR;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicFindAdapter: Setup info cmd failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Set number of buses.
|
||
//
|
||
|
||
ConfigInfo->NumberOfBuses = 1;
|
||
ConfigInfo->InitiatorBusId[0] = adapterTid;
|
||
CardPtr->HostTargetId = adapterTid;
|
||
|
||
// ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE;
|
||
ConfigInfo->ScatterGather = TRUE;
|
||
ConfigInfo->Master = TRUE;
|
||
ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS - 1;
|
||
CardPtr->MailBoxArray = ScsiPortGetUncachedExtension(
|
||
CardPtr,
|
||
ConfigInfo,
|
||
sizeof(NONCACHED_EXTENSION));
|
||
|
||
if (CardPtr->MailBoxArray == NULL) {
|
||
|
||
//
|
||
// Log error.
|
||
//
|
||
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
0,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
6 << 16
|
||
);
|
||
|
||
return(SP_RETURN_ERROR);
|
||
}
|
||
|
||
//
|
||
// Convert virtual to physical mailbox address.
|
||
//
|
||
|
||
CardPtr->MailBoxArray->MailboxPA =
|
||
ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(CardPtr,
|
||
NULL,
|
||
CardPtr->MailBoxArray->Mbo,
|
||
&length));
|
||
|
||
//
|
||
// Assume that physical address is below 16M
|
||
//
|
||
|
||
ASSERT(CardPtr->MailBoxArray->MailboxPA < 0x1000000);
|
||
|
||
// check for wide support ONLY if on NT 3.5 platform */
|
||
|
||
if (ConfigInfo->Length == CONFIG_INFO_VERSION_2)
|
||
{
|
||
CardPtr->Flags |= OS_SUPPORTS_WIDE;
|
||
|
||
// default to non-wide support
|
||
|
||
ConfigInfo->MaximumNumberOfTargets = 8;
|
||
|
||
// turn on wide support if available
|
||
|
||
NoErrorOnWide = TRUE;
|
||
|
||
if (!WriteCommandRegister(CardPtr, AC_WIDE_SUPPORT)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
NoErrorOnWide = FALSE;
|
||
}
|
||
else if (!CheckInvalid(CardPtr)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
// DebugPrint((0,"BLogicFindAdapter: check invalid failed \n"));
|
||
NoErrorOnWide = FALSE;
|
||
}
|
||
else if (!WriteCommandRegister(CardPtr, 0x01)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
NoErrorOnWide = FALSE;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
NoErrorOnWide = FALSE;
|
||
}
|
||
else if (NoErrorOnWide) {
|
||
CardPtr->Flags |= WIDE_ENABLED;
|
||
ConfigInfo->MaximumNumberOfTargets = 16;
|
||
|
||
}
|
||
} /* end if NT 3.5, then check for wide support */
|
||
|
||
DebugPrint((3,"BLogicFindAdapter: Configuration completed\n"));
|
||
|
||
|
||
//
|
||
// enable generation on interrupts to the host on HBAs that support
|
||
// the 0x25 command used previously to disable generation of ints
|
||
// during this routine's call to DetermineInstalled
|
||
//
|
||
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_INT_GENERATION_STATE)){
|
||
DebugPrint((1,"BLogicFindAdapter: ints enable/disable cmd failed\n"));
|
||
}
|
||
else if (!CheckInvalid(CardPtr)) {
|
||
DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n")); DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
|
||
|
||
}
|
||
else{
|
||
ThrowAway = ENABLE_INTS;
|
||
if (!WriteCommandRegister(CardPtr,ThrowAway)){
|
||
DebugPrint((1,"BLogicFindAdapter: ints enable/disable cmd failed\n"));
|
||
}
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
|
||
// this cmd DOES NOT generate an interrupt - so
|
||
// just check for command complete!
|
||
|
||
if (!(ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)
|
||
& (IOP_SCSI_HBA_IDLE))) {
|
||
DebugPrint((1,"BLogicFindAdapter: ints enable/disable cmd failed\n"));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set up DMA type based on bus type
|
||
//
|
||
|
||
ConfigInfo->Dma32BitAddresses =
|
||
(ConfigInfo->AdapterInterfaceType == Isa) ? FALSE : TRUE;
|
||
return SP_RETURN_FOUND;
|
||
|
||
} // end BLogicFindAdapter()
|
||
|
||
|
||
BOOLEAN
|
||
BLogicAdapterState(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PVOID Context,
|
||
IN BOOLEAN SaveState
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Buslogic adapters will take advantage of work done in the past to
|
||
support Novell networks. This means any MSDOS mode driver will be set
|
||
up to run without using mailboxes. This will save the work of having
|
||
to save/restore mailbox locations for the MSDOS driver in this routine.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
Context - Register base address
|
||
SaveState - TRUE == Save real mode state ; FALSE == Restore real mode state
|
||
|
||
Return Value:
|
||
|
||
TRUE - Save/Restore operation was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
return TRUE;
|
||
} // end BLogicAdapterState()
|
||
|
||
|
||
|
||
BOOLEAN
|
||
BLIsCloneIDByte(
|
||
IN PCARD_STRUC CardPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs the adapter ID command and determines if the
|
||
adapter is potentially a BusLogic adapter.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport data storage
|
||
|
||
Return Value:
|
||
|
||
TRUE if it looks like the adapter is a clone or if the command fails.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR byte;
|
||
UCHAR specialOptions;
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
|
||
ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
|
||
IOP_INTERRUPT_RESET);
|
||
|
||
if (!WriteCommandRegister(CardPtr, AC_ADAPTER_INQUIRY)) {
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Byte 0.
|
||
//
|
||
|
||
if ((ReadCommandRegister(CardPtr, &byte)) == FALSE) {
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Get the special options byte.
|
||
//
|
||
|
||
if ((ReadCommandRegister(CardPtr, &specialOptions)) == FALSE) {
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Get the last two bytes and clear the interrupt.
|
||
//
|
||
|
||
if ((ReadCommandRegister(CardPtr, &byte)) == FALSE) {
|
||
return TRUE;
|
||
}
|
||
|
||
if ((ReadCommandRegister(CardPtr, &byte)) == FALSE) {
|
||
return TRUE;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicIsClone: Setup info cmd failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if ((specialOptions == 0x30) || (specialOptions == 0x42)) {
|
||
|
||
//
|
||
// This is an adaptec or AMI adapter.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
} // end BLIsCloneIDByte()
|
||
|
||
|
||
ULONG
|
||
BLogicDetermineInstalled(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
IN OUT PBL_CONTEXT CurrContextPtr,
|
||
OUT PBOOLEAN Again
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if BusLogic SCSI adapter is installed in system
|
||
by reading the status register as each base I/O address
|
||
and looking for a pattern. If an adapter is found, the BaseIoAddres is
|
||
initialized.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
ConfigInfo - Supplies the known configuraiton information.
|
||
|
||
CurrContextPtr - Supplies the count of adapter slots which have been
|
||
tested and, in the case of PCI, the Device ID.
|
||
|
||
Again - Returns whehter the OS specific driver should call again.
|
||
|
||
Return Value:
|
||
|
||
Returns a status indicating whether a driver is present or not.
|
||
|
||
--*/
|
||
|
||
{
|
||
PBASE_REGISTER baseIoAddress;
|
||
PUCHAR ioSpace;
|
||
UCHAR ThrowAway,TaggedQueueSupport,EISAConfigReg;
|
||
UCHAR i;
|
||
BOOLEAN configProvided = FALSE;
|
||
UCHAR FoundVesaCard = 0;
|
||
ULONG *AdapterAddrPtr;
|
||
ULONG length;
|
||
SCSI_PHYSICAL_ADDRESS PhysAddr;
|
||
|
||
|
||
if (ConfigInfo->AdapterInterfaceType == Eisa)
|
||
InittedEISABoards = 1;
|
||
|
||
//
|
||
// Get the system physical address for this card. The card uses I/O space.
|
||
//
|
||
|
||
AdapterAddrPtr = (ConfigInfo->AdapterInterfaceType == PCIBus) ?
|
||
PciAdapterAddresses : AdapterAddresses;
|
||
|
||
//
|
||
// Scan though the adapter address looking for adapters.
|
||
//
|
||
|
||
ioSpace = NULL;
|
||
while (AdapterAddrPtr[CurrContextPtr->AdapterCount] != 0) {
|
||
|
||
//
|
||
// Free any previously allocated ioSpace.
|
||
//
|
||
|
||
if (ioSpace) {
|
||
ScsiPortFreeDeviceBase(
|
||
CardPtr,
|
||
ioSpace
|
||
);
|
||
}
|
||
|
||
//
|
||
// If the calling operating system has configuration information
|
||
// already established for the driver then the RangeLength will be
|
||
// set to zero instead of SP_UNINITIALIZED_VALUE. This is used
|
||
// to indicate the condition and this routine will search for an
|
||
// adapter based on the information provided.
|
||
//
|
||
|
||
configProvided = ((*ConfigInfo->AccessRanges)[0].RangeLength == 0) ? FALSE : TRUE;
|
||
if (configProvided) {
|
||
ioSpace = ScsiPortGetDeviceBase(
|
||
CardPtr, // CardPtr
|
||
ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
|
||
ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
|
||
(*ConfigInfo->AccessRanges)[0].RangeStart,
|
||
0x16, // NumberOfBytes
|
||
TRUE // InIoSpace
|
||
);
|
||
|
||
if (!ioSpace) {
|
||
return SP_RETURN_NOT_FOUND;
|
||
}
|
||
} else {
|
||
ioSpace = ScsiPortGetDeviceBase(
|
||
CardPtr, // CardPtr
|
||
ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
|
||
ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
|
||
ScsiPortConvertUlongToPhysicalAddress(AdapterAddrPtr[CurrContextPtr->AdapterCount]),
|
||
0x16, // NumberOfBytes
|
||
TRUE // InIoSpace
|
||
);
|
||
if (!ioSpace) {
|
||
continue;
|
||
}
|
||
}
|
||
baseIoAddress = (PBASE_REGISTER)ioSpace;
|
||
|
||
//
|
||
// Check to see if adapter present in system.
|
||
//
|
||
|
||
CardPtr->BaseIoAddress = baseIoAddress;
|
||
DebugPrint((1,"BLogic: Base IO address is %x\n", baseIoAddress));
|
||
|
||
//
|
||
// Update the adapter count.
|
||
//
|
||
|
||
(CurrContextPtr->AdapterCount)++;
|
||
|
||
|
||
|
||
//
|
||
// Check to make sure the I/O range is not already in use
|
||
//
|
||
PhysAddr = ScsiPortConvertUlongToPhysicalAddress((ULONG)baseIoAddress);
|
||
|
||
if (!(ScsiPortValidateRange(
|
||
CardPtr, // CardPtr
|
||
ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
|
||
ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
|
||
PhysAddr,
|
||
4, // NumberOfBytes
|
||
TRUE // InIoSpace
|
||
))) {
|
||
|
||
continue;
|
||
}
|
||
|
||
|
||
if (((ScsiPortReadPortUchar((PUCHAR)baseIoAddress)) & (~0x2C)) == 0x10) {
|
||
|
||
|
||
//
|
||
// Before sending any other host adapter commands, try to disable
|
||
// generation of interrupts to the host (HBA command 0x25).
|
||
// On f.w. that support this command, we will be able
|
||
// to initialize an HBA that is sharing an IRQ level with a
|
||
// previously-initialized HBA on the same IRQ without winding up
|
||
// in the ISR for the first HBA in an endless "not our interrupt"
|
||
// loop due to level-triggered int generated by second HBA (not yet
|
||
// registered by the OS for any ISR). This should allow us to share
|
||
// interrupts on critical platforms such as PCI.
|
||
//
|
||
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_INT_GENERATION_STATE)){
|
||
DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n"));
|
||
}
|
||
else if (!CheckInvalid(CardPtr)) {
|
||
DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n")); DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
|
||
}
|
||
else{
|
||
ThrowAway = DISABLE_INTS;
|
||
if (!WriteCommandRegister(CardPtr,ThrowAway)){
|
||
DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n"));
|
||
}
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
|
||
// this cmd DOES NOT generate an interrupt - so
|
||
// just check for command complete!
|
||
|
||
if (!(ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)
|
||
& (IOP_SCSI_HBA_IDLE))) {
|
||
DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n"));
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Check adapter inquiry to get rid of clones.
|
||
//
|
||
|
||
if (BLIsCloneIDByte(CardPtr)) {
|
||
DebugPrint((1, "BLogicDetermineInstalled: Clone byte not BusLogic\n"));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Send BusLogic Internal cmd (84h) to distinguish from clones
|
||
//
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_EXTENDED_FWREV)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Extended FW Rev command failed\n"));
|
||
continue;
|
||
}
|
||
|
||
if (!ReadCommandRegister(CardPtr,&ThrowAway)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Extended FW Rev cmd failed\n"));
|
||
continue;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Extended FW Rev cmd failed\n"));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Send Extended Setup Info cmd (8dh)
|
||
//
|
||
|
||
if (!WriteCommandRegister(CardPtr,
|
||
AC_EXTENDED_SETUP_INFO)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Get Extended Setup Info cmd failed\n"));
|
||
continue;
|
||
}
|
||
if (!WriteCommandRegister(CardPtr,
|
||
11)) { /* ask for 11 bytes */
|
||
DebugPrint((1,"BLogicDetermineInstalled: Get Extended Setup Info cmd failed\n"));
|
||
continue;
|
||
}
|
||
|
||
if (!ReadCommandRegister(CardPtr,&CardPtr->BusType)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Throw away next 8 bytes
|
||
//
|
||
|
||
for (i = 0; i < 8; i ++)
|
||
{
|
||
if (!ReadCommandRegister(CardPtr,&ThrowAway)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
|
||
break;
|
||
}
|
||
}
|
||
if (i != 8)
|
||
continue;
|
||
|
||
/* read EISA config reg - throw away byte for ISA and MCA */
|
||
|
||
if (!ReadCommandRegister(CardPtr,&EISAConfigReg)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
|
||
continue;
|
||
}
|
||
|
||
if (!ReadCommandRegister(CardPtr,&TaggedQueueSupport)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
|
||
continue;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: Extended Setup info cmd failed\n"));
|
||
continue;
|
||
}
|
||
|
||
if (TaggedQueueSupport != 0) {
|
||
CardPtr->Flags |= TAGGED_QUEUING;
|
||
}
|
||
|
||
switch (CardPtr->BusType) {
|
||
case ISA_HBA:
|
||
if (ConfigInfo->AdapterInterfaceType != Isa)
|
||
continue;
|
||
break;
|
||
|
||
case EISA_HBA:
|
||
|
||
// EISA, VESA, and PCI HBAs all , reporting back as bus type
|
||
// EISA, will always reflect accurate edge\level info in
|
||
// in "EISAConfigReg" below - I checked with FW group on this
|
||
|
||
ConfigInfo->InterruptMode = EISAConfigReg & LEVEL_TRIG ? LevelSensitive : Latched;
|
||
|
||
if (ConfigInfo->AdapterInterfaceType == Eisa)
|
||
{
|
||
if (!(FindOurEISAId(CardPtr,ConfigInfo,baseIoAddress)))
|
||
{
|
||
FoundVesaCard = 1;
|
||
}
|
||
break;
|
||
}
|
||
else if (ConfigInfo->AdapterInterfaceType == Isa)
|
||
{
|
||
/* if we already reported this HBA as an EISA board */
|
||
/* don't double report. Otherwise, this must be a VESA */
|
||
/* board on an ISA-VESA motherboard. */
|
||
|
||
if (InittedEISABoards)
|
||
continue;
|
||
else
|
||
{
|
||
FoundVesaCard = 1;
|
||
break;
|
||
}
|
||
}
|
||
else if (ConfigInfo->AdapterInterfaceType == PCIBus)
|
||
break;
|
||
|
||
case MCA_HBA:
|
||
if (ConfigInfo->AdapterInterfaceType != MicroChannel)
|
||
continue;
|
||
break;
|
||
|
||
} /* end switch */
|
||
|
||
//
|
||
// turn off ISA-compatible I/O mapping on compliant PCI HBAs.
|
||
//
|
||
|
||
if (ConfigInfo->AdapterInterfaceType == PCIBus)
|
||
{
|
||
//
|
||
// Turn off ISA-compatible I/O mapping for this HBA
|
||
//
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_ISA_COMPATIBLE_SUPPORT)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
|
||
continue;
|
||
}
|
||
else if (!CheckInvalid(CardPtr)) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
|
||
continue;
|
||
}
|
||
else{
|
||
ThrowAway = DISABLE_ISA_MAPPING;
|
||
if (!WriteCommandRegister(CardPtr,ThrowAway)){
|
||
DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
|
||
// this cmd DOES NOT generate an interrupt - so
|
||
// just check for command complete!
|
||
|
||
if (!(ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)
|
||
& (IOP_SCSI_HBA_IDLE))) {
|
||
DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
|
||
continue;
|
||
}
|
||
}
|
||
} // turn off ISA- compatible I/O mapping on PCI-compliant 946C cards
|
||
|
||
//
|
||
// An adapter has been found. Set the base address in the device
|
||
// extension, and request another call.
|
||
//
|
||
|
||
*Again = TRUE;
|
||
|
||
//
|
||
// Fill in the access array information.
|
||
//
|
||
|
||
if (!configProvided) {
|
||
(*ConfigInfo->AccessRanges)[0].RangeStart =
|
||
ScsiPortConvertUlongToPhysicalAddress(
|
||
AdapterAddresses[(CurrContextPtr->AdapterCount) - 1]);
|
||
}
|
||
(*ConfigInfo->AccessRanges)[0].RangeLength = 4;
|
||
(*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
|
||
|
||
|
||
return(FoundVesaCard ? RETURN_FOUND_VESA : SP_RETURN_FOUND);
|
||
|
||
} /* end if ((baseIoAddress) & (~0x2C)) == 0x10) */
|
||
} /* end adapter count loop */
|
||
|
||
//
|
||
// 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;
|
||
CurrContextPtr->AdapterCount = 0;
|
||
|
||
return(SP_RETURN_NOT_FOUND);
|
||
|
||
} // end BLogicDetermineInstalled()
|
||
|
||
ULONG
|
||
FindOurEISAId(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
||
PBASE_REGISTER baseIoAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if BusLogic HBA is an EISA or VESA board. Try to match both
|
||
our EISA ID and the base port of the board in question. If both match
|
||
this is an EISA board. If not, this must be our VESA board.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
ConfigInfo - Supplies the known configuration information.
|
||
|
||
baseIoAddress - Base IO port address for this HBA
|
||
|
||
Return Value:
|
||
|
||
Returns one if successful - means the card in question is an EISA card.
|
||
Returns zero if unsuccessful - means the card in question is a VESA card.
|
||
|
||
--*/
|
||
|
||
{
|
||
PEISA_ID eisaID;
|
||
ULONG eisaSlotNumber;
|
||
PVOID eisaAddress;
|
||
UCHAR Port;
|
||
|
||
//
|
||
// Clear any high order base address bits.
|
||
//
|
||
|
||
baseIoAddress = (PBASE_REGISTER)((ULONG) baseIoAddress & 0xFFF);
|
||
|
||
//
|
||
// Check to see if adapter EISA ID can be found
|
||
//
|
||
|
||
for (eisaSlotNumber= 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++)
|
||
{
|
||
|
||
//
|
||
// Get the system address for this card.
|
||
// The card uses I/O space.
|
||
//
|
||
|
||
eisaAddress = ScsiPortGetDeviceBase(CardPtr,
|
||
ConfigInfo->AdapterInterfaceType,
|
||
ConfigInfo->SystemIoBusNumber,
|
||
ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
|
||
0x1000,
|
||
TRUE);
|
||
|
||
eisaID =
|
||
(PEISA_ID)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
|
||
|
||
if ((ScsiPortReadPortUchar(&eisaID->BoardId[0]) == 0x0A) &&
|
||
(ScsiPortReadPortUchar(&eisaID->BoardId[1]) == 0xB3) &&
|
||
((ScsiPortReadPortUchar(&eisaID->BoardId[2]) == 0x42) ||
|
||
(ScsiPortReadPortUchar(&eisaID->BoardId[2]) == 0x47)))
|
||
{
|
||
|
||
/* still need to look for IO port match because we could */
|
||
/* have VESA and EISA BusLogic cards in same machine */
|
||
|
||
Port = (ScsiPortReadPortUchar(&eisaID->IOPort[0]) & PORTMASK);
|
||
|
||
switch (Port) {
|
||
case 0:
|
||
if ((ULONG)baseIoAddress == 0x330)
|
||
{
|
||
DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
|
||
eisaSlotNumber,baseIoAddress));
|
||
return(1);
|
||
}
|
||
break;
|
||
case 1:
|
||
if ((ULONG)baseIoAddress == 0x334)
|
||
{
|
||
DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
|
||
eisaSlotNumber,baseIoAddress));
|
||
return(1);
|
||
}
|
||
break;
|
||
case 2:
|
||
if ((ULONG)baseIoAddress == 0x230)
|
||
{
|
||
DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
|
||
eisaSlotNumber,baseIoAddress));
|
||
return(1);
|
||
}
|
||
break;
|
||
case 3:
|
||
if ((ULONG)baseIoAddress == 0x234)
|
||
{
|
||
DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
|
||
eisaSlotNumber,baseIoAddress));
|
||
return(1);
|
||
}
|
||
break;
|
||
case 4:
|
||
if ((ULONG)baseIoAddress == 0x130)
|
||
{
|
||
DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
|
||
eisaSlotNumber,baseIoAddress));
|
||
return(1);
|
||
}
|
||
break;
|
||
case 5:
|
||
if ((ULONG)baseIoAddress == 0x134)
|
||
{
|
||
DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
|
||
eisaSlotNumber,baseIoAddress));
|
||
return(1);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
} /* end switch */
|
||
|
||
} /* end if found BusLogic ID */
|
||
} /* end for loop */
|
||
|
||
DebugPrint((1,"BusLogic: VESA Adapter found at port %x\n",baseIoAddress));
|
||
return(0);
|
||
}
|
||
|
||
BOOLEAN
|
||
BLogicHwInitialize(
|
||
IN PCARD_STRUC CardPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is a required entry point.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
TRUE - if initialization successful.
|
||
FALSE - if initialization unsuccessful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNONCACHED_EXTENSION MailBoxArray =
|
||
CardPtr->MailBoxArray;
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
UCHAR status;
|
||
ULONG i;
|
||
PDEV_STRUC DevStruc;
|
||
UCHAR TargID;
|
||
UCHAR Lun;
|
||
|
||
DebugPrint((2,"BLogicHwInitialize: Reset BusLogic HBA and SCSI bus\n"));
|
||
|
||
//
|
||
// Reset HBA.
|
||
//
|
||
|
||
ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET);
|
||
|
||
ScsiPortStallExecution(500*1000);
|
||
|
||
//
|
||
// Wait up to 500 microseconds for adapter to initialize.
|
||
//
|
||
|
||
for (i = 0; i < 500; i++) {
|
||
|
||
ScsiPortStallExecution(1);
|
||
|
||
status = ScsiPortReadPortUchar(&CardPtr->BaseIoAddress->StatusRegister);
|
||
|
||
if (status & IOP_SCSI_HBA_IDLE) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check if reset failed or succeeded.
|
||
//
|
||
|
||
if (!(status & IOP_SCSI_HBA_IDLE) || !(status & IOP_MAILBOX_INIT_REQUIRED))
|
||
{
|
||
|
||
DebugPrint((0, "BLogicHwInitialize: Soft reset failed.\n"));
|
||
|
||
//
|
||
// If the soft reset does not work, try a hard reset.
|
||
//
|
||
|
||
if (!BLogicResetBus(CardPtr, 0)) {
|
||
DebugPrint((1,"BLogicHwInitialize: Reset SCSI bus failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Inform the port driver that the bus has been reset.
|
||
//
|
||
|
||
|
||
ScsiPortNotification(ResetDetected, CardPtr, 0);
|
||
|
||
DebugPrint((1,"BLogicHwInitialize: Reset completed\n"));
|
||
|
||
}
|
||
else /* soft reset succeeded */
|
||
{
|
||
|
||
//
|
||
// Complete all outstanding requests with SRB_STATUS_BUS_RESET.
|
||
//
|
||
|
||
ScsiPortCompleteRequest(CardPtr,
|
||
CardPtr->BusNum,
|
||
(UCHAR) -1,
|
||
(UCHAR) -1,
|
||
SRB_STATUS_BUS_RESET);
|
||
//
|
||
// Reinitialize Active CCBS pointer and counter in LUN extensions
|
||
//
|
||
|
||
for (TargID= 0; TargID < 8; TargID++)
|
||
for (Lun = 0; Lun < 8; Lun++)
|
||
{
|
||
if (DevStruc= (PDEV_STRUC) (ScsiPortGetLogicalUnit(CardPtr,0,TargID,Lun)))
|
||
{
|
||
DevStruc->CurrentCCB = 0;
|
||
DevStruc->NumActive = 0;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Zero out mailboxes.
|
||
//
|
||
|
||
for (i=0; i<MB_COUNT; i++) {
|
||
|
||
PMBO mailboxOut;
|
||
PMBI mailboxIn;
|
||
|
||
mailboxIn = &MailBoxArray->Mbi[i];
|
||
mailboxOut = &MailBoxArray->Mbo[i];
|
||
|
||
mailboxOut->Command = mailboxIn->Status = 0;
|
||
}
|
||
|
||
CardPtr->StartMBO = (PMBO)(&MailBoxArray->Mbo);
|
||
CardPtr->CurrMBO = (PMBO)(&MailBoxArray->Mbo);
|
||
CardPtr->LastMBO = ((PMBO)(&MailBoxArray->Mbo) + (MB_COUNT - 1));
|
||
CardPtr->StartMBI =(PMBI)( &MailBoxArray->Mbi);
|
||
CardPtr->CurrMBI = (PMBI)(&MailBoxArray->Mbi);
|
||
CardPtr->LastMBI = ((PMBI)(&MailBoxArray->Mbi) + (MB_COUNT - 1));
|
||
|
||
|
||
DebugPrint((3,"BLogicHwInitialize: Initialize mailbox\n"));
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_MBOX_EXTENDED_INIT)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Couldn't initialize mailboxes\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Send Adapter number of mailbox locations.
|
||
//
|
||
|
||
if (!WriteCommandRegister(CardPtr,MB_COUNT)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte0)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte1)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte2)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte3)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
//
|
||
// Override default setting for bus on time. This makes floppy
|
||
// drives work better with this adapter.
|
||
//
|
||
|
||
if (!WriteCommandRegister(CardPtr, AC_SET_BUS_ON_TIME)) {
|
||
|
||
DebugPrint((1,"BlogicHWInitialize:Can't set bus on time\n"));
|
||
return FALSE;
|
||
|
||
} else if (!WriteCommandRegister(CardPtr, 0x05)) {
|
||
|
||
DebugPrint((1,"BlogicHWInitialize:Can't set bus on time\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Set BUS On time failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
/* turn on wide support if available */
|
||
if (CardPtr->Flags & OS_SUPPORTS_WIDE)
|
||
{
|
||
// DebugPrint((0,"BLogicHwInitialize: about to send wide cmd\n"));
|
||
|
||
if (!WriteCommandRegister(CardPtr, AC_WIDE_SUPPORT)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
else if (!CheckInvalid(CardPtr)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
else if (!WriteCommandRegister(CardPtr, 0x01)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
else {
|
||
CardPtr->Flags |= WIDE_ENABLED;
|
||
}
|
||
} /* end if OS_SUPPORTS_WIDE */
|
||
|
||
return TRUE;
|
||
|
||
} // end BLogicHwInitialize()
|
||
|
||
|
||
BOOLEAN
|
||
BLogicStartIo(
|
||
IN PCARD_STRUC CardPtr,
|
||
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:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
Srb - IO request packet
|
||
|
||
Return Value:
|
||
|
||
TRUE
|
||
|
||
--*/
|
||
|
||
{
|
||
PNONCACHED_EXTENSION MailBoxArray =
|
||
CardPtr->MailBoxArray;
|
||
PCCB ccb;
|
||
PDEV_STRUC DevStruc;
|
||
PCCB ActiveCCB;
|
||
ULONG i = 0;
|
||
UCHAR MaxActive = 0;
|
||
UCHAR j;
|
||
|
||
DebugPrint((3,"BLogicStartIo: Enter routine\n"));
|
||
|
||
if (CardPtr->Flags & REINIT_REQUIRED)
|
||
{
|
||
if (!ReInitializeHBA(CardPtr,Srb->PathId))
|
||
{
|
||
DebugPrint((1,"BLogicStartIo: HBA reinitialization failed\n"));
|
||
return FALSE;
|
||
}
|
||
CardPtr->Flags &= (~REINIT_REQUIRED);
|
||
}
|
||
|
||
//
|
||
// Check if command is an ABORT request.
|
||
//
|
||
|
||
if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
|
||
|
||
//
|
||
// Get CCB to abort.
|
||
//
|
||
|
||
ccb = Srb->NextSrb->SrbExtension;
|
||
MaxActive =(Srb->NextSrb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ?
|
||
MAXACTIVE_TAGGED : MAXACTIVE;
|
||
|
||
//
|
||
// Verify that CCB to abort is still outstanding.
|
||
//
|
||
|
||
DevStruc =
|
||
ScsiPortGetLogicalUnit(CardPtr,
|
||
Srb->PathId,
|
||
Srb->TargetId,
|
||
Srb->Lun);
|
||
|
||
for (j=DevStruc->NumActive, ActiveCCB = DevStruc->CurrentCCB;
|
||
j > 0; j--)
|
||
{
|
||
if (ActiveCCB != ccb)
|
||
ActiveCCB = ActiveCCB->NxtActiveCCB;
|
||
else
|
||
break;
|
||
|
||
}
|
||
|
||
if (j == 0)
|
||
{
|
||
|
||
DebugPrint((1, "BLogicStartIo: SRB to abort already completed\n"));
|
||
|
||
//
|
||
// Complete abort SRB.
|
||
//
|
||
|
||
Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
CardPtr,
|
||
Srb);
|
||
//
|
||
// Adapter ready for next request.
|
||
//
|
||
if (DevStruc->NumActive < MaxActive)
|
||
ScsiPortNotification(NextLuRequest,CardPtr,Srb->PathId,
|
||
Srb->TargetId,Srb->Lun);
|
||
else
|
||
ScsiPortNotification(NextRequest,CardPtr,NULL);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// Set abort SRB for completion.
|
||
//
|
||
|
||
ccb->AbortSrb = Srb;
|
||
SendCCB(Srb,CardPtr,DevStruc);
|
||
|
||
if (DevStruc->NumActive < MaxActive)
|
||
ScsiPortNotification(NextLuRequest,CardPtr,Srb->PathId,
|
||
Srb->TargetId,Srb->Lun);
|
||
else
|
||
ScsiPortNotification(NextRequest,CardPtr,NULL);
|
||
|
||
return TRUE;
|
||
|
||
} /* end ABORT request handling */
|
||
|
||
|
||
ccb = Srb->SrbExtension;
|
||
|
||
ccb->SrbAddress = Srb; /* Save SRB back ptr in CCB */
|
||
MaxActive = (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ?
|
||
MAXACTIVE_TAGGED : MAXACTIVE;
|
||
|
||
DevStruc = ScsiPortGetLogicalUnit(CardPtr,Srb->PathId,Srb->TargetId,
|
||
Srb->Lun);
|
||
|
||
switch (Srb->Function) {
|
||
|
||
case SRB_FUNCTION_EXECUTE_SCSI:
|
||
|
||
//
|
||
// Get logical unit extension.
|
||
//
|
||
|
||
|
||
DevStruc->NumActive++;
|
||
|
||
//
|
||
// Build CCB.
|
||
//
|
||
|
||
BuildCcb(CardPtr, Srb);
|
||
SendCCB(Srb,CardPtr,DevStruc);
|
||
break;
|
||
|
||
case SRB_FUNCTION_RESET_BUS:
|
||
|
||
//
|
||
// Reset Adapter and SCSI bus.
|
||
//
|
||
|
||
DebugPrint((1, "BLogicStartIo: Reset bus request received\n"));
|
||
|
||
if (!BLogicResetBus(CardPtr,Srb->PathId)) {
|
||
DebugPrint((1,"BLogicStartIo: Reset bus failed\n"));
|
||
Srb->SrbStatus = SRB_STATUS_ERROR;
|
||
} else {
|
||
|
||
Srb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
}
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
CardPtr,
|
||
Srb);
|
||
break;
|
||
|
||
|
||
case SRB_FUNCTION_RESET_DEVICE:
|
||
|
||
DevStruc->NumActive++;
|
||
|
||
ccb->OperationCode = RESET_COMMAND;
|
||
ccb->TargID = Srb->TargetId;
|
||
ccb->Lun = Srb->Lun;
|
||
|
||
SendCCB(Srb,CardPtr,DevStruc);
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
CardPtr,
|
||
Srb);
|
||
|
||
break;
|
||
|
||
//
|
||
// Drop through to default.
|
||
//
|
||
|
||
default:
|
||
|
||
//
|
||
// Set error, complete request
|
||
//
|
||
|
||
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
||
|
||
ScsiPortNotification(RequestComplete,CardPtr,Srb);
|
||
|
||
} // end switch
|
||
|
||
//
|
||
// Adapter ready for next request.
|
||
//
|
||
|
||
if (DevStruc->NumActive < MaxActive)
|
||
ScsiPortNotification(NextLuRequest,CardPtr,Srb->PathId,
|
||
Srb->TargetId,Srb->Lun);
|
||
else
|
||
ScsiPortNotification(NextRequest,CardPtr,NULL);
|
||
|
||
return TRUE;
|
||
|
||
|
||
} // end BLogicStartIo()
|
||
|
||
|
||
BOOLEAN
|
||
BLogicInterrupt(
|
||
IN PCARD_STRUC CardPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the interrupt service routine for the 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:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
TRUE if MailboxIn full
|
||
|
||
--*/
|
||
|
||
{
|
||
PNONCACHED_EXTENSION MailBoxArray =
|
||
CardPtr->MailBoxArray;
|
||
PCCB ccb;
|
||
PSCSI_REQUEST_BLOCK srb,abortsrb;
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
PMBI mailboxIn;
|
||
ULONG physicalCcb;
|
||
PDEV_STRUC DevStruc;
|
||
UCHAR mbox_compcode;
|
||
UCHAR InterruptFlags;
|
||
UCHAR MaxActive=0;
|
||
UCHAR TargID;
|
||
UCHAR Lun;
|
||
|
||
InterruptFlags = ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister);
|
||
|
||
DebugPrint((3,"BLogicInterrupt: Interrupt flags %x\n", InterruptFlags));
|
||
|
||
if (!(InterruptFlags & IOP_ANY_INTERRUPT)) {
|
||
DebugPrint((4,"BLogicInterrupt: Not our interrupt!\n"));
|
||
return FALSE;
|
||
}
|
||
else
|
||
/* Clear interrupt on adapter. */
|
||
ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
|
||
|
||
//
|
||
// Determine cause of interrupt.
|
||
//
|
||
|
||
if (InterruptFlags & IOP_COMMAND_COMPLETE) {
|
||
|
||
//
|
||
// Adapter command completed.
|
||
//
|
||
|
||
DebugPrint((2,"BLogicInterrupt: Adapter Command complete\n"));
|
||
DebugPrint((3,"BLogicInterrupt: Status %x\n",
|
||
ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)));
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
else if (InterruptFlags & IOP_SCSI_RESET_DETECTED) {
|
||
|
||
DebugPrint((1,"BLogicInterrupt: SCSI Reset detected\n"));
|
||
//
|
||
// Notify of reset.
|
||
//
|
||
|
||
//
|
||
// Reset HBA because firmware may be in confused state with
|
||
// respect to outstanding CCBs.
|
||
//
|
||
|
||
ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET);
|
||
|
||
//
|
||
// Notify OS of SCSI bus reset.
|
||
//
|
||
|
||
ScsiPortNotification(ResetDetected,CardPtr,NULL);
|
||
|
||
// Complete all active requests for specified unit
|
||
|
||
ScsiPortCompleteRequest(CardPtr,
|
||
(UCHAR) 0,
|
||
(UCHAR) -1,
|
||
(UCHAR) -1,
|
||
SRB_STATUS_BUS_RESET);
|
||
|
||
//
|
||
// Reinitialize Active CCBS pointer and counter in LUN extensions
|
||
//
|
||
|
||
for (TargID= 0; TargID < 8; TargID++)
|
||
for (Lun = 0; Lun < 8; Lun++)
|
||
{
|
||
if (DevStruc=ScsiPortGetLogicalUnit(CardPtr,0,TargID,Lun))
|
||
{
|
||
DevStruc->CurrentCCB = 0;
|
||
DevStruc->NumActive = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set flag indicating HBA reinitialization will be required before
|
||
// any new requests can be serviced (due to soft reset above).
|
||
//
|
||
|
||
CardPtr->Flags |= REINIT_REQUIRED;
|
||
}
|
||
|
||
else if (InterruptFlags & IOP_MBI_FULL) {
|
||
DebugPrint((3,"BLogicInterrupt: MBI Full\n"));
|
||
|
||
while (mailboxIn = DoneMbox(CardPtr))
|
||
{
|
||
|
||
physicalCcb = mailboxIn->Address;
|
||
DebugPrint((3, "BLogicInterrupt: Physical CCB %lx\n", physicalCcb));
|
||
|
||
/* Check if physical CCB is zero. ( to cover for hardware errs) */
|
||
|
||
if (!physicalCcb) {
|
||
|
||
DebugPrint((1,"BLogicInterrupt: Physical CCB address is 0\n"));
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Convert Physical CCB to Virtual.
|
||
//
|
||
|
||
ccb = ScsiPortGetVirtualAddress(CardPtr, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
|
||
DebugPrint((3, "BLogicInterrupt: 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(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
CardPtr->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
5 << 8
|
||
);
|
||
|
||
return(TRUE);
|
||
|
||
}
|
||
|
||
mbox_compcode = mailboxIn->Status;
|
||
mailboxIn->Status = MBI_FREE; /* free this In Mailbox */
|
||
|
||
//
|
||
// Get SRB from CCB.
|
||
//
|
||
|
||
srb = ccb->SrbAddress;
|
||
|
||
//
|
||
// Get logical unit extension.
|
||
//
|
||
|
||
DevStruc =
|
||
ScsiPortGetLogicalUnit(CardPtr,
|
||
srb->PathId,
|
||
srb->TargetId,
|
||
srb->Lun);
|
||
|
||
if (mbox_compcode == MBI_NOT_FOUND) {
|
||
DebugPrint((1, "BLogicInterrupt: aborted CCB not found %lx\n", ccb));
|
||
continue;
|
||
}
|
||
|
||
if (!AdjustCCBqueue (ccb,DevStruc)) {
|
||
|
||
//
|
||
// We have no record of the CCB returned by the adapter.
|
||
// Log it as an error.
|
||
//
|
||
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
CardPtr->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
(7 << 8) | mbox_compcode
|
||
);
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
srb->ScsiStatus = ccb->TargetStatus;
|
||
|
||
DebugPrint((2, "BLogicInterrupt: SCSI Status %x\n", srb->ScsiStatus));
|
||
DebugPrint((2, "BLogicInterrupt: Adapter Status %x\n", ccb->HostStatus));
|
||
|
||
//
|
||
// Check MBI status.
|
||
//
|
||
|
||
switch (mbox_compcode) {
|
||
|
||
case MBI_SUCCESS:
|
||
|
||
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
ASSERT(DevStruc->CurrentCCB);
|
||
break;
|
||
|
||
case MBI_ABORT:
|
||
|
||
DebugPrint((1, "BLogicInterrupt: CCB aborted\n"));
|
||
|
||
srb->SrbStatus = SRB_STATUS_ABORTED;
|
||
|
||
//
|
||
// Get the abort SRB (requested the abort) from CCB.
|
||
//
|
||
|
||
abortsrb = ccb->AbortSrb;
|
||
|
||
//
|
||
// Call notification routine for the aborted SRB.
|
||
//
|
||
|
||
ScsiPortNotification(RequestComplete,
|
||
CardPtr,
|
||
srb);
|
||
|
||
//
|
||
// Set status for completing abort request itself.
|
||
//
|
||
|
||
abortsrb->SrbStatus = SRB_STATUS_SUCCESS;
|
||
srb = abortsrb;
|
||
break;
|
||
|
||
case MBI_ERROR:
|
||
|
||
DebugPrint((2, "BLogicInterrupt: Error occurred\n"));
|
||
|
||
srb->SrbStatus = MapError(CardPtr, srb, ccb);
|
||
if (ccb->TargetStatus == 2)
|
||
if (ccb->RequestSenseLength != 1)
|
||
srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Log the error.
|
||
//
|
||
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
CardPtr->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
(1 << 8) | mbox_compcode
|
||
);
|
||
|
||
DebugPrint((1, "BLogicInterrupt: Unrecognized mailbox status\n"));
|
||
|
||
continue;
|
||
|
||
} // end switch on mailbox-in completion status
|
||
|
||
DevStruc->NumActive--;
|
||
MaxActive = (srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ?
|
||
MAXACTIVE_TAGGED : MAXACTIVE;
|
||
|
||
ScsiPortNotification(RequestComplete,CardPtr,srb);
|
||
|
||
//
|
||
// Notify that we are ready for another request
|
||
//
|
||
|
||
if (DevStruc->NumActive == (MaxActive - 1))
|
||
ScsiPortNotification(NextLuRequest,CardPtr,srb->PathId,
|
||
srb->TargetId,srb->Lun);
|
||
else /* assume we already asked for req for this LUN */
|
||
ScsiPortNotification(NextRequest,CardPtr,NULL);
|
||
|
||
} /* while done MBI */
|
||
|
||
} /* end if MBI full */
|
||
else
|
||
{ /* unexpected interrupt status */
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
CardPtr->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
(8 << 8)
|
||
);
|
||
|
||
DebugPrint((1, "BLogicInterrupt: Spurious Interrupt\n"));
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
} // end BLogicInterrupt()
|
||
|
||
|
||
VOID
|
||
BuildCcb(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build CCB
|
||
|
||
Arguments:
|
||
|
||
DeviceExtenson
|
||
SRB
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCCB ccb = Srb->SrbExtension;
|
||
UCHAR *pchar;
|
||
USHORT i;
|
||
ULONG physReqSensePtr;
|
||
ULONG length;
|
||
|
||
DebugPrint((3,"BuildCcb: Enter routine\n"));
|
||
|
||
// zero-fill the CCB
|
||
|
||
pchar = (UCHAR *) ccb;
|
||
for (i=0; i < sizeof(CCB); i++)
|
||
*pchar++= 0;
|
||
|
||
ccb->SrbAddress = Srb; /* Save SRB back ptr in CCB */
|
||
|
||
//
|
||
// Set CCB Operation Code.
|
||
//
|
||
|
||
if (Srb->DataTransferLength > 0)
|
||
ccb->OperationCode = SCATTER_GATHER_COMMAND;
|
||
else
|
||
ccb->OperationCode = SCSI_INITIATOR_COMMAND;
|
||
//
|
||
// Set target id and LUN.
|
||
//
|
||
|
||
ccb->TargID = Srb->TargetId;
|
||
ccb->Lun = Srb->Lun;
|
||
|
||
|
||
if ((CardPtr->Flags & TAGGED_QUEUING) &&
|
||
(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE))
|
||
{
|
||
if (CardPtr->Flags & WIDE_ENABLED)
|
||
ccb->ControlByte |= ENABLE_TQ;
|
||
else
|
||
ccb->Lun |= ENABLE_TQ;
|
||
|
||
switch (Srb->QueueAction) {
|
||
|
||
case ORDERED_TAG:
|
||
ccb->Lun |= ORDERED;
|
||
break;
|
||
case SIMPLE_TAG:
|
||
ccb->Lun |= SIMPLE;
|
||
break;
|
||
case HEAD_OF_QUEUE:
|
||
ccb->Lun |= QUEUEHEAD;
|
||
break;
|
||
} /* end switch */
|
||
}
|
||
|
||
//
|
||
// Set transfer direction bit.
|
||
//
|
||
|
||
switch (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
|
||
case SRB_FLAGS_DATA_OUT:
|
||
ccb->ControlByte |= CCB_DATA_XFER_OUT;
|
||
break;
|
||
|
||
case SRB_FLAGS_DATA_IN:
|
||
ccb->ControlByte |= CCB_DATA_XFER_IN;
|
||
break;
|
||
|
||
case SRB_FLAGS_NO_DATA_TRANSFER:
|
||
ccb->ControlByte |= CCB_DATA_XFER_IN | CCB_DATA_XFER_OUT;
|
||
break;
|
||
}
|
||
|
||
if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) &&
|
||
Srb->SenseInfoBufferLength != 0) {
|
||
|
||
ccb->RequestSenseLength = Srb->SenseInfoBufferLength;
|
||
physReqSensePtr = ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(CardPtr, Srb,
|
||
Srb->SenseInfoBuffer, &length));
|
||
|
||
ccb->SensePointer = physReqSensePtr;
|
||
}
|
||
else
|
||
|
||
|
||
//
|
||
// 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);
|
||
|
||
|
||
//
|
||
// Build SDL in CCB if data transfer.
|
||
//
|
||
|
||
if (Srb->DataTransferLength > 0) {
|
||
BuildSdl(CardPtr, Srb);
|
||
}
|
||
|
||
//
|
||
// Move -1 to Target Status to indicate
|
||
// CCB has not completed.
|
||
//
|
||
|
||
ccb->TargetStatus = 0xff;
|
||
|
||
return;
|
||
|
||
} // end BuildCcb()
|
||
|
||
|
||
VOID
|
||
BuildSdl(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds a scatter/gather descriptor list for the CCB.
|
||
|
||
Arguments:
|
||
|
||
CardPtr
|
||
Srb
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID dataPointer = Srb->DataBuffer;
|
||
ULONG bytesLeft = Srb->DataTransferLength;
|
||
PCCB ccb = Srb->SrbExtension;
|
||
PSDL sdl = &ccb->Sdl;
|
||
PSGD sgd;
|
||
ULONG physicalSdl;
|
||
ULONG physicalAddress;
|
||
ULONG length;
|
||
ULONG i = 0;
|
||
|
||
DebugPrint((3,"BuildSdl: Enter routine\n"));
|
||
|
||
|
||
//
|
||
// Get physical SDL address.
|
||
//
|
||
|
||
physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(CardPtr, NULL,
|
||
sdl, &length));
|
||
|
||
//
|
||
// Assume physical memory contiguous for sizeof(SDL) bytes.
|
||
//
|
||
|
||
ASSERT(length >= sizeof(SDL));
|
||
|
||
sgd = sdl->Sgd;
|
||
|
||
//
|
||
// 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(CardPtr,
|
||
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;
|
||
}
|
||
|
||
sgd->Length = length;
|
||
sgd->Address = physicalAddress;
|
||
sgd++;
|
||
i++;
|
||
|
||
//
|
||
// Adjust counts.
|
||
//
|
||
|
||
dataPointer = (PUCHAR)dataPointer + length;
|
||
bytesLeft -= length;
|
||
|
||
} while (bytesLeft);
|
||
|
||
//
|
||
// Write Scatter/Gather Descriptor List length to CCB.
|
||
//
|
||
|
||
ccb->DataLength = i * sizeof(SGD);
|
||
|
||
DebugPrint((3,"BuildSdl: S/G list length is %d\n", ccb->DataLength));
|
||
|
||
if (ccb->DataLength > 8)
|
||
DebugPrint((3,"BuildSdl: Multiple elements in S/G list"));
|
||
|
||
//
|
||
// Write SDL address to CCB.
|
||
//
|
||
|
||
ccb->DataPointer = (PVOID) physicalSdl;
|
||
|
||
DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
|
||
|
||
DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
|
||
|
||
return;
|
||
|
||
} // end BuildSdl()
|
||
|
||
|
||
BOOLEAN
|
||
BLogicResetBus(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN ULONG PathId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reset BusLogic SCSI adapter and SCSI bus.
|
||
Initialize adapter mailbox.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR TargID,Lun;
|
||
PDEV_STRUC DevStruc;
|
||
|
||
DebugPrint((2,"BLogicResetBus: Reset BusLogic HBA and SCSI bus\n"));
|
||
|
||
if (!ResetBus(CardPtr,PathId)) {
|
||
DebugPrint((1,"BLogicResetBus: Reset bus failed\n"));
|
||
return FALSE;
|
||
}
|
||
//
|
||
// Complete all outstanding requests with SRB_STATUS_BUS_RESET.
|
||
//
|
||
|
||
ScsiPortCompleteRequest(CardPtr,
|
||
(UCHAR) PathId,
|
||
(UCHAR) -1,
|
||
(UCHAR) -1,
|
||
SRB_STATUS_BUS_RESET);
|
||
//
|
||
// Reinitialize Active CCBS pointer and counter in LUN extensions
|
||
//
|
||
|
||
for (TargID= 0; TargID < 8; TargID++)
|
||
for (Lun = 0; Lun < 8; Lun++)
|
||
{
|
||
if (DevStruc=ScsiPortGetLogicalUnit(CardPtr,0,TargID,Lun))
|
||
{
|
||
DevStruc->CurrentCCB = 0;
|
||
DevStruc->NumActive = 0;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // end BLogicResetBus()
|
||
|
||
|
||
BOOLEAN
|
||
ResetBus(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN ULONG PathId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reset BusLogic SCSI adapter and SCSI bus.
|
||
Initialize adapter mailbox.
|
||
Don't do callback on outstanding SRBs
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PNONCACHED_EXTENSION MailBoxArray =
|
||
CardPtr->MailBoxArray;
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
ULONG i;
|
||
PMBO mailboxOut;
|
||
PMBI mailboxIn;
|
||
UCHAR status;
|
||
|
||
DebugPrint((2,"ResetBus: Reset BusLogic HBA and SCSI bus\n"));
|
||
|
||
//
|
||
// Reset SCSI chip.
|
||
//
|
||
|
||
ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
|
||
|
||
// Separated out the previously-removed routine ReInitializeHBA
|
||
// because it is now called by StartIO as well
|
||
|
||
if (!ReInitializeHBA(CardPtr,PathId)) {
|
||
DebugPrint((1,"ResetBus: Reset bus failed\n"));
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
|
||
} // end ResetBus()
|
||
|
||
|
||
BOOLEAN
|
||
ReInitializeHBA(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN ULONG PathId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wait for HBA to reinitialize.
|
||
Initialize adapter mailbox.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - HBA miniport driver's adapter data storage
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PNONCACHED_EXTENSION MailBoxArray =
|
||
CardPtr->MailBoxArray;
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
ULONG i;
|
||
PMBO mailboxOut;
|
||
PMBI mailboxIn;
|
||
UCHAR status;
|
||
|
||
|
||
ScsiPortStallExecution(500 * 1000);
|
||
|
||
//
|
||
// Wait up to 500 microseconds for adapter to initialize.
|
||
//
|
||
|
||
for (i = 0; i < 500; i++) {
|
||
|
||
ScsiPortStallExecution(1);
|
||
|
||
status = ScsiPortReadPortUchar(&CardPtr->BaseIoAddress->StatusRegister);
|
||
|
||
if (status & IOP_SCSI_HBA_IDLE) {
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
if (!(status & IOP_SCSI_HBA_IDLE)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Zero out mailboxes.
|
||
//
|
||
|
||
for (i=0,mailboxIn = MailBoxArray->Mbi,mailboxOut = MailBoxArray->Mbo;
|
||
i<MB_COUNT; i++, mailboxIn++,mailboxOut++) {
|
||
mailboxOut->Command = mailboxIn->Status = 0;
|
||
}
|
||
|
||
CardPtr->StartMBO = (PMBO)(&MailBoxArray->Mbo);
|
||
CardPtr->CurrMBO = (PMBO)(&MailBoxArray->Mbo);
|
||
CardPtr->LastMBO = ((PMBO)(&MailBoxArray->Mbo) + (MB_COUNT - 1));
|
||
CardPtr->StartMBI =(PMBI)( &MailBoxArray->Mbi);
|
||
CardPtr->CurrMBI = (PMBI)(&MailBoxArray->Mbi);
|
||
CardPtr->LastMBI = ((PMBI)(&MailBoxArray->Mbi) + (MB_COUNT - 1));
|
||
|
||
|
||
DebugPrint((3,"ReInitializeHBA: Initialize mailbox\n"));
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_MBOX_EXTENDED_INIT)) {
|
||
DebugPrint((1,"ReInitializeHBA: Couldn't initialize mailboxes\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Send Adapter number of mailbox locations.
|
||
//
|
||
|
||
if (!WriteCommandRegister(CardPtr,MB_COUNT)) {
|
||
DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte0)) {
|
||
DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte1)) {
|
||
DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte2)) {
|
||
DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!WriteCommandRegister(CardPtr,
|
||
((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte3)) {
|
||
DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
/* turn on wide support if available */
|
||
if (CardPtr->Flags & OS_SUPPORTS_WIDE)
|
||
{
|
||
|
||
// DebugPrint((0,"ReInitializeHBA: about to send wide cmd\n"));
|
||
|
||
if (!WriteCommandRegister(CardPtr, AC_WIDE_SUPPORT)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
else if (!CheckInvalid(CardPtr)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
else if (!WriteCommandRegister(CardPtr, 0x01)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
if (!FinishHBACmd(CardPtr)) {
|
||
CardPtr->Flags &= ~WIDE_ENABLED;
|
||
}
|
||
else {
|
||
CardPtr->Flags |= WIDE_ENABLED;
|
||
}
|
||
} /* end if OS_SUPPORTS_WIDE */
|
||
|
||
return TRUE;
|
||
|
||
} // end ReInitializeHBA()
|
||
|
||
UCHAR
|
||
MapError(
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
IN PCCB Ccb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Translate BusLogic error to SRB error, and log an error if necessary.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - The hardware device extension.
|
||
|
||
Srb - The failing Srb.
|
||
|
||
Ccb - Command Control Block contains error.
|
||
|
||
Return Value:
|
||
|
||
SRB Error
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR status;
|
||
ULONG logError = 0;
|
||
|
||
switch (Ccb->HostStatus) {
|
||
|
||
case CCB_COMPLETE:
|
||
return SRB_STATUS_ERROR;
|
||
|
||
case CCB_SELECTION_TIMEOUT:
|
||
return SRB_STATUS_SELECTION_TIMEOUT;
|
||
|
||
case CCB_DATA_OVER_UNDER_RUN:
|
||
status = SRB_STATUS_DATA_OVERRUN;
|
||
|
||
//
|
||
// Don't log the protocol error anymore. it floods the system
|
||
// for underruns as well
|
||
//
|
||
// logError = SP_PROTOCOL_ERROR;
|
||
//
|
||
|
||
break;
|
||
|
||
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;
|
||
}
|
||
|
||
if(logError) {
|
||
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
Srb,
|
||
Srb->PathId,
|
||
Srb->TargetId,
|
||
Srb->Lun,
|
||
logError,
|
||
(2 << 8) | Ccb->HostStatus
|
||
);
|
||
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // end MapError()
|
||
|
||
|
||
BOOLEAN
|
||
ReadCommandRegister(
|
||
IN PCARD_STRUC CardPtr,
|
||
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 = CardPtr->BaseIoAddress;
|
||
ULONG i;
|
||
|
||
//
|
||
// Wait up to 500 microseconds for adapter to be ready.
|
||
//
|
||
|
||
for (i=0; i<500; i++) {
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
if (i==500) {
|
||
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
CardPtr->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
3 << 8
|
||
);
|
||
|
||
DebugPrint((1, "BLogic:ReadCommandRegister: Read command timed out\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
*DataByte = ScsiPortReadPortUchar(&baseIoAddress->CommandRegister);
|
||
|
||
return TRUE;
|
||
|
||
} // end ReadCommandRegister()
|
||
|
||
|
||
BOOLEAN
|
||
WriteCommandRegister(
|
||
IN PCARD_STRUC CardPtr,
|
||
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 = CardPtr->BaseIoAddress;
|
||
ULONG i;
|
||
|
||
//
|
||
// Wait up to 500 microseconds for adapter to be ready.
|
||
//
|
||
|
||
for (i=0; i<500; i++) {
|
||
|
||
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;
|
||
}
|
||
}
|
||
|
||
if (i==500) {
|
||
|
||
ScsiPortLogError(
|
||
CardPtr,
|
||
NULL,
|
||
0,
|
||
CardPtr->HostTargetId,
|
||
0,
|
||
SP_INTERNAL_ADAPTER_ERROR,
|
||
4 << 8
|
||
);
|
||
|
||
DebugPrint((1, "BLogic:WriteCommandRegister: Write command timed out\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, AdapterCommand);
|
||
|
||
return TRUE;
|
||
|
||
} // end WriteCommandRegister()
|
||
|
||
|
||
BOOLEAN
|
||
FinishHBACmd(
|
||
IN PCARD_STRUC CardPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wait for command complete interrupt, clear interrupt, chk cmd status.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - Pointer to adapter extension
|
||
|
||
Return Value:
|
||
|
||
TRUE if command completed successfully.
|
||
FALSE if timed out waiting for adapter or invalid command.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG i;
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
|
||
for (i=0; i<500; i++) {
|
||
|
||
if (!((ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) &
|
||
(IOP_COMMAND_COMPLETE | IOP_ANY_INTERRUPT))==
|
||
(IOP_COMMAND_COMPLETE | IOP_ANY_INTERRUPT))) {
|
||
|
||
//
|
||
// Stall 1 microsecond before
|
||
// trying again.
|
||
//
|
||
|
||
ScsiPortStallExecution(1);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Adapter ready. Break out of loop.
|
||
//
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i==500) {
|
||
|
||
DebugPrint((1, "BLogic:FinishHBACmd: Wait for CmdCmplt & AnyIntr failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
|
||
|
||
if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
|
||
(IOP_INVALID_COMMAND)) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // end FinishHBACmd()
|
||
|
||
|
||
BOOLEAN
|
||
CheckInvalid(
|
||
IN PCARD_STRUC CardPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read status register to check for invalid command.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtesion - Pointer to adapder extension
|
||
DataByte - Byte read from register
|
||
|
||
Return Value:
|
||
|
||
FALSE if invalid command bit on or timed out waiting for adapter.
|
||
TRUE if everything's o.k.
|
||
|
||
--*/
|
||
|
||
{
|
||
PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
|
||
ULONG i;
|
||
|
||
ScsiPortStallExecution(500 * 1000);
|
||
|
||
//
|
||
// Wait up to 500 microseconds for adapter to be ready.
|
||
//
|
||
|
||
for (i=0; i<500; i++) {
|
||
if (ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) &
|
||
IOP_COMMAND_COMPLETE) {
|
||
//
|
||
// Adapter command complete. Break out of loop.
|
||
//
|
||
|
||
break;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Stall 1 microsecond before
|
||
// trying again.
|
||
//
|
||
|
||
ScsiPortStallExecution(1);
|
||
}
|
||
}
|
||
|
||
if (i==500) {
|
||
// if command not complete, must not be invalid
|
||
return TRUE;
|
||
}
|
||
|
||
if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
|
||
IOP_INVALID_COMMAND)
|
||
return FALSE;
|
||
else
|
||
return TRUE;
|
||
|
||
} // end CheckInvalid()
|
||
|
||
|
||
|
||
BOOLEAN
|
||
SendCCB(
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
IN PCARD_STRUC CardPtr,
|
||
IN PDEV_STRUC DevStruc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds empty outgoing Mbox, stuffs CCB into it and sends start command.
|
||
|
||
Arguments:
|
||
|
||
CardPtr - Pointer to adapter extension
|
||
Srb - Pointer to SCSI Request Block
|
||
DevStruc - Pointer to device (TAR/LUN) structure
|
||
|
||
Return Value:
|
||
|
||
TRUE if command completed successfully.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PMBO mboxOut;
|
||
ULONG physicalCCB;
|
||
PCCB ccb;
|
||
ULONG length;
|
||
USHORT i;
|
||
|
||
while (1) /* wait for free mbox out */
|
||
{
|
||
for (i=0, mboxOut = CardPtr->CurrMBO ; i< MB_COUNT; i++,mboxOut++)
|
||
{ /* look for an open slot */
|
||
|
||
if (mboxOut > CardPtr->LastMBO)
|
||
mboxOut = CardPtr->StartMBO;
|
||
|
||
if (mboxOut->Command == MBO_FREE)
|
||
{
|
||
|
||
/* Insert Phys addr of CCB into MBO */
|
||
|
||
if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND)
|
||
ccb = (PCCB)(Srb->SrbExtension);
|
||
else
|
||
ccb = (PCCB)(Srb->NextSrb->SrbExtension);
|
||
|
||
physicalCCB = ScsiPortConvertPhysicalAddressToUlong(
|
||
ScsiPortGetPhysicalAddress(CardPtr, NULL, ccb, &length));
|
||
|
||
//
|
||
// Assume physical address is contiguous for size of CCB.
|
||
//
|
||
|
||
ASSERT(length >= sizeof(CCB));
|
||
mboxOut->Address = physicalCCB;
|
||
|
||
if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND) {
|
||
/* insert this SRB into active queue for this device */
|
||
|
||
ccb->NxtActiveCCB = DevStruc->CurrentCCB;
|
||
DevStruc->CurrentCCB = ccb;
|
||
mboxOut->Command = MBO_START;
|
||
}
|
||
else
|
||
mboxOut->Command = MBO_ABORT;
|
||
|
||
CardPtr->CurrMBO = mboxOut + 1;
|
||
|
||
if (!WriteCommandRegister(CardPtr,AC_START_SCSI_COMMAND)) {
|
||
DebugPrint((1,"BLogicStartIo: Can't write command to adapter\n"));
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} /* end for found a free MBO */
|
||
} /* end for 0 to mbox count */
|
||
} /* end while forever */
|
||
|
||
} /* end SendCCB() */
|
||
|
||
|
||
PMBI
|
||
DoneMbox(
|
||
IN PCARD_STRUC CardPtr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds Full incoming Mbox
|
||
|
||
Arguments:
|
||
|
||
CardPtr - Pointer to adapter extension
|
||
|
||
Return Value:
|
||
|
||
Pointer to full MBI if full found, FALSE if not
|
||
|
||
--*/
|
||
|
||
{
|
||
register PMBI mboxp;
|
||
int i;
|
||
|
||
mboxp = CardPtr->CurrMBI;
|
||
|
||
for (i = 0; i < MB_COUNT; i++, mboxp++)
|
||
{
|
||
if (mboxp > CardPtr->LastMBI)
|
||
mboxp = CardPtr->StartMBI;
|
||
|
||
if (mboxp->Status != MBI_FREE)
|
||
{
|
||
CardPtr->CurrMBI = mboxp + 1;
|
||
return (mboxp);
|
||
}
|
||
|
||
}
|
||
return ((PMBI) NULL);
|
||
} /* end DoneMbox() */
|
||
|
||
|
||
BOOLEAN
|
||
AdjustCCBqueue(
|
||
PCCB ccbp,
|
||
IN PDEV_STRUC devptr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes newly-completed CCB from outstanding CCB queue for a given
|
||
device.
|
||
|
||
Arguments:
|
||
|
||
ccbp - Pointer to the completed CCB
|
||
devptr - Pointer to device (TAR/LUN) structure
|
||
|
||
Return Value:
|
||
|
||
TRUE if matching CCB was found in active queue
|
||
FALSE if no match could be found
|
||
|
||
--*/
|
||
{
|
||
PCCB tempCCB = devptr->CurrentCCB; /* ptr to head of active CCBS */
|
||
|
||
if (tempCCB == 0)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
if (ccbp == tempCCB) /* match with head of active CCB queue */
|
||
{
|
||
devptr->CurrentCCB = tempCCB->NxtActiveCCB;
|
||
ccbp->NxtActiveCCB = (PCCB) 0;
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
while (tempCCB->NxtActiveCCB != 0 )
|
||
{
|
||
if (ccbp == tempCCB->NxtActiveCCB)
|
||
{
|
||
tempCCB->NxtActiveCCB = ccbp->NxtActiveCCB;
|
||
ccbp->NxtActiveCCB = (PCCB) 0;
|
||
return TRUE;
|
||
}
|
||
|
||
tempCCB = tempCCB->NxtActiveCCB;
|
||
}
|
||
|
||
return FALSE; /* no match found */
|
||
|
||
} /* end function AdjustCCBQueue */
|