summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/buslogic
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/miniport/buslogic/buslogic.c3181
-rw-r--r--private/ntos/miniport/buslogic/buslogic.h435
-rw-r--r--private/ntos/miniport/buslogic/buslogic.rc12
-rw-r--r--private/ntos/miniport/buslogic/makefile6
-rw-r--r--private/ntos/miniport/buslogic/sources35
5 files changed, 3669 insertions, 0 deletions
diff --git a/private/ntos/miniport/buslogic/buslogic.c b/private/ntos/miniport/buslogic/buslogic.c
new file mode 100644
index 000000000..5d3b3cee2
--- /dev/null
+++ b/private/ntos/miniport/buslogic/buslogic.c
@@ -0,0 +1,3181 @@
+/*++
+
+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 */
diff --git a/private/ntos/miniport/buslogic/buslogic.h b/private/ntos/miniport/buslogic/buslogic.h
new file mode 100644
index 000000000..ebeb69273
--- /dev/null
+++ b/private/ntos/miniport/buslogic/buslogic.h
@@ -0,0 +1,435 @@
+/*++
+
+Copyright (c) 1992 BusLogic, Inc.
+
+Module Name:
+
+ buslogic.h
+
+Abstract:
+
+ This module contains the structures, specific to the BusLogic
+ host bus adapters, used by the SCSI miniport driver. Data structures
+ that are part of standard ANSI SCSI will be defined in a header
+ file that will be available to all SCSI device drivers.
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB - BusLogic SCSI Command Control Block
+//
+// The CCB is a wrapper for the CDB (Command Descriptor Block)
+// and specifies detailed information about a SCSI command.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Byte 0 Command Control Block Operation Code
+//
+// Byte 1 Address and Direction Control
+//
+// Byte 2 SCSI_Command_Length - Length of SCSI CDB
+//
+// Byte 3 Request Sense Allocation Length
+//
+// Bytes 4, 5,6 & 7 Data Length // Data transfer byte count
+//
+// Bytes 8,9, A, & B Data Pointer // SG List or Data Bfr Ptr
+//
+// Bytes C & D Reserved
+//
+// Byte E Host Status // Host Adapter status
+//
+// Byte F Target Status // Target status
+//
+// Byte 10 Target ID // Target ID
+//
+// Byte 11 LUN
+//
+// Byte 12 thru 1D SCSI CDB // Command Desc. Block
+//
+// Byte 1E Reserved
+//
+// Byte 1F Link ID
+//
+// Byte 20 thru 23 Link pointer // physical link ptr
+//
+// Byte 24 thru 27 Sense pointer // phys. ptr to req. sense
+//
+// Driver-specific fields follow //
+
+//
+// Operation Code Definitions
+//
+#define SCSI_INITIATOR_COMMAND 0x00
+#define TARGET_MODE_COMMAND 0x01
+#define SCATTER_GATHER_COMMAND 0x02
+#define RESET_COMMAND 0x81
+//
+// Control Byte (byte 1) definitions
+//
+#define CCB_DATA_XFER_OUT 0x10 // Write
+#define CCB_DATA_XFER_IN 0x08 // Read
+#define CCB_LUN_MASK 0x07 // Logical Unit Number
+//
+// Request Sense Definitions
+//
+#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size
+#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Scatter/Gather Segment List Definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Adapter limits
+//
+
+#define MAX_SG_DESCRIPTORS 32
+#define MAX_TRANSFER_SIZE 256 * 1024
+
+//
+// Scatter/Gather Segment Descriptor Definition
+//
+
+typedef struct _SGD {
+ ULONG Length;
+ ULONG Address;
+} SGD, *PSGD;
+
+typedef struct _BL_CONTEXT {
+ ULONG AdapterCount;
+ ULONG PCIDevId;
+} BL_CONTEXT, *PBL_CONTEXT;
+
+
+typedef struct _SDL {
+ SGD Sgd[MAX_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+#define SEGMENT_LIST_SIZE MAX_SG_DESCRIPTORS * sizeof(SGD)
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB Typedef
+//
+
+typedef struct _CCB *PCCB;
+
+typedef struct _CCB {
+ UCHAR OperationCode;
+ UCHAR ControlByte;
+ UCHAR CdbLength;
+ UCHAR RequestSenseLength;
+ ULONG DataLength;
+ PVOID DataPointer;
+ USHORT CcbRes0;
+ UCHAR HostStatus;
+ UCHAR TargetStatus;
+ UCHAR TargID;
+ UCHAR Lun;
+ UCHAR Cdb[12];
+ UCHAR CcbRes1;
+ UCHAR LinkIdentifier;
+ PVOID LinkPointer;
+ ULONG SensePointer;
+ SDL Sdl;
+ PVOID SrbAddress;
+ PVOID AbortSrb;
+ PCCB NxtActiveCCB;
+
+ } CCB;
+
+//
+// CCB and request sense buffer
+//
+
+#define CCB_SIZE sizeof(CCB)
+
+
+//
+// Host Adapter Command Operation Codes
+//
+
+#define AC_NO_OPERATION 0x00
+#define AC_MAILBOX_INITIALIZATION 0x01
+#define AC_START_SCSI_COMMAND 0x02
+#define AC_START_BIOS_COMMAND 0x03
+#define AC_ADAPTER_INQUIRY 0x04
+#define AC_ENABLE_MBO_AVAIL_INT 0x05
+#define AC_SET_SELECTION_TIMEOUT 0x06
+#define AC_SET_BUS_ON_TIME 0x07
+#define AC_SET_BUS_OFF_TIME 0x08
+#define AC_SET_TRANSFER_SPEED 0x09
+#define AC_RET_INSTALLED_DEVICES 0x0A
+#define AC_RET_CONFIGURATION_DATA 0x0B
+#define AC_ENABLE_TARGET_MODE 0x0C
+#define AC_RETURN_SETUP_DATA 0x0D
+#define AC_WRITE_CHANNEL_2_BUFFER 0x1A
+#define AC_READ_CHANNEL_2_BUFFER 0x1B
+#define AC_WRITE_FIFO_BUFFER 0x1C
+#define AC_READ_FIFO_BUFFER 0x1D
+#define AC_ECHO_COMMAND_DATA 0x1F
+#define AC_SET_ADAPTER_OPTIONS 0x21
+#define AC_EXTENDED_SETUP_INFO 0x8D
+#define AC_EXTENDED_FWREV 0x84
+#define AC_MBOX_EXTENDED_INIT 0x81
+#define AC_ISA_COMPATIBLE_SUPPORT 0x95
+#define AC_WIDE_SUPPORT 0x96
+#define AC_PCI_INFO 0x86
+#define AC_INT_GENERATION_STATE 0x25
+
+#define DISABLE_ISA_MAPPING 0x6 // cmd 0x95 above
+#define ENABLE_INTS 0x1 // cmd 0x25 above
+#define DISABLE_INTS 0x0 // cmd 0x25 above
+
+//
+// Host status byte
+//
+#define CCB_COMPLETE 0x00 // CCB completed without error
+#define CCB_LINKED_COMPLETE 0x0A // Linked command completed
+#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt
+#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out
+#define CCB_DATA_OVER_UNDER_RUN 0x12
+#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY
+#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure
+#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2
+#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code
+#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first
+#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction
+#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB
+#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter
+
+//
+// DMA Transfer Speeds
+//
+
+#define DMA_SPEED_50_MBS 0x00
+
+//
+// LUN byte definitions
+//
+
+#define ENABLE_TQ 0x20 /* bit 5 in bytes 17 of CCB (LUN) */
+#define QUEUEHEAD 0x40 /* Head of Queue tag */
+#define ORDERED 0x80 /* Ordered Queue tag */
+#define SIMPLE 0x00 /* Simple Queue tag */
+
+
+//
+// I/O Port Interface
+//
+
+typedef struct _BASE_REGISTER {
+ UCHAR StatusRegister;
+ UCHAR CommandRegister;
+ UCHAR InterruptRegister;
+} BASE_REGISTER, *PBASE_REGISTER;
+
+//
+// Base+0 Write: Control Register
+//
+
+#define IOP_HARD_RESET 0x80 // bit 7
+#define IOP_SOFT_RESET 0x40 // bit 6
+#define IOP_INTERRUPT_RESET 0x20 // bit 5
+#define IOP_SCSI_BUS_RESET 0x10 // bit 4
+
+//
+// Base+0 Read: Status
+//
+
+#define IOP_SELF_TEST 0x80 // bit 7
+#define IOP_INTERNAL_DIAG_FAILURE 0x40 // bit 6
+#define IOP_MAILBOX_INIT_REQUIRED 0x20 // bit 5
+#define IOP_SCSI_HBA_IDLE 0x10 // bit 4
+#define IOP_COMMAND_DATA_OUT_FULL 0x08 // bit 3
+#define IOP_DATA_IN_PORT_FULL 0x04 // bit 2
+#define IOP_INVALID_COMMAND 0X01 // bit 1
+
+//
+// Base+1 Write: Command/Data Out
+//
+
+//
+// Base+1 Read: Data In
+//
+
+//
+// Base+2 Read: Interrupt Flags
+//
+
+
+#define IOP_ANY_INTERRUPT 0x80 // bit 7
+#define IOP_SCSI_RESET_DETECTED 0x08 // bit 3
+#define IOP_COMMAND_COMPLETE 0x04 // bit 2
+#define IOP_MBO_EMPTY 0x02 // bit 1
+#define IOP_MBI_FULL 0x01 // bit 0
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Mailbox Definitions
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Mailbox Definition
+//
+
+#define MB_COUNT 32 // number of mailboxes
+
+//
+// Mailbox Out
+//
+
+typedef struct _MBO {
+ ULONG Address;
+ UCHAR MboRes[3];
+ UCHAR Command;
+} MBO, *PMBO;
+
+//
+// MBO Command Values
+//
+
+#define MBO_FREE 0x00
+#define MBO_START 0x01
+#define MBO_ABORT 0x02
+
+//
+// Mailbox In
+//
+
+typedef struct _MBI {
+
+ ULONG Address;
+ UCHAR MbiHStat;
+ UCHAR MbiTStat;
+ UCHAR MbiRes;
+ UCHAR Status;
+} MBI, *PMBI;
+
+//
+// MBI Status Values
+//
+
+#define MBI_FREE 0x00
+#define MBI_SUCCESS 0x01
+#define MBI_ABORT 0x02
+#define MBI_NOT_FOUND 0x03
+#define MBI_ERROR 0x04
+
+//
+// Mailbox Initialization
+//
+
+typedef struct _MAILBOX_INIT {
+ ULONG Address;
+ UCHAR Count;
+} MAILBOX_INIT, *PMAILBOX_INIT;
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Physical base address of mailboxes
+ //
+
+ ULONG MailboxPA;
+
+ //
+ // Mailboxes
+ //
+
+ MBO Mbo[MB_COUNT];
+ MBI Mbi[MB_COUNT];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _CARD_STRUC {
+
+ PNONCACHED_EXTENSION MailBoxArray; /* NonCached Extension */
+ PBASE_REGISTER BaseIoAddress; /* Base I/O Address */
+ PMBO CurrMBO; /* Current Mbox Out */
+ PMBO StartMBO; /* First Mbox Out */
+ PMBO LastMBO; /* Last Mbox Out */
+ PMBI CurrMBI; /* Current Mbox In */
+ PMBI StartMBI; /* First Mbox In */
+ PMBI LastMBI; /* Last Mbox In */
+ ULONG Flags;
+ UCHAR BusType; /* ISA/EISA/ or MCA */
+ UCHAR BusNum; /* SCSI bus number */
+ UCHAR HostTargetId; /* HBA Target ID */
+ UCHAR Reserved; /* explicit DWORD align */
+} CARD_STRUC, *PCARD_STRUC;
+
+//
+// CardStruc BusType definitions
+//
+
+#define ISA_HBA 'A'
+#define EISA_HBA 'E'
+#define MCA_HBA 'M'
+
+//
+// CardStruc Flags definitions
+//
+#define TAGGED_QUEUING 0x1000
+#define REINIT_REQUIRED 0x100
+#define WIDE_ENABLED 0x10
+#define OS_SUPPORTS_WIDE 0x200
+
+//
+// Logical unit extension
+//
+
+typedef struct _DEV_STRUC {
+ PCCB CurrentCCB; /* pointer to most recent active CCB */
+ UCHAR NumActive;
+
+} DEV_STRUC, *PDEV_STRUC;
+
+#define MAXACTIVE 2
+#define MAXACTIVE_TAGGED 8
+
+
+//
+// miscellaneous definitions
+//
+
+#define SIMPLE_TAG 0x20
+#define HEAD_OF_QUEUE 0x21
+#define ORDERED_TAG 0x22
+
+#define LEVEL_TRIG 0x40
+
+#define RETURN_FOUND_VESA 4
+#define PORTMASK 0x7
+
+#define MAXIMUM_EISA_SLOTS 0x10
+#define EISA_ADDRESS_BASE 0x0C80
+
+typedef struct _EISA_ID {
+ UCHAR BoardId[4];
+ UCHAR Reserved[8];
+ UCHAR IOPort[1];
+} *PEISA_ID;
diff --git a/private/ntos/miniport/buslogic/buslogic.rc b/private/ntos/miniport/buslogic/buslogic.rc
new file mode 100644
index 000000000..7bfe96603
--- /dev/null
+++ b/private/ntos/miniport/buslogic/buslogic.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "BusLogic SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "BusLogic.sys"
+#define VER_ORIGINALFILENAME_STR "BusLogic.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/buslogic/makefile b/private/ntos/miniport/buslogic/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/buslogic/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/buslogic/sources b/private/ntos/miniport/buslogic/sources
new file mode 100644
index 000000000..5a19fd437
--- /dev/null
+++ b/private/ntos/miniport/buslogic/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=buslogic
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=buslogic.c buslogic.rc