diff options
Diffstat (limited to 'private/ntos/miniport/buslogic')
-rw-r--r-- | private/ntos/miniport/buslogic/buslogic.c | 3181 | ||||
-rw-r--r-- | private/ntos/miniport/buslogic/buslogic.h | 435 | ||||
-rw-r--r-- | private/ntos/miniport/buslogic/buslogic.rc | 12 | ||||
-rw-r--r-- | private/ntos/miniport/buslogic/makefile | 6 | ||||
-rw-r--r-- | private/ntos/miniport/buslogic/sources | 35 |
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 |