extern int hydra_probe(struct device *);
extern int yellowfin_probe(struct device *);
extern int eepro100_probe(struct device *);
-extern int epic_probe(struct device *);
+extern int epic100_probe(struct device *);
extern int rtl8139_probe(struct device *);
extern int tlan_probe(struct device *);
extern int isa515_probe(struct device *);
#ifdef CONFIG_EEXPRESS_PRO100B /* Intel EtherExpress Pro100B */
&& eepro100_probe(dev)
#endif
-#ifdef CONFIG_SMC_EPIC
- && epic_probe(dev)
+#ifdef CONFIG_EPIC
+ && epic100_probe(dev)
#endif
#if defined(CONFIG_HP100)
&& hp100_probe(dev)
return 1;
}
speedo_tx_timeout(dev);
- return 0;
+ return 1;
}
/* Caution: the write order is important here, set the base address
Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
- Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+ Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
*/
-#define BusLogic_DriverVersion "2.0.12"
-#define BusLogic_DriverDate "29 March 1998"
+#define BusLogic_DriverVersion "2.0.13"
+#define BusLogic_DriverDate "17 April 1998"
#include <linux/version.h>
*BusLogic_LastRegisteredHostAdapter = NULL;
-/*
- BusLogic_RegisteredHostAdapters is an array of linked lists of all the
- registered BusLogic Host Adapters, indexed by IRQ Channel.
-*/
-
-static BusLogic_HostAdapter_T
- *BusLogic_RegisteredHostAdapters[NR_IRQS] = { NULL };
-
-
/*
BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
*/
*BusLogic_CommandFailureReason;
-/*
- BusLogic_FirstCompletedCCB and BusLogic_LastCompletedCCB are pointers
- to the first and last CCBs that are queued for completion processing.
-*/
-
-static BusLogic_CCB_T
- *BusLogic_FirstCompletedCCB = NULL,
- *BusLogic_LastCompletedCCB = NULL;
-
-
/*
BusLogic_ProcDirectoryEntry is the BusLogic /proc/scsi directory entry.
*/
BusLogic_Announce("***** BusLogic SCSI Driver Version "
BusLogic_DriverVersion " of "
BusLogic_DriverDate " *****\n", HostAdapter);
- BusLogic_Announce("Copyright 1995 by Leonard N. Zubkoff "
+ BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff "
"<lnz@dandelion.com>\n", HostAdapter);
}
static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
{
- HostAdapter->NextAll = NULL;
+ HostAdapter->Next = NULL;
if (BusLogic_FirstRegisteredHostAdapter == NULL)
{
BusLogic_FirstRegisteredHostAdapter = HostAdapter;
}
else
{
- BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter;
+ BusLogic_LastRegisteredHostAdapter->Next = HostAdapter;
BusLogic_LastRegisteredHostAdapter = HostAdapter;
}
- HostAdapter->Next = NULL;
- if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL)
- {
- BusLogic_HostAdapter_T *LastHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
- BusLogic_HostAdapter_T *NextHostAdapter;
- while ((NextHostAdapter = LastHostAdapter->Next) != NULL)
- LastHostAdapter = NextHostAdapter;
- LastHostAdapter->Next = HostAdapter;
- }
- else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] = HostAdapter;
}
if (HostAdapter == BusLogic_FirstRegisteredHostAdapter)
{
BusLogic_FirstRegisteredHostAdapter =
- BusLogic_FirstRegisteredHostAdapter->NextAll;
+ BusLogic_FirstRegisteredHostAdapter->Next;
if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
BusLogic_LastRegisteredHostAdapter = NULL;
}
{
BusLogic_HostAdapter_T *PreviousHostAdapter =
BusLogic_FirstRegisteredHostAdapter;
- while (PreviousHostAdapter != NULL &&
- PreviousHostAdapter->NextAll != HostAdapter)
- PreviousHostAdapter = PreviousHostAdapter->NextAll;
- if (PreviousHostAdapter != NULL)
- PreviousHostAdapter->NextAll = HostAdapter->NextAll;
- }
- HostAdapter->NextAll = NULL;
- if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter)
- {
- BusLogic_HostAdapter_T *PreviousHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
while (PreviousHostAdapter != NULL &&
PreviousHostAdapter->Next != HostAdapter)
PreviousHostAdapter = PreviousHostAdapter->Next;
if (PreviousHostAdapter != NULL)
PreviousHostAdapter->Next = HostAdapter->Next;
}
- else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] =
- HostAdapter->Next;
HostAdapter->Next = NULL;
}
unsigned char *ReplyPointer = (unsigned char *) ReplyData;
BusLogic_StatusRegister_T StatusRegister;
BusLogic_InterruptRegister_T InterruptRegister;
- unsigned long ProcessorFlags = 0;
+ ProcessorFlags_T ProcessorFlags = 0;
int ReplyBytes = 0, Result;
long TimeoutCounter;
/*
Address should not be probed.
*/
HostAdapter->IO_Address = IO_Address;
+ BusLogic_InterruptReset(HostAdapter);
if (BusLogic_Command(HostAdapter,
BusLogic_InquirePCIHostAdapterInformation,
NULL, 0, &PCIHostAdapterInformation,
/*
BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic
- Host Adapter. It also determines the IRQ Channel for non-PCI Host Adapters.
+ Host Adapter.
*/
static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
{
- BusLogic_Configuration_T Configuration;
BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation;
BusLogic_RequestedReplyLength_T RequestedReplyLength;
boolean Result = true;
FlashPoint Host Adapters do not require this protection.
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
- /*
- Issue the Inquire Configuration command if the IRQ Channel is unknown.
- */
- if (HostAdapter->IRQ_Channel == 0)
- {
- if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
- NULL, 0, &Configuration, sizeof(Configuration))
- == sizeof(Configuration))
- {
- if (Configuration.IRQ_Channel9)
- HostAdapter->IRQ_Channel = 9;
- else if (Configuration.IRQ_Channel10)
- HostAdapter->IRQ_Channel = 10;
- else if (Configuration.IRQ_Channel11)
- HostAdapter->IRQ_Channel = 11;
- else if (Configuration.IRQ_Channel12)
- HostAdapter->IRQ_Channel = 12;
- else if (Configuration.IRQ_Channel14)
- HostAdapter->IRQ_Channel = 14;
- else if (Configuration.IRQ_Channel15)
- HostAdapter->IRQ_Channel = 15;
- else Result = false;
- }
- else Result = false;
- }
/*
Issue the Inquire Extended Setup Information command. Only genuine
BusLogic Host Adapters and true clones support this command. Adaptec 1542C
*/
HostAdapter->SCSI_ID = Configuration.HostAdapterID;
/*
- Determine the Bus Type and save it in the Host Adapter structure,
- and determine and save the DMA Channel for ISA Host Adapters.
+ Determine the Bus Type and save it in the Host Adapter structure, determine
+ and save the IRQ Channel if necessary, and determine and save the DMA
+ Channel for ISA Host Adapters.
*/
HostAdapter->HostAdapterBusType =
BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
+ if (HostAdapter->IRQ_Channel == 0)
+ {
+ if (Configuration.IRQ_Channel9)
+ HostAdapter->IRQ_Channel = 9;
+ else if (Configuration.IRQ_Channel10)
+ HostAdapter->IRQ_Channel = 10;
+ else if (Configuration.IRQ_Channel11)
+ HostAdapter->IRQ_Channel = 11;
+ else if (Configuration.IRQ_Channel12)
+ HostAdapter->IRQ_Channel = 12;
+ else if (Configuration.IRQ_Channel14)
+ HostAdapter->IRQ_Channel = 14;
+ else if (Configuration.IRQ_Channel15)
+ HostAdapter->IRQ_Channel = 15;
+ }
if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus)
{
if (Configuration.DMA_Channel5)
HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
/*
- Select appropriate values for the Mailbox Count, Driver Queue Depth,
+ Select appropriate values for the Mailbox Count, Driver Queue Depth,
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
*/
Common:
/*
- Initialize the Host Adapter Full Model Name and Interrupt Label fields
- from the Model Name.
+ Initialize the Host Adapter Full Model Name from the Model Name.
*/
strcpy(HostAdapter->FullModelName, "BusLogic ");
strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
- strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName);
/*
Select an appropriate value for the Tagged Queue Depth either from a
BusLogic Driver Options specification, or based on whether this Host
static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
{
- BusLogic_HostAdapter_T *FirstHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
if (HostAdapter->IRQ_Channel == 0)
{
BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
return false;
}
/*
- Acquire exclusive or shared access to the IRQ Channel if necessary.
+ Acquire shared access to the IRQ Channel.
*/
- if (FirstHostAdapter->Next == NULL)
+ if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
+ SA_INTERRUPT | SA_SHIRQ,
+ HostAdapter->FullModelName, HostAdapter) < 0)
{
- if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
- SA_INTERRUPT | SA_SHIRQ,
- HostAdapter->InterruptLabel, NULL) < 0)
- {
- BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
- HostAdapter, HostAdapter->IRQ_Channel);
- return false;
- }
- }
- else if (strlen(FirstHostAdapter->InterruptLabel) + 11
- < sizeof(FirstHostAdapter->InterruptLabel))
- {
- strcat(FirstHostAdapter->InterruptLabel, " + ");
- strcat(FirstHostAdapter->InterruptLabel, HostAdapter->ModelName);
+ BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
+ HostAdapter, HostAdapter->IRQ_Channel);
+ return false;
}
HostAdapter->IRQ_ChannelAcquired = true;
/*
static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter)
{
- BusLogic_HostAdapter_T *FirstHostAdapter =
- BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
/*
- Release exclusive or shared access to the IRQ Channel.
+ Release shared access to the IRQ Channel.
*/
if (HostAdapter->IRQ_ChannelAcquired)
- if (FirstHostAdapter->Next == NULL)
- free_irq(HostAdapter->IRQ_Channel, NULL);
+ free_irq(HostAdapter->IRQ_Channel, HostAdapter);
/*
Release exclusive access to the DMA Channel.
*/
BusLogic_RoundRobinModeRequest_T RoundRobinModeRequest;
BusLogic_SetCCBFormatRequest_T SetCCBFormatRequest;
int TargetID;
+ /*
+ Initialize the pointers to the first and last CCBs that are queued for
+ completion processing.
+ */
+ HostAdapter->FirstCompletedCCB = NULL;
+ HostAdapter->LastCompletedCCB = NULL;
/*
Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
Command Successful Flag, Active Commands, and Commands Since Reset
if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
HostAdapter != NULL;
- HostAdapter = HostAdapter->NextAll)
+ HostAdapter = HostAdapter->Next)
BusLogic_ReportTargetDeviceInfo(HostAdapter);
}
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
- properly dismissed by BusLogic_InterruptHandler, the Host Adapter
- must be registered.
+ Host Adapters.
*/
BusLogic_RegisterHostAdapter(HostAdapter);
/*
static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB)
{
+ BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
CCB->Status = BusLogic_CCB_Completed;
CCB->Next = NULL;
- if (BusLogic_FirstCompletedCCB == NULL)
+ if (HostAdapter->FirstCompletedCCB == NULL)
{
- BusLogic_FirstCompletedCCB = CCB;
- BusLogic_LastCompletedCCB = CCB;
+ HostAdapter->FirstCompletedCCB = CCB;
+ HostAdapter->LastCompletedCCB = CCB;
}
else
{
- BusLogic_LastCompletedCCB->Next = CCB;
- BusLogic_LastCompletedCCB = CCB;
+ HostAdapter->LastCompletedCCB->Next = CCB;
+ HostAdapter->LastCompletedCCB = CCB;
}
- CCB->HostAdapter->ActiveCommands[CCB->TargetID]--;
+ HostAdapter->ActiveCommands[CCB->TargetID]--;
}
/*
- BusLogic_ProcessCompletedCCBs iterates over the completed CCBs setting
- the SCSI Command Result Codes, deallocating the CCBs, and calling the
- SCSI Subsystem Completion Routines. Interrupts should already have been
- disabled by the caller.
+ BusLogic_ProcessCompletedCCBs iterates over the completed CCBs for Host
+ Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and
+ calling the SCSI Subsystem Completion Routines. The Host Adapter's Lock
+ should already have been acquired by the caller.
*/
-static void BusLogic_ProcessCompletedCCBs(void)
+static void BusLogic_ProcessCompletedCCBs(BusLogic_HostAdapter_T *HostAdapter)
{
- static boolean ProcessCompletedCCBsActive = false;
- if (ProcessCompletedCCBsActive) return;
- ProcessCompletedCCBsActive = true;
- while (BusLogic_FirstCompletedCCB != NULL)
+ if (HostAdapter->ProcessCompletedCCBsActive) return;
+ HostAdapter->ProcessCompletedCCBsActive = true;
+ while (HostAdapter->FirstCompletedCCB != NULL)
{
- BusLogic_CCB_T *CCB = BusLogic_FirstCompletedCCB;
+ BusLogic_CCB_T *CCB = HostAdapter->FirstCompletedCCB;
SCSI_Command_T *Command = CCB->Command;
- BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
- BusLogic_FirstCompletedCCB = CCB->Next;
- if (BusLogic_FirstCompletedCCB == NULL)
- BusLogic_LastCompletedCCB = NULL;
+ HostAdapter->FirstCompletedCCB = CCB->Next;
+ if (HostAdapter->FirstCompletedCCB == NULL)
+ HostAdapter->LastCompletedCCB = NULL;
/*
Process the Completed CCB.
*/
Command->scsi_done(Command);
}
}
- ProcessCompletedCCBsActive = false;
+ HostAdapter->ProcessCompletedCCBsActive = false;
}
void *DeviceIdentifier,
Registers_T *InterruptRegisters)
{
- BusLogic_HostAdapter_T *FirstHostAdapter =
- BusLogic_RegisteredHostAdapters[IRQ_Channel];
- boolean HostAdapterResetRequired = false;
- BusLogic_HostAdapter_T *HostAdapter;
- BusLogic_Lock_T Lock;
+ BusLogic_HostAdapter_T *HostAdapter =
+ (BusLogic_HostAdapter_T *) DeviceIdentifier;
+ ProcessorFlags_T ProcessorFlags;
/*
- Iterate over the installed BusLogic Host Adapters accepting any Incoming
- Mailbox entries and saving the completed CCBs for processing. This
- interrupt handler is installed as a fast interrupt, so interrupts are
- disabled when the interrupt handler is entered.
+ Acquire exclusive access to Host Adapter.
*/
- for (HostAdapter = FirstHostAdapter;
- HostAdapter != NULL;
- HostAdapter = HostAdapter->Next)
+ BusLogic_AcquireHostAdapterLockIH(HostAdapter, &ProcessorFlags);
+ /*
+ Handle Interrupts appropriately for each Host Adapter type.
+ */
+ if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
{
+ BusLogic_InterruptRegister_T InterruptRegister;
/*
- Acquire exclusive access to Host Adapter.
- */
- BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
- /*
- Handle Interrupts appropriately for each Host Adapter type.
+ Read the Host Adapter Interrupt Register.
*/
- if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
+ InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+ if (InterruptRegister.Bits.InterruptValid)
{
- BusLogic_InterruptRegister_T InterruptRegister;
/*
- Read the Host Adapter Interrupt Register.
+ Acknowledge the interrupt and reset the Host Adapter
+ Interrupt Register.
*/
- InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
- if (InterruptRegister.Bits.InterruptValid)
- {
- /*
- Acknowledge the interrupt and reset the Host Adapter
- Interrupt Register.
- */
- BusLogic_InterruptReset(HostAdapter);
- /*
- Process valid External SCSI Bus Reset and Incoming Mailbox
- Loaded Interrupts. Command Complete Interrupts are noted,
- and Outgoing Mailbox Available Interrupts are ignored, as
- they are never enabled.
- */
- if (InterruptRegister.Bits.ExternalBusReset)
- {
- HostAdapter->HostAdapterExternalReset = true;
- HostAdapterResetRequired = true;
- }
- else if (InterruptRegister.Bits.IncomingMailboxLoaded)
- BusLogic_ScanIncomingMailboxes(HostAdapter);
- else if (InterruptRegister.Bits.CommandComplete)
- HostAdapter->HostAdapterCommandCompleted = true;
- }
- }
- else
- {
+ BusLogic_InterruptReset(HostAdapter);
/*
- Check if there is a pending interrupt for this Host Adapter.
+ Process valid External SCSI Bus Reset and Incoming Mailbox
+ Loaded Interrupts. Command Complete Interrupts are noted,
+ and Outgoing Mailbox Available Interrupts are ignored, as
+ they are never enabled.
*/
- if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
- switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
- {
- case FlashPoint_NormalInterrupt:
- break;
- case FlashPoint_ExternalBusReset:
- HostAdapter->HostAdapterExternalReset = true;
- HostAdapterResetRequired = true;
- break;
- case FlashPoint_InternalError:
- BusLogic_Warning("Internal FlashPoint Error detected"
- " - Resetting Host Adapter\n", HostAdapter);
- HostAdapter->HostAdapterInternalError = true;
- HostAdapterResetRequired = true;
- break;
- }
+ if (InterruptRegister.Bits.ExternalBusReset)
+ HostAdapter->HostAdapterExternalReset = true;
+ else if (InterruptRegister.Bits.IncomingMailboxLoaded)
+ BusLogic_ScanIncomingMailboxes(HostAdapter);
+ else if (InterruptRegister.Bits.CommandComplete)
+ HostAdapter->HostAdapterCommandCompleted = true;
}
+ }
+ else
+ {
/*
- Release exclusive access to Host Adapter.
+ Check if there is a pending interrupt for this Host Adapter.
*/
- BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
+ if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
+ switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
+ {
+ case FlashPoint_NormalInterrupt:
+ break;
+ case FlashPoint_ExternalBusReset:
+ HostAdapter->HostAdapterExternalReset = true;
+ break;
+ case FlashPoint_InternalError:
+ BusLogic_Warning("Internal FlashPoint Error detected"
+ " - Resetting Host Adapter\n", HostAdapter);
+ HostAdapter->HostAdapterInternalError = true;
+ break;
+ }
}
/*
Process any completed CCBs.
*/
- if (BusLogic_FirstCompletedCCB != NULL)
- BusLogic_ProcessCompletedCCBs();
+ if (HostAdapter->FirstCompletedCCB != NULL)
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
/*
- Iterate over the Host Adapters performing any requested
- Host Adapter Resets.
+ Reset the Host Adapter if requested.
*/
- if (HostAdapterResetRequired)
- for (HostAdapter = FirstHostAdapter;
- HostAdapter != NULL;
- HostAdapter = HostAdapter->Next)
- if (HostAdapter->HostAdapterExternalReset ||
- HostAdapter->HostAdapterInternalError)
- {
- BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
- HostAdapter->HostAdapterExternalReset = false;
- HostAdapter->HostAdapterInternalError = false;
- scsi_mark_host_reset(HostAdapter->SCSI_Host);
- }
+ if (HostAdapter->HostAdapterExternalReset ||
+ HostAdapter->HostAdapterInternalError)
+ {
+ BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
+ HostAdapter->HostAdapterExternalReset = false;
+ HostAdapter->HostAdapterInternalError = false;
+ scsi_mark_host_reset(HostAdapter->SCSI_Host);
+ }
+ /*
+ Release exclusive access to Host Adapter.
+ */
+ BusLogic_ReleaseHostAdapterLockIH(HostAdapter, &ProcessorFlags);
}
void *BufferPointer = Command->request_buffer;
int BufferLength = Command->request_bufflen;
int SegmentCount = Command->use_sg;
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
BusLogic_CCB_T *CCB;
/*
SCSI REQUEST_SENSE commands will be executed automatically by the Host
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
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
been called, or it may still be pending.
*/
if (CCB->Status == BusLogic_CCB_Completed)
- BusLogic_ProcessCompletedCCBs();
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
}
/*
Release exclusive access to Host Adapter.
*/
Done:
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return 0;
}
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Command->host->hostdata;
int TargetID = Command->target;
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
BusLogic_CCB_T *CCB;
int Result;
BusLogic_IncrementErrorCounter(
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
If this Command has already completed, then no Abort is necessary.
*/
Result = SCSI_ABORT_PENDING;
if (CCB->Status == BusLogic_CCB_Completed)
{
- BusLogic_ProcessCompletedCCBs();
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
Result = SCSI_ABORT_SUCCESS;
}
}
Release exclusive access to Host Adapter.
*/
Done:
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return Result;
}
SCSI_Command_T *Command,
unsigned int ResetFlags)
{
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
BusLogic_CCB_T *CCB;
int TargetID, Result;
boolean HardReset;
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
If this is an Asynchronous Reset and this Command has already completed,
then no Reset is necessary.
Release exclusive access to Host Adapter.
*/
Done:
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return Result;
}
{
int TargetID = Command->target;
BusLogic_CCB_T *CCB, *XCCB;
- BusLogic_Lock_T Lock;
+ ProcessorFlags_T ProcessorFlags;
int Result = -1;
BusLogic_IncrementErrorCounter(
&HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested);
/*
Acquire exclusive access to Host Adapter.
*/
- BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_AcquireHostAdapterLock(HostAdapter, &ProcessorFlags);
/*
If this is an Asynchronous Reset and this Command has already completed,
then no Reset is necessary.
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
if (CCB->Status == BusLogic_CCB_Completed)
{
- BusLogic_ProcessCompletedCCBs();
+ BusLogic_ProcessCompletedCCBs(HostAdapter);
Result = SCSI_RESET_SUCCESS;
}
/*
/*
Release exclusive access to Host Adapter.
*/
- BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+ BusLogic_ReleaseHostAdapterLock(HostAdapter, &ProcessorFlags);
return Result;
}
if (WriteFlag) return 0;
for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
HostAdapter != NULL;
- HostAdapter = HostAdapter->NextAll)
+ HostAdapter = HostAdapter->Next)
if (HostAdapter->HostNumber == HostNumber) break;
if (HostAdapter == NULL)
{
#ifdef MODULE
-MODULE_PARM(BusLogic_Options, "s");
-
SCSI_Host_Template_T driver_template = BUSLOGIC;
#include "scsi_module.c"
Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
- Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+ Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
typedef kdev_t KernelDevice_T;
typedef struct proc_dir_entry PROC_DirectoryEntry_T;
+typedef unsigned long ProcessorFlags_T;
typedef struct pt_regs Registers_T;
typedef struct partition PartitionTable_T;
typedef Scsi_Host_Template SCSI_Host_Template_T;
typedef unsigned char BusLogic_RequestedReplyLength_T;
-/*
- Define the Lock data structure. Until a true symmetric multiprocessing
- kernel with fine grained locking is available, acquiring the lock is
- implemented as saving the processor flags and disabling interrupts, and
- releasing the lock restores the saved processor flags.
-*/
-
-typedef unsigned long BusLogic_Lock_T;
-
-
/*
Define the Outgoing Mailbox Action Codes.
*/
unsigned char ModelName[9];
unsigned char FirmwareVersion[6];
unsigned char FullModelName[18];
- unsigned char InterruptLabel[68];
unsigned char Bus;
unsigned char Device;
unsigned char IRQ_Channel;
boolean HostAdapterInitialized:1;
boolean HostAdapterExternalReset:1;
boolean HostAdapterInternalError:1;
- volatile boolean HostAdapterCommandCompleted:1;
+ boolean ProcessCompletedCCBsActive;
+ volatile boolean HostAdapterCommandCompleted;
unsigned short HostAdapterScatterGatherLimit;
unsigned short DriverScatterGatherLimit;
unsigned short MaxTargetDevices;
FlashPoint_Info_T FlashPointInfo;
FlashPoint_CardHandle_T CardHandle;
struct BusLogic_HostAdapter *Next;
- struct BusLogic_HostAdapter *NextAll;
BusLogic_CCB_T *All_CCBs;
BusLogic_CCB_T *Free_CCBs;
+ BusLogic_CCB_T *FirstCompletedCCB;
+ BusLogic_CCB_T *LastCompletedCCB;
BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
BusLogic_ErrorRecoveryStrategy_T
ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
static inline
void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+ ProcessorFlags_T *ProcessorFlags)
{
- save_flags(*Lock);
+ save_flags(*ProcessorFlags);
cli();
}
static inline
void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+ ProcessorFlags_T *ProcessorFlags)
{
- restore_flags(*Lock);
+ restore_flags(*ProcessorFlags);
}
/*
- BusLogic_AcquireHostAdapterLockID acquires exclusive access to Host Adapter,
- but is only called when interrupts are disabled.
+ BusLogic_AcquireHostAdapterLockIH acquires exclusive access to Host Adapter,
+ but is only called from the interrupt handler when interrupts are disabled.
*/
static inline
-void BusLogic_AcquireHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+ ProcessorFlags_T *ProcessorFlags)
{
}
/*
- BusLogic_ReleaseHostAdapterLockID releases exclusive access to Host Adapter,
- but is only called when interrupts are disabled.
+ BusLogic_ReleaseHostAdapterLockIH releases exclusive access to Host Adapter,
+ but is only called from the interrupt handler when interrupts are disabled.
*/
static inline
-void BusLogic_ReleaseHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
- BusLogic_Lock_T *Lock)
+void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
+ ProcessorFlags_T *ProcessorFlags)
{
}
/*
Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
- 32 Bit Kernel Virtual Addresses. This avoids compilation warnings
- on 64 Bit architectures.
+ 32 bit Kernel Virtual Addresses. This avoids compilation warnings
+ on 64 bit architectures.
*/
static inline
}
-/*
- Define compatibility macros between Linux 2.0 and Linux 2.1.
-*/
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#define MODULE_PARM(Variable, Type)
-
-#endif
-
-
/*
Define the version number of the FlashPoint Firmware (SCCB Manager).
*/
BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
- Version 2.0.12 for Linux 2.0
+ Version 2.0.13 for Linux 2.0
PRODUCTION RELEASE
- 29 March 1998
+ 17 April 1998
Leonard N. Zubkoff
Dandelion Digital
lnz@dandelion.com
- Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
+ Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
INTRODUCTION
replacing "/usr/src" with wherever you keep your Linux kernel source tree:
cd /usr/src
- tar -xvzf BusLogic-2.0.12.tar.gz
+ tar -xvzf BusLogic-2.0.13.tar.gz
mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
patch -p < BusLogic.patch
cd linux
The Mylex DAC960 PCI RAID Controllers are not supported at the present time,
but work on a Linux driver for the DAC960 is in progress. Please consult
http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
-Please see the file README.BusLogic for information about Linux support for
-Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
-
-The Mylex DAC960 PCI RAID Controllers are not supported at the present time,
-but work on a Linux driver for the DAC960 is in progress. Please consult
-http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
{
scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
if (scbp)
- scbq_insert_tail(&p->waiting_scbs, scbp);
+ {
+ if (queue_depth == 1)
+ {
+ /*
+ * Give extra preference to untagged devices, such as CD-R devices
+ * This makes it more likely that a drive *won't* stuff up while
+ * waiting on data at a critical time, such as CD-R writing and
+ * audio CD ripping operations. Should also benefit tape drives.
+ */
+ scbq_insert_head(&p->waiting_scbs, scbp);
+ }
+ else
+ {
+ scbq_insert_tail(&p->waiting_scbs, scbp);
+ }
+ }
if ( (queue_depth > p->dev_active_cmds[tindex]) && scbp)
{
scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
{
scbq_remove(&p->delayed_scbs[i], prev_scbp);
- if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
+ if ( !(prev_scbp->flags & SCB_WAITINGQ) )
{
p->dev_active_cmds[i]++;
p->activescbs++;
if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
{
scbq_remove(&p->waiting_scbs, prev_scbp);
- if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
+ if ( !(prev_scbp->flags & SCB_WAITINGQ) )
{
p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
p->activescbs++;
if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
{
next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+ if ( !(scbp->flags & SCB_WAITINGQ) )
+ {
+ p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+ p->activescbs++;
+ }
scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
if (prev == SCB_LIST_NULL)
if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
{
next = aic7xxx_rem_scb_from_disc_list(p, next);
+ if ( !(scbp->flags & SCB_WAITINGQ) )
+ {
+ p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+ p->activescbs++;
+ }
scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
scbp->hscb->control = 0;
(unsigned long) scb->cmd);
continue;
}
+ else if (scb->flags & SCB_QUEUED_ABORT)
+ {
+ pause_sequencer(p);
+ if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
+ (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
+ {
+ unpause_sequencer(p, FALSE);
+ continue;
+ }
+ aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
+ scb->cmd->lun, scb->cmd->lun);
+ scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
+ SCB_QUEUED_ABORT);
+ unpause_sequencer(p, FALSE);
+ }
switch (status_byte(scb->hscb->target_status))
{
case QUEUE_FULL:
if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
{
/* Send the abort message to the active SCB. */
- aic_outb(p, MSG_BUS_DEV_RESET, MSG_OUT);
+ aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, lastphase | ATNO, SCSISIGO);
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Device reset message in "
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
- *
+ *
+ * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
+ * Reworked interrupt handler.
+ *
+ * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
+ * Major reliability improvement: when a batch with overlapping
+ * requests is detected, requests are queued one at a time
+ * eliminating any possible board or drive reordering.
+ *
+ * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ * Improved SMP support (if linux version >= 2.1.95).
+ *
+ * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ * Added support for new PCI code and IO-APIC remapping of irqs.
+ * Performance improvement: when sequential i/o is detected,
+ * always use direct sort instead of reverse sort.
+ *
* 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
* io_port is now unsigned long.
*
* Use new scsi error handling code (if linux version >= 2.1.88).
* Use new interrupt code.
*
- *
* 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
* Use of udelay inside the wait loops to avoid timeout
* problems with fast cpus.
* Use of serial_number_at_timeout in abort and reset processing.
* Use of the __initfunc and __initdata macro in setup code.
* Minor cleanups in the list_statistics code.
- * Increased controller busy timeout in order to better support
+ * Increased controller busy timeout in order to better support
* slow SCSI devices.
*
* 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
* Fixed data transfer direction for some SCSI opcodes.
* Immediate acknowledge to request sense commands.
* Linked commands to each disk device are now reordered by elevator
- * sorting. Rare cases in which reordering of write requests could
+ * sorting. Rare cases in which reordering of write requests could
* cause wrong results are managed.
* Fixed spurious timeouts caused by long simple queue tag sequences.
* New command line option (tm:[0-3]) to choose the type of tags:
*
* 28 Jan 1995 rev. 1.14 for linux 1.1.86
* Added module support.
- * Log and do a retry when a disk drive returns a target status
+ * Log and do a retry when a disk drive returns a target status
* different from zero on a recovered error.
*
* 24 Jan 1995 rev. 1.13 for linux 1.1.85
*
* 17 Dec 1994 rev. 1.11 for linux 1.1.74
* Use the scsicam_bios_param routine. This allows an easy
- * migration path from disk partition tables created using
+ * migration path from disk partition tables created using
* different SCSI drivers and non optimal disk geometry.
*
* 15 Dec 1994 rev. 1.10 for linux 1.1.74
* The DPT PM2001 provides only the EATA/PIO interface and hence is not
* supported by this driver.
*
- * This code has been tested with up to 3 Distributed Processing Technology
+ * This code has been tested with up to 3 Distributed Processing Technology
* PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
* in any combination of private and shared IRQ.
- * PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
+ * PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
* v003.D0, firmware v07G.0).
*
* DPT SmartRAID boards support "Hardware Array" - a group of disk drives
*
* WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix"
* as the current OS in the DPTMGR "Initial System Installation" menu.
- * Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
+ * Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
* which is not supported by the actual SCSI subsystem.
* To get the "Array Group" functionality, the Linux MD driver must be used
* instead of the DPT "Array Group" feature.
*
* Multiple ISA, EISA and PCI boards can be configured in the same system.
* It is suggested to put all the EISA boards on the same IRQ level, all
- * the PCI boards on another IRQ level, while ISA boards cannot share
+ * the PCI boards on another IRQ level, while ISA boards cannot share
* interrupts.
*
* If you configure multiple boards on the same IRQ, the interrupt must
* bus, or even if you system has no EISA bus at all.
* Do not force any ISA address on EATA PCI boards.
*
- * If PCI bios support is configured into the kernel, BIOS32 is used to
+ * If PCI bios support is configured into the kernel, BIOS32 is used to
* include in the list of i/o ports to be probed all the PCI SCSI controllers.
*
* Due to a DPT BIOS "feature", it might not be possible to force an EISA
*
* The sequence of detection probes is:
*
- * - ISA 0x1F0;
+ * - ISA 0x1F0;
* - PCI SCSI controllers (only if BIOS32 is available);
* - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
* - ISA 0x170, 0x230, 0x330.
- *
+ *
* The above list of detection probes can be totally replaced by the
* boot command line option: "eata=port0,port1,port2,...", where the
* port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
* in the elevator sorting queue. When the active command completes, the
* commands in this queue are sorted by sector address. The sort is chosen
* between increasing or decreasing by minimizing the seek distance between
- * the sector of the commands just completed and the sector of the first
- * command in the list to be sorted.
+ * the sector of the commands just completed and the sector of the first
+ * command in the list to be sorted.
* Trivial math assures that the unsorted average seek distance when doing
* random seeks over S sectors is S/3.
* When (Q-1) requests are uniformly distributed over S sectors, the average
* distance between two adjacent requests is S/((Q-1) + 1), so the sorted
* average seek distance for (Q-1) random requests over S sectors is S/Q.
* The elevator sorting hence divides the seek distance by a factor Q/3.
- * The above pure geometric remarks are valid in all cases and the
+ * The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
* does not necessarily results in a noticeable performance improvement:
*
* Note: command reordering inside a batch of queued commands could cause
* wrong results only if there is at least one write request and the
- * intersection (sector-wise) of all requests is not empty.
+ * intersection (sector-wise) of all requests is not empty.
* When the driver detects a batch including overlapping requests
* (a really rare event) strict serial (pid) order is enforced.
* ----------------------------------------------------------------------------
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
+#include <linux/version.h>
+
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#define MAX_INT_PARAM 10
+
#if defined(MODULE)
#include <linux/module.h>
-#include <linux/version.h>
+
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
MODULE_PARM(linked_comm, "i");
MODULE_PARM(tag_mode, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/byteorder.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+#include <asm/spinlock.h>
+#endif
+
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include "scsi.h"
#include "eata.h"
#include <linux/stat.h>
#include <linux/config.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,93)
+#include <linux/bios32.h>
+#endif
+
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,36)
#include <linux/init.h>
#else
#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
+#undef DEBUG_PCI_DETECT
#undef DEBUG_INTERRUPT
#undef DEBUG_RESET
#define MAX_ISA 4
-#define MAX_VESA 0
+#define MAX_VESA 0
#define MAX_EISA 15
#define MAX_PCI 16
#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
unchar target_status; /* SCSI status received after data transfer */
unchar unused[2];
ulong inv_res_len; /* Number of bytes not transferred */
- Scsi_Cmnd *SCpnt; /* Address set in cp */
+ struct mscp *cpp; /* Address set in cp */
char mess[12];
};
reqsen:1, /* Transfer Request Sense Data to addr using DMA */
sg:1, /* Use Scatter/Gather */
:1,
- interp:1, /* The controller interprets cp, not the target */
+ interp:1, /* The controller interprets cp, not the target */
dout:1, /* Direction of Transfer is Out (Host to Target) */
din:1; /* Direction of Transfer is In (Target to Host) */
unchar sense_len; /* Request Sense Length */
unchar mess[3]; /* Massage to/from Target */
unchar cdb[12]; /* Command Descriptor Block */
ulong data_len; /* If sg=0 Data Length, if sg=1 sglist length */
- Scsi_Cmnd *SCpnt; /* Address to be returned in sp */
+ struct mscp *cpp; /* Address to be returned in sp */
ulong data_address; /* If sg=0 Data Address, if sg=1 sglist address */
ulong sp_addr; /* Address where sp is DMA'ed when cp completes */
ulong sense_addr; /* Address where Sense Data is DMA'ed on error */
+ Scsi_Cmnd *SCpnt;
unsigned int index; /* cp index */
struct sg_list *sglist;
};
unsigned long last_retried_pid; /* Pid of last retried command */
unsigned char subversion; /* Bus type, either ISA or EISA/PCI */
unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */
- struct mssp sp[MAX_MAILBOXES]; /* Returned status for this board */
+ struct mssp sp[2]; /* Returned status for this board */
};
static struct Scsi_Host *sh[MAX_BOARDS + 1];
/* Initialize num_boards so that ihdlr can work while detect is in progress */
static unsigned int num_boards = MAX_BOARDS;
-static unsigned long io_port[] __initdata = {
+static unsigned long io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
/* MAX_EISA ports */
0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
- 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
+ 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
/* Other (MAX_ISA - 1) ports */
0x170, 0x230, 0x330,
-
+
/* End of list */
0x0
};
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
-static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
+static void do_interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
Scsi_Device *dev;
- int j, ntag = 0, nuntag = 0, tqd, utqd;
+ int j, ntag = 0, nuntag = 0, tqd, utqd;
unsigned long flags;
save_flags(flags);
return FALSE;
}
+__initfunc (static inline int
+ get_pci_irq(unsigned long port_base, unsigned char *apic_irq)) {
+
+#if defined(CONFIG_PCI)
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+ unsigned int addr;
+ struct pci_dev *dev = NULL;
+
+ if (!pci_present()) return FALSE;
+
+ while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+
+ if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+ printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n",
+ driver_name, dev->bus->number, dev->devfn, addr, dev->irq);
+#endif
+
+ if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ continue;
+
+ if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) {
+ *apic_irq = dev->irq;
+ return TRUE;
+ }
+
+ }
+
+#endif /* end new style PCI code */
+
+#endif /* end CONFIG_PCI */
+
+ return FALSE;
+}
+
__initfunc (static inline int port_detect \
(unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) {
unsigned char irq, dma_channel, subversion, i;
- unsigned char protocol_rev;
+ unsigned char protocol_rev, apic_irq;
struct eata_info info;
char *bus_type, dma_name[16], tag_type;
if (do_dma(port_base, 0, READ_CONFIG_PIO)) return FALSE;
/* Read the info structure */
- if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0]))
+ if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0]))
return FALSE;
/* Check the controller "EATA" signature */
if (info.sign != EATA_SIGNATURE) return FALSE;
if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
- printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+ printk("%s: config structure size (%ld bytes) too short, detaching.\n",
name, DEV2H(info.data_len));
return FALSE;
}
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
name, irq);
+ if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) {
+ printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq);
+ irq = apic_irq;
+ }
+
/* Board detected, allocate its IRQ */
- if (request_irq(irq, eata2x_interrupt_handler,
+ if (request_irq(irq, do_interrupt_handler,
SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
/* DPT PM2012 does not allow to detect can_queue correctly */
if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue < 2) {
- printk("%s: detect, wrong n. of Mbox %d, fixed.\n",
+ printk("%s: detect, wrong n. of mbox %d, fixed.\n",
BN(j), sh[j]->can_queue);
sh[j]->can_queue = MAX_MAILBOXES;
}
for (i = 0; i < sh[j]->can_queue; i++)
if (! ((&HD(j)->cp[i])->sglist = kmalloc(
- sh[j]->sg_tablesize * sizeof(struct sg_list),
+ sh[j]->sg_tablesize * sizeof(struct sg_list),
(sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
eata2x_release(sh[j]);
return FALSE;
}
-
- if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
+
+ if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
if (protocol_rev == 'C')
printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "\
- "raidnum %u.\n", name, info.max_lun, info.m1, info.idquest,
+ "raidnum %u.\n", name, info.max_lun, info.m1, info.idquest,
info.pci, info.eisa, info.raidnum);
#endif
if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
- for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
-
+ for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
+
io_port[i] = 0;
setup_done = TRUE;
}
#if defined(CONFIG_PCI)
+ unsigned int addr, k;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+ struct pci_dev *dev = NULL;
+
+ if (!pci_present()) return;
+
+ for (k = 0; k < MAX_PCI; k++) {
+
+ if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break;
+
+ if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;
+
+#if defined(DEBUG_PCI_DETECT)
+ printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+ driver_name, k, dev->bus->number, dev->devfn, addr);
+#endif
+
+ if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+ continue;
+
+ /* Reverse the returned address order */
+ io_port[MAX_INT_PARAM + MAX_PCI - k] =
+ (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+ }
+
+#else /* else old style PCI code */
+
unsigned short i = 0;
unsigned char bus, devfn;
- unsigned int addr, k;
if (!pcibios_present()) return;
if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
!= PCIBIOS_SUCCESSFUL) continue;
-#if defined(DEBUG_DETECT)
+#if defined(DEBUG_PCI_DETECT)
printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
driver_name, k, bus, devfn, addr);
#endif
continue;
/* Reverse the returned address order */
- io_port[MAX_INT_PARAM + MAX_PCI - k] =
+ io_port[MAX_INT_PARAM + MAX_PCI - k] =
(addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
}
-#endif
+
+#endif /* end old style PCI code */
+
+#endif /* end CONFIG_PCI */
return;
}
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
}
- if (j > 0)
+ if (j > 0)
printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
num_boards = j;
static const unsigned char data_out_cmds[] = {
0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
- 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
+ 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
};
if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
- SCpnt->result = DID_OK << 16;
+ SCpnt->result = DID_OK << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
restore_flags(flags);
- done(SCpnt);
+ done(SCpnt);
return 0;
}
- /* i is the mailbox number, look for the first free mailbox
+ /* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
i = HD(j)->last_cp_used + 1;
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
- if (HD(j)->in_reset)
+ if (HD(j)->in_reset)
printk("%s: qcomm, already in reset.\n", BN(j));
else if (eata2x_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
- == SCSI_RESET_SUCCESS)
+ == SCSI_RESET_SUCCESS)
panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
- SCpnt->result = DID_BUS_BUSY << 16;
+ SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
restore_flags(flags);
- done(SCpnt);
+ done(SCpnt);
return 1;
}
memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
/* Set pointer to status packet structure */
- spp = &HD(j)->sp[i];
-
- memset(spp, 0, sizeof(struct mssp));
+ spp = &HD(j)->sp[0];
/* The EATA protocol uses Big Endian format */
cpp->sp_addr = V2DEV(spp);
+ cpp->cpp = cpp;
SCpnt->scsi_done = done;
cpp->index = i;
SCpnt->host_scribble = (unsigned char *) &cpp->index;
cpp->one = TRUE;
cpp->channel = SCpnt->channel;
cpp->target = SCpnt->target;
- cpp->lun = SCpnt->lun;
+ cpp->lun = SCpnt->lun;
cpp->SCpnt = SCpnt;
- cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
+ cpp->sense_addr = V2DEV(SCpnt->sense_buffer);
cpp->sense_len = sizeof SCpnt->sense_buffer;
-
+
if (SCpnt->device->tagged_queue) {
if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] ||
/* Send control packet to the board */
if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
- SCpnt->result = DID_ERROR << 16;
+ SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy, DID_ERROR,"\
" done.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
SCpnt->pid);
restore_flags(flags);
- done(SCpnt);
+ done(SCpnt);
return 1;
}
}
i = *(unsigned int *)SCarg->host_scribble;
- printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+ printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
BN(j), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid);
if (i >= sh[j]->can_queue)
save_flags(flags);
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
+ printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
reset_flags);
if (SCpnt->host_scribble == NULL)
panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
- if (*(unsigned int *)SCpnt->host_scribble != i)
+ if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
- if (SCpnt->scsi_done == NULL)
+ if (SCpnt->scsi_done == NULL)
panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
for (i = 0; i < n - 1; i++) {
k = i;
- for (j = k + 1; j < n; j++)
+ for (j = k + 1; j < n; j++)
if (rev) {
if (sk[j] > sk[k]) k = j;
}
return;
}
-static inline void reorder(unsigned int j, unsigned long cursec,
+static inline int reorder(unsigned int j, unsigned long cursec,
unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
Scsi_Cmnd *SCpnt;
struct mscp *cpp;
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+ unsigned long ioseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount + 1),
+ seeknosort / (readycount + 1),
seeksorted / (readycount + 1));
- if (n_ready <= 1) return;
+ if (n_ready <= 1) return FALSE;
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
if (sl[n] < sl[n - 1]) s = FALSE;
if (sl[n] > sl[n - 1]) r = FALSE;
-
+
if (link_statistics) {
if (sl[n] > sl[n - 1])
seek += sl[n] - sl[n - 1];
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
+ if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
if (!input_only) for (n = 0; n < n_ready; n++) {
ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
if (!n) continue;
-
+
if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
|| (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
}
if (link_statistics) {
if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
- batchcount++; readycount += n_ready, seeknosort += seek / 1024;
+ batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
- if (overlap) { ovlcount++; seeksorted += seek / 1024; }
+ if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
(ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
- YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
+ YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(overlap), cpp->din);
}
#endif
+ return overlap;
}
static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
il[n_ready++] = k;
}
- reorder(j, cursec, ihdlr, il, n_ready);
-
+ if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
+
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) {
- printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
+ printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
" busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
HD(j)->cp_stat[k] = ABORTING;
}
-static void eata2x_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs) {
+static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
- unsigned int i, j, k, c, status, tstatus, reg;
- unsigned int n, n_ready, il[MAX_MAILBOXES];
- struct mssp *spp;
+ unsigned int i, k, c, status, tstatus, reg;
+ struct mssp *dspp, *spp;
struct mscp *cpp;
- /* Check if the interrupt must be processed by this handler */
- if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
-
if (sh[j]->irq != irq)
panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
-
- if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
- HD(j)->iocount);
-
+
/* Check if this board need to be serviced */
if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) return;
- n_ready = 0;
+ HD(j)->iocount++;
- /* Find the mailboxes to be serviced on this board */
- for (i = 0; i < sh[j]->can_queue; i++) {
- spp = &HD(j)->sp[i];
-
- /* Check if this mailbox has completed the operation */
- if (spp->eoc == FALSE) continue;
+ if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
+ HD(j)->iocount);
- spp->eoc = FALSE;
- il[n_ready++] = i;
+ /* Check if this board is still busy */
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+ reg = inb(sh[j]->io_port + REG_STATUS);
+ printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
+ BN(j), irq, reg, HD(j)->iocount);
+ return;
}
+ dspp = &HD(j)->sp[0];
+ spp = &HD(j)->sp[1];
+
+ /* Make a local copy just before clearing the interrupt indication */
+ memcpy(spp, dspp, sizeof(struct mssp));
+
+ /* Clear the completion flag and cp pointer on the dynamic copy of sp */
+ memset(dspp, 0, sizeof(struct mssp));
+
/* Read the status register to clear the interrupt indication */
reg = inb(sh[j]->io_port + REG_STATUS);
- /* Mailbox service loop */
- for (n = 0; n < n_ready; n++) {
- i = il[n];
- spp = &HD(j)->sp[i];
+ /* Reject any sp with supspect data */
+ if (spp->eoc == FALSE)
+ printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n",
+ BN(j), irq, reg, HD(j)->iocount);
+ if (spp->cpp == NULL)
+ printk("%s: ihdlr, spp->cpp == NULL, irq %d, reg 0x%x, count %d.\n",
+ BN(j), irq, reg, HD(j)->iocount);
+ if (spp->eoc == FALSE || spp->cpp == NULL) return;
- if (HD(j)->cp_stat[i] == IGNORE) {
- HD(j)->cp_stat[i] = FREE;
- return;
- }
- else if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
- HD(j)->iocount);
- return;
- }
- else if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
- HD(j)->iocount);
- return;
- }
- else if (HD(j)->cp_stat[i] == IN_RESET)
- printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
- else if (HD(j)->cp_stat[i] != IN_USE)
- panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+ cpp = spp->cpp;
+
+ /* Find the mailbox to be serviced on this board */
+ i = cpp - HD(j)->cp;
+
+ if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
+ || i >= sh[j]->can_queue)
+ panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
+ cpp, HD(j)->cp);
+ if (HD(j)->cp_stat[i] == IGNORE) {
+ HD(j)->cp_stat[i] = FREE;
+ return;
+ }
+ else if (HD(j)->cp_stat[i] == LOCKED) {
HD(j)->cp_stat[i] = FREE;
- cpp = &HD(j)->cp[i];
- SCpnt = spp->SCpnt;
+ printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
+ HD(j)->iocount);
+ return;
+ }
+ else if (HD(j)->cp_stat[i] == FREE) {
+ printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
+ HD(j)->iocount);
+ return;
+ }
+ else if (HD(j)->cp_stat[i] == IN_RESET)
+ printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+ else if (HD(j)->cp_stat[i] != IN_USE)
+ panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+ BN(j), i, HD(j)->cp_stat[i]);
- if(SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ HD(j)->cp_stat[i] = FREE;
+ SCpnt = cpp->SCpnt;
- if (SCpnt != cpp->SCpnt)
- panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n", BN(j), i,
- SCpnt, cpp->SCpnt);
+ if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
- if (SCpnt->host_scribble == NULL)
- panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
- SCpnt->pid, SCpnt);
+ if (SCpnt->host_scribble == NULL)
+ panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
+ SCpnt->pid, SCpnt);
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d, irq %d.\n",
- BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble, irq);
+ if (*(unsigned int *)SCpnt->host_scribble != i)
+ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
+ BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
- if (linked_comm && SCpnt->device->queue_depth > 2
- && TLDEV(SCpnt->device->type))
+ if (linked_comm && SCpnt->device->queue_depth > 2
+ && TLDEV(SCpnt->device->type))
flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE);
- tstatus = status_byte(spp->target_status);
-
- switch (spp->adapter_status) {
- case ASOK: /* status OK */
-
- /* Forces a reset if a disk drive keeps returning BUSY */
- if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
- status = DID_ERROR << 16;
-
- /* If there was a bus reset, redo operation on each target */
- else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
- && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
- status = DID_BUS_BUSY << 16;
-
- /* Works around a flaw in scsi.c */
- else if (tstatus == CHECK_CONDITION
- && SCpnt->device->type == TYPE_DISK
- && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
- status = DID_BUS_BUSY << 16;
-
- else
- status = DID_OK << 16;
-
- if (tstatus == GOOD)
- HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
-
- if (spp->target_status && SCpnt->device->type == TYPE_DISK)
- printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
- "target_status 0x%x, sense key 0x%x.\n", BN(j),
- SCpnt->channel, SCpnt->target, SCpnt->lun,
- SCpnt->pid, spp->target_status,
- SCpnt->sense_buffer[2]);
-
- HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
-
- if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
-
- break;
- case ASST: /* Selection Time Out */
- case 0x02: /* Command Time Out */
-
- if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
- status = DID_ERROR << 16;
- else {
- status = DID_TIME_OUT << 16;
- HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
- }
-
- break;
-
- /* Perform a limited number of internal retries */
- case 0x03: /* SCSI Bus Reset Received */
- case 0x04: /* Initial Controller Power-up */
-
- for (c = 0; c <= sh[j]->max_channel; c++)
- for (k = 0; k < sh[j]->max_id; k++)
- HD(j)->target_redo[k][c] = TRUE;
-
- if (SCpnt->device->type != TYPE_TAPE
- && HD(j)->retries < MAX_INTERNAL_RETRIES) {
- status = DID_BUS_BUSY << 16;
- HD(j)->retries++;
- HD(j)->last_retried_pid = SCpnt->pid;
- }
- else
- status = DID_ERROR << 16;
-
- break;
- case 0x05: /* Unexpected Bus Phase */
- case 0x06: /* Unexpected Bus Free */
- case 0x07: /* Bus Parity Error */
- case 0x08: /* SCSI Hung */
- case 0x09: /* Unexpected Message Reject */
- case 0x0a: /* SCSI Bus Reset Stuck */
- case 0x0b: /* Auto Request-Sense Failed */
- case 0x0c: /* Controller Ram Parity Error */
- default:
+ tstatus = status_byte(spp->target_status);
+
+ switch (spp->adapter_status) {
+ case ASOK: /* status OK */
+
+ /* Forces a reset if a disk drive keeps returning BUSY */
+ if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
status = DID_ERROR << 16;
- break;
- }
- SCpnt->result = status | spp->target_status;
- HD(j)->iocount++;
+ /* If there was a bus reset, redo operation on each target */
+ else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+ && HD(j)->target_redo[SCpnt->target][SCpnt->channel])
+ status = DID_BUS_BUSY << 16;
+
+ /* Works around a flaw in scsi.c */
+ else if (tstatus == CHECK_CONDITION
+ && SCpnt->device->type == TYPE_DISK
+ && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+ status = DID_BUS_BUSY << 16;
+
+ else
+ status = DID_OK << 16;
+
+ if (tstatus == GOOD)
+ HD(j)->target_redo[SCpnt->target][SCpnt->channel] = FALSE;
+
+ if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+ printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+ "target_status 0x%x, sense key 0x%x.\n", BN(j),
+ SCpnt->channel, SCpnt->target, SCpnt->lun,
+ SCpnt->pid, spp->target_status,
+ SCpnt->sense_buffer[2]);
+
+ HD(j)->target_to[SCpnt->target][SCpnt->channel] = 0;
+
+ if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+
+ break;
+ case ASST: /* Selection Time Out */
+ case 0x02: /* Command Time Out */
+
+ if (HD(j)->target_to[SCpnt->target][SCpnt->channel] > 1)
+ status = DID_ERROR << 16;
+ else {
+ status = DID_TIME_OUT << 16;
+ HD(j)->target_to[SCpnt->target][SCpnt->channel]++;
+ }
+
+ break;
+
+ /* Perform a limited number of internal retries */
+ case 0x03: /* SCSI Bus Reset Received */
+ case 0x04: /* Initial Controller Power-up */
+
+ for (c = 0; c <= sh[j]->max_channel; c++)
+ for (k = 0; k < sh[j]->max_id; k++)
+ HD(j)->target_redo[k][c] = TRUE;
+
+ if (SCpnt->device->type != TYPE_TAPE
+ && HD(j)->retries < MAX_INTERNAL_RETRIES) {
+ status = DID_BUS_BUSY << 16;
+ HD(j)->retries++;
+ HD(j)->last_retried_pid = SCpnt->pid;
+ }
+ else
+ status = DID_ERROR << 16;
+
+ break;
+ case 0x05: /* Unexpected Bus Phase */
+ case 0x06: /* Unexpected Bus Free */
+ case 0x07: /* Bus Parity Error */
+ case 0x08: /* SCSI Hung */
+ case 0x09: /* Unexpected Message Reject */
+ case 0x0a: /* SCSI Bus Reset Stuck */
+ case 0x0b: /* Auto Request-Sense Failed */
+ case 0x0c: /* Controller Ram Parity Error */
+ default:
+ status = DID_ERROR << 16;
+ break;
+ }
+
+ SCpnt->result = status | spp->target_status;
#if defined (DEBUG_INTERRUPT)
- if (SCpnt->result || do_trace)
+ if (SCpnt->result || do_trace)
#else
- if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
- (spp->adapter_status != ASOK &&
- spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
- do_trace || msg_byte(spp->target_status))
+ if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
+ (spp->adapter_status != ASOK &&
+ spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+ do_trace || msg_byte(spp->target_status))
#endif
- printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
- " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
- BN(j), i, spp->adapter_status, spp->target_status,
- SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
- reg, HD(j)->iocount);
+ printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
+ " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
+ BN(j), i, spp->adapter_status, spp->target_status,
+ SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+ reg, HD(j)->iocount);
- /* Set the command state to inactive */
- SCpnt->host_scribble = NULL;
-
- SCpnt->scsi_done(SCpnt);
+ /* Set the command state to inactive */
+ SCpnt->host_scribble = NULL;
- } /* Mailbox loop */
-
- if (n_ready > 1)
- printk("%s: ihdlr, multiple commands (%d) completed.\n", BN(j), n_ready);
+ SCpnt->scsi_done(SCpnt);
if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
HD(j)->iocount);
return;
}
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+
+ unsigned int j;
+
+ /* Check if the interrupt must be processed by this handler */
+ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&io_request_lock, flags);
+ ihdlr(irq, j);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+#else
+ ihdlr(irq, j);
+#endif
+
+}
+
int eata2x_release(struct Scsi_Host *shpnt) {
unsigned long flags;
unsigned int i, j;
cli();
for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
-
+
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
- for (i = 0; i < sh[j]->can_queue; i++)
+ for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
free_irq(sh[j]->irq, &sha[j]);
#define _EATA_H
#include <scsi/scsicam.h>
+#include <linux/version.h>
int eata2x_detect(Scsi_Host_Template *);
int eata2x_release(struct Scsi_Host *);
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "4.02.00"
+#define EATA_VERSION "4.20.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
+ * Reworked interrupt handler.
+ *
+ * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
+ * Major reliability improvement: when a batch with overlapping
+ * requests is detected, requests are queued one at a time
+ * eliminating any possible board or drive reordering.
+ *
+ * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ * Improved SMP support (if linux version >= 2.1.95).
+ *
+ * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ * Performance improvement: when sequential i/o is detected,
+ * always use direct sort instead of reverse sort.
+ *
* 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
* io_port is now unsigned long.
*
* Fixed data transfer direction for some SCSI opcodes.
* Immediate acknowledge to request sense commands.
* Linked commands to each disk device are now reordered by elevator
- * sorting. Rare cases in which reordering of write requests could
+ * sorting. Rare cases in which reordering of write requests could
* cause wrong results are managed.
*
* 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
* 28 Oct 1994 rev. 1.09 for linux 1.1.58 Final BETA release.
* 16 Jul 1994 rev. 1.00 for linux 1.1.29 Initial ALPHA release.
*
- * This driver is a total replacement of the original UltraStor
+ * This driver is a total replacement of the original UltraStor
* scsi driver, but it supports ONLY the 14F and 34F boards.
* It can be configured in the same kernel in which the original
* ultrastor driver is configured to allow the original U24F
* support.
- *
+ *
* Multiple U14F and/or U34F host adapters are supported.
*
* Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com)
* 24F - EISA Bus Master HA with floppy support and WD1003 emulation.
* 34F - VESA Local-Bus Bus Master HA (no WD1003 emulation).
*
- * This code has been tested with up to two U14F boards, using both
+ * This code has been tested with up to two U14F boards, using both
* firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware
- * 28004-006/38004-005 (BIOS rev. 2.01).
+ * 28004-006/38004-005 (BIOS rev. 2.01).
*
- * The latest firmware is required in order to get reliable operations when
+ * The latest firmware is required in order to get reliable operations when
* clustering is enabled. ENABLE_CLUSTERING provides a performance increase
* up to 50% on sequential access.
*
* have their BIOS disabled, or enabled to an higher address.
* Boards are named Ux4F0, Ux4F1..., according to the port address order in
* the io_port[] array.
- *
+ *
* The following facts are based on real testing results (not on
* documentation) on the above U14F board.
- *
- * - The U14F board should be jumpered for bus on time less or equal to 7
- * microseconds, while the default is 11 microseconds. This is order to
- * get acceptable performance while using floppy drive and hard disk
- * together. The jumpering for 7 microseconds is: JP13 pin 15-16,
+ *
+ * - The U14F board should be jumpered for bus on time less or equal to 7
+ * microseconds, while the default is 11 microseconds. This is order to
+ * get acceptable performance while using floppy drive and hard disk
+ * together. The jumpering for 7 microseconds is: JP13 pin 15-16,
* JP14 pin 7-8 and pin 9-10.
* The reduction has a little impact on scsi performance.
- *
+ *
* - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced
* from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8).
*
* - If U14F on board firmware is older than 28004-006/38004-005,
- * the U14F board is unable to provide reliable operations if the scsi
+ * the U14F board is unable to provide reliable operations if the scsi
* request length exceeds 16Kbyte. When this length is exceeded the
- * behavior is:
+ * behavior is:
* - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94;
* - adapter_status equal 0 and target_status equal 2 on for all targets
* in the next operation following the reset.
* Any reset of the scsi bus is going to kill tape operations, since
* no retry is allowed for tapes. Bus resets are more likely when the
* scsi bus is under heavy load.
- * Requests using scatter/gather have a maximum length of 16 x 1024 bytes
+ * Requests using scatter/gather have a maximum length of 16 x 1024 bytes
* when DISABLE_CLUSTERING is in effect, but unscattered requests could be
* larger than 16Kbyte.
*
* in the elevator sorting queue. When the active command completes, the
* commands in this queue are sorted by sector address. The sort is chosen
* between increasing or decreasing by minimizing the seek distance between
- * the sector of the commands just completed and the sector of the first
- * command in the list to be sorted.
+ * the sector of the commands just completed and the sector of the first
+ * command in the list to be sorted.
* Trivial math assures that the unsorted average seek distance when doing
* random seeks over S sectors is S/3.
* When (Q-1) requests are uniformly distributed over S sectors, the average
* distance between two adjacent requests is S/((Q-1) + 1), so the sorted
* average seek distance for (Q-1) random requests over S sectors is S/Q.
* The elevator sorting hence divides the seek distance by a factor Q/3.
- * The above pure geometric remarks are valid in all cases and the
+ * The above pure geometric remarks are valid in all cases and the
* driver effectively reduces the seek distance by the predicted factor
* when there are Q concurrent read i/o operations on the device, but this
* does not necessarily results in a noticeable performance improvement:
*
* Note: command reordering inside a batch of queued commands could cause
* wrong results only if there is at least one write request and the
- * intersection (sector-wise) of all requests is not empty.
+ * intersection (sector-wise) of all requests is not empty.
* When the driver detects a batch including overlapping requests
* (a really rare event) strict serial (pid) order is enforced.
* ----------------------------------------------------------------------------
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
+#include <linux/version.h>
+
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#define MAX_INT_PARAM 10
+
#if defined(MODULE)
#include <linux/module.h>
-#include <linux/version.h>
+
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26)
MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i");
MODULE_PARM(linked_comm, "i");
MODULE_PARM(max_queue_depth, "i");
MODULE_AUTHOR("Dario Ballabio");
#endif
+
#endif
#include <linux/string.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/byteorder.h>
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+#include <asm/spinlock.h>
+#endif
+
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include "scsi.h"
#undef DEBUG_RESET
#define MAX_ISA 3
-#define MAX_VESA 1
+#define MAX_VESA 1
#define MAX_EISA 0
#define MAX_PCI 0
#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
/* Initialize num_boards so that ihdlr can work while detect is in progress */
static unsigned int num_boards = MAX_BOARDS;
-static unsigned long io_port[] __initdata = {
+static unsigned long io_port[] __initdata = {
/* Space for MAX_INT_PARAM ports usable while loading as a module */
SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
-static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
+static void do_interrupt_handler(int, void *, struct pt_regs *);
static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
Scsi_Device *dev;
- int j, ntag = 0, nuntag = 0, tqd, utqd;
+ int j, ntag = 0, nuntag = 0, tqd, utqd;
unsigned long flags;
save_flags(flags);
char *bus_type, dma_name[16];
/* Allowed BIOS base addresses (NULL indicates reserved) */
- void *bios_segment_table[8] = {
- NULL,
+ void *bios_segment_table[8] = {
+ NULL,
(void *) 0xc4000, (void *) 0xc8000, (void *) 0xcc000, (void *) 0xd0000,
(void *) 0xd4000, (void *) 0xd8000, (void *) 0xdc000
};
-
+
/* Allowed IRQs */
unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
-
+
/* Allowed DMA channels for ISA (0 indicates reserved) */
unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
-
+
/* Head/sector mappings */
struct {
unsigned char heads;
unsigned char sectors;
- } mapping_table[4] = {
+ } mapping_table[4] = {
{ 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
};
subversion = (in_byte & 0x0f);
/* Board detected, allocate its IRQ */
- if (request_irq(irq, u14_34f_interrupt_handler,
+ if (request_irq(irq, do_interrupt_handler,
SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
for (i = 0; i < sh[j]->can_queue; i++)
if (! ((&HD(j)->cp[i])->sglist = kmalloc(
- sh[j]->sg_tablesize * sizeof(struct sg_list),
+ sh[j]->sg_tablesize * sizeof(struct sg_list),
(sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
u14_34f_release(sh[j]);
return FALSE;
}
-
- if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
+
+ if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
- for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
-
+ for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
+
io_port[i] = 0;
setup_done = TRUE;
}
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
}
- if (j > 0)
+ if (j > 0)
printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
num_boards = j;
static const unsigned char data_out_cmds[] = {
0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
- 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
+ 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b
};
if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid);
if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) {
- SCpnt->result = DID_OK << 16;
+ SCpnt->result = DID_OK << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n",
BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid);
restore_flags(flags);
- done(SCpnt);
+ done(SCpnt);
return 0;
}
- /* i is the mailbox number, look for the first free mailbox
+ /* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
i = HD(j)->last_cp_used + 1;
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
- if (HD(j)->in_reset)
+ if (HD(j)->in_reset)
printk("%s: qcomm, already in reset.\n", BN(j));
- else if (u14_34f_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
- == SCSI_RESET_SUCCESS)
+ else if (u14_34f_reset(SCpnt, SCSI_RESET_SUGGEST_BUS_RESET)
+ == SCSI_RESET_SUCCESS)
panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
- SCpnt->result = DID_BUS_BUSY << 16;
+ SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, pid %ld, DID_BUS_BUSY, done.\n", BN(j), SCpnt->pid);
restore_flags(flags);
- done(SCpnt);
+ done(SCpnt);
return 1;
}
SCpnt->host_scribble = (unsigned char *) &cpp->index;
if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
- BN(j), i, SCpnt->channel, SCpnt->target,
+ BN(j), i, SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid);
cpp->xdir = DTD_IN;
save_flags(flags);
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
- printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
+ printk("%s: reset, enter, target %d.%d:%d, pid %ld, reset_flags %u.\n",
BN(j), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid,
reset_flags);
if (SCpnt->host_scribble == NULL)
panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
- if (*(unsigned int *)SCpnt->host_scribble != i)
+ if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
- if (SCpnt->scsi_done == NULL)
+ if (SCpnt->scsi_done == NULL)
panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
for (i = 0; i < n - 1; i++) {
k = i;
- for (j = k + 1; j < n; j++)
+ for (j = k + 1; j < n; j++)
if (rev) {
if (sk[j] > sk[k]) k = j;
}
return;
}
-static inline void reorder(unsigned int j, unsigned long cursec,
+static inline int reorder(unsigned int j, unsigned long cursec,
unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
Scsi_Cmnd *SCpnt;
struct mscp *cpp;
unsigned int input_only = TRUE, overlap = FALSE;
unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+ unsigned long ioseek = 0;
static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
" av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
ovlcount, readycount, readysorted, sortcount, revcount,
- seeknosort / (readycount + 1),
+ seeknosort / (readycount + 1),
seeksorted / (readycount + 1));
- if (n_ready <= 1) return;
+ if (n_ready <= 1) return FALSE;
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector;
sl[n] = SCpnt->request.sector;
+ ioseek += SCpnt->request.nr_sectors;
if (!n) continue;
if (sl[n] < sl[n - 1]) s = FALSE;
if (sl[n] > sl[n - 1]) r = FALSE;
-
+
if (link_statistics) {
if (sl[n] > sl[n - 1])
seek += sl[n] - sl[n - 1];
if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
+ if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
if (!input_only) for (n = 0; n < n_ready; n++) {
ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid;
if (!n) continue;
-
+
if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
|| (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
}
if (link_statistics) {
if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
- batchcount++; readycount += n_ready, seeknosort += seek / 1024;
+ batchcount++; readycount += n_ready, seeknosort += seek / 1024;
if (input_only) inputcount++;
- if (overlap) { ovlcount++; seeksorted += seek / 1024; }
+ if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
else seeksorted += (iseek + maxsec - minsec) / 1024;
if (rev && !r) { revcount++; readysorted += n_ready; }
if (!rev && !s) { sortcount++; readysorted += n_ready; }
(ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
SCpnt->request.sector, SCpnt->request.nr_sectors, cursec,
- YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
+ YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(overlap), cpp->xdir);
}
#endif
+ return overlap;
}
static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j,
il[n_ready++] = k;
}
- reorder(j, cursec, ihdlr, il, n_ready);
-
+ if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
+
for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
- printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\
+ printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
" busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k);
HD(j)->cp_stat[k] = ABORTING;
outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
HD(j)->cp_stat[k] = IN_USE;
}
+
}
-static void u14_34f_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs) {
+static inline void ihdlr(int irq, unsigned int j) {
Scsi_Cmnd *SCpnt;
- unsigned int i, j, k, c, status, tstatus, reg, ret;
- struct mscp *spp;
-
- /* Check if the interrupt must be processed by this handler */
- if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
+ unsigned int i, k, c, status, tstatus, reg, ret;
+ struct mscp *spp, *cpp;
if (sh[j]->irq != irq)
panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
+ /* Check if this board need to be serviced */
+ if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return;
+
+ HD(j)->iocount++;
+
if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
HD(j)->iocount);
- /* Check if this board need to be serviced */
- if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return;
+ /* Check if this board is still busy */
+ if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+ printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
+ BN(j), irq, reg, HD(j)->iocount);
+ return;
+ }
spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
+ cpp = spp;
/* Clear interrupt pending flag */
outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
- i = spp - HD(j)->cp;
+ /* Find the mailbox to be serviced on this board */
+ i = cpp - HD(j)->cp;
- if (spp < HD(j)->cp || spp >= HD(j)->cp + sh[j]->can_queue
+ if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue
|| i >= sh[j]->can_queue)
panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
(void *)ret, HD(j)->cp);
}
else if (HD(j)->cp_stat[i] == IN_RESET)
printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
- else if (HD(j)->cp_stat[i] != IN_USE)
- panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+ else if (HD(j)->cp_stat[i] != IN_USE)
+ panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+ BN(j), i, HD(j)->cp_stat[i]);
HD(j)->cp_stat[i] = FREE;
- SCpnt = spp->SCpnt;
+ SCpnt = cpp->SCpnt;
if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
- if (SCpnt->host_scribble == NULL)
+ if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
SCpnt->pid, SCpnt);
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d, irq %d.\n",
- BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble, irq);
+ if (*(unsigned int *)SCpnt->host_scribble != i)
+ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
+ BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
if (linked_comm && SCpnt->device->queue_depth > 2
&& TLDEV(SCpnt->device->type))
case ASOK: /* status OK */
/* Forces a reset if a disk drive keeps returning BUSY */
- if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+ if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
status = DID_ERROR << 16;
/* If there was a bus reset, redo operation on each target */
if (spp->target_status && SCpnt->device->type == TYPE_DISK)
printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
- "target_status 0x%x, sense key 0x%x.\n", BN(j),
+ "target_status 0x%x, sense key 0x%x.\n", BN(j),
SCpnt->channel, SCpnt->target, SCpnt->lun,
SCpnt->pid, spp->target_status,
SCpnt->sense_buffer[2]);
case 0x96: /* Illegal SCSI command */
case 0xa3: /* SCSI bus reset error */
- for (c = 0; c <= sh[j]->max_channel; c++)
- for (k = 0; k < sh[j]->max_id; k++)
+ for (c = 0; c <= sh[j]->max_channel; c++)
+ for (k = 0; k < sh[j]->max_id; k++)
HD(j)->target_redo[k][c] = TRUE;
-
+
case 0x92: /* Data over/under-run */
HD(j)->retries++;
HD(j)->last_retried_pid = SCpnt->pid;
}
- else
+ else
status = DID_ERROR << 16;
break;
}
SCpnt->result = status | spp->target_status;
- HD(j)->iocount++;
#if defined (DEBUG_INTERRUPT)
- if (SCpnt->result || do_trace)
+ if (SCpnt->result || do_trace)
#else
if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
- (spp->adapter_status != ASOK &&
+ (spp->adapter_status != ASOK &&
spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
do_trace || msg_byte(spp->target_status))
#endif
return;
}
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+
+ unsigned int j;
+
+ /* Check if the interrupt must be processed by this handler */
+ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&io_request_lock, flags);
+ ihdlr(irq, j);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+#else
+ ihdlr(irq, j);
+#endif
+
+}
+
int u14_34f_release(struct Scsi_Host *shpnt) {
unsigned long flags;
unsigned int i, j;
cli();
for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
-
+
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
- for (i = 0; i < sh[j]->can_queue; i++)
+ for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
free_irq(sh[j]->irq, &sha[j]);
#ifndef _U14_34F_H
#define _U14_34F_H
+#include <linux/version.h>
+
int u14_34f_detect(Scsi_Host_Template *);
int u14_34f_release(struct Scsi_Host *);
int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "4.02.00"
+#define U14_34F_VERSION "4.20.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+++ /dev/null
-#ifdef MODVERSIONS
-#undef CONFIG_MODVERSIONS
-#define CONFIG_MODVERSIONS
-#ifndef _set_ver
-#define _set_ver(sym,vers) sym ## _R ## vers
-#endif
-#include <linux/modules/b1capi.ver>
-#include <linux/modules/b1pci.ver>
-#include <linux/modules/capidrv.ver>
-#include <linux/modules/capiutil.ver>
-#include <linux/modules/fatfs_syms.ver>
-#include <linux/modules/firewall.ver>
-#include <linux/modules/isdn_syms.ver>
-#include <linux/modules/ksyms.ver>
-#include <linux/modules/md.ver>
-#include <linux/modules/misc.ver>
-#include <linux/modules/msdosfs_syms.ver>
-#include <linux/modules/netsyms.ver>
-#include <linux/modules/nls.ver>
-#include <linux/modules/p8022.ver>
-#include <linux/modules/p8022tr.ver>
-#include <linux/modules/ppp.ver>
-#include <linux/modules/procfs_syms.ver>
-#include <linux/modules/psnap.ver>
-#include <linux/modules/scsi_syms.ver>
-#include <linux/modules/serial.ver>
-#include <linux/modules/slhc.ver>
-#include <linux/modules/vfatfs_syms.ver>
-#undef CONFIG_MODVERSIONS
-#endif
if(len>65535)
{
- printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr));
+ NETDEBUG(printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr)));
ip_statistics.IpReasmFails++;
ip_free(qp);
return NULL;
*/
int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
+#ifdef CONFIG_SYN_COOKIES
+ extern unsigned int ui_c_send_cookies;
+ static unsigned int ui_c_last_send_cookies = 0;
+#endif
/* From net/socket.c */
extern int socket_get_info(char *, char **, off_t, int);
extern struct proto packet_prot;
raw_prot.inuse, raw_prot.highestinuse);
len += sprintf(buffer+len,"PAC: inuse %d highest %d\n",
packet_prot.inuse, packet_prot.highestinuse);
+
+#if defined(CONFIG_SYN_COOKIES)
+ len += sprintf(buffer+len,"SYN_COOKIES: count %u since_last_check %u\n",
+ ui_c_send_cookies, (ui_c_send_cookies - ui_c_last_send_cookies));
+
+ ui_c_last_send_cookies = ui_c_send_cookies;
+#endif
*start = buffer + offset;
len -= offset;
if (len > length)
* (e.g. long delay packet radio links, 1200 baud modems.)
*/
static __u32 cookie_mtu[8] = { 64, 256, 512, 536, 1024, 1440, 1460, 4312 };
+unsigned int ui_c_send_cookies = 0;
#endif
extern void tcp_v4_hash(struct sock *sk);
#endif
#ifdef CONFIG_SYN_COOKIES
send_cookie = 1;
+ ui_c_send_cookies++;
#else
/* If we only have RST cookies we should
* not drop through to the rest of the response code.
echo "# Using defaults found in" $DEFAULTS
echo "#"
. $DEFAULTS
- sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > /tmp/conf.$$
- . /tmp/conf.$$
- rm /tmp/conf.$$
+ sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .tmp.conf.$$
+ . .tmp.conf.$$
+ rm .tmp.conf.$$
else
echo "#"
echo "# No defaults found"