/*

  Linux Driver for BusLogic MultiMaster SCSI Host Adapters

  Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>

  This program is free software; you may redistribute and/or modify it under
  the terms of the GNU General Public License Version 2 as published by the
  Free Software Foundation, provided that none of the source code or runtime
  copyright notices are removed or modified.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  for complete details.

  The author respectfully requests that any modifications to this software be
  sent directly to him for evaluation and testing.

  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 types for some of the structures that interface with the rest
  of the Linux Kernel and SCSI Subsystem.
*/

typedef struct pt_regs Registers_T;
typedef Scsi_Host_Template SCSI_Host_Template_T;
typedef struct Scsi_Host SCSI_Host_T;
typedef struct scsi_device SCSI_Device_T;
typedef struct scsi_disk SCSI_Disk_T;
typedef struct scsi_cmnd SCSI_Command_T;
typedef struct scatterlist SCSI_ScatterList_T;
typedef kdev_t KernelDevice_T;


/*
  Define prototypes for the BusLogic Driver Interface Functions.
*/

const char *BusLogic_DriverInfo(SCSI_Host_T *);
int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *);
int BusLogic_ReleaseHostAdapter(SCSI_Host_T *);
int BusLogic_QueueCommand(SCSI_Command_T *,
			  void (*CompletionRoutine)(SCSI_Command_T *));
int BusLogic_AbortCommand(SCSI_Command_T *);
int BusLogic_ResetCommand(SCSI_Command_T *, unsigned int);
int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *);


/*
  Define the BusLogic SCSI Host Template structure.
*/

#define BUSLOGIC							 \
  { NULL,				/* Next			     */  \
    NULL,				/* Usage Count Pointer	     */  \
    NULL,				/* /proc Directory Entry     */	 \
    NULL,				/* /proc Info Function	     */	 \
    "BusLogic",				/* Driver Name		     */  \
    BusLogic_DetectHostAdapter,		/* Detect Host Adapter	     */  \
    BusLogic_ReleaseHostAdapter,	/* Release Host Adapter	     */  \
    BusLogic_DriverInfo,		/* Driver Info Function	     */  \
    NULL,				/* Command Function	     */  \
    BusLogic_QueueCommand,		/* Queue Command Function    */  \
    BusLogic_AbortCommand,		/* Abort Command Function    */  \
    BusLogic_ResetCommand,		/* Reset Command Function    */  \
    NULL,				/* Slave Attach Function     */  \
    BusLogic_BIOSDiskParameters,	/* Disk BIOS Parameters	     */  \
    0,					/* Can Queue		     */  \
    0,					/* This ID		     */  \
    0,					/* Scatter/Gather Table Size */  \
    0,					/* SCSI Commands per LUN     */  \
    0,					/* Present		     */  \
    1,					/* Default Unchecked ISA DMA */  \
    ENABLE_CLUSTERING }			/* Enable Clustering	     */


/*
  BusLogic_DriverVersion protects the private portion of this file.
*/

#ifdef BusLogic_DriverVersion


/*
  Define the maximum number of BusLogic Host Adapters that are supported.
*/

#define BusLogic_MaxHostAdapters		10


/*
  Define the maximum number of I/O Addresses that may be probed.
*/

#define BusLogic_IO_MaxProbeAddresses		16


/*
  Define the maximum number of Target Devices supported by this driver.
*/

#define BusLogic_MaxTargetDevices		16


/*
  Define the maximum number of Scatter/Gather Segments used by this driver.
  For optimal performance, it is important that this limit be at least as
  large as the maximum single request generated by the I/O Subsystem.
*/

#define BusLogic_ScatterGatherLimit		128


/*
  Define the maximum, preferred, and default Queue Depth to allow for Target
  Devices depending on whether or not they support Tagged Queuing and whether
  or not ISA Bounce Buffers are required.
*/

#define BusLogic_MaxTaggedQueueDepth		63
#define BusLogic_PreferredTaggedQueueDepth	28
#define BusLogic_TaggedQueueDepth_BB		2
#define BusLogic_UntaggedQueueDepth		3


/*
  Define the default amount of time in seconds to wait between a 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.
*/

#define BusLogic_DefaultBusSettleTime		2


/*
  Define the possible Probe Options.
*/

#define BusLogic_NoProbe			1
#define BusLogic_NoProbeISA			2
#define BusLogic_NoSortPCI			4


/*
  Define the possible Local Options.
*/

#define BusLogic_InhibitTargetInquiry		1


/*
  Define the possible Global Options.
*/

#define BusLogic_TraceProbe			1
#define BusLogic_TraceHardReset			2
#define BusLogic_TraceConfiguration		4
#define BusLogic_TraceErrors			8
#define BusLogic_TraceQueueDepths		16


/*
  Define the possible Error Recovery Strategy Options.
*/

#define BusLogic_ErrorRecovery_Default		0
#define BusLogic_ErrorRecovery_HardReset	1
#define BusLogic_ErrorRecovery_BusDeviceReset	2
#define BusLogic_ErrorRecovery_None		3

static char
  *BusLogic_ErrorRecoveryStrategyNames[] =
    { "Default", "Hard Reset", "Bus Device Reset", "None" },
  *BusLogic_ErrorRecoveryStrategyLetters[] =
    { "D", "H", "B", "N" };


/*
  Define a boolean data type.
*/

#define false 0
#define true  1
typedef unsigned char boolean;


/*
  Define a 32 bit bus address data type.
*/

typedef unsigned int bus_address_t;


/*
  Define the BusLogic SCSI Host Adapter I/O Register Offsets.
*/

#define BusLogic_IO_PortCount			4	/* I/O Registers */
#define BusLogic_ControlRegister		0	/* WO register */
#define BusLogic_StatusRegister			0	/* RO register */
#define BusLogic_CommandParameterRegister	1	/* WO register */
#define BusLogic_DataInRegister			1	/* RO register */
#define BusLogic_InterruptRegister		2	/* RO register */
#define BusLogic_GeometryRegister		3	/* RO register */


/*
  Define the bits in the write-only Control Register.
*/

#define BusLogic_ReservedCR			0x0F
#define BusLogic_SCSIBusReset			0x10
#define BusLogic_InterruptReset			0x20
#define BusLogic_SoftReset			0x40
#define BusLogic_HardReset			0x80


/*
  Define the bits in the read-only Status Register.
*/

#define BusLogic_CommandInvalid			0x01
#define BusLogic_ReservedSR			0x02
#define BusLogic_DataInRegisterReady		0x04
#define BusLogic_CommandParameterRegisterBusy	0x08
#define BusLogic_HostAdapterReady		0x10
#define BusLogic_InitializationRequired		0x20
#define BusLogic_DiagnosticFailure		0x40
#define BusLogic_DiagnosticActive		0x80


/*
  Define the bits in the read-only Interrupt Register.
*/

#define BusLogic_IncomingMailboxLoaded		0x01
#define BusLogic_OutgoingMailboxAvailable	0x02
#define BusLogic_CommandComplete		0x04
#define BusLogic_SCSIResetState			0x08
#define BusLogic_ReservedIR			0x70
#define BusLogic_InterruptValid			0x80


/*
  Define the bits in the read-only Geometry Register.
*/

#define BusLogic_Drive0Geometry			0x03
#define BusLogic_Drive1Geometry			0x0C
#define BusLogic_ReservedGR			0x70
#define BusLogic_ExtendedTranslationEnabled	0x80


/*
  Define the BusLogic SCSI Host Adapter Command Register Operation Codes.
*/

typedef enum
{
  BusLogic_TestCommandCompleteInterrupt =	0x00,
  BusLogic_InitializeMailbox =			0x01,
  BusLogic_ExecuteMailboxCommand =		0x02,
  BusLogic_ExecuteBIOSCommand =			0x03,
  BusLogic_InquireBoardID =			0x04,
  BusLogic_EnableOutgoingMailboxAvailableInt =	0x05,
  BusLogic_SetSCSISelectionTimeout =		0x06,
  BusLogic_SetPreemptTimeOnBus =		0x07,
  BusLogic_SetTimeOffBus =			0x08,
  BusLogic_SetBusTransferRate =			0x09,
  BusLogic_InquireInstalledDevicesID0to7 =	0x0A,
  BusLogic_InquireConfiguration =		0x0B,
  BusLogic_EnableTargetMode =			0x0C,
  BusLogic_InquireSetupInformation =		0x0D,
  BusLogic_WriteAdapterLocalRAM =		0x1A,
  BusLogic_ReadAdapterLocalRAM =		0x1B,
  BusLogic_WriteBusMasterChipFIFO =		0x1C,
  BusLogic_ReadBusMasterChipFIFO =		0x1D,
  BusLogic_EchoCommandData =			0x1F,
  BusLogic_HostAdapterDiagnostic =		0x20,
  BusLogic_SetAdapterOptions =			0x21,
  BusLogic_InquireInstalledDevicesID8to15 =	0x23,
  BusLogic_InquireTargetDevices =		0x24,
  BusLogic_DisableHostAdapterInterrupt =	0x25,
  BusLogic_InitializeExtendedMailbox =		0x81,
  BusLogic_ExecuteSCSICommand =			0x83,
  BusLogic_InquireFirmwareVersion3rdDigit =	0x84,
  BusLogic_InquireFirmwareVersionLetter =	0x85,
  BusLogic_InquireGenericIOPortInformation =	0x86,
  BusLogic_InquireControllerModelNumber =	0x8B,
  BusLogic_InquireSynchronousPeriod =		0x8C,
  BusLogic_InquireExtendedSetupInformation =	0x8D,
  BusLogic_EnableStrictRoundRobinMode =		0x8F,
  BusLogic_StoreHostAdapterLocalRAM =		0x90,
  BusLogic_FetchHostAdapterLocalRAM =		0x91,
  BusLogic_StoreLocalDataInEEPROM =		0x92,
  BusLogic_UploadAutoSCSICode =			0x94,
  BusLogic_ModifyIOAddress =			0x95,
  BusLogic_SetCCBFormat =			0x96,
  BusLogic_WriteInquiryBuffer =			0x9A,
  BusLogic_ReadInquiryBuffer =			0x9B,
  BusLogic_FlashROMUploadDownload =		0xA7,
  BusLogic_ReadSCAMData =			0xA8,
  BusLogic_WriteSCAMData =			0xA9
}
BusLogic_OperationCode_T;


/*
  Define the Inquire Board ID reply structure.
*/

typedef struct BusLogic_BoardID
{
  unsigned char BoardType;				/* Byte 0 */
  unsigned char CustomFeatures;				/* Byte 1 */
  unsigned char FirmwareVersion1stDigit;		/* Byte 2 */
  unsigned char FirmwareVersion2ndDigit;		/* Byte 3 */
}
BusLogic_BoardID_T;


/*
  Define the Inquire Installed Devices ID 0 to 7 and Inquire Installed
  Devices ID 8 to 15 reply type.  For each Target Device, a byte is returned
  where bit 0 set indicates that Logical Unit 0 exists, bit 1 set indicates
  that Logical Unit 1 exists, and so on.
*/

typedef unsigned char BusLogic_InstalledDevices8_T[8];


/*
  Define the Inquire Target Devices reply type.  Inquire Target Devices only
  tests Logical Unit 0 of each Target Device unlike the Inquire Installed
  Devices commands which test Logical Units 0 - 7.  Two bytes are returned,
  where bit 0 set indicates that Target Device 0 exists, and so on.
*/

typedef unsigned short BusLogic_InstalledDevices_T;


/*
  Define the Inquire Configuration reply structure.
*/

typedef struct BusLogic_Configuration
{
  unsigned char :5;					/* Byte 0 Bits 0-4 */
  boolean DMA_Channel5:1;				/* Byte 0 Bit 5 */
  boolean DMA_Channel6:1;				/* Byte 0 Bit 6 */
  boolean DMA_Channel7:1;				/* Byte 0 Bit 7 */
  boolean IRQ_Channel9:1;				/* Byte 1 Bit 0 */
  boolean IRQ_Channel10:1;				/* Byte 1 Bit 1 */
  boolean IRQ_Channel11:1;				/* Byte 1 Bit 2 */
  boolean IRQ_Channel12:1;				/* Byte 1 Bit 3 */
  unsigned char :1;					/* Byte 1 Bit 4 */
  boolean IRQ_Channel14:1;				/* Byte 1 Bit 5 */
  boolean IRQ_Channel15:1;				/* Byte 1 Bit 6 */
  unsigned char :1;					/* Byte 1 Bit 7 */
  unsigned char HostAdapterID:4;			/* Byte 2 Bits 0-3 */
  unsigned char :4;					/* Byte 2 Bits 4-7 */
}
BusLogic_Configuration_T;


/*
  Define the Inquire Setup Information reply structure.
*/

typedef struct BusLogic_SynchronousValue
{
  unsigned char Offset:4;				/* Bits 0-3 */
  unsigned char TransferPeriod:3;			/* Bits 4-6 */
  boolean Synchronous:1;				/* Bit 7 */
}
BusLogic_SynchronousValue_T;

typedef BusLogic_SynchronousValue_T
  BusLogic_SynchronousValues8_T[8];

typedef BusLogic_SynchronousValue_T
  BusLogic_SynchronousValues_T[BusLogic_MaxTargetDevices];

typedef struct BusLogic_SetupInformation
{
  boolean SynchronousInitiationEnabled:1;		/* Byte 0 Bit 0 */
  boolean ParityCheckEnabled:1;				/* Byte 0 Bit 1 */
  unsigned char :6;					/* Byte 0 Bits 2-7 */
  unsigned char BusTransferRate;			/* Byte 1 */
  unsigned char PreemptTimeOnBus;			/* Byte 2 */
  unsigned char TimeOffBus;				/* Byte 3 */
  unsigned char MailboxCount;				/* Byte 4 */
  unsigned char MailboxAddress[3];			/* Bytes 5-7 */
  BusLogic_SynchronousValues8_T SynchronousValuesID0to7; /* Bytes 8-15 */
  unsigned char DisconnectPermittedID0to7;		/* Byte 16 */
  unsigned char Signature;				/* Byte 17 */
  unsigned char CharacterD;				/* Byte 18 */
  unsigned char HostBusType;				/* Byte 19 */
  unsigned char :8;					/* Byte 20 */
  unsigned char :8;					/* Byte 21 */
  BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */
  unsigned char DisconnectPermittedID8to15;		/* Byte 30 */
}
BusLogic_SetupInformation_T;


/*
  Define the Initialize Extended Mailbox request structure.
*/

typedef struct BusLogic_ExtendedMailboxRequest
{
  unsigned char MailboxCount;				/* Byte 0 */
  bus_address_t BaseMailboxAddress __attribute__ ((packed)); /* Bytes 1-4 */
}
BusLogic_ExtendedMailboxRequest_T;


/*
  Define the Inquire Firmware Version 3rd Digit reply type.
*/

typedef unsigned char BusLogic_FirmwareVersion3rdDigit_T;


/*
  Define the Inquire Firmware Version Letter reply type.
*/

typedef unsigned char BusLogic_FirmwareVersionLetter_T;


/*
  Define the Inquire Generic I/O Port Information reply type.
*/

typedef struct BusLogic_GenericIOPortInformation
{
  unsigned char ISACompatibleIOPort;			/* Byte 0 */
  unsigned char PCIAssignedIRQChannel;			/* Byte 1 */
  boolean LowByteTerminated:1;				/* Byte 2 Bit 0 */
  boolean HighByteTerminated:1;				/* Byte 2 Bit 1 */
  unsigned char :2;					/* Byte 2 Bits 2-3 */
  boolean JP1:1;					/* Byte 2 Bit 4 */
  boolean JP2:1;					/* Byte 2 Bit 5 */
  boolean JP3:1;					/* Byte 2 Bit 6 */
  boolean Valid:1;					/* Byte 2 Bit 7 */
  unsigned char :8;					/* Byte 3 */
}
BusLogic_GenericIOPortInformation_T;


/*
  Define the Inquire Controller Model Number reply type.
*/

typedef unsigned char BusLogic_ControllerModelNumber_T[5];


/*
  Define the Inquire Synchronous Period reply type.  For each Target Device,
  a byte is returned which represents the Synchronous Transfer Period in units
  of 10 nanoseconds.
*/

typedef unsigned char BusLogic_SynchronousPeriod_T[BusLogic_MaxTargetDevices];


/*
  Define the Inquire Extended Setup Information reply structure.
*/

typedef struct BusLogic_ExtendedSetupInformation
{
  unsigned char BusType;				/* Byte 0 */
  unsigned char BIOS_Address;				/* Byte 1 */
  unsigned short ScatterGatherLimit;			/* Bytes 2-3 */
  unsigned char MailboxCount;				/* Byte 4 */
  bus_address_t BaseMailboxAddress __attribute__ ((packed)); /* Bytes 5-8 */
  struct { unsigned char :6;				/* Byte 9 Bits 0-5 */
	   boolean LevelSensitiveInterrupts:1;		/* Byte 9 Bit 6 */
	   unsigned char :1; } Misc;			/* Byte 9 Bit 7 */
  unsigned char FirmwareRevision[3];			/* Bytes 10-12 */
  boolean HostWideSCSI:1;				/* Byte 13 Bit 0 */
  boolean HostDifferentialSCSI:1;			/* Byte 13 Bit 1 */
  boolean HostAutomaticConfiguration:1;			/* Byte 13 Bit 2 */
  boolean HostUltraSCSI:1;				/* Byte 13 Bit 3 */
  boolean HostSmartTermination:1;			/* Byte 13 Bit 4 */
  unsigned char :3;					/* Byte 13 Bits 5-7 */
}
BusLogic_ExtendedSetupInformation_T;


/*
  Define the Enable Strict Round Robin Mode request type.
*/

#define BusLogic_AggressiveRoundRobinMode	0x00
#define BusLogic_StrictRoundRobinMode		0x01

typedef unsigned char BusLogic_RoundRobinModeRequest_T;


/*
  Define the Fetch Host Adapter Local RAM request type.
*/

#define BusLogic_BIOS_BaseOffset		0
#define BusLogic_AutoSCSI_BaseOffset		64

typedef struct BusLogic_FetchHostAdapterLocalRAMRequest
{
  unsigned char ByteOffset;				/* Byte 0 */
  unsigned char ByteCount;				/* Byte 1 */
}
BusLogic_FetchHostAdapterLocalRAMRequest_T;


/*
  Define the Host Adapter Local RAM Auto SCSI Byte 15 reply structure.
*/

typedef struct BusLogic_AutoSCSIByte15
{
  unsigned char LowByteTerminated:1;			/* Bit 0 */
  unsigned char :1;					/* Bit 1 */
  unsigned char HighByteTerminated:1;			/* Bit 2 */
  unsigned char :5;					/* Bits 3-7 */
}
BusLogic_AutoSCSIByte15_T;


/*
  Define the Host Adapter Local RAM Auto SCSI Byte 45 reply structure.
*/

typedef struct BusLogic_AutoSCSIByte45
{
  unsigned char ForceBusDeviceScanningOrder:1;		/* Bit 0 */
  unsigned char :7;					/* Bits 1-7 */
}
BusLogic_AutoSCSIByte45_T;


/*
  Define the Modify I/O Address request type.  On PCI Host Adapters, the
  Modify I/O Address command allows modification of the ISA compatible I/O
  Address that the Host Adapter responds to; it does not affect the PCI
  compliant I/O Address assigned at system initialization.
*/

#define BusLogic_ModifyIO_330			0x00
#define BusLogic_ModifyIO_334			0x01
#define BusLogic_ModifyIO_230			0x02
#define BusLogic_ModifyIO_234			0x03
#define BusLogic_ModifyIO_130			0x04
#define BusLogic_ModifyIO_134			0x05
#define BusLogic_ModifyIO_Disable		0x06
#define BusLogic_ModifyIO_Disable2		0x07

typedef unsigned char BusLogic_ModifyIOAddressRequest_T;


/*
  Define the Set CCB Format request type.  64 LUN Format CCBs are necessary to
  support 64 Logical Units per Target Device.  8 LUN Format CCBs only support 8
  Logical Units per Target Device.
*/

#define BusLogic_8LUNFormatCCB			0x00
#define BusLogic_64LUNFormatCCB			0x01

typedef unsigned char BusLogic_SetCCBFormatRequest_T;


/*
  Define the Requested Reply Length type used by the Inquire Setup Information,
  Inquire Controller Model Number, Inquire Synchronous Period, and Inquire
  Extended Setup Information commands.
*/

typedef unsigned char BusLogic_RequestedReplyLength_T;


/*
  Define a 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.
*/

typedef enum
{
  BusLogic_OutgoingMailboxFree =		0,
  BusLogic_MailboxStartCommand =		1,
  BusLogic_MailboxAbortCommand =		2
}
BusLogic_ActionCode_T;


/*
  Define the Incoming Mailbox Completion Codes.
*/

typedef enum
{
  BusLogic_IncomingMailboxFree =		0,
  BusLogic_CommandCompletedWithoutError =	1,
  BusLogic_CommandAbortedAtHostRequest =	2,
  BusLogic_AbortedCommandNotFound =		3,
  BusLogic_CommandCompletedWithError =		4
}
BusLogic_CompletionCode_T;


/*
  Define the Command Control Block (CCB) Opcodes.
*/

typedef enum
{
  BusLogic_InitiatorCCB =			0x00,
  BusLogic_TargetCCB =				0x01,
  BusLogic_InitiatorCCB_ScatterGather =		0x02,
  BusLogic_InitiatorCCB_ResidualDataLength =	0x03,
  BusLogic_InitiatorCCB_ScatterGatherResidual =	0x04,
  BusLogic_BusDeviceReset =			0x81
}
BusLogic_CCB_Opcode_T;


/*
  Define the CCB Data Direction Codes.
*/

typedef enum
{
  BusLogic_UncheckedDataTransfer =		0x00,
  BusLogic_DataInLengthChecked =		0x01,
  BusLogic_DataOutLengthChecked =		0x02,
  BusLogic_NoDataTransfer =			0x03
}
BusLogic_DataDirection_T;


/*
  Define the Host Adapter Status Codes.
*/

typedef enum
{
  BusLogic_CommandCompletedNormally =		0x00,
  BusLogic_LinkedCommandCompleted =		0x0A,
  BusLogic_LinkedCommandCompletedWithFlag =	0x0B,
  BusLogic_SCSISelectionTimeout =		0x11,
  BusLogic_DataOverUnderRun =			0x12,
  BusLogic_UnexpectedBusFree =			0x13,
  BusLogic_InvalidBusPhaseRequested =		0x14,
  BusLogic_InvalidOutgoingMailboxActionCode =	0x15,
  BusLogic_InvalidCommandOperationCode =	0x16,
  BusLogic_LinkedCCBhasInvalidLUN =		0x17,
  BusLogic_InvalidCommandParameter =		0x1A,
  BusLogic_AutoRequestSenseFailed =		0x1B,
  BusLogic_TaggedQueuingMessageRejected =	0x1C,
  BusLogic_UnsupportedMessageReceived =		0x1D,
  BusLogic_HostAdapterHardwareFailed =		0x20,
  BusLogic_TargetFailedResponseToATN =		0x21,
  BusLogic_HostAdapterAssertedRST =		0x22,
  BusLogic_OtherDeviceAssertedRST =		0x23,
  BusLogic_TargetDeviceReconnectedImproperly =	0x24,
  BusLogic_HostAdapterAssertedBusDeviceReset =	0x25,
  BusLogic_AbortQueueGenerated =		0x26,
  BusLogic_HostAdapterSoftwareError =		0x27,
  BusLogic_HostAdapterHardwareTimeoutError =	0x30,
  BusLogic_SCSIParityErrorDetected =		0x34
}
BusLogic_HostAdapterStatus_T;


/*
  Define the SCSI Target Device Status Codes.
*/

typedef enum
{
  BusLogic_OperationGood =			0x00,
  BusLogic_CheckCondition =			0x02,
  BusLogic_DeviceBusy =				0x08
}
BusLogic_TargetDeviceStatus_T;


/*
  Define the Queue Tag Codes.
*/

typedef enum
{
  BusLogic_SimpleQueueTag =			0x00,
  BusLogic_HeadOfQueueTag =			0x01,
  BusLogic_OrderedQueueTag =			0x02,
  BusLogic_ReservedQT =				0x03
}
BusLogic_QueueTag_T;


/*
  Define the SCSI Command Descriptor Block (CDB).
*/

#define BusLogic_CDB_MaxLength			12

typedef unsigned char SCSI_CDB_T[BusLogic_CDB_MaxLength];


/*
  Define the Scatter/Gather Segment structure required by the Host Adapter
  Firmware Interface.
*/

typedef struct BusLogic_ScatterGatherSegment
{
  unsigned int SegmentByteCount;			/* Bytes 0-3 */
  bus_address_t SegmentDataPointer;			/* Bytes 4-7 */
}
BusLogic_ScatterGatherSegment_T;


/*
  Define the 32 Bit Mode Command Control Block (CCB) structure.  The first 40
  bytes are defined by the Host Adapter Firmware Interface.  The remaining
  components are defined by the Linux BusLogic Driver.  64 LUN Format CCBs
  differ from standard 8 LUN Format 32 Bit Mode CCBs only in having the
  TagEnable and QueueTag fields moved from byte 17 to byte 1, and the Logical
  Unit field in byte 17 expanded to 6 bits; unfortunately, using a union of
  structs containing enumeration type bitfields to provide both definitions
  leads to packing problems, so the following definition is used which requires
  setting TagEnable to Logical Unit bit 5 in 64 LUN Format CCBs.
*/

typedef struct BusLogic_CCB
{
  /*
    BusLogic Host Adapter Firmware Portion.
  */
  BusLogic_CCB_Opcode_T Opcode:8;			/* Byte 0 */
  unsigned char :3;					/* Byte 1 Bits 0-2 */
  BusLogic_DataDirection_T DataDirection:2;		/* Byte 1 Bits 3-4 */
  boolean TagEnable64LUN:1;				/* Byte 1 Bit 5 */
  BusLogic_QueueTag_T QueueTag64LUN:2;			/* Byte 1 Bits 6-7 */
  unsigned char CDB_Length;				/* Byte 2 */
  unsigned char SenseDataLength;			/* Byte 3 */
  unsigned int DataLength;				/* Bytes 4-7 */
  bus_address_t DataPointer;				/* Bytes 8-11 */
  unsigned char :8;					/* Byte 12 */
  unsigned char :8;					/* Byte 13 */
  BusLogic_HostAdapterStatus_T HostAdapterStatus:8;	/* Byte 14 */
  BusLogic_TargetDeviceStatus_T TargetDeviceStatus:8;	/* Byte 15 */
  unsigned char TargetID;				/* Byte 16 */
  unsigned char LogicalUnit:5;				/* Byte 17 Bits 0-4 */
  boolean TagEnable:1;					/* Byte 17 Bit 5 */
  BusLogic_QueueTag_T QueueTag:2;			/* Byte 17 Bits 6-7 */
  SCSI_CDB_T CDB;					/* Bytes 18-29 */
  unsigned char :8;					/* Byte 30 */
  unsigned char :8;					/* Byte 31 */
  unsigned int :32;					/* Bytes 32-35 */
  bus_address_t SenseDataPointer;			/* Bytes 36-39 */
  /*
    BusLogic Linux Driver Portion.
  */
  struct BusLogic_HostAdapter *HostAdapter;
  SCSI_Command_T *Command;
  enum { BusLogic_CCB_Free =	    0,
	 BusLogic_CCB_Active =	    1,
	 BusLogic_CCB_Completed =   2,
	 BusLogic_CCB_Reset =	    3 } Status;
  BusLogic_CompletionCode_T MailboxCompletionCode;
  unsigned long SerialNumber;
  struct BusLogic_CCB *Next;
  struct BusLogic_CCB *NextAll;
  BusLogic_ScatterGatherSegment_T
    ScatterGatherList[BusLogic_ScatterGatherLimit];
}
BusLogic_CCB_T;


/*
  Define the 32 Bit Mode Outgoing Mailbox structure.
*/

typedef struct BusLogic_OutgoingMailbox
{
  bus_address_t CCB;					/* Bytes 0-3 */
  unsigned int :24;					/* Byte 4 */
  BusLogic_ActionCode_T ActionCode:8;			/* Bytes 5-7 */
}
BusLogic_OutgoingMailbox_T;


/*
  Define the 32 Bit Mode Incoming Mailbox structure.
*/

typedef struct BusLogic_IncomingMailbox
{
  bus_address_t CCB;					/* Bytes 0-3 */
  BusLogic_HostAdapterStatus_T HostAdapterStatus:8;	/* Byte 4 */
  BusLogic_TargetDeviceStatus_T TargetDeviceStatus:8;	/* Byte 5 */
  unsigned char :8;					/* Byte 6 */
  BusLogic_CompletionCode_T CompletionCode:8;		/* Byte 7 */
}
BusLogic_IncomingMailbox_T;


/*
  Define the possible Bus Types.
*/

typedef enum
{
  BusLogic_Unknown_Bus =			0,
  BusLogic_ISA_Bus =				1,
  BusLogic_MCA_Bus =				2,
  BusLogic_EISA_Bus =				3,
  BusLogic_VESA_Bus =				4,
  BusLogic_PCI_Bus =				5
}
BusLogic_BusType_T;

static char
  *BusLogic_BusNames[] =
    { "Unknown", "ISA", "MCA", "EISA", "VESA", "PCI" };


/*
  Define the Linux BusLogic Driver Command Line Entry structure.
*/

typedef struct BusLogic_CommandLineEntry
{
  unsigned int IO_Address;
  unsigned short TaggedQueueDepth;
  unsigned short BusSettleTime;
  unsigned short LocalOptions;
  unsigned short TaggedQueuingPermitted;
  unsigned short TaggedQueuingPermittedMask;
  unsigned char ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
}
BusLogic_CommandLineEntry_T;


/*
  Define the Linux BusLogic Driver Host Adapter structure.
*/

typedef struct BusLogic_HostAdapter
{
  SCSI_Host_T *SCSI_Host;
  unsigned int IO_Address;
  unsigned char HostNumber;
  unsigned char ModelName[9];
  unsigned char FirmwareVersion[6];
  unsigned char ControllerName[18];
  unsigned char InterruptLabel[62];
  unsigned char IRQ_Channel;
  unsigned char DMA_Channel;
  unsigned char SCSI_ID;
  BusLogic_BusType_T BusType:3;
  boolean IRQ_ChannelAcquired:1;
  boolean DMA_ChannelAcquired:1;
  boolean SynchronousInitiation:1;
  boolean ParityChecking:1;
  boolean ExtendedTranslation:1;
  boolean LevelSensitiveInterrupts:1;
  boolean HostWideSCSI:1;
  boolean HostDifferentialSCSI:1;
  boolean HostAutomaticConfiguration:1;
  boolean HostUltraSCSI:1;
  boolean TerminationInfoValid:1;
  boolean LowByteTerminated:1;
  boolean HighByteTerminated:1;
  boolean BounceBuffersRequired:1;
  boolean StrictRoundRobinModeSupport:1;
  boolean Host64LUNSupport:1;
  boolean HostAdapterResetRequested:1;
  volatile boolean HostAdapterCommandCompleted:1;
  unsigned short HostAdapterScatterGatherLimit;
  unsigned short DriverScatterGatherLimit;
  unsigned short MaxTargetDevices;
  unsigned short MaxLogicalUnits;
  unsigned short MailboxCount;
  unsigned short InitialCCBs;
  unsigned short IncrementalCCBs;
  unsigned short TotalQueueDepth;
  unsigned short TaggedQueueDepth;
  unsigned short UntaggedQueueDepth;
  unsigned short BusSettleTime;
  unsigned short LocalOptions;
  unsigned short DisconnectPermitted;
  unsigned short TaggedQueuingPermitted;
  bus_address_t BIOS_Address;
  BusLogic_InstalledDevices_T InstalledDevices;
  BusLogic_SynchronousValues_T SynchronousValues;
  BusLogic_SynchronousPeriod_T SynchronousPeriod;
  BusLogic_CommandLineEntry_T *CommandLineEntry;
  struct BusLogic_HostAdapter *Next;
  BusLogic_CCB_T *All_CCBs;
  BusLogic_CCB_T *Free_CCBs;
  BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
  unsigned char ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
  unsigned char TaggedQueuingActive[BusLogic_MaxTargetDevices];
  unsigned char CommandSuccessfulFlag[BusLogic_MaxTargetDevices];
  unsigned char ActiveCommandCount[BusLogic_MaxTargetDevices];
  unsigned long TotalCommandCount[BusLogic_MaxTargetDevices];
  unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
  unsigned long LastResetTime[BusLogic_MaxTargetDevices];
  BusLogic_OutgoingMailbox_T *FirstOutgoingMailbox;
  BusLogic_OutgoingMailbox_T *LastOutgoingMailbox;
  BusLogic_OutgoingMailbox_T *NextOutgoingMailbox;
  BusLogic_IncomingMailbox_T *FirstIncomingMailbox;
  BusLogic_IncomingMailbox_T *LastIncomingMailbox;
  BusLogic_IncomingMailbox_T *NextIncomingMailbox;
}
BusLogic_HostAdapter_T;


/*
  Define a structure for the BIOS Disk Parameters.
*/

typedef struct BIOS_DiskParameters
{
  int Heads;
  int Sectors;
  int Cylinders;
}
BIOS_DiskParameters_T;


/*
  BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter.
*/

static inline
void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
				     BusLogic_Lock_T *Lock)
{
  save_flags(*Lock);
  cli();
}


/*
  BusLogic_ReleaseHostAdapterLock releases exclusive access to Host Adapter.
*/

static inline
void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
				     BusLogic_Lock_T *Lock)
{
  restore_flags(*Lock);
}


/*
  BusLogic_AcquireHostAdapterLockID acquires exclusive access to Host Adapter,
  but is only called when interrupts are disabled.
*/

static inline
void BusLogic_AcquireHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
				       BusLogic_Lock_T *Lock)
{
}


/*
  BusLogic_ReleaseHostAdapterLockID releases exclusive access to Host Adapter,
  but is only called when interrupts are disabled.
*/

static inline
void BusLogic_ReleaseHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
				       BusLogic_Lock_T *Lock)
{
}


/*
  Define functions to provide an abstraction for reading and writing the
  Host Adapter I/O Registers.
*/

static inline
void BusLogic_WriteControlRegister(BusLogic_HostAdapter_T *HostAdapter,
				   unsigned char Value)
{
  outb(Value, HostAdapter->IO_Address + BusLogic_ControlRegister);
}

static inline
unsigned char BusLogic_ReadStatusRegister(BusLogic_HostAdapter_T *HostAdapter)
{
  return inb(HostAdapter->IO_Address + BusLogic_StatusRegister);
}

static inline
void BusLogic_WriteCommandParameterRegister(BusLogic_HostAdapter_T *HostAdapter,
					    unsigned char Value)
{
  outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegister);
}

static inline
unsigned char BusLogic_ReadDataInRegister(BusLogic_HostAdapter_T *HostAdapter)
{
  return inb(HostAdapter->IO_Address + BusLogic_DataInRegister);
}

static inline
unsigned char BusLogic_ReadInterruptRegister(BusLogic_HostAdapter_T
					     *HostAdapter)
{
  return inb(HostAdapter->IO_Address + BusLogic_InterruptRegister);
}

static inline
unsigned char BusLogic_ReadGeometryRegister(BusLogic_HostAdapter_T *HostAdapter)
{
  return inb(HostAdapter->IO_Address + BusLogic_GeometryRegister);
}


/*
  BusLogic_StartMailboxCommand issues an Execute Mailbox Command, which
  notifies the Host Adapter that an entry has been made in an Outgoing
  Mailbox.
*/

static inline
void BusLogic_StartMailboxCommand(BusLogic_HostAdapter_T *HostAdapter)
{
  BusLogic_WriteCommandParameterRegister(HostAdapter,
					 BusLogic_ExecuteMailboxCommand);
}


/*
  BusLogic_Delay waits for Seconds to elapse.
*/

static inline void BusLogic_Delay(int Seconds)
{
  unsigned long TimeoutJiffies = jiffies + Seconds * HZ;
  unsigned long ProcessorFlags;
  save_flags(ProcessorFlags);
  sti();
  while (jiffies < TimeoutJiffies) barrier();
  restore_flags(ProcessorFlags);
}


/*
  Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
  and PCI/VLB/EISA/ISA Bus Addresses.
*/

static inline bus_address_t Virtual_to_Bus(void *VirtualAddress)
{
  return (bus_address_t) virt_to_bus(VirtualAddress);
}

static inline void *Bus_to_Virtual(bus_address_t BusAddress)
{
  return (void *) bus_to_virt(BusAddress);
}


/*
  Define prototypes for the forward referenced BusLogic Driver
  Internal Functions.
*/

static void BusLogic_InterruptHandler(int, void *, Registers_T *);
static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *,
				     SCSI_Command_T *,
				     unsigned int);


#endif /* BusLogic_DriverVersion */
