diff options
author | Thomas Bushnell <thomas@gnu.org> | 1999-04-26 05:35:47 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1999-04-26 05:35:47 +0000 |
commit | 3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0 (patch) | |
tree | 50b56b8570e175dbcff43b5f0d61103b6fea5906 /i386/i386at/gpl/linux/scsi/BusLogic.c | |
parent | 002b9c7d51f7fdb0fe222d4a6023655687c6e501 (diff) | |
download | gnumach-3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0.tar.gz gnumach-3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0.tar.bz2 gnumach-3a4e8f5c1c60f87e1c9e0878ddb6cf7dac8c59c0.zip |
1998-11-06 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* i386/i386at/gpl/linux: Moved to ...
* linuxdev: ... here.
* i386/Makefrag: Linux drivers specific code moved to ...
* linuxdev/Makefrag: ... here.
* i386/Files: Recreated.
* i386/Subdirs: Likewise.
* linuxdev/drivers: New directory.
* linuxdev/arch: Likewise.
* linuxdev/arch/i386: Likewise.
* linuxdev/{block,scsi,net,pci}: Moved to ...
* linuxdev/drivers/{block,scsi,net,pci}: ... here.
* i386/{Drivers.in,device-drivers.h.in,driverlist.in}: Moved to ...
* linuxdev/{Drivers.in,device-drivers.h.in,driverlist.in}: ... here.
* linuxdev/{linux_emul.h,linux_*.c}: Moved to ...
* linuxdev/arch/i386/{linux_emul.h,linux_*.c}: ... here.
* linuxdev/arch/i386/linux_block.c: Include <linux_emul.h>, instead
of <i386at/gpl/linux/linux_emul.h>.
* linuxdev/arch/i386/linux_init.c: Likewise.
* linuxdev/arch/i386/linux_kmem.c: Likewise.
* linuxdev/arch/i386/linux_misc.c: Likewise.
* linuxdev/arch/i386/linux_net.c: Likewise.
* linuxdev/arch/i386/linux_sched.c: Likewise.
* device/ds_routines.c: Include <linuxdev/device-drivers.h>, instead
of <i386/device-drivers.h>.
* linuxdev/arch/i386/linux_init.c: Likewise.
* linuxdev/include/linux/autoconf.h: Likewise.
* Makefile.in: Include $(srcdir)/linuxdev/Makefrag.
* linuxdev/Drivers.in (AC_INIT): Use include/linux/autoconf.h,
instead of i386/i386asm.sym.
Diffstat (limited to 'i386/i386at/gpl/linux/scsi/BusLogic.c')
-rw-r--r-- | i386/i386at/gpl/linux/scsi/BusLogic.c | 2779 |
1 files changed, 0 insertions, 2779 deletions
diff --git a/i386/i386at/gpl/linux/scsi/BusLogic.c b/i386/i386at/gpl/linux/scsi/BusLogic.c deleted file mode 100644 index 7472dc3d..00000000 --- a/i386/i386at/gpl/linux/scsi/BusLogic.c +++ /dev/null @@ -1,2779 +0,0 @@ -/* - - Linux Driver for BusLogic MultiMaster SCSI Host Adapters - - Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com> - - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation, provided that none of the source code or runtime - copyright notices are removed or modified. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for complete details. - - The author respectfully requests that all modifications to this software be - sent directly to him for evaluation and testing. - - Special thanks to Alex T. Win of BusLogic, whose advice has been invaluable, - to David B. Gentzel, for writing the original Linux BusLogic driver, and to - Paul Gortmaker, for being such a dedicated test site. - -*/ - - -#define BusLogic_DriverVersion "1.3.1" -#define BusLogic_DriverDate "31 December 1995" - - -#include <linux/module.h> -#include <linux/config.h> -#include <linux/types.h> -#include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/kernel_stat.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/stat.h> -#include <linux/pci.h> -#include <linux/bios32.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <asm/system.h> -#include "scsi.h" -#include "hosts.h" -#include "sd.h" -#include "BusLogic.h" - - -/* - BusLogic_CommandLineEntryCount is a count of the number of "BusLogic=" - entries provided on the Linux Kernel Command Line. -*/ - -static int - BusLogic_CommandLineEntryCount = 0; - - -/* - BusLogic_CommandLineEntries is an array of Command Line Entry structures - representing the "BusLogic=" entries provided on the Linux Kernel Command - Line. -*/ - -static BusLogic_CommandLineEntry_T - BusLogic_CommandLineEntries[BusLogic_MaxHostAdapters]; - - -/* - BusLogic_GlobalOptions is a bit mask of Global Options to be applied - across all Host Adapters. -*/ - -static int - BusLogic_GlobalOptions = 0; - - -/* - BusLogic_RegisteredHostAdapters is a linked list of all the registered - BusLogic Host Adapters. -*/ - -static BusLogic_HostAdapter_T - *BusLogic_RegisteredHostAdapters = NULL; - - -/* - BusLogic_Standard_IO_Addresses is the list of standard I/O Addresses at which - BusLogic Host Adapters may potentially be found. -*/ - -static unsigned short - BusLogic_IO_StandardAddresses[] = - { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0 }; - - -/* - BusLogic_IO_AddressProbeList is the list of I/O Addresses to be probed for - potential BusLogic Host Adapters. It is initialized by interrogating the - PCI Configuration Space on PCI machines as well as from the list of - standard BusLogic I/O Addresses. -*/ - -static unsigned short - BusLogic_IO_AddressProbeList[BusLogic_IO_MaxProbeAddresses+1] = { 0 }; - - -/* - BusLogic_IRQ_UsageCount stores a count of the number of Host Adapters using - a given IRQ Channel, which is necessary to support PCI, EISA, or MCA shared - interrupts. Only IRQ Channels 9, 10, 11, 12, 14, and 15 are supported by - BusLogic Host Adapters. -*/ - -static short - BusLogic_IRQ_UsageCount[7] = { 0 }; - - -/* - BusLogic_CommandFailureReason holds a string identifying the reason why a - call to BusLogic_Command failed. It is only valid when BusLogic_Command - returns a failure code. -*/ - -static char - *BusLogic_CommandFailureReason; - - -/* - BusLogic_ProcDirectoryEntry is the BusLogic /proc/scsi directory entry. -*/ - -static struct proc_dir_entry - BusLogic_ProcDirectoryEntry = - { PROC_SCSI_BUSLOGIC, 8, "BusLogic", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - - -/* - BusLogic_AnnounceDriver announces the Driver Version and Date, Author's - Name, Copyright Notice, and Contact Address. -*/ - -static void BusLogic_AnnounceDriver(void) -{ - static boolean DriverAnnouncementPrinted = false; - if (DriverAnnouncementPrinted) return; - printk("scsi: ***** BusLogic SCSI Driver Version " - BusLogic_DriverVersion " of " BusLogic_DriverDate " *****\n"); - printk("scsi: Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>\n"); - DriverAnnouncementPrinted = true; -} - - -/* - BusLogic_DriverInfo returns the Board Name to identify this SCSI Driver - and Host Adapter. -*/ - -const char *BusLogic_DriverInfo(SCSI_Host_T *Host) -{ - BusLogic_HostAdapter_T *HostAdapter = - (BusLogic_HostAdapter_T *) Host->hostdata; - return HostAdapter->BoardName; -} - - -/* - BusLogic_InitializeAddressProbeList initializes the list of I/O Addresses - to be probed for potential BusLogic SCSI Host Adapters by interrogating the - PCI Configuration Space on PCI machines as well as from the list of standard - BusLogic I/O Addresses. -*/ - -static void BusLogic_InitializeAddressProbeList(void) -{ - int DestinationIndex = 0, SourceIndex = 0; - /* - If BusLogic_Setup has been called, do not override the Kernel Command - Line specifications. - */ - if (BusLogic_IO_AddressProbeList[0] != 0) return; -#ifdef CONFIG_PCI - /* - Interrogate PCI Configuration Space for any BusLogic SCSI Host Adapters. - */ - if (pcibios_present()) - { - unsigned short Index = 0, VendorID; - unsigned char Bus, DeviceAndFunction; - unsigned int BaseAddress0; - while (pcibios_find_class(PCI_CLASS_STORAGE_SCSI<<8, Index++, - &Bus, &DeviceAndFunction) == 0) - if (pcibios_read_config_word(Bus, DeviceAndFunction, - PCI_VENDOR_ID, &VendorID) == 0 && - VendorID == PCI_VENDOR_ID_BUSLOGIC && - pcibios_read_config_dword(Bus, DeviceAndFunction, - PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 && - (BaseAddress0 & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_IO) - { - BusLogic_IO_AddressProbeList[DestinationIndex++] = - BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK; - } - } -#endif - /* - Append the list of standard BusLogic I/O Addresses. - */ - while (DestinationIndex < BusLogic_IO_MaxProbeAddresses && - BusLogic_IO_StandardAddresses[SourceIndex] > 0) - BusLogic_IO_AddressProbeList[DestinationIndex++] = - BusLogic_IO_StandardAddresses[SourceIndex++]; - BusLogic_IO_AddressProbeList[DestinationIndex] = 0; -} - - -/* - BusLogic_RegisterHostAdapter adds Host Adapter to the list of registered - BusLogic Host Adapters. -*/ - -static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter) -{ - HostAdapter->Next = NULL; - if (BusLogic_RegisteredHostAdapters != NULL) - { - BusLogic_HostAdapter_T *LastHostAdapter = BusLogic_RegisteredHostAdapters; - BusLogic_HostAdapter_T *NextHostAdapter; - while ((NextHostAdapter = LastHostAdapter->Next) != NULL) - LastHostAdapter = NextHostAdapter; - LastHostAdapter->Next = HostAdapter; - } - else BusLogic_RegisteredHostAdapters = HostAdapter; -} - - -/* - BusLogic_UnregisterHostAdapter removes Host Adapter from the list of - registered BusLogic Host Adapters. -*/ - -static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter) -{ - if (BusLogic_RegisteredHostAdapters != HostAdapter) - { - BusLogic_HostAdapter_T *LastHostAdapter = BusLogic_RegisteredHostAdapters; - while (LastHostAdapter != NULL && LastHostAdapter->Next != HostAdapter) - LastHostAdapter = LastHostAdapter->Next; - if (LastHostAdapter != NULL) - LastHostAdapter->Next = HostAdapter->Next; - } - else BusLogic_RegisteredHostAdapters = HostAdapter->Next; - HostAdapter->Next = NULL; -} - - -/* - BusLogic_CreateCCBs allocates the initial Command Control Blocks (CCBs) - for Host Adapter. -*/ - -static boolean BusLogic_CreateCCBs(BusLogic_HostAdapter_T *HostAdapter) -{ - int i; - for (i = 0; i < BusLogic_InitialCCBs; i++) - { - BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) - scsi_init_malloc(sizeof(BusLogic_CCB_T), GFP_ATOMIC | GFP_DMA); - if (CCB == NULL) - { - printk("scsi%d: UNABLE TO ALLOCATE CCB %d - DETACHING\n", - HostAdapter->HostNumber, i); - return false; - } - memset(CCB, 0, sizeof(BusLogic_CCB_T)); - CCB->HostAdapter = HostAdapter; - CCB->Status = BusLogic_CCB_Free; - CCB->Next = HostAdapter->Free_CCBs; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->Free_CCBs = CCB; - HostAdapter->All_CCBs = CCB; - } - return true; -} - - -/* - BusLogic_DestroyCCBs deallocates the CCBs for Host Adapter. -*/ - -static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter) -{ - BusLogic_CCB_T *NextCCB = HostAdapter->All_CCBs, *CCB; - HostAdapter->All_CCBs = NULL; - HostAdapter->Free_CCBs = NULL; - while ((CCB = NextCCB) != NULL) - { - NextCCB = CCB->NextAll; - scsi_init_free((char *) CCB, sizeof(BusLogic_CCB_T)); - } -} - - -/* - BusLogic_AllocateCCB allocates a CCB from the Host Adapter's free list, - allocating more memory from the Kernel if necessary. -*/ - -static BusLogic_CCB_T *BusLogic_AllocateCCB(BusLogic_HostAdapter_T *HostAdapter) -{ - static unsigned int SerialNumber = 0; - BusLogic_CCB_T *CCB; - BusLogic_LockHostAdapter(HostAdapter); - CCB = HostAdapter->Free_CCBs; - if (CCB != NULL) - { - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - BusLogic_UnlockHostAdapter(HostAdapter); - return CCB; - } - BusLogic_UnlockHostAdapter(HostAdapter); - CCB = (BusLogic_CCB_T *) scsi_init_malloc(sizeof(BusLogic_CCB_T), - GFP_ATOMIC | GFP_DMA); - if (CCB == NULL) - { - printk("scsi%d: Failed to allocate an additional CCB\n", - HostAdapter->HostNumber); - return NULL; - } - printk("scsi%d: Allocated an additional CCB\n", HostAdapter->HostNumber); - memset(CCB, 0, sizeof(BusLogic_CCB_T)); - CCB->HostAdapter = HostAdapter; - CCB->Status = BusLogic_CCB_Free; - BusLogic_LockHostAdapter(HostAdapter); - CCB->SerialNumber = ++SerialNumber; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->All_CCBs = CCB; - BusLogic_UnlockHostAdapter(HostAdapter); - return CCB; -} - - -/* - BusLogic_DeallocateCCB deallocates a CCB, returning it to the Host Adapter's - free list. -*/ - -static void BusLogic_DeallocateCCB(BusLogic_CCB_T *CCB) -{ - BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter; - BusLogic_LockHostAdapter(HostAdapter); - CCB->Command = NULL; - CCB->Status = BusLogic_CCB_Free; - CCB->Next = HostAdapter->Free_CCBs; - HostAdapter->Free_CCBs = CCB; - BusLogic_UnlockHostAdapter(HostAdapter); -} - - -/* - BusLogic_Command sends the command OperationCode to HostAdapter, optionally - providing ParameterLength bytes of ParameterData and receiving at most - ReplyLength bytes of ReplyData; any excess reply data is received but - discarded. - - On success, this function returns the number of reply bytes read from - the Host Adapter (including any discarded data); on failure, it returns - -1 if the command was invalid, or -2 if a timeout occurred. - - This function is only called during board detection and initialization, so - performance and latency are not critical, and exclusive access to the Host - Adapter hardware is assumed. Once the board and driver are initialized, the - only Host Adapter command that is issued is the single byte Start Mailbox - Scan command, which does not require waiting for the Host Adapter Ready bit - to be set in the Status Register. -*/ - -static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter, - BusLogic_OperationCode_T OperationCode, - void *ParameterData, - int ParameterLength, - void *ReplyData, - int ReplyLength) -{ - unsigned char *ParameterPointer = (unsigned char *) ParameterData; - unsigned char *ReplyPointer = (unsigned char *) ReplyData; - unsigned char StatusRegister = 0, InterruptRegister; - long TimeoutCounter; - int ReplyBytes = 0; - /* - Clear out the Reply Data if provided. - */ - if (ReplyLength > 0) - memset(ReplyData, 0, ReplyLength); - /* - Wait for the Host Adapter Ready bit to be set and the Command/Parameter - Register Busy bit to be reset in the Status Register. - */ - TimeoutCounter = loops_per_sec >> 3; - while (--TimeoutCounter >= 0) - { - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if ((StatusRegister & BusLogic_HostAdapterReady) && - !(StatusRegister & BusLogic_CommandParameterRegisterBusy)) - break; - } - BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; - if (TimeoutCounter < 0) return -2; - /* - Write the OperationCode to the Command/Parameter Register. - */ - HostAdapter->HostAdapterCommandCompleted = false; - BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); - /* - Write any additional Parameter Bytes. - */ - TimeoutCounter = 10000; - while (ParameterLength > 0 && --TimeoutCounter >= 0) - { - /* - Wait 100 microseconds to give the Host Adapter enough time to determine - whether the last value written to the Command/Parameter Register was - valid or not. If the Command Complete bit is set in the Interrupt - Register, then the Command Invalid bit in the Status Register will be - reset if the Operation Code or Parameter was valid and the command - has completed, or set if the Operation Code or Parameter was invalid. - If the Data In Register Ready bit is set in the Status Register, then - the Operation Code was valid, and data is waiting to be read back - from the Host Adapter. Otherwise, wait for the Command/Parameter - Register Busy bit in the Status Register to be reset. - */ - udelay(100); - InterruptRegister = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister & BusLogic_CommandComplete) break; - if (HostAdapter->HostAdapterCommandCompleted) break; - if (StatusRegister & BusLogic_DataInRegisterReady) break; - if (StatusRegister & BusLogic_CommandParameterRegisterBusy) continue; - BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); - ParameterLength--; - } - BusLogic_CommandFailureReason = "Timeout waiting for Parameter Acceptance"; - if (TimeoutCounter < 0) return -2; - /* - The Modify I/O Address command does not cause a Command Complete Interrupt. - */ - if (OperationCode == BusLogic_ModifyIOAddress) - { - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; - if (StatusRegister & BusLogic_CommandInvalid) return -1; - BusLogic_CommandFailureReason = NULL; - return 0; - } - /* - Select an appropriate timeout value for awaiting command completion. - */ - switch (OperationCode) - { - case BusLogic_InquireInstalledDevicesID0to7: - case BusLogic_InquireInstalledDevicesID8to15: - /* Approximately 60 seconds. */ - TimeoutCounter = loops_per_sec << 2; - break; - default: - /* Approximately 1 second. */ - TimeoutCounter = loops_per_sec >> 4; - break; - } - /* - Receive any Reply Bytes, waiting for either the Command Complete bit to - be set in the Interrupt Register, or for the Interrupt Handler to set the - Host Adapter Command Completed bit in the Host Adapter structure. - */ - while (--TimeoutCounter >= 0) - { - InterruptRegister = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister & BusLogic_CommandComplete) break; - if (HostAdapter->HostAdapterCommandCompleted) break; - if (StatusRegister & BusLogic_DataInRegisterReady) - if (++ReplyBytes <= ReplyLength) - *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); - else BusLogic_ReadDataInRegister(HostAdapter); - } - BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; - if (TimeoutCounter < 0) return -2; - /* - If testing Command Complete Interrupts, wait a short while in case the - loop immediately above terminated due to the Command Complete bit being - set in the Interrupt Register, but the interrupt hasn't actually been - processed yet. Otherwise, acknowledging the interrupt here could prevent - the interrupt test from succeeding. - */ - if (OperationCode == BusLogic_TestCommandCompleteInterrupt) - udelay(10000); - /* - Clear any pending Command Complete Interrupt. - */ - BusLogic_WriteControlRegister(HostAdapter, BusLogic_InterruptReset); - if (BusLogic_GlobalOptions & BusLogic_TraceConfiguration) - if (OperationCode != BusLogic_TestCommandCompleteInterrupt) - { - int i; - printk("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", - OperationCode, StatusRegister, ReplyLength, ReplyBytes); - if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; - for (i = 0; i < ReplyLength; i++) - printk(" %02X", ((unsigned char *) ReplyData)[i]); - printk("\n"); - } - /* - Process Command Invalid conditions. - */ - if (StatusRegister & BusLogic_CommandInvalid) - { - /* - Some early BusLogic Host Adapters may not recover properly from - a Command Invalid condition, so if this appears to be the case, - a Soft Reset is issued to the Host Adapter. Potentially invalid - commands are never attempted after Mailbox Initialization is - performed, so there should be no Host Adapter state lost by a - Soft Reset in response to a Command Invalid condition. - */ - udelay(1000); - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister != (BusLogic_HostAdapterReady | - BusLogic_InitializationRequired)) - { - BusLogic_WriteControlRegister(HostAdapter, BusLogic_SoftReset); - udelay(1000); - } - BusLogic_CommandFailureReason = "Command Invalid"; - return -1; - } - /* - Handle Excess Parameters Supplied conditions. - */ - BusLogic_CommandFailureReason = "Excess Parameters Supplied"; - if (ParameterLength > 0) return -1; - /* - Indicate the command completed successfully. - */ - BusLogic_CommandFailureReason = NULL; - return ReplyBytes; -} - - -/* - BusLogic_Failure prints a standardized error message, and then returns false. -*/ - -static boolean BusLogic_Failure(BusLogic_HostAdapter_T *HostAdapter, - char *ErrorMessage) -{ - BusLogic_AnnounceDriver(); - printk("While configuring BusLogic Host Adapter at I/O Address 0x%X:\n", - HostAdapter->IO_Address); - printk("%s FAILED - DETACHING\n", ErrorMessage); - if (BusLogic_CommandFailureReason != NULL) - printk("ADDITIONAL FAILURE INFO - %s\n", BusLogic_CommandFailureReason); - return false; -} - - -/* - BusLogic_ProbeHostAdapter probes for a BusLogic Host Adapter. -*/ - -static boolean BusLogic_ProbeHostAdapter(BusLogic_HostAdapter_T *HostAdapter) -{ - boolean TraceProbe = (BusLogic_GlobalOptions & BusLogic_TraceProbe); - unsigned char StatusRegister, GeometryRegister; - /* - Read the Status Register to test if there is an I/O port that responds. A - nonexistent I/O port will return 0xFF, in which case there is definitely no - BusLogic Host Adapter at this base I/O Address. - */ - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if (TraceProbe) - printk("BusLogic_Probe(0x%X): Status 0x%02X\n", - HostAdapter->IO_Address, StatusRegister); - if (StatusRegister == 0xFF) return false; - /* - Read the undocumented BusLogic Geometry Register to test if there is an I/O - port that responds. Adaptec Host Adapters do not implement the Geometry - Register, so this test helps serve to avoid incorrectly recognizing an - Adaptec 1542A or 1542B as a BusLogic. Unfortunately, the Adaptec 1542C - series does respond to the Geometry Register I/O port, but it will be - rejected later when the Inquire Extended Setup Information command is - issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a - BusLogic clone that implements the same interface as earlier BusLogic - boards, including the undocumented commands, and is therefore supported by - this driver. However, the AMI FastDisk always returns 0x00 upon reading - the Geometry Register, so the extended translation option should always be - left disabled on the AMI FastDisk. - */ - GeometryRegister = BusLogic_ReadGeometryRegister(HostAdapter); - if (TraceProbe) - printk("BusLogic_Probe(0x%X): Geometry 0x%02X\n", - HostAdapter->IO_Address, GeometryRegister); - if (GeometryRegister == 0xFF) return false; - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; -} - - -/* - BusLogic_HardResetHostAdapter issues a Hard Reset to the Host Adapter, - and waits for Host Adapter Diagnostics to complete. -*/ - -static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T - *HostAdapter) -{ - boolean TraceHardReset = (BusLogic_GlobalOptions & BusLogic_TraceHardReset); - long TimeoutCounter = loops_per_sec >> 2; - unsigned char StatusRegister = 0; - /* - Issue a Hard Reset Command to the Host Adapter. The Host Adapter should - respond by setting Diagnostic Active in the Status Register. - */ - BusLogic_WriteControlRegister(HostAdapter, BusLogic_HardReset); - /* - Wait until Diagnostic Active is set in the Status Register. - */ - while (--TimeoutCounter >= 0) - { - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if ((StatusRegister & BusLogic_DiagnosticActive)) break; - } - if (TraceHardReset) - printk("BusLogic_HardReset(0x%X): Diagnostic Active, Status 0x%02X\n", - HostAdapter->IO_Address, StatusRegister); - if (TimeoutCounter < 0) return false; - /* - Wait 100 microseconds to allow completion of any initial diagnostic - activity which might leave the contents of the Status Register - unpredictable. - */ - udelay(100); - /* - Wait until Diagnostic Active is reset in the Status Register. - */ - while (--TimeoutCounter >= 0) - { - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if (!(StatusRegister & BusLogic_DiagnosticActive)) break; - } - if (TraceHardReset) - printk("BusLogic_HardReset(0x%X): Diagnostic Completed, Status 0x%02X\n", - HostAdapter->IO_Address, StatusRegister); - if (TimeoutCounter < 0) return false; - /* - Wait until at least one of the Diagnostic Failure, Host Adapter Ready, - or Data In Register Ready bits is set in the Status Register. - */ - while (--TimeoutCounter >= 0) - { - StatusRegister = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister & (BusLogic_DiagnosticFailure | - BusLogic_HostAdapterReady | - BusLogic_DataInRegisterReady)) - break; - } - if (TraceHardReset) - printk("BusLogic_HardReset(0x%X): Host Adapter Ready, Status 0x%02X\n", - HostAdapter->IO_Address, StatusRegister); - if (TimeoutCounter < 0) return false; - /* - If Diagnostic Failure is set or Host Adapter Ready is reset, then an - error occurred during the Host Adapter diagnostics. If Data In Register - Ready is set, then there is an Error Code available. - */ - if ((StatusRegister & BusLogic_DiagnosticFailure) || - !(StatusRegister & BusLogic_HostAdapterReady)) - { - BusLogic_CommandFailureReason = NULL; - BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS"); - printk("HOST ADAPTER STATUS REGISTER = %02X\n", StatusRegister); - if (StatusRegister & BusLogic_DataInRegisterReady) - { - unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter); - printk("HOST ADAPTER ERROR CODE = %d\n", ErrorCode); - } - return false; - } - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; -} - - -/* - BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic - Host Adapter. -*/ - -static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter) -{ - BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation; - BusLogic_RequestedReplyLength_T RequestedReplyLength; - unsigned long ProcessorFlags; - int Result; - /* - Issue the Inquire Extended Setup Information command. Only genuine - BusLogic Host Adapters and true clones support this command. Adaptec 1542C - series Host Adapters that respond to the Geometry Register I/O port will - fail this command. Interrupts must be disabled around the call to - BusLogic_Command since a Command Complete interrupt could occur if the IRQ - Channel was previously enabled for another BusLogic Host Adapter sharing - the same IRQ Channel. - */ - save_flags(ProcessorFlags); - cli(); - RequestedReplyLength = sizeof(ExtendedSetupInformation); - Result = BusLogic_Command(HostAdapter, - BusLogic_InquireExtendedSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &ExtendedSetupInformation, - sizeof(ExtendedSetupInformation)); - restore_flags(ProcessorFlags); - if (BusLogic_GlobalOptions & BusLogic_TraceProbe) - printk("BusLogic_Check(0x%X): Result %d\n", - HostAdapter->IO_Address, Result); - return (Result == sizeof(ExtendedSetupInformation)); -} - - -/* - BusLogic_ReadHostAdapterConfiguration reads the Configuration Information - from Host Adapter. -*/ - -static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T - *HostAdapter) -{ - BusLogic_BoardID_T BoardID; - BusLogic_Configuration_T Configuration; - BusLogic_SetupInformation_T SetupInformation; - BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation; - BusLogic_BoardModelNumber_T BoardModelNumber; - BusLogic_FirmwareVersion3rdDigit_T FirmwareVersion3rdDigit; - BusLogic_FirmwareVersionLetter_T FirmwareVersionLetter; - BusLogic_RequestedReplyLength_T RequestedReplyLength; - unsigned char GeometryRegister, *TargetPointer, Character; - unsigned short AllTargetsMask, DisconnectPermitted; - unsigned short TaggedQueuingPermitted, TaggedQueuingPermittedDefault; - boolean CommonErrorRecovery; - int TargetID, i; - /* - Issue the Inquire Board ID command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, - &BoardID, sizeof(BoardID)) != sizeof(BoardID)) - return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID"); - /* - Issue the Inquire Configuration command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, - &Configuration, sizeof(Configuration)) - != sizeof(Configuration)) - return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION"); - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - /* - Issue the Inquire Extended Setup Information command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &ExtendedSetupInformation, - sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); - /* - Issue the Inquire Board Model Number command. - */ - if (!(BoardID.FirmwareVersion1stDigit == '2' && - ExtendedSetupInformation.BusType == 'A')) - { - RequestedReplyLength = sizeof(BoardModelNumber); - if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardModelNumber, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &BoardModelNumber, sizeof(BoardModelNumber)) - != sizeof(BoardModelNumber)) - return BusLogic_Failure(HostAdapter, "INQUIRE BOARD MODEL NUMBER"); - } - else strcpy(BoardModelNumber, "542B"); - /* - Issue the Inquire Firmware Version 3rd Digit command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, - NULL, 0, &FirmwareVersion3rdDigit, - sizeof(FirmwareVersion3rdDigit)) - != sizeof(FirmwareVersion3rdDigit)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); - /* - Issue the Inquire Firmware Version Letter command. - */ - FirmwareVersionLetter = '\0'; - if (BoardID.FirmwareVersion1stDigit > '3' || - (BoardID.FirmwareVersion1stDigit == '3' && - BoardID.FirmwareVersion2ndDigit >= '3')) - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, - NULL, 0, &FirmwareVersionLetter, - sizeof(FirmwareVersionLetter)) - != sizeof(FirmwareVersionLetter)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER"); - /* - BusLogic Host Adapters can be identified by their model number and - the major version number of their firmware as follows: - - 4.xx BusLogic "C" Series Host Adapters: - BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF - 3.xx BusLogic "S" Series Host Adapters: - BT-747S/747D/757S/757D/445S/545S/542D - BT-542B/742A (revision H) - 2.xx BusLogic "A" Series Host Adapters: - BT-542B/742A (revision G and below) - 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter - */ - /* - Save the Model Name and Board Name in the Host Adapter structure. - */ - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(BoardModelNumber); i++) - { - Character = BoardModelNumber[i]; - if (Character == ' ' || Character == '\0') break; - *TargetPointer++ = Character; - } - *TargetPointer++ = '\0'; - strcpy(HostAdapter->BoardName, "BusLogic "); - strcat(HostAdapter->BoardName, HostAdapter->ModelName); - strcpy(HostAdapter->InterruptLabel, HostAdapter->BoardName); - /* - Save the Firmware Version in the Host Adapter structure. - */ - TargetPointer = HostAdapter->FirmwareVersion; - *TargetPointer++ = BoardID.FirmwareVersion1stDigit; - *TargetPointer++ = '.'; - *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; - if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') - *TargetPointer++ = FirmwareVersion3rdDigit; - if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') - *TargetPointer++ = FirmwareVersionLetter; - *TargetPointer++ = '\0'; - /* - Determine the IRQ Channel and save it in the Host Adapter structure. - */ - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - /* - Determine the DMA Channel and save it in the Host Adapter structure. - */ - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; - /* - Save the Host Adapter SCSI ID in the Host Adapter structure. - */ - HostAdapter->SCSI_ID = Configuration.HostAdapterID; - /* - Save the Synchronous Initiation flag and SCSI Parity Checking flag - in the Host Adapter structure. - */ - HostAdapter->SynchronousInitiation = - SetupInformation.SynchronousInitiationEnabled; - HostAdapter->ParityChecking = SetupInformation.ParityCheckEnabled; - /* - Determine the Bus Type and save it in the Host Adapter structure, - overriding the DMA Channel if it is inappropriate for the bus type. - */ - if (ExtendedSetupInformation.BusType == 'A') - HostAdapter->BusType = BusLogic_ISA_Bus; - else - switch (HostAdapter->ModelName[3]) - { - case '4': - HostAdapter->BusType = BusLogic_VESA_Bus; - HostAdapter->DMA_Channel = 0; - break; - case '5': - HostAdapter->BusType = BusLogic_ISA_Bus; - break; - case '6': - HostAdapter->BusType = BusLogic_MCA_Bus; - HostAdapter->DMA_Channel = 0; - break; - case '7': - HostAdapter->BusType = BusLogic_EISA_Bus; - HostAdapter->DMA_Channel = 0; - break; - case '9': - HostAdapter->BusType = BusLogic_PCI_Bus; - HostAdapter->DMA_Channel = 0; - break; - } - /* - Determine whether Extended Translation is enabled and save it in - the Host Adapter structure. - */ - GeometryRegister = BusLogic_ReadGeometryRegister(HostAdapter); - if (GeometryRegister & BusLogic_ExtendedTranslationEnabled) - HostAdapter->ExtendedTranslation = true; - /* - Save the Disconnect/Reconnect Permitted flag bits in the Host Adapter - structure. The Disconnect Permitted information is only valid on "C" - Series boards, but Disconnect/Reconnect is always permitted on "S" and - "A" Series boards. - */ - if (HostAdapter->FirmwareVersion[0] >= '4') - HostAdapter->DisconnectPermitted = - (SetupInformation.DisconnectPermittedID8to15 << 8) - | SetupInformation.DisconnectPermittedID0to7; - else HostAdapter->DisconnectPermitted = 0xFF; - /* - Save the Scatter Gather Limits, Level Sensitive Interrupts flag, - Wide SCSI flag, and Differential SCSI flag in the Host Adapter structure. - */ - HostAdapter->HostAdapterScatterGatherLimit = - ExtendedSetupInformation.ScatterGatherLimit; - HostAdapter->DriverScatterGatherLimit = - HostAdapter->HostAdapterScatterGatherLimit; - if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit) - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupts) - HostAdapter->LevelSensitiveInterrupts = true; - if (ExtendedSetupInformation.HostWideSCSI) - { - HostAdapter->HostWideSCSI = true; - HostAdapter->MaxTargetIDs = 16; - HostAdapter->MaxLogicalUnits = 64; - } - else - { - HostAdapter->HostWideSCSI = false; - HostAdapter->MaxTargetIDs = 8; - HostAdapter->MaxLogicalUnits = 8; - } - HostAdapter->HostDifferentialSCSI = - ExtendedSetupInformation.HostDifferentialSCSI; - /* - Determine the Host Adapter BIOS Address if the BIOS is enabled and - save it in the Host Adapter structure. The BIOS is disabled if the - BIOS_Address is 0. - */ - HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12; - /* - BusLogic BT-445S Host Adapters prior to board revision D have a hardware - bug whereby when the BIOS is enabled, transfers to/from the same address - range the BIOS occupies modulo 16MB are handled incorrectly. Only properly - functioning BT-445S boards have firmware version 3.37, so we require that - ISA bounce buffers be used for the buggy BT-445S models as well as for all - ISA models. - */ - if (HostAdapter->BusType == BusLogic_ISA_Bus || - (HostAdapter->BIOS_Address > 0 && - strcmp(HostAdapter->ModelName, "BT-445S") == 0 && - strcmp(HostAdapter->FirmwareVersion, "3.37") < 0)) - HostAdapter->BounceBuffersRequired = true; - /* - Select an appropriate value for Concurrency (Commands per Logical Unit) - either from a Command Line Entry, or based on whether this Host Adapter - requires that ISA bounce buffers be used. - */ - if (HostAdapter->CommandLineEntry != NULL && - HostAdapter->CommandLineEntry->Concurrency > 0) - HostAdapter->Concurrency = HostAdapter->CommandLineEntry->Concurrency; - else if (HostAdapter->BounceBuffersRequired) - HostAdapter->Concurrency = BusLogic_Concurrency_BB; - else HostAdapter->Concurrency = BusLogic_Concurrency; - /* - Select an appropriate value for Bus Settle Time either from a Command - Line Entry, or from BusLogic_DefaultBusSettleTime. - */ - if (HostAdapter->CommandLineEntry != NULL && - HostAdapter->CommandLineEntry->BusSettleTime > 0) - HostAdapter->BusSettleTime = HostAdapter->CommandLineEntry->BusSettleTime; - else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; - /* - Select an appropriate value for Local Options from a Command Line Entry. - */ - if (HostAdapter->CommandLineEntry != NULL) - HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions; - /* - Select appropriate values for the Error Recovery Option array either from - a Command Line Entry, or using BusLogic_ErrorRecoveryDefault. - */ - if (HostAdapter->CommandLineEntry != NULL) - memcpy(HostAdapter->ErrorRecoveryOption, - HostAdapter->CommandLineEntry->ErrorRecoveryOption, - sizeof(HostAdapter->ErrorRecoveryOption)); - else memset(HostAdapter->ErrorRecoveryOption, - BusLogic_ErrorRecoveryDefault, - sizeof(HostAdapter->ErrorRecoveryOption)); - /* - Tagged Queuing support is available and operates properly only on "C" - Series boards with firmware version 4.22 and above and on "S" Series - boards with firmware version 3.35 and above. Tagged Queuing is disabled - by default when the Concurrency value is 1 since queuing multiple commands - is not possible. - */ - TaggedQueuingPermittedDefault = 0; - if (HostAdapter->Concurrency > 1) - switch (HostAdapter->FirmwareVersion[0]) - { - case '5': - TaggedQueuingPermittedDefault = 0xFFFF; - break; - case '4': - if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0) - TaggedQueuingPermittedDefault = 0xFFFF; - break; - case '3': - if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0) - TaggedQueuingPermittedDefault = 0xFFFF; - break; - } - /* - Tagged Queuing is only useful if Disconnect/Reconnect is permitted. - Therefore, mask the Tagged Queuing Permitted Default bits with the - Disconnect/Reconnect Permitted bits. - */ - TaggedQueuingPermittedDefault &= HostAdapter->DisconnectPermitted; - /* - Combine the default Tagged Queuing Permitted Default bits with any - Command Line Entry Tagged Queuing specification. - */ - if (HostAdapter->CommandLineEntry != NULL) - HostAdapter->TaggedQueuingPermitted = - (HostAdapter->CommandLineEntry->TaggedQueuingPermitted & - HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask) | - (TaggedQueuingPermittedDefault & - ~HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask); - else HostAdapter->TaggedQueuingPermitted = TaggedQueuingPermittedDefault; - /* - Announce the Host Adapter Configuration. - */ - printk("scsi%d: Configuring BusLogic Model %s %s%s%s SCSI Host Adapter\n", - HostAdapter->HostNumber, HostAdapter->ModelName, - BusLogic_BusNames[HostAdapter->BusType], - (HostAdapter->HostWideSCSI ? " Wide" : ""), - (HostAdapter->HostDifferentialSCSI ? " Differential" : "")); - printk("scsi%d: Firmware Version: %s, I/O Address: 0x%X, " - "IRQ Channel: %d/%s\n", - HostAdapter->HostNumber, HostAdapter->FirmwareVersion, - HostAdapter->IO_Address, HostAdapter->IRQ_Channel, - (HostAdapter->LevelSensitiveInterrupts ? "Level" : "Edge")); - printk("scsi%d: DMA Channel: ", HostAdapter->HostNumber); - if (HostAdapter->DMA_Channel > 0) - printk("%d, ", HostAdapter->DMA_Channel); - else printk("None, "); - if (HostAdapter->BIOS_Address > 0) - printk("BIOS Address: 0x%lX, ", HostAdapter->BIOS_Address); - else printk("BIOS Address: None, "); - printk("Host Adapter SCSI ID: %d\n", HostAdapter->SCSI_ID); - printk("scsi%d: Scatter/Gather Limit: %d segments, " - "Synchronous Initiation: %s\n", HostAdapter->HostNumber, - HostAdapter->HostAdapterScatterGatherLimit, - (HostAdapter->SynchronousInitiation ? "Enabled" : "Disabled")); - printk("scsi%d: SCSI Parity Checking: %s, " - "Extended Disk Translation: %s\n", HostAdapter->HostNumber, - (HostAdapter->ParityChecking ? "Enabled" : "Disabled"), - (HostAdapter->ExtendedTranslation ? "Enabled" : "Disabled")); - AllTargetsMask = (1 << HostAdapter->MaxTargetIDs) - 1; - DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask; - printk("scsi%d: Disconnect/Reconnect: ", HostAdapter->HostNumber); - if (DisconnectPermitted == 0) - printk("Disabled"); - else if (DisconnectPermitted == AllTargetsMask) - printk("Enabled"); - else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++) - printk("%c", (DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N'); - printk(", Tagged Queuing: "); - TaggedQueuingPermitted = - HostAdapter->TaggedQueuingPermitted & AllTargetsMask; - if (TaggedQueuingPermitted == 0) - printk("Disabled"); - else if (TaggedQueuingPermitted == AllTargetsMask) - printk("Enabled"); - else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++) - printk("%c", (TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N'); - printk("\n"); - CommonErrorRecovery = true; - for (TargetID = 1; TargetID < HostAdapter->MaxTargetIDs; TargetID++) - if (HostAdapter->ErrorRecoveryOption[TargetID] != - HostAdapter->ErrorRecoveryOption[0]) - { - CommonErrorRecovery = false; - break; - } - printk("scsi%d: Error Recovery: ", HostAdapter->HostNumber); - if (CommonErrorRecovery) - printk("%s", BusLogic_ErrorRecoveryOptions[ - HostAdapter->ErrorRecoveryOption[0]]); - else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++) - printk("%s", BusLogic_ErrorRecoveryOptions2[ - HostAdapter->ErrorRecoveryOption[TargetID]]); - printk(", Mailboxes: %d, Initial CCBs: %d\n", - BusLogic_MailboxCount, BusLogic_InitialCCBs); - printk("scsi%d: Driver Scatter/Gather Limit: %d segments, " - "Concurrency: %d\n", HostAdapter->HostNumber, - HostAdapter->DriverScatterGatherLimit, HostAdapter->Concurrency); - /* - Indicate reading the Host Adapter Configuration completed successfully. - */ - return true; -} - - -/* - BusLogic_AcquireResources acquires the system resources necessary to use Host - Adapter, and initializes the fields in the SCSI Host structure. The base, - io_port, n_io_ports, irq, and dma_channel fields in the SCSI Host structure - are intentionally left uninitialized, as this driver handles acquisition and - release of these resources explicitly, as well as ensuring exclusive access - to the Host Adapter hardware and data structures through explicit locking. -*/ - -static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter, - SCSI_Host_T *Host) -{ - /* - Acquire exclusive or shared access to the IRQ Channel. A usage count is - maintained so that PCI, EISA, or MCA shared Interrupts can be supported. - */ - if (BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]++ == 0) - { - if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, - SA_INTERRUPT, HostAdapter->InterruptLabel) < 0) - { - BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]--; - printk("scsi%d: UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", - HostAdapter->HostNumber, HostAdapter->IRQ_Channel); - return false; - } - } - else - { - BusLogic_HostAdapter_T *FirstHostAdapter = - BusLogic_RegisteredHostAdapters; - while (FirstHostAdapter != NULL) - { - if (FirstHostAdapter->IRQ_Channel == HostAdapter->IRQ_Channel) - { - if (strlen(FirstHostAdapter->InterruptLabel) + 11 - < sizeof(FirstHostAdapter->InterruptLabel)) - { - strcat(FirstHostAdapter->InterruptLabel, " + "); - strcat(FirstHostAdapter->InterruptLabel, - HostAdapter->ModelName); - } - break; - } - FirstHostAdapter = FirstHostAdapter->Next; - } - } - HostAdapter->IRQ_ChannelAcquired = true; - /* - Acquire exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_Channel > 0) - { - if (request_dma(HostAdapter->DMA_Channel, HostAdapter->BoardName) < 0) - { - printk("scsi%d: UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", - HostAdapter->HostNumber, HostAdapter->DMA_Channel); - return false; - } - set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE); - enable_dma(HostAdapter->DMA_Channel); - HostAdapter->DMA_ChannelAcquired = true; - } - /* - Initialize necessary fields in the SCSI Host structure. - */ - Host->max_id = HostAdapter->MaxTargetIDs; - Host->max_lun = HostAdapter->MaxLogicalUnits; - Host->max_channel = 0; - Host->this_id = HostAdapter->SCSI_ID; - Host->can_queue = BusLogic_MailboxCount; - Host->cmd_per_lun = HostAdapter->Concurrency; - Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit; - Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired; - /* - Indicate the System Resource Acquisition completed successfully, - */ - return true; -} - - -/* - BusLogic_ReleaseResources releases any system resources previously acquired - by BusLogic_AcquireResources. -*/ - -static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter) -{ - /* - Release exclusive or shared access to the IRQ Channel. - */ - if (HostAdapter->IRQ_ChannelAcquired) - if (--BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9] == 0) - free_irq(HostAdapter->IRQ_Channel); - /* - Release exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_ChannelAcquired) - free_dma(HostAdapter->DMA_Channel); -} - - -/* - BusLogic_TestInterrupts tests for proper functioning of the Host Adapter - Interrupt Register and that interrupts generated by the Host Adapter are - getting through to the Interrupt Handler. A large proportion of initial - problems with installing PCI Host Adapters are due to configuration problems - where either the Host Adapter or Motherboard is configured incorrectly, and - interrupts do not get through as a result. -*/ - -static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter) -{ - unsigned int InitialInterruptCount, FinalInterruptCount; - int TestCount = 5, i; - InitialInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel]; - /* - Issue the Test Command Complete Interrupt commands. - */ - for (i = 0; i < TestCount; i++) - BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt, - NULL, 0, NULL, 0); - /* - Verify that BusLogic_InterruptHandler was called at least TestCount times. - Shared IRQ Channels could cause more than TestCount interrupts to occur, - but there should never be fewer than TestCount. - */ - FinalInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel]; - if (FinalInterruptCount < InitialInterruptCount + TestCount) - { - BusLogic_Failure(HostAdapter, "HOST ADAPTER INTERRUPT TEST"); - printk("\n\ -Interrupts are not getting through from the Host Adapter to the BusLogic\n\ -Driver Interrupt Handler. The most likely cause is that either the Host\n\ -Adapter or Motherboard is configured incorrectly. Please check the Host\n\ -Adapter configuration with AutoSCSI or by examining any dip switch and\n\ -jumper settings on the Host Adapter, and verify that no other device is\n\ -attempting to use the same IRQ Channel. For PCI Host Adapters, it may also\n\ -be necessary to investigate and manually set the PCI interrupt assignments\n\ -and edge/level interrupt type selection in the BIOS Setup Program or with\n\ -Motherboard jumpers.\n\n"); - return false; - } - /* - Indicate the Host Adapter Interrupt Test completed successfully. - */ - return true; -} - - -/* - BusLogic_InitializeHostAdapter initializes Host Adapter. This is the only - function called during SCSI Host Adapter detection which modifies the state - of the Host Adapter from its initial power on or hard reset state. -*/ - -static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T - *HostAdapter) -{ - BusLogic_ExtendedMailboxRequest_T ExtendedMailboxRequest; - BusLogic_RoundRobinModeRequest_T RoundRobinModeRequest; - BusLogic_WideModeCCBRequest_T WideModeCCBRequest; - BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; - /* - Initialize the Command Successful Flag, Read/Write Operation Count, - and Queued Operation Count for each Target. - */ - memset(HostAdapter->CommandSuccessfulFlag, false, - sizeof(HostAdapter->CommandSuccessfulFlag)); - memset(HostAdapter->ReadWriteOperationCount, 0, - sizeof(HostAdapter->ReadWriteOperationCount)); - memset(HostAdapter->QueuedOperationCount, 0, - sizeof(HostAdapter->QueuedOperationCount)); - /* - Initialize the Outgoing and Incoming Mailbox structures. - */ - memset(HostAdapter->OutgoingMailboxes, 0, - sizeof(HostAdapter->OutgoingMailboxes)); - memset(HostAdapter->IncomingMailboxes, 0, - sizeof(HostAdapter->IncomingMailboxes)); - /* - Initialize the pointers to the First, Last, and Next Mailboxes. - */ - HostAdapter->FirstOutgoingMailbox = &HostAdapter->OutgoingMailboxes[0]; - HostAdapter->LastOutgoingMailbox = - &HostAdapter->OutgoingMailboxes[BusLogic_MailboxCount-1]; - HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->FirstIncomingMailbox = &HostAdapter->IncomingMailboxes[0]; - HostAdapter->LastIncomingMailbox = - &HostAdapter->IncomingMailboxes[BusLogic_MailboxCount-1]; - HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - /* - Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. - */ - ExtendedMailboxRequest.MailboxCount = BusLogic_MailboxCount; - ExtendedMailboxRequest.BaseMailboxAddress = HostAdapter->OutgoingMailboxes; - if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, - &ExtendedMailboxRequest, - sizeof(ExtendedMailboxRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION"); - /* - Enable Strict Round Robin Mode if supported by the Host Adapter. In Strict - Round Robin Mode, the Host Adapter only looks at the next Outgoing Mailbox - for each new command, rather than scanning through all the Outgoing - Mailboxes to find any that have new commands in them. BusLogic indicates - that Strict Round Robin Mode is significantly more efficient. - */ - if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) - { - RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; - if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, - &RoundRobinModeRequest, - sizeof(RoundRobinModeRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); - } - /* - For Wide SCSI Host Adapters, issue the Enable Wide Mode CCB command to - allow more than 8 Logical Units per Target to be supported. - */ - if (HostAdapter->HostWideSCSI) - { - WideModeCCBRequest = BusLogic_WideModeCCB; - if (BusLogic_Command(HostAdapter, BusLogic_EnableWideModeCCB, - &WideModeCCBRequest, - sizeof(WideModeCCBRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "ENABLE WIDE MODE CCB"); - } - /* - For PCI Host Adapters being accessed through the PCI compliant I/O - Address, disable the ISA compatible I/O Address to avoid detecting the - same Host Adapter at both I/O Addresses. - */ - if (HostAdapter->BusType == BusLogic_PCI_Bus) - { - int Index; - for (Index = 0; BusLogic_IO_StandardAddresses[Index] > 0; Index++) - if (HostAdapter->IO_Address == BusLogic_IO_StandardAddresses[Index]) - break; - if (BusLogic_IO_StandardAddresses[Index] == 0) - { - ModifyIOAddressRequest = BusLogic_ModifyIO_Disable; - if (BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, - &ModifyIOAddressRequest, - sizeof(ModifyIOAddressRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "MODIFY I/O ADDRESS"); - } - } - /* - Announce Successful Initialization. - */ - printk("scsi%d: *** %s Initialized Successfully ***\n", - HostAdapter->HostNumber, HostAdapter->BoardName); - /* - Indicate the Host Adapter Initialization completed successfully. - */ - return true; -} - - -/* - BusLogic_InquireTargetDevices inquires about the Target Devices accessible - through Host Adapter and reports on the results. -*/ - -static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T - *HostAdapter) -{ - BusLogic_InstalledDevices8_T InstalledDevicesID0to7; - BusLogic_InstalledDevices8_T InstalledDevicesID8to15; - BusLogic_SetupInformation_T SetupInformation; - BusLogic_SynchronousPeriod_T SynchronousPeriod; - BusLogic_RequestedReplyLength_T RequestedReplyLength; - int TargetDevicesFound = 0, TargetID; - /* - Wait a few seconds between the Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI commands. Some SCSI devices get - confused if they receive SCSI commands too soon after a SCSI Bus Reset. - */ - BusLogic_Delay(HostAdapter->BusSettleTime); - /* - Inhibit the Target Devices Inquiry if requested. - */ - if (HostAdapter->LocalOptions & BusLogic_InhibitTargetInquiry) - { - printk("scsi%d: Target Device Inquiry Inhibited\n", - HostAdapter->HostNumber); - return true; - } - /* - Issue the Inquire Installed Devices ID 0 to 7 command, and for Wide SCSI - Host Adapters the Inquire Installed Devices ID 8 to 15 command. This is - necessary to force Synchronous Transfer Negotiation so that the Inquire - Setup Information and Inquire Synchronous Period commands will return - valid data. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, - NULL, 0, &InstalledDevicesID0to7, - sizeof(InstalledDevicesID0to7)) - != sizeof(InstalledDevicesID0to7)) - return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7"); - if (HostAdapter->HostWideSCSI) - if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID8to15, - NULL, 0, &InstalledDevicesID8to15, - sizeof(InstalledDevicesID8to15)) - != sizeof(InstalledDevicesID8to15)) - return BusLogic_Failure(HostAdapter, - "INQUIRE INSTALLED DEVICES ID 8 TO 15"); - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - /* - Issue the Inquire Synchronous Period command. - */ - if (HostAdapter->FirmwareVersion[0] >= '3') - { - RequestedReplyLength = sizeof(SynchronousPeriod); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, - &RequestedReplyLength, sizeof(RequestedReplyLength), - &SynchronousPeriod, sizeof(SynchronousPeriod)) - != sizeof(SynchronousPeriod)) - return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); - } - else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++) - if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) - SynchronousPeriod[TargetID] = - 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] - .TransferPeriod; - else SynchronousPeriod[TargetID] = 0; - /* - Save the Installed Devices, Synchronous Values, and Synchronous Period - information in the Host Adapter structure. - */ - memcpy(HostAdapter->InstalledDevices, InstalledDevicesID0to7, - sizeof(BusLogic_InstalledDevices8_T)); - memcpy(HostAdapter->SynchronousValues, - SetupInformation.SynchronousValuesID0to7, - sizeof(BusLogic_SynchronousValues8_T)); - if (HostAdapter->HostWideSCSI) - { - memcpy(&HostAdapter->InstalledDevices[8], InstalledDevicesID8to15, - sizeof(BusLogic_InstalledDevices8_T)); - memcpy(&HostAdapter->SynchronousValues[8], - SetupInformation.SynchronousValuesID8to15, - sizeof(BusLogic_SynchronousValues8_T)); - } - memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod, - sizeof(BusLogic_SynchronousPeriod_T)); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++) - if (HostAdapter->InstalledDevices[TargetID] != 0) - { - int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID]; - if (SynchronousPeriod > 10) - { - int SynchronousTransferRate = 100000000 / SynchronousPeriod; - int RoundedSynchronousTransferRate = - (SynchronousTransferRate + 5000) / 10000; - printk("scsi%d: Target %d: Synchronous at " - "%d.%02d mega-transfers/second, offset %d\n", - HostAdapter->HostNumber, TargetID, - RoundedSynchronousTransferRate / 100, - RoundedSynchronousTransferRate % 100, - HostAdapter->SynchronousValues[TargetID].Offset); - } - else if (SynchronousPeriod > 0) - { - int SynchronousTransferRate = 100000000 / SynchronousPeriod; - int RoundedSynchronousTransferRate = - (SynchronousTransferRate + 50000) / 100000; - printk("scsi%d: Target %d: Synchronous at " - "%d.%01d mega-transfers/second, offset %d\n", - HostAdapter->HostNumber, TargetID, - RoundedSynchronousTransferRate / 10, - RoundedSynchronousTransferRate % 10, - HostAdapter->SynchronousValues[TargetID].Offset); - } - else printk("scsi%d: Target %d: Asynchronous\n", - HostAdapter->HostNumber, TargetID); - TargetDevicesFound++; - } - if (TargetDevicesFound == 0) - printk("scsi%d: No Target Devices Found\n", HostAdapter->HostNumber); - /* - Indicate the Target Device Inquiry completed successfully. - */ - return true; -} - - -/* - BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard - I/O Addresses where they may be located, initializing, registering, and - reporting the configuration of each BusLogic Host Adapter it finds. It - returns the number of BusLogic Host Adapters successfully initialized and - registered. -*/ - -int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate) -{ - int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0; - int AddressProbeIndex = 0; - BusLogic_InitializeAddressProbeList(); - while (BusLogic_IO_AddressProbeList[AddressProbeIndex] > 0) - { - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; - SCSI_Host_T *Host; - memset(HostAdapter, 0, sizeof(BusLogic_HostAdapter_T)); - HostAdapter->IO_Address = - BusLogic_IO_AddressProbeList[AddressProbeIndex++]; - /* - Initialize the Command Line Entry field if an explicit I/O Address - was specified. - */ - if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount && - BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == - HostAdapter->IO_Address) - HostAdapter->CommandLineEntry = - &BusLogic_CommandLineEntries[CommandLineEntryIndex++]; - /* - Check whether the I/O Address range is already in use. - */ - if (check_region(HostAdapter->IO_Address, BusLogic_IO_PortCount) < 0) - continue; - /* - Probe the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_ProbeHostAdapter(HostAdapter)) continue; - /* - Hard Reset the Host Adapter. If unsuccessful, abort further - initialization. - */ - if (!BusLogic_HardResetHostAdapter(HostAdapter)) continue; - /* - Check the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_CheckHostAdapter(HostAdapter)) continue; - /* - Initialize the Command Line Entry field if an explicit I/O Address - was not specified. - */ - if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount && - BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == 0) - HostAdapter->CommandLineEntry = - &BusLogic_CommandLineEntries[CommandLineEntryIndex++]; - /* - Announce the Driver Version and Date, Author's Name, Copyright Notice, - and Contact Address. - */ - BusLogic_AnnounceDriver(); - /* - Register usage of the I/O Address range. From this point onward, any - failure will be assumed to be due to a problem with the Host Adapter, - rather than due to having mistakenly identified this port as belonging - to a BusLogic Host Adapter. The I/O Address range will not be - released, thereby preventing it from being incorrectly identified as - any other type of Host Adapter. - */ - request_region(HostAdapter->IO_Address, BusLogic_IO_PortCount, - "BusLogic"); - /* - Register the SCSI Host structure. - */ - HostTemplate->proc_dir = &BusLogic_ProcDirectoryEntry; - Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T)); - HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; - memcpy(HostAdapter, &HostAdapterPrototype, - sizeof(BusLogic_HostAdapter_T)); - HostAdapter->SCSI_Host = Host; - HostAdapter->HostNumber = Host->host_no; - /* - Add Host Adapter to the end of the list of registered BusLogic - Host Adapters. In order for Command Complete Interrupts to be - properly dismissed by BusLogic_InterruptHandler, the Host Adapter - must be registered. This must be done before the IRQ Channel is - acquired, and in a shared IRQ Channel environment, must be done - before any Command Complete Interrupts occur, since the IRQ Channel - may have already been acquired by a previous BusLogic Host Adapter. - */ - BusLogic_RegisterHostAdapter(HostAdapter); - /* - Read the Host Adapter Configuration, Acquire the System Resources - necessary to use Host Adapter and initialize the fields in the SCSI - Host structure, then Test Interrupts, Create the CCBs, Initialize - the Host Adapter, and finally Inquire about the Target Devices. - */ - if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && - BusLogic_AcquireResources(HostAdapter, Host) && - BusLogic_TestInterrupts(HostAdapter) && - BusLogic_CreateCCBs(HostAdapter) && - BusLogic_InitializeHostAdapter(HostAdapter) && - BusLogic_InquireTargetDevices(HostAdapter)) - { - /* - Initialization has been completed successfully. Release and - re-register usage of the I/O Address range so that the Model - Name of the Host Adapter will appear. - */ - release_region(HostAdapter->IO_Address, BusLogic_IO_PortCount); - request_region(HostAdapter->IO_Address, BusLogic_IO_PortCount, - HostAdapter->BoardName); - BusLogicHostAdapterCount++; - } - else - { - /* - An error occurred during Host Adapter Configuration Querying, - Resource Acquisition, Interrupt Testing, CCB Creation, Host - Adapter Initialization, or Target Device Inquiry, so remove - Host Adapter from the list of registered BusLogic Host Adapters, - destroy the CCBs, Release the System Resources, and Unregister - the SCSI Host. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - BusLogic_UnregisterHostAdapter(HostAdapter); - scsi_unregister(Host); - } - } - return BusLogicHostAdapterCount; -} - - -/* - BusLogic_ReleaseHostAdapter releases all resources previously acquired to - support a specific Host Adapter, including the I/O Address range, and - unregisters the BusLogic Host Adapter. -*/ - -int BusLogic_ReleaseHostAdapter(SCSI_Host_T *Host) -{ - BusLogic_HostAdapter_T *HostAdapter = - (BusLogic_HostAdapter_T *) Host->hostdata; - /* - Destroy the CCBs and release any system resources acquired to use - Host Adapter. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - /* - Release usage of the I/O Address range. - */ - release_region(HostAdapter->IO_Address, BusLogic_IO_PortCount); - /* - Remove Host Adapter from the list of registered BusLogic Host Adapters. - */ - BusLogic_UnregisterHostAdapter(HostAdapter); - return 0; -} - - -/* - BusLogic_ComputeResultCode computes a SCSI Subsystem Result Code from - the Host Adapter Status and Target Device Status. -*/ - -static int BusLogic_ComputeResultCode(BusLogic_HostAdapterStatus_T - HostAdapterStatus, - BusLogic_TargetDeviceStatus_T - TargetDeviceStatus) -{ - int HostStatus; - switch (HostAdapterStatus) - { - case BusLogic_CommandCompletedNormally: - case BusLogic_LinkedCommandCompleted: - case BusLogic_LinkedCommandCompletedWithFlag: - HostStatus = DID_OK; - break; - case BusLogic_SCSISelectionTimeout: - HostStatus = DID_TIME_OUT; - break; - case BusLogic_InvalidOutgoingMailboxActionCode: - case BusLogic_InvalidCommandOperationCode: - case BusLogic_InvalidCommandParameter: - printk("BusLogic: BusLogic Driver Protocol Error 0x%02X\n", - HostAdapterStatus); - case BusLogic_DataOverUnderRun: - case BusLogic_UnexpectedBusFree: - case BusLogic_LinkedCCBhasInvalidLUN: - case BusLogic_AutoRequestSenseFailed: - case BusLogic_TaggedQueuingMessageRejected: - case BusLogic_UnsupportedMessageReceived: - case BusLogic_HostAdapterHardwareFailed: - case BusLogic_TargetDeviceReconnectedImproperly: - case BusLogic_AbortQueueGenerated: - case BusLogic_HostAdapterSoftwareError: - case BusLogic_HostAdapterHardwareTimeoutError: - case BusLogic_SCSIParityErrorDetected: - HostStatus = DID_ERROR; - break; - case BusLogic_InvalidBusPhaseRequested: - case BusLogic_TargetFailedResponseToATN: - case BusLogic_HostAdapterAssertedRST: - case BusLogic_OtherDeviceAssertedRST: - case BusLogic_HostAdapterAssertedBusDeviceReset: - HostStatus = DID_RESET; - break; - default: - printk("BusLogic: unknown Host Adapter Status 0x%02X\n", - HostAdapterStatus); - HostStatus = DID_ERROR; - break; - } - return (HostStatus << 16) | TargetDeviceStatus; -} - - -/* - BusLogic_InterruptHandler handles hardware interrupts from BusLogic Host - Adapters. To simplify handling shared IRQ Channels, all installed BusLogic - Host Adapters are scanned whenever any one of them signals a hardware - interrupt. -*/ - -static void BusLogic_InterruptHandler(int IRQ_Channel, - Registers_T *InterruptRegisters) -{ - BusLogic_CCB_T *FirstCompletedCCB = NULL, *LastCompletedCCB = NULL; - BusLogic_HostAdapter_T *HostAdapter; - int HostAdapterResetPendingCount = 0; - /* - Iterate over the installed BusLogic Host Adapters accepting any Incoming - Mailbox entries and saving the completed CCBs for processing. This - interrupt handler is installed with SA_INTERRUPT, so interrupts are - disabled when the interrupt handler is entered. - */ - for (HostAdapter = BusLogic_RegisteredHostAdapters; - HostAdapter != NULL; - HostAdapter = HostAdapter->Next) - { - unsigned char InterruptRegister; - /* - Acquire exclusive access to Host Adapter. - */ - BusLogic_LockHostAdapterID(HostAdapter); - /* - Read the Host Adapter Interrupt Register. - */ - InterruptRegister = BusLogic_ReadInterruptRegister(HostAdapter); - if (InterruptRegister & BusLogic_InterruptValid) - { - /* - Acknowledge the interrupt and reset the Host Adapter - Interrupt Register. - */ - BusLogic_WriteControlRegister(HostAdapter, BusLogic_InterruptReset); - /* - Process valid SCSI Reset State and Incoming Mailbox Loaded - interrupts. Command Complete interrupts are noted, and - Outgoing Mailbox Available interrupts are ignored, as they - are never enabled. - */ - if (InterruptRegister & BusLogic_SCSIResetState) - { - HostAdapter->HostAdapterResetPending = true; - HostAdapterResetPendingCount++; - } - else if (InterruptRegister & BusLogic_IncomingMailboxLoaded) - { - /* - Scan through the Incoming Mailboxes in Strict Round Robin - fashion, saving any completed CCBs for further processing. - It is essential that for each CCB and SCSI Command issued, - command completion processing is performed exactly once. - Therefore, only Incoming Mailboxes with completion code - Command Completed Without Error, Command Completed With - Error, or Command Aborted At Host Request are saved for - completion processing. When an Incoming Mailbox has a - completion code of Aborted Command Not Found, the CCB had - already completed or been aborted before the current Abort - request was processed, and so completion processing has - already occurred and no further action should be taken. - */ - BusLogic_IncomingMailbox_T *NextIncomingMailbox = - HostAdapter->NextIncomingMailbox; - BusLogic_CompletionCode_T MailboxCompletionCode; - while ((MailboxCompletionCode = - NextIncomingMailbox->CompletionCode) != - BusLogic_IncomingMailboxFree) - { - BusLogic_CCB_T *CCB = NextIncomingMailbox->CCB; - if (MailboxCompletionCode != BusLogic_AbortedCommandNotFound) - if (CCB->Status == BusLogic_CCB_Active) - { - /* - Mark this CCB as completed and add it to the end - of the list of completed CCBs. - */ - CCB->Status = BusLogic_CCB_Completed; - CCB->MailboxCompletionCode = MailboxCompletionCode; - CCB->Next = NULL; - if (FirstCompletedCCB == NULL) - { - FirstCompletedCCB = CCB; - LastCompletedCCB = CCB; - } - else - { - LastCompletedCCB->Next = CCB; - LastCompletedCCB = CCB; - } - HostAdapter->QueuedOperationCount[CCB->TargetID]--; - } - else - { - /* - If a CCB ever appears in an Incoming Mailbox and - is not marked as status Active, then there is - most likely a bug in the Host Adapter firmware. - */ - printk("scsi%d: Illegal CCB #%d status %d in " - "Incoming Mailbox\n", HostAdapter->HostNumber, - CCB->SerialNumber, CCB->Status); - } - else printk("scsi%d: Aborted CCB #%d to Target %d " - "Not Found\n", HostAdapter->HostNumber, - CCB->SerialNumber, CCB->TargetID); - NextIncomingMailbox->CompletionCode = - BusLogic_IncomingMailboxFree; - if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) - NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - } - HostAdapter->NextIncomingMailbox = NextIncomingMailbox; - } - else if (InterruptRegister & BusLogic_CommandComplete) - HostAdapter->HostAdapterCommandCompleted = true; - } - /* - Release exclusive access to Host Adapter. - */ - BusLogic_UnlockHostAdapterID(HostAdapter); - } - /* - Enable interrupts while the completed CCBs are processed. - */ - sti(); - /* - Iterate over the Host Adapters performing any pending Host Adapter Resets. - */ - if (HostAdapterResetPendingCount > 0) - for (HostAdapter = BusLogic_RegisteredHostAdapters; - HostAdapter != NULL; - HostAdapter = HostAdapter->Next) - if (HostAdapter->HostAdapterResetPending) - { - BusLogic_ResetHostAdapter(HostAdapter, NULL); - HostAdapter->HostAdapterResetPending = false; - scsi_mark_host_bus_reset(HostAdapter->SCSI_Host); - } - /* - Iterate over the completed CCBs setting the SCSI Command Result Codes, - deallocating the CCBs, and calling the Completion Routines. - */ - while (FirstCompletedCCB != NULL) - { - BusLogic_CCB_T *CCB = FirstCompletedCCB; - SCSI_Command_T *Command = CCB->Command; - FirstCompletedCCB = FirstCompletedCCB->Next; - HostAdapter = CCB->HostAdapter; - /* - Bus Device Reset CCBs have the Command field non-NULL only when a Bus - Device Reset was requested for a command that was not currently active - in the Host Adapter, and hence would not have its Completion Routine - called otherwise. - */ - if (CCB->Opcode == BusLogic_SCSIBusDeviceReset) - { - printk("scsi%d: Bus Device Reset CCB #%d to Target %d Completed\n", - HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); - if (Command != NULL) Command->result = DID_RESET << 16; - } - else - /* - Translate the Mailbox Completion Code, Host Adapter Status, and - Target Device Status into a SCSI Subsystem Result Code. - */ - switch (CCB->MailboxCompletionCode) - { - case BusLogic_IncomingMailboxFree: - case BusLogic_AbortedCommandNotFound: - printk("scsi%d: CCB #%d to Target %d Impossible State\n", - HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); - break; - case BusLogic_CommandCompletedWithoutError: - HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true; - Command->result = DID_OK << 16; - break; - case BusLogic_CommandAbortedAtHostRequest: - printk("scsi%d: CCB #%d to Target %d Aborted\n", - HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); - Command->result = DID_ABORT << 16; - break; - case BusLogic_CommandCompletedWithError: - Command->result = - BusLogic_ComputeResultCode(CCB->HostAdapterStatus, - CCB->TargetDeviceStatus); - if (BusLogic_GlobalOptions & BusLogic_TraceErrors) - if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) - { - int i; - printk("scsi%d: CCB #%d Target %d: Result %X " - "Host Adapter Status %02X Target Status %02X\n", - HostAdapter->HostNumber, CCB->SerialNumber, - CCB->TargetID, Command->result, - CCB->HostAdapterStatus, CCB->TargetDeviceStatus); - printk("scsi%d: CDB ", HostAdapter->HostNumber); - for (i = 0; i < CCB->CDB_Length; i++) - printk(" %02X", CCB->CDB[i]); - printk("\n"); - printk("scsi%d: Sense ", HostAdapter->HostNumber); - for (i = 0; i < CCB->SenseDataLength; i++) - printk(" %02X", (*CCB->SenseDataPointer)[i]); - printk("\n"); - } - break; - } - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); - /* - Call the SCSI Command Completion Routine if appropriate. - */ - if (Command != NULL) Command->scsi_done(Command); - } -} - - -/* - BusLogic_WriteOutgoingMailbox places CCB and Action Code into an Outgoing - Mailbox for execution by Host Adapter. -*/ - -static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T - *HostAdapter, - BusLogic_ActionCode_T ActionCode, - BusLogic_CCB_T *CCB) -{ - BusLogic_OutgoingMailbox_T *NextOutgoingMailbox; - boolean Result = false; - BusLogic_LockHostAdapter(HostAdapter); - NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox; - if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) - { - CCB->Status = BusLogic_CCB_Active; - /* - The CCB field must be written before the Action Code field since - the Host Adapter is operating asynchronously and the locking code - does not protect against simultaneous access by the Host Adapter. - */ - NextOutgoingMailbox->CCB = CCB; - NextOutgoingMailbox->ActionCode = ActionCode; - BusLogic_StartMailboxScan(HostAdapter); - if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) - NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox; - if (ActionCode == BusLogic_MailboxStartCommand) - HostAdapter->QueuedOperationCount[CCB->TargetID]++; - Result = true; - } - BusLogic_UnlockHostAdapter(HostAdapter); - return Result; -} - - -/* - BusLogic_QueueCommand creates a CCB for Command and places it into an - Outgoing Mailbox for execution by the associated Host Adapter. -*/ - -int BusLogic_QueueCommand(SCSI_Command_T *Command, - void (*CompletionRoutine)(SCSI_Command_T *)) -{ - BusLogic_HostAdapter_T *HostAdapter = - (BusLogic_HostAdapter_T *) Command->host->hostdata; - unsigned char *CDB = Command->cmnd; - unsigned char CDB_Length = Command->cmd_len; - unsigned char TargetID = Command->target; - unsigned char LogicalUnit = Command->lun; - void *BufferPointer = Command->request_buffer; - int BufferLength = Command->request_bufflen; - int SegmentCount = Command->use_sg; - BusLogic_CCB_T *CCB; - long EnableTQ; - /* - SCSI REQUEST_SENSE commands will be executed automatically by the Host - Adapter for any errors, so they should not be executed explicitly unless - the Sense Data is zero indicating that no error occurred. - */ - if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) - { - Command->result = DID_OK << 16; - CompletionRoutine(Command); - return 0; - } - /* - Allocate a CCB from the Host Adapter's free list. If there are none - available and memory allocation fails, return a result code of Bus Busy - so that this Command will be retried. - */ - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) - { - Command->result = DID_BUS_BUSY << 16; - CompletionRoutine(Command); - return 0; - } - /* - Initialize the fields in the BusLogic Command Control Block (CCB). - */ - if (SegmentCount == 0) - { - CCB->Opcode = BusLogic_InitiatorCCB; - CCB->DataLength = BufferLength; - CCB->DataPointer = BufferPointer; - } - else - { - SCSI_ScatterList_T *ScatterList = (SCSI_ScatterList_T *) BufferPointer; - int Segment; - CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; - CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T); - CCB->DataPointer = CCB->ScatterGatherList; - for (Segment = 0; Segment < SegmentCount; Segment++) - { - CCB->ScatterGatherList[Segment].SegmentByteCount = - ScatterList[Segment].length; - CCB->ScatterGatherList[Segment].SegmentDataPointer = - ScatterList[Segment].address; - } - } - switch (CDB[0]) - { - case READ_6: - case READ_10: - CCB->DataDirection = BusLogic_DataInLengthChecked; - HostAdapter->ReadWriteOperationCount[TargetID]++; - break; - case WRITE_6: - case WRITE_10: - CCB->DataDirection = BusLogic_DataOutLengthChecked; - HostAdapter->ReadWriteOperationCount[TargetID]++; - break; - default: - CCB->DataDirection = BusLogic_UncheckedDataTransfer; - break; - } - CCB->CDB_Length = CDB_Length; - CCB->SenseDataLength = sizeof(Command->sense_buffer); - CCB->HostAdapterStatus = 0; - CCB->TargetDeviceStatus = 0; - CCB->TargetID = TargetID; - CCB->LogicalUnit = LogicalUnit; - /* - For Wide SCSI Host Adapters, Wide Mode CCBs are used to support more than - 8 Logical Units per Target, and this requires setting the overloaded - TagEnable field to Logical Unit bit 5. - */ - if (HostAdapter->HostWideSCSI) - { - CCB->TagEnable = LogicalUnit >> 5; - CCB->WideModeTagEnable = false; - } - else CCB->TagEnable = false; - /* - BusLogic recommends that after a Reset the first couple of commands that - are sent to a Target be sent in a non Tagged Queue fashion so that the Host - Adapter and Target can establish Synchronous Transfer before Queue Tag - messages can interfere with the Synchronous Negotiation message. By - waiting to enable tagged Queuing until after the first 16 read/write - commands have been sent, it is assured that the Tagged Queuing message - will not occur while the partition table is printed. - */ - if ((HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) && - Command->device->tagged_supported && - (EnableTQ = HostAdapter->ReadWriteOperationCount[TargetID] - 16) >= 0) - { - BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag; - unsigned long CurrentTime = jiffies; - if (EnableTQ == 0) - printk("scsi%d: Tagged Queuing now active for Target %d\n", - HostAdapter->HostNumber, TargetID); - /* - When using Tagged Queuing with Simple Queue Tags, it appears that disk - drive controllers do not guarantee that a queued command will not - remain in a disconnected state indefinitely if commands that read or - write nearer the head position continue to arrive without interruption. - Therefore, for each Target Device this driver keeps track of the last - time either the queue was empty or an Ordered Queue Tag was issued. If - more than 2 seconds have elapsed since this last sequence point, this - command will be issued with an Ordered Queue Tag rather than a Simple - Queue Tag, which forces the Target Device to complete all previously - queued commands before this command may be executed. - */ - if (HostAdapter->QueuedOperationCount[TargetID] == 0) - HostAdapter->LastSequencePoint[TargetID] = CurrentTime; - else if (CurrentTime - HostAdapter->LastSequencePoint[TargetID] > 2*HZ) - { - HostAdapter->LastSequencePoint[TargetID] = CurrentTime; - QueueTag = BusLogic_OrderedQueueTag; - } - if (HostAdapter->HostWideSCSI) - { - CCB->WideModeTagEnable = true; - CCB->WideModeQueueTag = QueueTag; - } - else - { - CCB->TagEnable = true; - CCB->QueueTag = QueueTag; - } - } - memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataPointer = (SCSI_SenseData_T *) &Command->sense_buffer; - CCB->Command = Command; - Command->scsi_done = CompletionRoutine; - /* - Place the CCB in an Outgoing Mailbox. If there are no Outgoing - Mailboxes available, return a result code of Bus Busy so that this - Command will be retried. - */ - if (!(BusLogic_WriteOutgoingMailbox(HostAdapter, - BusLogic_MailboxStartCommand, CCB))) - { - printk("scsi%d: cannot write Outgoing Mailbox\n", - HostAdapter->HostNumber); - BusLogic_DeallocateCCB(CCB); - Command->result = DID_BUS_BUSY << 16; - CompletionRoutine(Command); - } - return 0; -} - - -/* - BusLogic_AbortCommand aborts Command if possible. -*/ - -int BusLogic_AbortCommand(SCSI_Command_T *Command) -{ - BusLogic_HostAdapter_T *HostAdapter = - (BusLogic_HostAdapter_T *) Command->host->hostdata; - unsigned long CommandPID = Command->pid; - unsigned char InterruptRegister; - BusLogic_CCB_T *CCB; - int Result; - /* - If the Host Adapter has posted an interrupt but the Interrupt Handler - has not been called for some reason (i.e. the interrupt was lost), try - calling the Interrupt Handler directly to process the commands that - have been completed. - */ - InterruptRegister = BusLogic_ReadInterruptRegister(HostAdapter); - if (InterruptRegister & BusLogic_InterruptValid) - { - unsigned long ProcessorFlags; - printk("scsi%d: Recovering Lost/Delayed Interrupt for IRQ Channel %d\n", - HostAdapter->HostNumber, HostAdapter->IRQ_Channel); - save_flags(ProcessorFlags); - cli(); - BusLogic_InterruptHandler(HostAdapter->IRQ_Channel, NULL); - restore_flags(ProcessorFlags); - return SCSI_ABORT_SNOOZE; - } - /* - Find the CCB to be aborted if possible. - */ - BusLogic_LockHostAdapter(HostAdapter); - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Command == Command) break; - BusLogic_UnlockHostAdapter(HostAdapter); - if (CCB == NULL) - { - printk("scsi%d: Unable to Abort Command to Target %d - No CCB Found\n", - HostAdapter->HostNumber, Command->target); - return SCSI_ABORT_NOT_RUNNING; - } - /* - Briefly pause to see if this command will complete. - */ - printk("scsi%d: Pausing briefly to see if CCB #%d " - "to Target %d will complete\n", - HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); - BusLogic_Delay(2); - /* - If this CCB is still Active and still refers to the same Command, then - actually aborting this Command is necessary. - */ - BusLogic_LockHostAdapter(HostAdapter); - Result = SCSI_ABORT_NOT_RUNNING; - if (CCB->Status == BusLogic_CCB_Active && - CCB->Command == Command && Command->pid == CommandPID) - { - /* - Attempt to abort this CCB. - */ - if (BusLogic_WriteOutgoingMailbox(HostAdapter, - BusLogic_MailboxAbortCommand, CCB)) - { - printk("scsi%d: Aborting CCB #%d to Target %d\n", - HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); - Result = SCSI_ABORT_PENDING; - } - else - { - printk("scsi%d: Unable to Abort CCB #%d to Target %d - " - "No Outgoing Mailboxes\n", HostAdapter->HostNumber, - CCB->SerialNumber, CCB->TargetID); - Result = SCSI_ABORT_BUSY; - } - } - else printk("scsi%d: CCB #%d to Target %d completed\n", - HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); - BusLogic_UnlockHostAdapter(HostAdapter); - return Result; -} - - -/* - BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all - currently executing SCSI commands as having been reset, as well as - the specified Command if non-NULL. -*/ - -static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter, - SCSI_Command_T *Command) -{ - BusLogic_CCB_T *CCB; - if (Command == NULL) - printk("scsi%d: Resetting %s due to SCSI Reset State Interrupt\n", - HostAdapter->HostNumber, HostAdapter->BoardName); - else printk("scsi%d: Resetting %s due to Target %d\n", - HostAdapter->HostNumber, HostAdapter->BoardName, Command->target); - /* - Attempt to Reset and Reinitialize the Host Adapter. - */ - BusLogic_LockHostAdapter(HostAdapter); - if (!(BusLogic_HardResetHostAdapter(HostAdapter) && - BusLogic_InitializeHostAdapter(HostAdapter))) - { - printk("scsi%d: Resetting %s Failed\n", - HostAdapter->HostNumber, HostAdapter->BoardName); - BusLogic_UnlockHostAdapter(HostAdapter); - return SCSI_RESET_ERROR; - } - BusLogic_UnlockHostAdapter(HostAdapter); - /* - Wait a few seconds between the Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI commands. Some SCSI devices get - confused if they receive SCSI commands too soon after a SCSI Bus Reset. - */ - BusLogic_Delay(HostAdapter->BusSettleTime); - /* - Mark all currently executing CCBs as having been reset. - */ - BusLogic_LockHostAdapter(HostAdapter); - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Status == BusLogic_CCB_Active) - { - CCB->Status = BusLogic_CCB_Reset; - if (CCB->Command == Command) - { - CCB->Command = NULL; - /* - Disable Tagged Queuing if it was active for this Target Device. - */ - if (((HostAdapter->HostWideSCSI && CCB->WideModeTagEnable) || - (!HostAdapter->HostWideSCSI && CCB->TagEnable)) && - (HostAdapter->TaggedQueuingPermitted & (1 << CCB->TargetID))) - { - HostAdapter->TaggedQueuingPermitted &= ~(1 << CCB->TargetID); - printk("scsi%d: Tagged Queuing now disabled for Target %d\n", - HostAdapter->HostNumber, CCB->TargetID); - } - } - } - BusLogic_UnlockHostAdapter(HostAdapter); - /* - Perform completion processing for the Command being Reset. - */ - if (Command != NULL) - { - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - } - /* - Perform completion processing for any other active CCBs. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Status == BusLogic_CCB_Reset) - { - Command = CCB->Command; - BusLogic_DeallocateCCB(CCB); - if (Command != NULL) - { - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - } - } - return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; -} - - -/* - BusLogic_BusDeviceReset sends a Bus Device Reset to the Target - associated with Command. -*/ - -static int BusLogic_BusDeviceReset(BusLogic_HostAdapter_T *HostAdapter, - SCSI_Command_T *Command) -{ - BusLogic_CCB_T *CCB = BusLogic_AllocateCCB(HostAdapter), *XCCB; - unsigned char TargetID = Command->target; - /* - If sending a Bus Device Reset is impossible, attempt a full Host - Adapter Hard Reset and SCSI Bus Reset. - */ - if (CCB == NULL) - return BusLogic_ResetHostAdapter(HostAdapter, Command); - printk("scsi%d: Sending Bus Device Reset CCB #%d to Target %d\n", - HostAdapter->HostNumber, CCB->SerialNumber, TargetID); - CCB->Opcode = BusLogic_SCSIBusDeviceReset; - CCB->TargetID = TargetID; - CCB->Command = Command; - /* - If there is a currently executing CCB in the Host Adapter for this Command, - then an Incoming Mailbox entry will be made with a completion code of - BusLogic_HostAdapterAssertedBusDeviceReset. Otherwise, the CCB's Command - field will be left pointing to the Command so that the interrupt for the - completion of the Bus Device Reset can call the Completion Routine for the - Command. - */ - BusLogic_LockHostAdapter(HostAdapter); - for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll) - if (XCCB->Command == Command && XCCB->Status == BusLogic_CCB_Active) - { - CCB->Command = NULL; - /* - Disable Tagged Queuing if it was active for this Target Device. - */ - if (((HostAdapter->HostWideSCSI && XCCB->WideModeTagEnable) || - (!HostAdapter->HostWideSCSI && XCCB->TagEnable)) && - (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) - { - HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); - printk("scsi%d: Tagged Queuing now disabled for Target %d\n", - HostAdapter->HostNumber, TargetID); - } - break; - } - BusLogic_UnlockHostAdapter(HostAdapter); - /* - Attempt to write an Outgoing Mailbox with the Bus Device Reset CCB. - If sending a Bus Device Reset is impossible, attempt a full Host - Adapter Hard Reset and SCSI Bus Reset. - */ - if (!(BusLogic_WriteOutgoingMailbox(HostAdapter, - BusLogic_MailboxStartCommand, CCB))) - { - printk("scsi%d: cannot write Outgoing Mailbox for Bus Device Reset\n", - HostAdapter->HostNumber); - BusLogic_DeallocateCCB(CCB); - return BusLogic_ResetHostAdapter(HostAdapter, Command); - } - HostAdapter->ReadWriteOperationCount[TargetID] = 0; - HostAdapter->QueuedOperationCount[TargetID] = 0; - return SCSI_RESET_PENDING; -} - - -/* - BusLogic_ResetCommand takes appropriate action to reset Command. -*/ - -int BusLogic_ResetCommand(SCSI_Command_T *Command) -{ - BusLogic_HostAdapter_T *HostAdapter = - (BusLogic_HostAdapter_T *) Command->host->hostdata; - unsigned char TargetID = Command->target; - unsigned char ErrorRecoveryOption = - HostAdapter->ErrorRecoveryOption[TargetID]; - if (ErrorRecoveryOption == BusLogic_ErrorRecoveryDefault) - if (Command->host->suggest_bus_reset) - ErrorRecoveryOption = BusLogic_ErrorRecoveryHardReset; - else ErrorRecoveryOption = BusLogic_ErrorRecoveryBusDeviceReset; - switch (ErrorRecoveryOption) - { - case BusLogic_ErrorRecoveryHardReset: - return BusLogic_ResetHostAdapter(HostAdapter, Command); - case BusLogic_ErrorRecoveryBusDeviceReset: - if (HostAdapter->CommandSuccessfulFlag[TargetID]) - { - HostAdapter->CommandSuccessfulFlag[TargetID] = false; - return BusLogic_BusDeviceReset(HostAdapter, Command); - } - else return BusLogic_ResetHostAdapter(HostAdapter, Command); - } - printk("scsi%d: Error Recovery for Target %d Suppressed\n", - HostAdapter->HostNumber, TargetID); - return SCSI_RESET_PUNT; -} - - -/* - BusLogic_BIOSDiskParameters returns the Heads/Sectors/Cylinders BIOS Disk - Parameters for Disk. The default disk geometry is 64 heads, 32 sectors, and - the appropriate number of cylinders so as not to exceed drive capacity. In - order for disks equal to or larger than 1 GB to be addressable by the BIOS - without exceeding the BIOS limitation of 1024 cylinders, Extended Translation - may be enabled in AutoSCSI on "C" Series boards or by a dip switch setting - on older boards. With Extended Translation enabled, drives between 1 GB - inclusive and 2 GB exclusive are given a disk geometry of 128 heads and 32 - sectors, and drives between 2 GB inclusive and 8 GB exclusive are given a - disk geometry of 255 heads and 63 sectors. On "C" Series boards the firmware - can be queried for the precise translation in effect for each drive - individually, but there is really no need to do so since we know the total - capacity of the drive and whether Extended Translation is enabled, hence we - can deduce the BIOS disk geometry that must be in effect. -*/ - -int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device, - int *Parameters) -{ - BusLogic_HostAdapter_T *HostAdapter = - (BusLogic_HostAdapter_T *) Disk->device->host->hostdata; - BIOS_DiskParameters_T *DiskParameters = (BIOS_DiskParameters_T *) Parameters; - if (HostAdapter->ExtendedTranslation && - Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */) - if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - } - else - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - } - else - { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - } - DiskParameters->Cylinders = - Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors); - return 0; -} - - -/* - BusLogic_Setup handles processing of Kernel Command Line Arguments. - - For the BusLogic driver, a kernel command line entry comprises the driver - identifier "BusLogic=" optionally followed by a comma-separated sequence of - integers and then optionally followed by a comma-separated sequence of - strings. Each command line entry applies to one BusLogic Host Adapter. - Multiple command line entries may be used in systems which contain multiple - BusLogic Host Adapters. - - The first integer specified is the I/O Address at which the Host Adapter is - located. If unspecified, it defaults to 0 which means to apply this entry to - the first BusLogic Host Adapter found during the default probe sequence. If - any I/O Address parameters are provided on the command line, then the default - probe sequence is omitted. - - The second integer specified is the number of Concurrent Commands per Logical - Unit to allow for Target Devices on the Host Adapter. If unspecified, it - defaults to 0 which means to use the value of BusLogic_Concurrency for - non-ISA Host Adapters, or BusLogic_Concurrency_ISA for ISA Host Adapters. - - The third integer specified is the Bus Settle Time in seconds. This is - the amount of time to wait between a Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI commands. If unspecified, it defaults - to 0 which means to use the value of BusLogic_DefaultBusSettleTime. - - The fourth integer specified is the Local Options. If unspecified, it - defaults to 0. Note that Local Options are only applied to a specific Host - Adapter. - - The fifth integer specified is the Global Options. If unspecified, it - defaults to 0. Note that Global Options are applied across all Host - Adapters. - - The string options are used to provide control over Tagged Queuing and Error - Recovery. If both Tagged Queuing and Error Recovery strings are provided, the - Tagged Queuing specification string must come first. - - The Tagged Queuing specification begins with "TQ:" and allows for explicitly - specifying whether Tagged Queuing is permitted on Target Devices that support - it. The following specification options are available: - - TQ:Default Tagged Queuing will be permitted based on the firmware - version of the BusLogic Host Adapter and based on - whether the Concurrency value allows queuing multiple - commands. - - TQ:Enable Tagged Queuing will be enabled for all Target Devices - on this Host Adapter overriding any limitation that - would otherwise be imposed based on the Host Adapter - firmware version. - - TQ:Disable Tagged Queuing will be disabled for all Target Devices - on this Host Adapter. - - TQ:<Per-Target-Spec> Tagged Queuing will be controlled individually for each - Target Device. <Per-Target-Spec> is a sequence of "Y", - "N", and "X" characters. "Y" enabled Tagged Queuing, - "N" disables Tagged Queuing, and "X" accepts the - default based on the firmware version. The first - character refers to Target 0, the second to Target 1, - and so on; if the sequence of "Y", "N", and "X" - characters does not cover all the Target Devices, - unspecified characters are assumed to be "X". - - Note that explicitly requesting Tagged Queuing may lead to problems; this - facility is provided primarily to allow disabling Tagged Queuing on Target - Devices that do not implement it correctly. - - The Error Recovery specification begins with "ER:" and allows for explicitly - specifying the Error Recovery action to be performed when ResetCommand is - called due to a SCSI Command failing to complete successfully. The following - specification options are available: - - ER:Default Error Recovery will select between the Hard Reset and - Bus Device Reset options based on the recommendation - of the SCSI Subsystem. - - ER:HardReset Error Recovery will initiate a Host Adapter Hard Reset - which also causes a SCSI Bus Reset. - - ER:BusDeviceReset Error Recovery will send a Bus Device Reset message to - the individual Target Device causing the error. If - Error Recovery is again initiated for this Target - Device and no SCSI Command to this Target Device has - completed successfully since the Bus Device Reset - message was sent, then a Hard Reset will be attempted. - - ER:None Error Recovery will be suppressed. This option should - only be selected if a SCSI Bus Reset or Bus Device - Reset will cause the Target Device to fail completely - and unrecoverably. - - ER:<Per-Target-Spec> Error Recovery will be controlled individually for each - Target Device. <Per-Target-Spec> is a sequence of "D", - "H", "B", and "N" characters. "D" selects Default, "H" - selects Hard Reset, "B" selects Bus Device Reset, and - "N" selects None. The first character refers to Target - 0, the second to Target 1, and so on; if the sequence - of "D", "H", "B", and "N" characters does not cover all - the Target Devices, unspecified characters are assumed - to be "D". -*/ - -void BusLogic_Setup(char *Strings, int *Integers) -{ - BusLogic_CommandLineEntry_T *CommandLineEntry = - &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++]; - static int ProbeListIndex = 0; - int IntegerCount = Integers[0], TargetID, i; - CommandLineEntry->IO_Address = 0; - CommandLineEntry->Concurrency = 0; - CommandLineEntry->BusSettleTime = 0; - CommandLineEntry->LocalOptions = 0; - CommandLineEntry->TaggedQueuingPermitted = 0; - CommandLineEntry->TaggedQueuingPermittedMask = 0; - memset(CommandLineEntry->ErrorRecoveryOption, - BusLogic_ErrorRecoveryDefault, - sizeof(CommandLineEntry->ErrorRecoveryOption)); - if (IntegerCount > 5) - printk("BusLogic: Unexpected Command Line Integers ignored\n"); - if (IntegerCount >= 1) - { - unsigned short IO_Address = Integers[1]; - if (IO_Address > 0) - { - for (i = 0; ; i++) - if (BusLogic_IO_StandardAddresses[i] == 0) - { - printk("BusLogic: Invalid Command Line Entry " - "(illegal I/O Address 0x%X)\n", IO_Address); - return; - } - else if (i < ProbeListIndex && - IO_Address == BusLogic_IO_AddressProbeList[i]) - { - printk("BusLogic: Invalid Command Line Entry " - "(duplicate I/O Address 0x%X)\n", IO_Address); - return; - } - else if (IO_Address >= 0x1000 || - IO_Address == BusLogic_IO_StandardAddresses[i]) break; - BusLogic_IO_AddressProbeList[ProbeListIndex++] = IO_Address; - BusLogic_IO_AddressProbeList[ProbeListIndex] = 0; - } - CommandLineEntry->IO_Address = IO_Address; - } - if (IntegerCount >= 2) - { - unsigned short Concurrency = Integers[2]; - if (Concurrency > BusLogic_MailboxCount) - { - printk("BusLogic: Invalid Command Line Entry " - "(illegal Concurrency %d)\n", Concurrency); - return; - } - CommandLineEntry->Concurrency = Concurrency; - } - if (IntegerCount >= 3) - CommandLineEntry->BusSettleTime = Integers[3]; - if (IntegerCount >= 4) - CommandLineEntry->LocalOptions = Integers[4]; - if (IntegerCount >= 5) - BusLogic_GlobalOptions |= Integers[5]; - if (!(BusLogic_CommandLineEntryCount == 0 || ProbeListIndex == 0 || - BusLogic_CommandLineEntryCount == ProbeListIndex)) - { - printk("BusLogic: Invalid Command Line Entry " - "(all or no I/O Addresses must be specified)\n"); - return; - } - if (Strings == NULL) return; - if (strncmp(Strings, "TQ:", 3) == 0) - { - Strings += 3; - if (strncmp(Strings, "Default", 7) == 0) - Strings += 7; - else if (strncmp(Strings, "Enable", 6) == 0) - { - Strings += 6; - CommandLineEntry->TaggedQueuingPermitted = 0xFFFF; - CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF; - } - else if (strncmp(Strings, "Disable", 7) == 0) - { - Strings += 7; - CommandLineEntry->TaggedQueuingPermitted = 0x0000; - CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF; - } - else - for (TargetID = 0; TargetID < BusLogic_MaxTargetIDs; TargetID++) - switch (*Strings++) - { - case 'Y': - CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID; - CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID; - break; - case 'N': - CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID; - break; - case 'X': - break; - default: - Strings--; - TargetID = BusLogic_MaxTargetIDs; - break; - } - } - if (*Strings == ',') Strings++; - if (strncmp(Strings, "ER:", 3) == 0) - { - Strings += 3; - if (strncmp(Strings, "Default", 7) == 0) - Strings += 7; - else if (strncmp(Strings, "HardReset", 9) == 0) - { - Strings += 9; - memset(CommandLineEntry->ErrorRecoveryOption, - BusLogic_ErrorRecoveryHardReset, - sizeof(CommandLineEntry->ErrorRecoveryOption)); - } - else if (strncmp(Strings, "BusDeviceReset", 14) == 0) - { - Strings += 14; - memset(CommandLineEntry->ErrorRecoveryOption, - BusLogic_ErrorRecoveryBusDeviceReset, - sizeof(CommandLineEntry->ErrorRecoveryOption)); - } - else if (strncmp(Strings, "None", 4) == 0) - { - Strings += 4; - memset(CommandLineEntry->ErrorRecoveryOption, - BusLogic_ErrorRecoveryNone, - sizeof(CommandLineEntry->ErrorRecoveryOption)); - } - else - for (TargetID = 0; TargetID < BusLogic_MaxTargetIDs; TargetID++) - switch (*Strings++) - { - case 'D': - CommandLineEntry->ErrorRecoveryOption[TargetID] = - BusLogic_ErrorRecoveryDefault; - break; - case 'H': - CommandLineEntry->ErrorRecoveryOption[TargetID] = - BusLogic_ErrorRecoveryHardReset; - break; - case 'B': - CommandLineEntry->ErrorRecoveryOption[TargetID] = - BusLogic_ErrorRecoveryBusDeviceReset; - break; - case 'N': - CommandLineEntry->ErrorRecoveryOption[TargetID] = - BusLogic_ErrorRecoveryNone; - break; - default: - Strings--; - TargetID = BusLogic_MaxTargetIDs; - break; - } - } - if (*Strings != '\0') - printk("BusLogic: Unexpected Command Line String '%s' ignored\n", Strings); -} - - -/* - Include Module support if requested. -*/ - - -#ifdef MODULE - -SCSI_Host_Template_T driver_template = BUSLOGIC; - -#include "scsi_module.c" - -#endif |