Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3181 lines
77 KiB

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