patch-1.3.89 linux/drivers/scsi/BusLogic.c
Next file: linux/drivers/scsi/BusLogic.h
Previous file: linux/drivers/net/wic.c
Back to the patch index
Back to the overall index
- Lines: 2641
- Date:
Sun Apr 14 11:21:08 1996
- Orig file:
v1.3.88/linux/drivers/scsi/BusLogic.c
- Orig date:
Sat Mar 9 15:41:12 1996
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
@@ -14,18 +14,18 @@
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
+ The author respectfully requests that any 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.
+ Special thanks to Wayne Yen and Alex Win of BusLogic, whose advice has been
+ invaluable, to David 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"
+#define BusLogic_DriverVersion "1.3.2"
+#define BusLogic_DriverDate "13 April 1996"
#include <linux/module.h>
@@ -87,8 +87,8 @@
/*
- BusLogic_Standard_IO_Addresses is the list of standard I/O Addresses at which
- BusLogic Host Adapters may potentially be found.
+ BusLogic_StandardAddresses is the list of standard ISA I/O Addresses at
+ which BusLogic Host Adapters may potentially be found.
*/
static unsigned short
@@ -120,7 +120,7 @@
/*
BusLogic_CommandFailureReason holds a string identifying the reason why a
- call to BusLogic_Command failed. It is only valid when BusLogic_Command
+ call to BusLogic_Command failed. It is only non-NULL when BusLogic_Command
returns a failure code.
*/
@@ -167,56 +167,6 @@
/*
- 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.
*/
@@ -257,6 +207,52 @@
/*
+ BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for
+ Host Adapter.
+*/
+
+static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter)
+{
+ HostAdapter->FirstOutgoingMailbox =
+ (BusLogic_OutgoingMailbox_T *)
+ scsi_init_malloc(HostAdapter->MailboxCount
+ * (sizeof(BusLogic_OutgoingMailbox_T)
+ + sizeof(BusLogic_IncomingMailbox_T)),
+ (HostAdapter->BounceBuffersRequired
+ ? GFP_ATOMIC | GFP_DMA
+ : GFP_ATOMIC));
+ if (HostAdapter->FirstOutgoingMailbox == NULL)
+ {
+ printk("scsi%d: UNABLE TO ALLOCATE MAILBOXES - DETACHING\n",
+ HostAdapter->HostNumber);
+ return false;
+ }
+ HostAdapter->LastOutgoingMailbox =
+ HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
+ HostAdapter->FirstIncomingMailbox =
+ (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
+ HostAdapter->LastIncomingMailbox =
+ HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
+ return true;
+}
+
+
+/*
+ BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes
+ for Host Adapter.
+*/
+
+static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter)
+{
+ if (HostAdapter->FirstOutgoingMailbox == NULL) return;
+ scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox,
+ HostAdapter->MailboxCount
+ * (sizeof(BusLogic_OutgoingMailbox_T)
+ + sizeof(BusLogic_IncomingMailbox_T)));
+}
+
+
+/*
BusLogic_CreateCCBs allocates the initial Command Control Blocks (CCBs)
for Host Adapter.
*/
@@ -264,10 +260,13 @@
static boolean BusLogic_CreateCCBs(BusLogic_HostAdapter_T *HostAdapter)
{
int i;
- for (i = 0; i < BusLogic_InitialCCBs; i++)
+ for (i = 0; i < HostAdapter->InitialCCBs; i++)
{
BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
- scsi_init_malloc(sizeof(BusLogic_CCB_T), GFP_ATOMIC | GFP_DMA);
+ scsi_init_malloc(sizeof(BusLogic_CCB_T),
+ (HostAdapter->BounceBuffersRequired
+ ? GFP_ATOMIC | GFP_DMA
+ : GFP_ATOMIC));
if (CCB == NULL)
{
printk("scsi%d: UNABLE TO ALLOCATE CCB %d - DETACHING\n",
@@ -305,59 +304,68 @@
/*
BusLogic_AllocateCCB allocates a CCB from the Host Adapter's free list,
- allocating more memory from the Kernel if necessary.
+ allocating more memory from the Kernel if necessary. The Host Adapter's
+ Lock should have already been acquired by the caller.
*/
static BusLogic_CCB_T *BusLogic_AllocateCCB(BusLogic_HostAdapter_T *HostAdapter)
{
static unsigned int SerialNumber = 0;
BusLogic_CCB_T *CCB;
- BusLogic_LockHostAdapter(HostAdapter);
+ int Allocated;
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);
+ for (Allocated = 0; Allocated < HostAdapter->IncrementalCCBs; Allocated++)
+ {
+ CCB = (BusLogic_CCB_T *)
+ scsi_init_malloc(sizeof(BusLogic_CCB_T),
+ (HostAdapter->BounceBuffersRequired
+ ? GFP_ATOMIC | GFP_DMA
+ : GFP_ATOMIC));
+ if (CCB == NULL) break;
+ 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;
+ }
+ CCB = HostAdapter->Free_CCBs;
if (CCB == NULL)
{
- printk("scsi%d: Failed to allocate an additional CCB\n",
+ printk("scsi%d: Failed to allocate additional CCBs\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);
+ printk("scsi%d: Allocated %d additional CCBs\n",
+ HostAdapter->HostNumber, Allocated);
CCB->SerialNumber = ++SerialNumber;
- CCB->NextAll = HostAdapter->All_CCBs;
- HostAdapter->All_CCBs = CCB;
- BusLogic_UnlockHostAdapter(HostAdapter);
+ HostAdapter->Free_CCBs = CCB->Next;
+ CCB->Next = NULL;
return CCB;
}
/*
BusLogic_DeallocateCCB deallocates a CCB, returning it to the Host Adapter's
- free list.
+ free list. The Host Adapter's Lock should have already been acquired by the
+ caller.
*/
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);
}
@@ -374,9 +382,9 @@
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.
+ only Host Adapter command that is issued is the single byte Execute Mailbox
+ Command operation code , 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,
@@ -463,6 +471,7 @@
{
case BusLogic_InquireInstalledDevicesID0to7:
case BusLogic_InquireInstalledDevicesID8to15:
+ case BusLogic_InquireDevices:
/* Approximately 60 seconds. */
TimeoutCounter = loops_per_sec << 2;
break;
@@ -486,6 +495,8 @@
if (++ReplyBytes <= ReplyLength)
*ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
else BusLogic_ReadDataInRegister(HostAdapter);
+ if (OperationCode == BusLogic_FetchHostAdapterLocalRAM &&
+ (StatusRegister & BusLogic_HostAdapterReady)) break;
}
BusLogic_CommandFailureReason = "Timeout waiting for Command Complete";
if (TimeoutCounter < 0) return -2;
@@ -551,6 +562,121 @@
/*
+ 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 provided an I/O Address probe list, 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 BusDeviceFunction[BusLogic_IO_MaxProbeAddresses];
+ unsigned short Index = 0, VendorID, DeviceID;
+ boolean NonIncreasingScanningOrder = false;
+ unsigned char Bus, DeviceFunction;
+ unsigned int BaseAddress0;
+ while (pcibios_find_class(PCI_CLASS_STORAGE_SCSI<<8, Index++,
+ &Bus, &DeviceFunction) == 0)
+ if (pcibios_read_config_word(Bus, DeviceFunction,
+ PCI_VENDOR_ID, &VendorID) == 0 &&
+ VendorID == PCI_VENDOR_ID_BUSLOGIC &&
+ pcibios_read_config_word(Bus, DeviceFunction,
+ PCI_DEVICE_ID, &DeviceID) == 0 &&
+ (DeviceID == PCI_DEVICE_ID_BUSLOGIC_946C ||
+ DeviceID == PCI_DEVICE_ID_BUSLOGIC_946C_2) &&
+ pcibios_read_config_dword(Bus, DeviceFunction,
+ 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;
+ BusDeviceFunction[DestinationIndex] = (Bus << 8) | DeviceFunction;
+ if (DestinationIndex > 0 &&
+ BusDeviceFunction[DestinationIndex] <
+ BusDeviceFunction[DestinationIndex-1])
+ NonIncreasingScanningOrder = true;
+ DestinationIndex++;
+ }
+ /*
+ If there are multiple BusLogic PCI SCSI Host Adapters present and if
+ they are enumerated by the PCI BIOS in an order other than by strictly
+ increasing Bus Number and Device Number, then interrogate the setting
+ of the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
+ If it is ON, sort the PCI Host Adapter I/O Addresses by increasing Bus
+ Number and Device Number so that the Host Adapters are recognized in
+ the same order by the Linux kernel as by the Host Adapter's BIOS.
+ */
+ if (DestinationIndex > 1 && NonIncreasingScanningOrder)
+ {
+ BusLogic_FetchHostAdapterLocalRAMRequest_T
+ FetchHostAdapterLocalRAMRequest;
+ BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
+ BusLogic_HostAdapter_T HostAdapterPrototype;
+ BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+ HostAdapter->IO_Address = BusLogic_IO_AddressProbeList[0];
+ FetchHostAdapterLocalRAMRequest.ByteOffset =
+ BusLogic_AutoSCSI_BaseOffset + 45;
+ FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte45);
+ AutoSCSIByte45.ForceBusDeviceScanningOrder = false;
+ BusLogic_Command(HostAdapter,
+ BusLogic_FetchHostAdapterLocalRAM,
+ &FetchHostAdapterLocalRAMRequest,
+ sizeof(FetchHostAdapterLocalRAMRequest),
+ &AutoSCSIByte45, sizeof(AutoSCSIByte45));
+ if (AutoSCSIByte45.ForceBusDeviceScanningOrder)
+ {
+ /*
+ Sort the I/O Addresses such that the corrseponding PCI devices
+ are in ascending order by Bus Number and Device Number.
+ */
+ int LastInterchange = DestinationIndex-1, Bound, j;
+ while (LastInterchange > 0)
+ {
+ Bound = LastInterchange;
+ LastInterchange = 0;
+ for (j = 0; j < Bound; j++)
+ if (BusDeviceFunction[j] > BusDeviceFunction[j+1])
+ {
+ unsigned short Temp;
+ Temp = BusDeviceFunction[j];
+ BusDeviceFunction[j] = BusDeviceFunction[j+1];
+ BusDeviceFunction[j+1] = Temp;
+ Temp = BusLogic_IO_AddressProbeList[j];
+ BusLogic_IO_AddressProbeList[j] =
+ BusLogic_IO_AddressProbeList[j+1];
+ BusLogic_IO_AddressProbeList[j+1] = Temp;
+ LastInterchange = j;
+ }
+ }
+ }
+ }
+ }
+#endif
+ /*
+ Append the list of standard BusLogic ISA 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_Failure prints a standardized error message, and then returns false.
*/
@@ -749,6 +875,9 @@
BusLogic_BoardModelNumber_T BoardModelNumber;
BusLogic_FirmwareVersion3rdDigit_T FirmwareVersion3rdDigit;
BusLogic_FirmwareVersionLetter_T FirmwareVersionLetter;
+ BusLogic_GenericIOPortInformation_T GenericIOPortInformation;
+ BusLogic_FetchHostAdapterLocalRAMRequest_T FetchHostAdapterLocalRAMRequest;
+ BusLogic_AutoSCSIByte15_T AutoSCSIByte15;
BusLogic_RequestedReplyLength_T RequestedReplyLength;
unsigned char GeometryRegister, *TargetPointer, Character;
unsigned short AllTargetsMask, DisconnectPermitted;
@@ -825,6 +954,8 @@
BusLogic Host Adapters can be identified by their model number and
the major version number of their firmware as follows:
+ 5.xx BusLogic "W" Series Host Adapters:
+ BT-948/958/958D
4.xx BusLogic "C" Series Host Adapters:
BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF
3.xx BusLogic "S" Series Host Adapters:
@@ -835,6 +966,54 @@
0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter
*/
/*
+ Issue the Inquire Generic I/O Port Information command to read the
+ termination information from "W" Series Host Adapters.
+ */
+ if (BoardID.FirmwareVersion1stDigit == '5')
+ {
+ if (BusLogic_Command(HostAdapter,
+ BusLogic_InquireGenericIOPortInformation,
+ NULL, 0, &GenericIOPortInformation,
+ sizeof(GenericIOPortInformation))
+ != sizeof(GenericIOPortInformation))
+ return BusLogic_Failure(HostAdapter,
+ "INQUIRE GENERIC I/O PORT INFORMATION");
+ /*
+ Save the Termination Information in the Host Adapter structure.
+ */
+ if (GenericIOPortInformation.Valid)
+ {
+ HostAdapter->TerminationInfoValid = true;
+ HostAdapter->LowByteTerminated =
+ GenericIOPortInformation.LowByteTerminated;
+ HostAdapter->HighByteTerminated =
+ GenericIOPortInformation.HighByteTerminated;
+ }
+ }
+ /*
+ Issue the Fetch Host Adapter Local RAM command to read the termination
+ information from the AutoSCSI area of "C" Series Host Adapters.
+ */
+ if (BoardID.FirmwareVersion1stDigit == '4')
+ {
+ FetchHostAdapterLocalRAMRequest.ByteOffset =
+ BusLogic_AutoSCSI_BaseOffset + 15;
+ FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte15);
+ if (BusLogic_Command(HostAdapter,
+ BusLogic_FetchHostAdapterLocalRAM,
+ &FetchHostAdapterLocalRAMRequest,
+ sizeof(FetchHostAdapterLocalRAMRequest),
+ &AutoSCSIByte15, sizeof(AutoSCSIByte15))
+ != sizeof(AutoSCSIByte15))
+ return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM");
+ /*
+ Save the Termination Information in the Host Adapter structure.
+ */
+ HostAdapter->TerminationInfoValid = true;
+ HostAdapter->LowByteTerminated = AutoSCSIByte15.LowByteTerminated;
+ HostAdapter->HighByteTerminated = AutoSCSIByte15.HighByteTerminated;
+ }
+ /*
Save the Model Name and Board Name in the Host Adapter structure.
*/
TargetPointer = HostAdapter->ModelName;
@@ -902,31 +1081,28 @@
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;
- }
+ 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.
@@ -936,8 +1112,8 @@
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
+ structure. The Disconnect Permitted information is only valid on "W" and
+ "C" Series boards, but Disconnect/Reconnect is always permitted on "S" and
"A" Series boards.
*/
if (HostAdapter->FirmwareVersion[0] >= '4')
@@ -946,8 +1122,9 @@
| 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.
+ Save the Scatter Gather Limits, Level Sensitive Interrupts flag, Wide
+ SCSI flag, Differential SCSI flag, Automatic Configuration flag, and
+ Ultra SCSI flag in the Host Adapter structure.
*/
HostAdapter->HostAdapterScatterGatherLimit =
ExtendedSetupInformation.ScatterGatherLimit;
@@ -957,20 +1134,12 @@
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->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI;
HostAdapter->HostDifferentialSCSI =
ExtendedSetupInformation.HostDifferentialSCSI;
+ HostAdapter->HostAutomaticConfiguration =
+ ExtendedSetupInformation.HostAutomaticConfiguration;
+ HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI;
/*
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
@@ -978,29 +1147,98 @@
*/
HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12;
/*
- BusLogic BT-445S Host Adapters prior to board revision D have a hardware
+ ISA Host Adapters require Bounce Buffers if there is more than 16MB memory.
+ */
+ if (HostAdapter->BusType == BusLogic_ISA_Bus && high_memory > MAX_DMA_ADDRESS)
+ HostAdapter->BounceBuffersRequired = true;
+ /*
+ BusLogic BT-445S Host Adapters prior to board revision E 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.
+ ISA Bounce Buffers be used for the buggy BT-445S models if there is more
+ than 16MB memory.
*/
- if (HostAdapter->BusType == BusLogic_ISA_Bus ||
- (HostAdapter->BIOS_Address > 0 &&
- strcmp(HostAdapter->ModelName, "BT-445S") == 0 &&
- strcmp(HostAdapter->FirmwareVersion, "3.37") < 0))
+ if (HostAdapter->BIOS_Address > 0 &&
+ strcmp(HostAdapter->ModelName, "BT-445S") == 0 &&
+ strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 &&
+ high_memory > MAX_DMA_ADDRESS)
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.
+ Determine the maximum number of Target IDs and Logical Units supported by
+ this driver for Wide and Narrow Host Adapters.
+ */
+ if (HostAdapter->HostWideSCSI)
+ {
+ HostAdapter->MaxTargetDevices = 16;
+ HostAdapter->MaxLogicalUnits = 64;
+ }
+ else
+ {
+ HostAdapter->MaxTargetDevices = 8;
+ HostAdapter->MaxLogicalUnits = 8;
+ }
+ /*
+ Select appropriate values for the Mailbox Count, Initial CCBs, and
+ Incremental CCBs variables based on whether or not Strict Round Robin Mode
+ is supported. If Strict Round Robin Mode is supported, then there is no
+ performance degradation in using the maximum possible number of Outgoing
+ and Incoming Mailboxes and allowing the Tagged and Untagged Queue Depths to
+ determine the actual utilization. If Strict Round Robin Mode is not
+ supported, then the Host Adapter must scan all the Outgoing Mailboxes
+ whenever an Outgoing Mailbox entry is made, which can cause a substantial
+ performance penalty. The Host Adapters actually have room to store the
+ following number of CCBs internally; that is, they can internally queue and
+ manage this many active commands on the SCSI bus simultaneously.
+ Performance measurements demonstrate that the Mailbox Count should be set
+ to the maximum possible, rather than the internal CCB capacity, as it is
+ more efficient to have the queued commands waiting in Outgoing Mailboxes if
+ necessary than to block the process in the higher levels of the SCSI
+ Subsystem.
+
+ 192 BT-948/958/958D
+ 100 BT-946C/956C/956CD/747C/757C/757CD/445C
+ 50 BT-545C/540CF
+ 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A
+ */
+ if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
+ {
+ HostAdapter->StrictRoundRobinModeSupported = true;
+ HostAdapter->MailboxCount = 255;
+ HostAdapter->InitialCCBs = 64;
+ HostAdapter->IncrementalCCBs = 32;
+ }
+ else
+ {
+ HostAdapter->StrictRoundRobinModeSupported = false;
+ HostAdapter->MailboxCount = 32;
+ HostAdapter->InitialCCBs = 32;
+ HostAdapter->IncrementalCCBs = 4;
+ }
+ if (HostAdapter->FirmwareVersion[0] == '5')
+ HostAdapter->TotalQueueDepth = 192;
+ else if (HostAdapter->FirmwareVersion[0] == '4')
+ HostAdapter->TotalQueueDepth =
+ (HostAdapter->BusType != BusLogic_ISA_Bus ? 100 : 50);
+ else HostAdapter->TotalQueueDepth = 30;
+ /*
+ Select an appropriate value for the Tagged Queue Depth either from a
+ Command Line Entry, or based on whether this Host Adapter requires that
+ ISA Bounce Buffers be used. The Tagged Queue Depth is left at 0 for
+ automatic determination in BusLogic_SelectQueueDepths. Initialize the
+ Untagged Queue Depth.
*/
if (HostAdapter->CommandLineEntry != NULL &&
- HostAdapter->CommandLineEntry->Concurrency > 0)
- HostAdapter->Concurrency = HostAdapter->CommandLineEntry->Concurrency;
+ HostAdapter->CommandLineEntry->TaggedQueueDepth > 0)
+ HostAdapter->TaggedQueueDepth =
+ HostAdapter->CommandLineEntry->TaggedQueueDepth;
else if (HostAdapter->BounceBuffersRequired)
- HostAdapter->Concurrency = BusLogic_Concurrency_BB;
- else HostAdapter->Concurrency = BusLogic_Concurrency;
+ HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepth_BB;
+ else HostAdapter->TaggedQueueDepth = 0;
+ HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
+ if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth &&
+ HostAdapter->TaggedQueueDepth > 0)
+ HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth;
/*
Select an appropriate value for Bus Settle Time either from a Command
Line Entry, or from BusLogic_DefaultBusSettleTime.
@@ -1015,25 +1253,25 @@
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.
+ Select appropriate values for the Error Recovery Strategy array either from
+ a Command Line Entry, or using BusLogic_ErrorRecovery_Default.
*/
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.
+ memcpy(HostAdapter->ErrorRecoveryStrategy,
+ HostAdapter->CommandLineEntry->ErrorRecoveryStrategy,
+ sizeof(HostAdapter->ErrorRecoveryStrategy));
+ else memset(HostAdapter->ErrorRecoveryStrategy,
+ BusLogic_ErrorRecovery_Default,
+ sizeof(HostAdapter->ErrorRecoveryStrategy));
+ /*
+ Tagged Queuing support is available and operates properly on all "W" Series
+ boards, 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 Tagged Queue Depth is 1 since queuing multiple
+ commands is not possible.
*/
TaggedQueuingPermittedDefault = 0;
- if (HostAdapter->Concurrency > 1)
+ if (HostAdapter->TaggedQueueDepth != 1)
switch (HostAdapter->FirmwareVersion[0])
{
case '5':
@@ -1055,8 +1293,8 @@
*/
TaggedQueuingPermittedDefault &= HostAdapter->DisconnectPermitted;
/*
- Combine the default Tagged Queuing Permitted Default bits with any
- Command Line Entry Tagged Queuing specification.
+ Combine the default Tagged Queuing Permitted bits with any Command
+ Line Entry Tagged Queuing specification.
*/
if (HostAdapter->CommandLineEntry != NULL)
HostAdapter->TaggedQueuingPermitted =
@@ -1068,11 +1306,12 @@
/*
Announce the Host Adapter Configuration.
*/
- printk("scsi%d: Configuring BusLogic Model %s %s%s%s SCSI Host Adapter\n",
+ printk("scsi%d: Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n",
HostAdapter->HostNumber, HostAdapter->ModelName,
BusLogic_BusNames[HostAdapter->BusType],
(HostAdapter->HostWideSCSI ? " Wide" : ""),
- (HostAdapter->HostDifferentialSCSI ? " Differential" : ""));
+ (HostAdapter->HostDifferentialSCSI ? " Differential" : ""),
+ (HostAdapter->HostUltraSCSI ? " Ultra" : ""));
printk("scsi%d: Firmware Version: %s, I/O Address: 0x%X, "
"IRQ Channel: %d/%s\n",
HostAdapter->HostNumber, HostAdapter->FirmwareVersion,
@@ -1086,15 +1325,16 @@
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,
+ printk("scsi%d: Scatter/Gather Limit: %d of %d segments, "
+ "Parity Checking: %s\n", HostAdapter->HostNumber,
+ HostAdapter->DriverScatterGatherLimit,
HostAdapter->HostAdapterScatterGatherLimit,
- (HostAdapter->SynchronousInitiation ? "Enabled" : "Disabled"));
- printk("scsi%d: SCSI Parity Checking: %s, "
+ (HostAdapter->ParityChecking ? "Enabled" : "Disabled"));
+ printk("scsi%d: Synchronous Initiation: %s, "
"Extended Disk Translation: %s\n", HostAdapter->HostNumber,
- (HostAdapter->ParityChecking ? "Enabled" : "Disabled"),
+ (HostAdapter->SynchronousInitiation ? "Enabled" : "Disabled"),
(HostAdapter->ExtendedTranslation ? "Enabled" : "Disabled"));
- AllTargetsMask = (1 << HostAdapter->MaxTargetIDs) - 1;
+ AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1;
DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask;
printk("scsi%d: Disconnect/Reconnect: ", HostAdapter->HostNumber);
if (DisconnectPermitted == 0)
@@ -1102,7 +1342,7 @@
else if (DisconnectPermitted == AllTargetsMask)
printk("Enabled");
else
- for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
printk("%c", (DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N');
printk(", Tagged Queuing: ");
TaggedQueuingPermitted =
@@ -1112,30 +1352,43 @@
else if (TaggedQueuingPermitted == AllTargetsMask)
printk("Enabled");
else
- for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
printk("%c", (TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N');
printk("\n");
+ printk("scsi%d: Total Queue Depth: %d, Mailboxes: %d, Initial CCBs: %d\n",
+ HostAdapter->HostNumber, HostAdapter->TotalQueueDepth,
+ HostAdapter->MailboxCount, HostAdapter->InitialCCBs);
+ printk("scsi%d: Tagged Queue Depth: ", HostAdapter->HostNumber);
+ if (HostAdapter->TaggedQueueDepth > 0)
+ printk("%d", HostAdapter->TaggedQueueDepth);
+ else printk("Automatic");
+ printk(", Untagged Queue Depth: %d\n", HostAdapter->UntaggedQueueDepth);
+ if (HostAdapter->TerminationInfoValid)
+ if (HostAdapter->HostWideSCSI)
+ printk("scsi%d: Host Adapter SCSI Bus Termination (Low/High): %s/%s\n",
+ HostAdapter->HostNumber,
+ (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled"),
+ (HostAdapter->HighByteTerminated ? "Enabled" : "Disabled"));
+ else printk("scsi%d: Host Adapter SCSI Bus Termination: %s\n",
+ HostAdapter->HostNumber,
+ (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled"));
CommonErrorRecovery = true;
- for (TargetID = 1; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
- if (HostAdapter->ErrorRecoveryOption[TargetID] !=
- HostAdapter->ErrorRecoveryOption[0])
+ for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ if (HostAdapter->ErrorRecoveryStrategy[TargetID] !=
+ HostAdapter->ErrorRecoveryStrategy[0])
{
CommonErrorRecovery = false;
break;
}
- printk("scsi%d: Error Recovery: ", HostAdapter->HostNumber);
+ printk("scsi%d: Error Recovery Strategy: ", HostAdapter->HostNumber);
if (CommonErrorRecovery)
- printk("%s", BusLogic_ErrorRecoveryOptions[
- HostAdapter->ErrorRecoveryOption[0]]);
+ printk("%s", BusLogic_ErrorRecoveryStrategyNames[
+ HostAdapter->ErrorRecoveryStrategy[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);
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ printk("%s", BusLogic_ErrorRecoveryStrategyLetters[
+ HostAdapter->ErrorRecoveryStrategy[TargetID]]);
+ printk("\n");
/*
Indicate reading the Host Adapter Configuration completed successfully.
*/
@@ -1144,25 +1397,27 @@
/*
- 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.
+ BusLogic_AcquireResources acquires the system resources necessary to use
+ Host Adapter.
*/
-static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter,
- SCSI_Host_T *Host)
+static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
{
+ if (HostAdapter->IRQ_Channel == 0)
+ {
+ printk("scsi%d: NO INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
+ HostAdapter->HostNumber);
+ return false;
+ }
/*
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.
+ 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, NULL) < 0)
+ SA_INTERRUPT | SA_SHIRQ,
+ HostAdapter->InterruptLabel, NULL) < 0)
{
BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]--;
printk("scsi%d: UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
@@ -1207,17 +1462,6 @@
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;
@@ -1306,51 +1550,51 @@
BusLogic_RoundRobinModeRequest_T RoundRobinModeRequest;
BusLogic_WideModeCCBRequest_T WideModeCCBRequest;
BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
+ int TargetID;
/*
- Initialize the Command Successful Flag, Read/Write Operation Count,
- and Queued Operation Count for each Target.
- */
+ Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
+ Command Successful Flag, Active Command Count, and Total Command Count
+ for each Target Device.
+ */
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+ memset(HostAdapter->TaggedQueuingActive, false,
+ sizeof(HostAdapter->TaggedQueuingActive));
memset(HostAdapter->CommandSuccessfulFlag, false,
sizeof(HostAdapter->CommandSuccessfulFlag));
- memset(HostAdapter->ReadWriteOperationCount, 0,
- sizeof(HostAdapter->ReadWriteOperationCount));
- memset(HostAdapter->QueuedOperationCount, 0,
- sizeof(HostAdapter->QueuedOperationCount));
+ memset(HostAdapter->ActiveCommandCount, 0,
+ sizeof(HostAdapter->ActiveCommandCount));
+ memset(HostAdapter->TotalCommandCount, 0,
+ sizeof(HostAdapter->TotalCommandCount));
/*
Initialize the Outgoing and Incoming Mailbox structures.
*/
- memset(HostAdapter->OutgoingMailboxes, 0,
- sizeof(HostAdapter->OutgoingMailboxes));
- memset(HostAdapter->IncomingMailboxes, 0,
- sizeof(HostAdapter->IncomingMailboxes));
+ memset(HostAdapter->FirstOutgoingMailbox, 0,
+ HostAdapter->MailboxCount * sizeof(BusLogic_OutgoingMailbox_T));
+ memset(HostAdapter->FirstIncomingMailbox, 0,
+ HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T));
/*
- Initialize the pointers to the First, Last, and Next Mailboxes.
+ Initialize the pointers to the 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;
+ ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
+ ExtendedMailboxRequest.BaseMailboxAddress = HostAdapter->FirstOutgoingMailbox;
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.
+ 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. Strict
+ Round Robin Mode is significantly more efficient.
*/
- if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
+ if (HostAdapter->StrictRoundRobinModeSupported)
{
RoundRobinModeRequest = BusLogic_StrictRoundRobinMode;
if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode,
@@ -1360,7 +1604,7 @@
}
/*
For Wide SCSI Host Adapters, issue the Enable Wide Mode CCB command to
- allow more than 8 Logical Units per Target to be supported.
+ allow more than 8 Logical Units per Target Device to be supported.
*/
if (HostAdapter->HostWideSCSI)
{
@@ -1410,16 +1654,16 @@
static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T
*HostAdapter)
{
+ BusLogic_InstalledDevices_T InstalledDevices;
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.
+ 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);
/*
@@ -1432,24 +1676,34 @@
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 Devices command for "W" and "C" Series boards or the
+ Inquire Installed Devices ID 0 to 7 command for "S" and "A" Series boards.
+ This is necessary to force Synchronous Transfer Negotiation so that the
+ Inquire Setup Information and Inquire Synchronous Period commands will
+ return valid data. The Inquire Devices command is preferable to Inquire
+ Installed Devices ID 0 to 7 since it only probes Logical Unit 0 of each
+ Target Device.
+ */
+ if (HostAdapter->FirmwareVersion[0] >= '4')
+ {
+ if (BusLogic_Command(HostAdapter, BusLogic_InquireDevices, NULL, 0,
+ &InstalledDevices, sizeof(InstalledDevices))
+ != sizeof(InstalledDevices))
+ return BusLogic_Failure(HostAdapter, "INQUIRE DEVICES");
+ }
+ else
+ {
+ if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7,
+ NULL, 0, &InstalledDevicesID0to7,
+ sizeof(InstalledDevicesID0to7))
+ != sizeof(InstalledDevicesID0to7))
+ return BusLogic_Failure(HostAdapter,
+ "INQUIRE INSTALLED DEVICES ID 0 TO 7");
+ InstalledDevices = 0;
+ for (TargetID = 0; TargetID < 8; TargetID++)
+ if (InstalledDevicesID0to7[TargetID] != 0)
+ InstalledDevices |= (1 << TargetID);
+ }
/*
Issue the Inquire Setup Information command.
*/
@@ -1472,7 +1726,7 @@
return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD");
}
else
- for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0)
SynchronousPeriod[TargetID] =
20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID]
@@ -1482,23 +1736,21 @@
Save the Installed Devices, Synchronous Values, and Synchronous Period
information in the Host Adapter structure.
*/
- memcpy(HostAdapter->InstalledDevices, InstalledDevicesID0to7,
- sizeof(BusLogic_InstalledDevices8_T));
+ HostAdapter->InstalledDevices = InstalledDevices;
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->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)
+ /*
+ Report on the Target Devices found.
+ */
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ if (HostAdapter->InstalledDevices & (1 << TargetID))
{
int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID];
if (SynchronousPeriod > 10)
@@ -1539,6 +1791,75 @@
/*
+ BusLogic_InitializeHostStructure 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 acquisition and release of the Host Adapter's Lock.
+*/
+
+static void BusLogic_InitializeHostStructure(BusLogic_HostAdapter_T
+ *HostAdapter,
+ SCSI_Host_T *Host)
+{
+ Host->max_id = HostAdapter->MaxTargetDevices;
+ Host->max_lun = HostAdapter->MaxLogicalUnits;
+ Host->max_channel = 0;
+ Host->unique_id = HostAdapter->IO_Address;
+ Host->this_id = HostAdapter->SCSI_ID;
+ Host->can_queue = HostAdapter->MailboxCount;
+ Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit;
+ Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired;
+ Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth;
+}
+
+
+/*
+ BusLogic_SelectQueueDepths selects Queue Depths for each Target Device
+ based on the Host Adapter's Total Queue Depth and the number, type, speed,
+ and capabilities of the Target Devices.
+*/
+
+static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
+ SCSI_Device_T *DeviceList)
+{
+ BusLogic_HostAdapter_T *HostAdapter =
+ (BusLogic_HostAdapter_T *) Host->hostdata;
+ int TaggedQueueDepth = HostAdapter->TaggedQueueDepth;
+ int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth;
+ int TaggedDeviceCount = 0, UntaggedDeviceCount = 0;
+ SCSI_Device_T *Device;
+ for (Device = DeviceList; Device != NULL; Device = Device->next)
+ if (Device->host == Host)
+ {
+ if (Device->tagged_supported &&
+ (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
+ TaggedDeviceCount++;
+ else UntaggedDeviceCount++;
+ }
+ if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0)
+ TaggedQueueDepth =
+ 1 + ((HostAdapter->TotalQueueDepth
+ - UntaggedDeviceCount * UntaggedQueueDepth)
+ / TaggedDeviceCount);
+ if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
+ TaggedQueueDepth = BusLogic_MaxTaggedQueueDepth;
+ for (Device = DeviceList; Device != NULL; Device = Device->next)
+ if (Device->host == Host)
+ {
+ if (Device->tagged_supported &&
+ (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
+ Device->queue_depth = TaggedQueueDepth;
+ else Device->queue_depth = UntaggedQueueDepth;
+ if (BusLogic_GlobalOptions & BusLogic_TraceQueueDepths)
+ printk("scsi%d: Setting Queue Depth for Target %d to %d\n",
+ HostAdapter->HostNumber, Device->id, Device->queue_depth);
+ }
+}
+
+
+/*
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
@@ -1619,6 +1940,7 @@
sizeof(BusLogic_HostAdapter_T));
HostAdapter->SCSI_Host = Host;
HostAdapter->HostNumber = Host->host_no;
+ Host->select_queue_depths = BusLogic_SelectQueueDepths;
/*
Add Host Adapter to the end of the list of registered BusLogic
Host Adapters. In order for Command Complete Interrupts to be
@@ -1632,12 +1954,14 @@
/*
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.
+ Host structure, then Test Interrupts, Create the Mailboxes and CCBs,
+ Initialize the Host Adapter, and finally Inquire about the Target
+ Devices.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
- BusLogic_AcquireResources(HostAdapter, Host) &&
+ BusLogic_AcquireResources(HostAdapter) &&
BusLogic_TestInterrupts(HostAdapter) &&
+ BusLogic_CreateMailboxes(HostAdapter) &&
BusLogic_CreateCCBs(HostAdapter) &&
BusLogic_InitializeHostAdapter(HostAdapter) &&
BusLogic_InquireTargetDevices(HostAdapter))
@@ -1645,24 +1969,27 @@
/*
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.
+ Name of the Host Adapter will appear, and initialize the SCSI
+ Host structure.
*/
release_region(HostAdapter->IO_Address, BusLogic_IO_PortCount);
request_region(HostAdapter->IO_Address, BusLogic_IO_PortCount,
HostAdapter->BoardName);
+ BusLogic_InitializeHostStructure(HostAdapter, Host);
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
+ 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 and Mailboxes, Release the System Resources, and Unregister
the SCSI Host.
*/
BusLogic_DestroyCCBs(HostAdapter);
+ BusLogic_DestroyMailboxes(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
BusLogic_UnregisterHostAdapter(HostAdapter);
scsi_unregister(Host);
@@ -1683,10 +2010,11 @@
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Host->hostdata;
/*
- Destroy the CCBs and release any system resources acquired to use
- Host Adapter.
+ Destroy the CCBs and Mailboxes, and release any system resources acquired
+ to support Host Adapter.
*/
BusLogic_DestroyCCBs(HostAdapter);
+ BusLogic_DestroyMailboxes(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
/*
Release usage of the I/O Address range.
@@ -1770,11 +2098,12 @@
{
BusLogic_CCB_T *FirstCompletedCCB = NULL, *LastCompletedCCB = NULL;
BusLogic_HostAdapter_T *HostAdapter;
- int HostAdapterResetPendingCount = 0;
+ int HostAdapterResetRequestedCount = 0;
+ BusLogic_Lock_T Lock;
/*
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
+ interrupt handler is installed as a fast interrupt, so interrupts are
disabled when the interrupt handler is entered.
*/
for (HostAdapter = BusLogic_RegisteredHostAdapters;
@@ -1785,7 +2114,7 @@
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_LockHostAdapterID(HostAdapter);
+ BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
/*
Read the Host Adapter Interrupt Register.
*/
@@ -1799,14 +2128,14 @@
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
+ 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++;
+ HostAdapter->HostAdapterResetRequested = true;
+ HostAdapterResetRequestedCount++;
}
else if (InterruptRegister & BusLogic_IncomingMailboxLoaded)
{
@@ -1833,7 +2162,8 @@
{
BusLogic_CCB_T *CCB = NextIncomingMailbox->CCB;
if (MailboxCompletionCode != BusLogic_AbortedCommandNotFound)
- if (CCB->Status == BusLogic_CCB_Active)
+ if (CCB->Status == BusLogic_CCB_Active ||
+ CCB->Status == BusLogic_CCB_Reset)
{
/*
Mark this CCB as completed and add it to the end
@@ -1852,14 +2182,14 @@
LastCompletedCCB->Next = CCB;
LastCompletedCCB = CCB;
}
- HostAdapter->QueuedOperationCount[CCB->TargetID]--;
+ HostAdapter->ActiveCommandCount[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.
+ is not marked as status Active or Reset, 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,
@@ -1881,26 +2211,9 @@
/*
Release exclusive access to Host Adapter.
*/
- BusLogic_UnlockHostAdapterID(HostAdapter);
+ BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
}
/*
- 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.
*/
@@ -1911,77 +2224,133 @@
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.
+ Acquire exclusive access to Host Adapter.
+ */
+ BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
+ /*
+ Process the Completed CCB.
*/
- if (CCB->Opcode == BusLogic_SCSIBusDeviceReset)
+ if (CCB->Opcode == BusLogic_BusDeviceReset)
{
+ unsigned char TargetID = CCB->TargetID;
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;
+ HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
+ HostAdapter->TotalCommandCount[TargetID] = 0;
+ HostAdapter->TaggedQueuingActive[TargetID] = false;
+ /*
+ Place CCB back on the Host Adapter's free list.
+ */
+ BusLogic_DeallocateCCB(CCB);
+ /*
+ Bus Device Reset CCBs have the Command field non-NULL only when a
+ Bus Device Reset was requested for a Command that did not have a
+ currently active CCB in the Host Adapter (i.e., a Synchronous
+ Bus Device Reset), and hence would not have its Completion Routine
+ called otherwise.
+ */
+ while (Command != NULL)
+ {
+ SCSI_Command_T *NextCommand = Command->reset_chain;
+ Command->reset_chain = NULL;
+ Command->result = DID_RESET << 16;
+ Command->scsi_done(Command);
+ Command = NextCommand;
+ }
+ /*
+ Iterate over the CCBs for this Host Adapter performing completion
+ processing for any CCBs marked as Reset for this Target.
+ */
+ for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+ if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID)
+ {
+ Command = CCB->Command;
+ BusLogic_DeallocateCCB(CCB);
+ HostAdapter->ActiveCommandCount[TargetID]--;
+ Command->result = DID_RESET << 16;
+ Command->scsi_done(Command);
+ }
+ HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
}
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);
+ {
+ /*
+ 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.
+ */
+ Command->scsi_done(Command);
+ }
/*
- Call the SCSI Command Completion Routine if appropriate.
+ Release exclusive access to Host Adapter.
*/
- if (Command != NULL) Command->scsi_done(Command);
+ BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
}
+ /*
+ Iterate over the Host Adapters performing any requested Host Adapter Resets.
+ */
+ if (HostAdapterResetRequestedCount == 0) return;
+ for (HostAdapter = BusLogic_RegisteredHostAdapters;
+ HostAdapter != NULL;
+ HostAdapter = HostAdapter->Next)
+ if (HostAdapter->HostAdapterResetRequested)
+ {
+ BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
+ HostAdapter->HostAdapterResetRequested = false;
+ scsi_mark_host_bus_reset(HostAdapter->SCSI_Host);
+ }
}
/*
BusLogic_WriteOutgoingMailbox places CCB and Action Code into an Outgoing
- Mailbox for execution by Host Adapter.
+ Mailbox for execution by Host Adapter. The Host Adapter's Lock should have
+ already been acquired by the caller.
*/
static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T
@@ -1990,8 +2359,6 @@
BusLogic_CCB_T *CCB)
{
BusLogic_OutgoingMailbox_T *NextOutgoingMailbox;
- boolean Result = false;
- BusLogic_LockHostAdapter(HostAdapter);
NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox;
if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree)
{
@@ -2003,16 +2370,15 @@
*/
NextOutgoingMailbox->CCB = CCB;
NextOutgoingMailbox->ActionCode = ActionCode;
- BusLogic_StartMailboxScan(HostAdapter);
+ BusLogic_StartMailboxCommand(HostAdapter);
if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox)
NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox;
if (ActionCode == BusLogic_MailboxStartCommand)
- HostAdapter->QueuedOperationCount[CCB->TargetID]++;
- Result = true;
+ HostAdapter->ActiveCommandCount[CCB->TargetID]++;
+ return true;
}
- BusLogic_UnlockHostAdapter(HostAdapter);
- return Result;
+ return false;
}
@@ -2033,8 +2399,8 @@
void *BufferPointer = Command->request_buffer;
int BufferLength = Command->request_bufflen;
int SegmentCount = Command->use_sg;
+ BusLogic_Lock_T Lock;
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
@@ -2047,16 +2413,26 @@
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.
+ Acquire exclusive access to Host Adapter.
+ */
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ /*
+ Allocate a CCB from the Host Adapter's free list. In the unlikely event
+ that there are none available and memory allocation fails, wait 1 second
+ and try again. If that fails, the Host Adapter is probably hung so we
+ signal an error as a Host Adapter Hard Reset should be initiated soon.
*/
CCB = BusLogic_AllocateCCB(HostAdapter);
if (CCB == NULL)
{
- Command->result = DID_BUS_BUSY << 16;
- CompletionRoutine(Command);
- return 0;
+ BusLogic_Delay(1);
+ CCB = BusLogic_AllocateCCB(HostAdapter);
+ if (CCB == NULL)
+ {
+ Command->result = DID_ERROR << 16;
+ CompletionRoutine(Command);
+ goto Done;
+ }
}
/*
Initialize the fields in the BusLogic Command Control Block (CCB).
@@ -2087,12 +2463,10 @@
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;
@@ -2117,22 +2491,27 @@
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)
+ are sent to a Target Device be sent in a non Tagged Queue fashion so that
+ the Host Adapter and Target Device can establish Synchronous and Wide
+ Transfer before Queue Tag messages can interfere with the Synchronous and
+ Wide Negotiation message. By waiting to enable Tagged Queuing until after
+ the first BusLogic_MaxTaggedQueueDepth commands have been sent, it is
+ assured that after a Reset any pending commands are resent before Tagged
+ Queuing is enabled and that the Tagged Queuing message will not occur while
+ the partition table is being printed.
+ */
+ if (HostAdapter->TotalCommandCount[TargetID]++ ==
+ BusLogic_MaxTaggedQueueDepth &&
+ (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) &&
+ Command->device->tagged_supported)
+ {
+ HostAdapter->TaggedQueuingActive[TargetID] = true;
+ printk("scsi%d: Tagged Queuing now active for Target %d\n",
+ HostAdapter->HostNumber, TargetID);
+ }
+ if (HostAdapter->TaggedQueuingActive[TargetID])
{
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
@@ -2140,16 +2519,17 @@
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)
+ more than 5 seconds (half the 10 second disk timeout) 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->ActiveCommandCount[TargetID] == 0)
+ HostAdapter->LastSequencePoint[TargetID] = jiffies;
+ else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 5*HZ)
{
- HostAdapter->LastSequencePoint[TargetID] = CurrentTime;
+ HostAdapter->LastSequencePoint[TargetID] = jiffies;
QueueTag = BusLogic_OrderedQueueTag;
}
if (HostAdapter->HostWideSCSI)
@@ -2168,19 +2548,34 @@
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.
+ Place the CCB in an Outgoing Mailbox. The higher levels of the SCSI
+ Subsystem should not attempt to queue more commands than can be placed in
+ Outgoing Mailboxes, so there should always be one free. In the unlikely
+ event that there are none available, wait 1 second and try again. If
+ that fails, the Host Adapter is probably hung so we signal an error as
+ a Host Adapter Hard Reset should be initiated soon.
*/
- if (!(BusLogic_WriteOutgoingMailbox(HostAdapter,
- BusLogic_MailboxStartCommand, CCB)))
+ if (!BusLogic_WriteOutgoingMailbox(HostAdapter,
+ BusLogic_MailboxStartCommand, CCB))
{
- printk("scsi%d: cannot write Outgoing Mailbox\n",
+ printk("scsi%d: cannot write Outgoing Mailbox - Pausing for 1 second\n",
HostAdapter->HostNumber);
- BusLogic_DeallocateCCB(CCB);
- Command->result = DID_BUS_BUSY << 16;
- CompletionRoutine(Command);
+ BusLogic_Delay(1);
+ if (!BusLogic_WriteOutgoingMailbox(HostAdapter,
+ BusLogic_MailboxStartCommand, CCB))
+ {
+ printk("scsi%d: still cannot write Outgoing Mailbox - "
+ "Host Adapter Dead?\n", HostAdapter->HostNumber);
+ BusLogic_DeallocateCCB(CCB);
+ Command->result = DID_ERROR << 16;
+ Command->scsi_done(Command);
+ }
}
+ /*
+ Release exclusive access to Host Adapter.
+ */
+Done:
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
return 0;
}
@@ -2193,92 +2588,148 @@
{
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Command->host->hostdata;
- unsigned long CommandPID = Command->pid;
- unsigned char InterruptRegister;
+ unsigned char TargetID = Command->target;
+ BusLogic_Lock_T Lock;
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, NULL);
- restore_flags(ProcessorFlags);
- return SCSI_ABORT_SNOOZE;
+ Acquire exclusive access to Host Adapter.
+ */
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ /*
+ If this Command has already completed, then no Abort is necessary.
+ */
+ if (Command->serial_number != Command->serial_number_at_timeout)
+ {
+ printk("scsi%d: Unable to Abort Command to Target %d - "
+ "Already Completed\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_ABORT_NOT_RUNNING;
+ goto Done;
}
/*
- Find the CCB to be aborted if possible.
+ Attempt to find an Active CCB for this Command. If no Active CCB for this
+ Command is found, then no Abort is necessary.
*/
- 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;
+ HostAdapter->HostNumber, TargetID);
+ Result = SCSI_ABORT_NOT_RUNNING;
+ goto Done;
+ }
+ else if (CCB->Status == BusLogic_CCB_Completed)
+ {
+ printk("scsi%d: Unable to Abort Command to Target %d - CCB Completed\n",
+ HostAdapter->HostNumber, TargetID);
+ Result = SCSI_ABORT_NOT_RUNNING;
+ goto Done;
+ }
+ else if (CCB->Status == BusLogic_CCB_Reset)
+ {
+ printk("scsi%d: Unable to Abort Command to Target %d - CCB Reset\n",
+ HostAdapter->HostNumber, TargetID);
+ Result = SCSI_ABORT_NOT_RUNNING;
+ goto Done;
+ }
+ /*
+ Attempt to Abort this CCB. Firmware versions prior to 5.xx do not generate
+ Abort Tag messages, but only generate the non-tagged Abort message. Since
+ non-tagged commands are not sent by the Host Adapter until the queue of
+ outstanding tagged commands has completed, and the Abort message is treated
+ as a non-tagged command, it is effectively impossible to abort commands
+ when Tagged Queuing is active. Firmware version 5.xx does generate Abort
+ Tag messages, so it is possible to abort commands when Tagged Queuing is
+ active.
+ */
+ if (HostAdapter->TaggedQueuingActive[TargetID] &&
+ HostAdapter->FirmwareVersion[0] < '5')
+ {
+ printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
+ "Abort Tag Not Supported\n", HostAdapter->HostNumber,
+ CCB->SerialNumber, TargetID);
+ Result = SCSI_ABORT_SNOOZE;
+ }
+ else if (BusLogic_WriteOutgoingMailbox(HostAdapter,
+ BusLogic_MailboxAbortCommand, CCB))
+ {
+ printk("scsi%d: Aborting CCB #%d to Target %d\n",
+ HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
+ Result = SCSI_ABORT_PENDING;
}
- /*
- 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)
+ else
{
- /*
- 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;
- }
+ printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
+ "No Outgoing Mailboxes\n", HostAdapter->HostNumber,
+ CCB->SerialNumber, 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);
+ /*
+ Release exclusive access to Host Adapter.
+ */
+Done:
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
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.
+ currently executing SCSI Commands as having been Reset.
*/
static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
- SCSI_Command_T *Command)
+ SCSI_Command_T *Command,
+ unsigned int ResetFlags)
{
+ BusLogic_Lock_T Lock;
BusLogic_CCB_T *CCB;
+ int TargetID, Result;
+ /*
+ Acquire exclusive access to Host Adapter.
+ */
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ /*
+ If this is an Asynchronous Reset and this Command has already completed,
+ then no Reset is necessary.
+ */
+ if (ResetFlags & SCSI_RESET_ASYNCHRONOUS)
+ {
+ TargetID = Command->target;
+ if (Command->serial_number != Command->serial_number_at_timeout)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "Already Completed or Reset\n",
+ HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_NOT_RUNNING;
+ goto Done;
+ }
+ for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+ if (CCB->Command == Command) break;
+ if (CCB == NULL)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "No CCB Found\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_NOT_RUNNING;
+ goto Done;
+ }
+ else if (CCB->Status == BusLogic_CCB_Completed)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "CCB Completed\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_NOT_RUNNING;
+ goto Done;
+ }
+ else if (CCB->Status == BusLogic_CCB_Reset &&
+ HostAdapter->BusDeviceResetPendingCCB[TargetID] == NULL)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "Reset Pending\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_PENDING;
+ goto Done;
+ }
+ }
if (Command == NULL)
printk("scsi%d: Resetting %s due to SCSI Reset State Interrupt\n",
HostAdapter->HostNumber, HostAdapter->BoardName);
@@ -2287,121 +2738,166 @@
/*
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;
+ Result = SCSI_RESET_ERROR;
+ goto Done;
}
- 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.
+ 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);
+ CCB->Status = BusLogic_CCB_Reset;
+ /*
+ 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.
+ Note that a timer interrupt may occur here, but all active CCBs have
+ already been marked Reset and so a reentrant call will return Pending.
+ */
+ BusLogic_Delay(HostAdapter->BusSettleTime);
/*
- Perform completion processing for the Command being Reset.
+ If this is a Synchronous Reset, perform completion processing for
+ the Command being Reset.
*/
- if (Command != NULL)
+ if (ResetFlags & SCSI_RESET_SYNCHRONOUS)
{
Command->result = DID_RESET << 16;
Command->scsi_done(Command);
}
/*
- Perform completion processing for any other active CCBs.
+ Perform completion processing for all CCBs marked as Reset.
*/
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)
+ while (Command != NULL)
{
+ SCSI_Command_T *NextCommand = Command->reset_chain;
+ Command->reset_chain = NULL;
Command->result = DID_RESET << 16;
Command->scsi_done(Command);
+ Command = NextCommand;
}
}
- return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ HostAdapter->LastResetTime[TargetID] = jiffies;
+ Result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+ /*
+ Release exclusive access to Host Adapter.
+ */
+Done:
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ return Result;
}
/*
- BusLogic_BusDeviceReset sends a Bus Device Reset to the Target
- associated with Command.
+ BusLogic_SendBusDeviceReset sends a Bus Device Reset to the Target
+ Device associated with Command.
*/
-static int BusLogic_BusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
- SCSI_Command_T *Command)
+static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
+ SCSI_Command_T *Command,
+ unsigned int ResetFlags)
{
- BusLogic_CCB_T *CCB = BusLogic_AllocateCCB(HostAdapter), *XCCB;
unsigned char TargetID = Command->target;
+ BusLogic_Lock_T Lock;
+ BusLogic_CCB_T *CCB;
+ int Result = -1;
/*
- If sending a Bus Device Reset is impossible, attempt a full Host
- Adapter Hard Reset and SCSI Bus Reset.
+ Acquire exclusive access to Host Adapter.
*/
- if (CCB == NULL)
- return BusLogic_ResetHostAdapter(HostAdapter, Command);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ /*
+ If this is an Asynchronous Reset and this Command has already completed,
+ then no Reset is necessary.
+ */
+ if (ResetFlags & SCSI_RESET_ASYNCHRONOUS)
+ {
+ if (Command->serial_number != Command->serial_number_at_timeout)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "Already Completed\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_NOT_RUNNING;
+ goto Done;
+ }
+ for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+ if (CCB->Command == Command) break;
+ if (CCB == NULL)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "No CCB Found\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_NOT_RUNNING;
+ goto Done;
+ }
+ else if (CCB->Status == BusLogic_CCB_Completed)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "CCB Completed\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_NOT_RUNNING;
+ goto Done;
+ }
+ else if (CCB->Status == BusLogic_CCB_Reset)
+ {
+ printk("scsi%d: Unable to Reset Command to Target %d - "
+ "Reset Pending\n", HostAdapter->HostNumber, TargetID);
+ Result = SCSI_RESET_PENDING;
+ goto Done;
+ }
+ }
+ /*
+ If this is a Synchronous Reset and a Bus Device Reset is already pending
+ for this Target Device, do not send a second one. Add this Command to
+ the list of Commands for which completion processing must be performed
+ when the Bus Device Reset CCB completes.
+ */
+ if (ResetFlags & SCSI_RESET_SYNCHRONOUS)
+ if ((CCB = HostAdapter->BusDeviceResetPendingCCB[TargetID]) != NULL)
+ {
+ Command->reset_chain = CCB->Command;
+ CCB->Command = Command;
+ Result = SCSI_RESET_PENDING;
+ goto Done;
+ }
+ /*
+ Firmware versions prior to 5.xx treat a Bus Device Reset as a non-tagged
+ command. Since non-tagged commands are not sent by the Host Adapter until
+ the queue of outstanding tagged commands has completed, it is effectively
+ impossible to send a Bus Device Reset while there are tagged commands
+ outstanding. Therefore, in that case a full Host Adapter Hard Reset and
+ SCSI Bus Reset must be done.
+ */
+ if (HostAdapter->TaggedQueuingActive[TargetID] &&
+ HostAdapter->ActiveCommandCount[TargetID] > 0 &&
+ HostAdapter->FirmwareVersion[0] < '5')
+ goto Done;
+ /*
+ Allocate a CCB from the Host Adapter's free list. In the unlikely event
+ that there are none available and memory allocation fails, attempt a full
+ Host Adapter Hard Reset and SCSI Bus Reset.
+ */
+ CCB = BusLogic_AllocateCCB(HostAdapter);
+ if (CCB == NULL) goto Done;
printk("scsi%d: Sending Bus Device Reset CCB #%d to Target %d\n",
HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
- CCB->Opcode = BusLogic_SCSIBusDeviceReset;
+ CCB->Opcode = BusLogic_BusDeviceReset;
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);
+ For Synchronous Resets, arrange for the interrupt handler to perform
+ completion processing for the Command being Reset.
+ */
+ if (ResetFlags & SCSI_RESET_SYNCHRONOUS)
+ {
+ Command->reset_chain = NULL;
+ CCB->Command = Command;
+ }
/*
Attempt to write an Outgoing Mailbox with the Bus Device Reset CCB.
If sending a Bus Device Reset is impossible, attempt a full Host
@@ -2413,11 +2909,42 @@
printk("scsi%d: cannot write Outgoing Mailbox for Bus Device Reset\n",
HostAdapter->HostNumber);
BusLogic_DeallocateCCB(CCB);
- return BusLogic_ResetHostAdapter(HostAdapter, Command);
+ goto Done;
}
- HostAdapter->ReadWriteOperationCount[TargetID] = 0;
- HostAdapter->QueuedOperationCount[TargetID] = 0;
- return SCSI_RESET_PENDING;
+ /*
+ If there is a currently executing CCB in the Host Adapter for this Command
+ (i.e. this is an Asynchronous Reset), then an Incoming Mailbox entry may be
+ made with a completion code of BusLogic_HostAdapterAssertedBusDeviceReset.
+ If there is no active CCB for this Command (i.e. this is a Synchronous
+ Reset), then the Bus Device Reset CCB's Command field will have been set
+ to the Command so that the interrupt for the completion of the Bus Device
+ Reset can call the Completion Routine for the Command. On successful
+ execution of a Bus Device Reset, older firmware versions did return the
+ pending CCBs with the appropriate completion code, but more recent firmware
+ versions only return the Bus Device Reset CCB itself. This driver handles
+ both cases by marking all the currently executing CCBs to this Target
+ Device as Reset. When the Bus Device Reset CCB is processed by the
+ interrupt handler, any remaining CCBs marked as Reset will have completion
+ processing performed.
+ */
+ HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB;
+ HostAdapter->LastResetTime[TargetID] = jiffies;
+ for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+ if (CCB->Status == BusLogic_CCB_Active && CCB->TargetID == TargetID)
+ CCB->Status = BusLogic_CCB_Reset;
+ Result = SCSI_RESET_PENDING;
+ /*
+ If a Bus Device Reset was not possible for some reason, force a full
+ Host Adapter Hard Reset and SCSI Bus Reset.
+ */
+Done:
+ if (Result < 0)
+ Result = BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags);
+ /*
+ Release exclusive access to Host Adapter.
+ */
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ return Result;
}
@@ -2425,28 +2952,50 @@
BusLogic_ResetCommand takes appropriate action to reset Command.
*/
-int BusLogic_ResetCommand(SCSI_Command_T *Command)
+int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
{
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])
+ unsigned char ErrorRecoveryStrategy =
+ HostAdapter->ErrorRecoveryStrategy[TargetID];
+ /*
+ Disable Tagged Queuing if it is active for this Target Device and if
+ it has been less than 10 minutes since the last reset occurred, or since
+ the system was initialized if no prior resets have occurred.
+ */
+ if (HostAdapter->TaggedQueuingActive[TargetID] &&
+ jiffies - HostAdapter->LastResetTime[TargetID] < 10*60*HZ)
+ {
+ HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
+ HostAdapter->TaggedQueuingActive[TargetID] = false;
+ printk("scsi%d: Tagged Queuing now disabled for Target %d\n",
+ HostAdapter->HostNumber, TargetID);
+ }
+ if (ErrorRecoveryStrategy == BusLogic_ErrorRecovery_Default)
+ if (ResetFlags & SCSI_RESET_SUGGEST_BUS_RESET)
+ ErrorRecoveryStrategy = BusLogic_ErrorRecovery_HardReset;
+ else ErrorRecoveryStrategy = BusLogic_ErrorRecovery_BusDeviceReset;
+ switch (ErrorRecoveryStrategy)
+ {
+ case BusLogic_ErrorRecovery_HardReset:
+ return BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags);
+ case BusLogic_ErrorRecovery_BusDeviceReset:
+ /*
+ The Bus Device Reset Error Recovery Strategy only graduates to a Hard
+ Reset when no commands have completed successfully since the last Bus
+ Device Reset and it has been at least 100 milliseconds. This prevents
+ a sequence of commands that all timeout together from immediately
+ forcing a Hard Reset before the Bus Device Reset has had a chance to
+ clear the error condition.
+ */
+ if (HostAdapter->CommandSuccessfulFlag[TargetID] ||
+ jiffies - HostAdapter->LastResetTime[TargetID] < HZ/10)
{
HostAdapter->CommandSuccessfulFlag[TargetID] = false;
- return BusLogic_BusDeviceReset(HostAdapter, Command);
+ return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags);
}
- else return BusLogic_ResetHostAdapter(HostAdapter, Command);
+ else return BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags);
}
printk("scsi%d: Error Recovery for Target %d Suppressed\n",
HostAdapter->HostNumber, TargetID);
@@ -2456,19 +3005,18 @@
/*
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.
+ 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 "W" and "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 above 2 GB inclusive are given a
+ disk geometry of 255 heads and 63 sectors. However, if the BIOS detects
+ that the Extended Translation setting does not match the geometry in the
+ partition table, then the translation inferred from the partition table
+ will be used by the BIOS, and a warning may be displayed.
*/
int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
@@ -2477,6 +3025,7 @@
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Disk->device->host->hostdata;
BIOS_DiskParameters_T *DiskParameters = (BIOS_DiskParameters_T *) Parameters;
+ struct buffer_head *BufferHead;
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 */)
@@ -2496,6 +3045,54 @@
}
DiskParameters->Cylinders =
Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+ /*
+ Attempt to read the first 1024 bytes from the disk device.
+ */
+ BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, 1024);
+ if (BufferHead == NULL) return 0;
+ /*
+ If the boot sector partition table flag is valid, search for a partition
+ table entry whose end_head matches one of the standard BusLogic geometry
+ translations (64/32, 128/32, or 255/63).
+ */
+ if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55)
+ {
+ struct partition *PartitionEntry =
+ (struct partition *) (BufferHead->b_data + 0x1BE);
+ int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
+ for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++)
+ {
+ if (PartitionEntry->end_head == 64-1)
+ {
+ DiskParameters->Heads = 64;
+ DiskParameters->Sectors = 32;
+ break;
+ }
+ else if (PartitionEntry->end_head == 128-1)
+ {
+ DiskParameters->Heads = 128;
+ DiskParameters->Sectors = 32;
+ break;
+ }
+ else if (PartitionEntry->end_head == 255-1)
+ {
+ DiskParameters->Heads = 255;
+ DiskParameters->Sectors = 63;
+ break;
+ }
+ PartitionEntry++;
+ }
+ DiskParameters->Cylinders =
+ Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+ if (SavedCylinders != DiskParameters->Cylinders)
+ printk("scsi%d: Warning: Extended Translation Setting "
+ "(> 1GB Switch) does not match\n"
+ "scsi%d: Partition Table - Adopting %d/%d Geometry "
+ "from Partition Table\n",
+ HostAdapter->HostNumber, HostAdapter->HostNumber,
+ DiskParameters->Heads, DiskParameters->Sectors);
+ }
+ brelse(BufferHead);
return 0;
}
@@ -2503,7 +3100,7 @@
/*
BusLogic_Setup handles processing of Kernel Command Line Arguments.
- For the BusLogic driver, a kernel command line entry comprises the driver
+ 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.
@@ -2516,14 +3113,20 @@
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 second integer specified is the Tagged Queue Depth to use for Target
+ Devices that support Tagged Queuing. The Queue Depth is the number of SCSI
+ commands that are allowed to be concurrently presented for execution. If
+ unspecified, it defaults to 0 which means to use a value determined
+ automatically based on the Host Adapter's Total Queue Depth and the number,
+ type, speed, and capabilities of the detected Target Devices. For Host
+ Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is
+ automatically set to BusLogic_TaggedQueueDepth_BB to avoid excessive
+ preallocation of DMA Bounce Buffer memory. Target Devices that do not
+ support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth.
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
+ 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
@@ -2544,8 +3147,8 @@
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.
+ whether the Tagged Queue Depth value allows queuing
+ multiple commands.
TQ:Enable Tagged Queuing will be enabled for all Target Devices
on this Host Adapter overriding any limitation that
@@ -2560,19 +3163,19 @@
"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".
+ character refers to Target Device 0, the second to
+ Target Device 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:
+ The Error Recovery Strategy 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
@@ -2598,10 +3201,10 @@
"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".
+ Device 0, the second to Target Device 1, and so on; if
+ the sequence of "D", "H", "B", and "N" characters does
+ not cover all the possible Target Devices, unspecified
+ characters are assumed to be "D".
*/
void BusLogic_Setup(char *Strings, int *Integers)
@@ -2611,14 +3214,14 @@
static int ProbeListIndex = 0;
int IntegerCount = Integers[0], TargetID, i;
CommandLineEntry->IO_Address = 0;
- CommandLineEntry->Concurrency = 0;
+ CommandLineEntry->TaggedQueueDepth = 0;
CommandLineEntry->BusSettleTime = 0;
CommandLineEntry->LocalOptions = 0;
CommandLineEntry->TaggedQueuingPermitted = 0;
CommandLineEntry->TaggedQueuingPermittedMask = 0;
- memset(CommandLineEntry->ErrorRecoveryOption,
- BusLogic_ErrorRecoveryDefault,
- sizeof(CommandLineEntry->ErrorRecoveryOption));
+ memset(CommandLineEntry->ErrorRecoveryStrategy,
+ BusLogic_ErrorRecovery_Default,
+ sizeof(CommandLineEntry->ErrorRecoveryStrategy));
if (IntegerCount > 5)
printk("BusLogic: Unexpected Command Line Integers ignored\n");
if (IntegerCount >= 1)
@@ -2640,7 +3243,7 @@
"(duplicate I/O Address 0x%X)\n", IO_Address);
return;
}
- else if (IO_Address >= 0x1000 ||
+ else if (IO_Address >= 0x400 ||
IO_Address == BusLogic_IO_StandardAddresses[i]) break;
BusLogic_IO_AddressProbeList[ProbeListIndex++] = IO_Address;
BusLogic_IO_AddressProbeList[ProbeListIndex] = 0;
@@ -2649,14 +3252,14 @@
}
if (IntegerCount >= 2)
{
- unsigned short Concurrency = Integers[2];
- if (Concurrency > BusLogic_MailboxCount)
+ unsigned short TaggedQueueDepth = Integers[2];
+ if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
{
printk("BusLogic: Invalid Command Line Entry "
- "(illegal Concurrency %d)\n", Concurrency);
+ "(illegal Tagged Queue Depth %d)\n", TaggedQueueDepth);
return;
}
- CommandLineEntry->Concurrency = Concurrency;
+ CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth;
}
if (IntegerCount >= 3)
CommandLineEntry->BusSettleTime = Integers[3];
@@ -2690,7 +3293,7 @@
CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
}
else
- for (TargetID = 0; TargetID < BusLogic_MaxTargetIDs; TargetID++)
+ for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
switch (*Strings++)
{
case 'Y':
@@ -2704,7 +3307,7 @@
break;
default:
Strings--;
- TargetID = BusLogic_MaxTargetIDs;
+ TargetID = BusLogic_MaxTargetDevices;
break;
}
}
@@ -2717,47 +3320,47 @@
else if (strncmp(Strings, "HardReset", 9) == 0)
{
Strings += 9;
- memset(CommandLineEntry->ErrorRecoveryOption,
- BusLogic_ErrorRecoveryHardReset,
- sizeof(CommandLineEntry->ErrorRecoveryOption));
+ memset(CommandLineEntry->ErrorRecoveryStrategy,
+ BusLogic_ErrorRecovery_HardReset,
+ sizeof(CommandLineEntry->ErrorRecoveryStrategy));
}
else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
{
Strings += 14;
- memset(CommandLineEntry->ErrorRecoveryOption,
- BusLogic_ErrorRecoveryBusDeviceReset,
- sizeof(CommandLineEntry->ErrorRecoveryOption));
+ memset(CommandLineEntry->ErrorRecoveryStrategy,
+ BusLogic_ErrorRecovery_BusDeviceReset,
+ sizeof(CommandLineEntry->ErrorRecoveryStrategy));
}
else if (strncmp(Strings, "None", 4) == 0)
{
Strings += 4;
- memset(CommandLineEntry->ErrorRecoveryOption,
- BusLogic_ErrorRecoveryNone,
- sizeof(CommandLineEntry->ErrorRecoveryOption));
+ memset(CommandLineEntry->ErrorRecoveryStrategy,
+ BusLogic_ErrorRecovery_None,
+ sizeof(CommandLineEntry->ErrorRecoveryStrategy));
}
else
- for (TargetID = 0; TargetID < BusLogic_MaxTargetIDs; TargetID++)
+ for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
switch (*Strings++)
{
case 'D':
- CommandLineEntry->ErrorRecoveryOption[TargetID] =
- BusLogic_ErrorRecoveryDefault;
+ CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_Default;
break;
case 'H':
- CommandLineEntry->ErrorRecoveryOption[TargetID] =
- BusLogic_ErrorRecoveryHardReset;
+ CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_HardReset;
break;
case 'B':
- CommandLineEntry->ErrorRecoveryOption[TargetID] =
- BusLogic_ErrorRecoveryBusDeviceReset;
+ CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_BusDeviceReset;
break;
case 'N':
- CommandLineEntry->ErrorRecoveryOption[TargetID] =
- BusLogic_ErrorRecoveryNone;
+ CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_None;
break;
default:
Strings--;
- TargetID = BusLogic_MaxTargetIDs;
+ TargetID = BusLogic_MaxTargetDevices;
break;
}
}
@@ -2769,7 +3372,6 @@
/*
Include Module support if requested.
*/
-
#ifdef MODULE
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this