patch-2.0.37 linux/drivers/scsi/tripace.c

Next file: linux/drivers/scsi/tripace.h
Previous file: linux/drivers/scsi/tmscsim.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/tripace.c linux/drivers/scsi/tripace.c
@@ -0,0 +1,1562 @@
+/* tc2550.c -- Tripace TC-2550x based PCI SCSI Adapter  SCSI driver
+ * Created:D.Ravi jun 8 1998 at chennai lab of Tripace 
+ * Copyright 1998 Tripace Europe BV
+ *
+ * Driver version 1.00.000 (904)
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * 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 more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ **************************************************************************
+
+ DESCRIPTION:
+
+
+
+
+ REFERENCES USED:
+
+ 1.0 Design Kit for the Tripace TC-2550x based PCI SCSI  Adapter
+
+ 2.0 Tripace IOLAYER document.
+
+ 3.0 LINUX driver sources in /usr/linux/drivers/scsi directory.
+
+
+ ALPHA TESTERS:
+
+ 1.0 so far no external testers,only developer testing has been done.
+
+ 2.0 Testing with IBMHDD,Quantum HDD,zip drive and sony CDROM has been 
+ done.
+
+
+ NOTES ON USER DEFINABLE OPTIONS:
+
+ 1.0 The following are the command line options that are possible for the
+ TRIPACE TC-2550 PCI SCSI controller without BIOS.
+
+ tripace=fast clock,discon,sync,tag
+
+
+ The values for these four options can be either 0 or 1.
+ If fast clock is set to 1 ,then the chip uses a 60mhz clock.If ultra
+ scsi devices are used this should be set and the controller should have a
+ 60mhz crystal.
+
+ if disconnect is 1 ,then disconnect/reconnect is allowed for all scsi
+ devices connected to the controller.if it is 0 ,it is off.
+
+ sync = 1 means that synchronous negotiation will be done with scsi
+ devices.currently,though the flag is set ,the function is not implemented.
+
+ Tag = 1 means that tagged queue commands can be sent to the scsi devices.
+ This is not implemnted as yet in the driver. 
+
+ The default values are 0,1,1,1
+
+ **************************************************************************/
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/head.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+#include "tripace.h"
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "tripace_mcode.h"
+
+#define VERSION          "$Revision: 1.00 $"
+
+/* #define DEBUG */
+
+
+#define   MAXTARGET               8
+#define   MAXSRBS		  16
+
+#define   RISC_ENTRY1             0
+
+#define   DEV_PARAM_REG_BASE      CFG_BASE+0x20
+
+#define   SCSI_DMA_POINTER        CFG_BASE+0x40
+#define   SCSI_DMA_COUNTER        CFG_BASE+0x44
+#define   HOST_DMA_POINTER        CFG_BASE+0x48
+#define   HOST_DMA_COUNTER        CFG_BASE+0x4c
+#define   MBX_IN_BASE             CFG_BASE+0x50
+#define   MBX_OUT_BASE            CFG_BASE+0x54
+#define   DEV_HDR_BASE            CFG_BASE+0x58
+#define   TASK_Q_BASE             CFG_BASE+0x5c
+#define   CURRENT_DEV_PTR         CFG_BASE+0x60
+#define   CURRENT_TASK_PTR        CFG_BASE+0x64
+#define   SG_LIST_PTR             CFG_BASE+0x68
+#define   ACC                     CFG_BASE+0x6c
+#define   SCRATCHB                CFG_BASE+0x70
+#define   CURRENT_INST            CFG_BASE+0x74
+#define   FLAG                    CFG_BASE+0x78
+#define   SCRATCHC                CFG_BASE+0x7a
+#define   MBX_IN_INDEX            CFG_BASE+0x7b
+#define   PC                      CFG_BASE+0x7c
+#define   MBX_OUT_INDEX           CFG_BASE+0x7f
+#define   PROGRAM_DATA_REG        CFG_BASE+0x80
+#define   CONTROL_REG             CFG_BASE+0x84
+#define   STATUS_INT_REG          CFG_BASE+0x86
+#define   SCSI_DATA               CFG_BASE+0x88
+#define   SCSI_CONTROL            CFG_BASE+0x8A
+#define   SCSI_ID_REG             CFG_BASE+0x8b
+
+#define   INFO_BASE               0x780
+#define   SIG_BASE                0x7D4
+
+#define   Q_FILE_SIZE             8192
+#define   DEVHDR_SIZE              512
+#define   MBOX_SIZE                 48
+#define   BIOS_SIGNATURE          0x55AAC731
+
+#define   PCI_1                   1
+#define   PCI_2                   2
+#define   MAX                     28
+
+#define   PCI_BUS                 1
+#define   PCI_INDEX_PORT          0xCF8
+#define   PCI_INDEX               0xF0
+#define   PCI_CONFIG              0xC000  /* this needs to include slot number */
+
+#define   FAIL                   -1
+/* #define   GOOD                 0 */
+#define   ERR                     1
+#define   DONE                    2
+#define   INT_HALT             0xfe000000	/* interrupt code */
+
+#define   SRB_DONE                0
+#define   SRB_ACTIVE              2
+#define   SRB_READY               1
+#define   SRB_CLEAN               4
+#define   SRB_ASSIGNED            8
+#define   SRB_STOP                2
+
+#define   STOP_RISC               2
+#define   FIRST_CMD               1
+#define   SPECIAL_CMD             1
+#define   MAX_OFFSET             30
+/* #define   MAX_PERIOD             12 */
+#define   MAX_PERIOD             12
+#define   W_MAX_OFFSET           14
+
+/* msg */
+#define   CMD_ABORT              0x6
+#define   DEVICE_RESET           0xC
+
+
+#define   CHECK_SYNC             0xA
+#define   CHECK_WIDE             0xD
+#define   SYNC_NORESPONSE        0x8
+#define   SYNC_REJECTED          0x9
+#define   SEL_TIME_OUT	         0x11
+#define   ERR_OVERRUN		 0x12
+#define   ERR_BUSFREE		 0x13
+#define   ERR_PHASE		 0x14
+#define   CHECK_COND		 0x04
+#define   ERR_PARITY  		 0x05
+#define   ERR_MESSAGE 		 0x07
+#define   WIDE_NORESPONSE        0x0b
+#define   WIDE_REJECTED          0x0c
+
+
+#define   DO_WIDE_NEGO           0x02
+#define   DO_SYNC_NEGO           0x04
+#define   FIRST_COMMAND          0x01
+
+#define   ENABLE_WIDE_BUS        0x100
+#define   ENABLE_TAG_MSG         0x200
+
+/*---------------------------------------------------------*
+**  parameter in register definitions                      *
+**                                                         *
+**---------------------------------------------------------*/
+/*
+   status register (read only)
+ */
+#define      INTR_PENDING         0x01
+#define      INTR_DIS             0x02
+#define      SCAM_INTR_DIS        0x04
+#define      POWER_SAVE_ON        0x08
+#define      SCSI_RESET_OUT       0x10
+#define      SCAM_INTR            0x20
+#define      RISC_HALT            0x40
+#define      SELECTION_TIMEOUT    0x80
+#define      SCSI_PARITY_ERR      0x100
+#define      SCSI_RESET_LAT       0x200
+#define      STS_SCSI_RESET       0x400
+#define      EEPROM_IN            0x800
+#define      SCAM_ARB_WIN         0x1000
+#define      EN_DMA               0x2000
+#define      EN_ARB_SEL           0x4000
+/*
+   **   interrupt control register (write only)
+ */
+#define      RESET_INTR_LATCH     0x01
+#define      DIS_INTR             0x02
+#define      DIS_SCAM_INTR        0x04
+#define      POWER_SAVE           0x08
+#define      RESET_SCSI_BUS       0x10
+/*ravi 10/3/98 changed for term power disable/enable in command line */
+/*#define      EN_TERM_PWR          0x20 */
+#define      TERM_PWR_EN            0x20
+/*
+   **   control register ( read/write )
+ */
+#define      RISC_CHIP_RESET      0x01
+#define      RISC_SINGLE_SETP     0x02
+#define      HALT_RISC            0x04
+#define      EN_SCSI_SCAM         0x08
+#define      DIS_SCSI_PARITY      0x10
+#define      EN_TARGET_MODE       0x20
+#define      FAST_CLOCK           0x40
+#define      EN_MEMORY_WRITE      0x80
+#define      DIS_PCI_BURST        0x100
+#define      DIS_PCI_CACHE_LINE   0x200
+#define      DIS_MUL_CACHE_LINE   0x400
+#define      EEPROM_CLOCK         0x800
+#define      EEPROM_DATA_OUT      0x1000
+#define      EEPROM_CHIP_SEL      0x2000
+#define      FAST_SELECTION       0x4000
+#define      EN_SCAM_ARB          0x8000
+
+#define      TASK_DONE            0x80
+
+
+/***************************************************************************
+**	 filename: newtypes.h
+**	 usage   : type definition 
+****************************************************************************/
+
+
+/***************************************************************************
+**	 filename: newtypes.h
+**	 usage   : type definition 
+****************************************************************************/
+
+#define   MAX_Adapter   4	/* maximu adapters allow                */
+
+/*
+   **   command related structure (7 bytes)
+ */
+typedef struct _task_cmd
+{
+	u8 CmdInProcess;
+	u8 * REQ_Header;
+	void (*complete) (void);
+}
+TaskCmd, *PTaskCmd;
+
+/*
+   ** total 128 bytes
+ */
+typedef struct _HIM
+{
+	u8 status;		/* device status, 0xFF not installed    */
+	u8 Target_ID;		/* target ID                            */
+	u8 type;		/* target type mapped to device name    */
+	u16 attrib;		/* lo 4bit: 1-Wide, 2-Sync, 4-Tag,      */
+	/*          8-removable,                */
+	/* hi 4bit: 10h do wide, 20h do sync,   */
+	/*          40h do tag, 0x80h - disc    */ 
+	/* bit 15: under BIOS, bit 8: > 1GB     */
+	 u8 op_param;		/* bit 7-5:period, bit4-0:offset        */
+	u8 drv_num;		/* current ID --> 8x for BIOS used only */
+	u8 sect_per_track;	/* sector per track                     */
+	u8 head_per_cyl;	/* sector per track                     */
+	u8 byte_per_sect;	/* byte per sector (BIOS is 512)        */
+	u8 link_count;	/* SRB link count:                      */
+	u8 * ASPICMDLink;	/* SRB link starting pointer            */
+	TaskCmd task[16];	/* array structure for each task        */
+	
+}
+DEVStruct;
+
+/*
+   ** total (4K+ 36) bytes for each adapter 
+ */
+typedef struct _Adapter
+{
+	u16 IoPort;		/* I/O Port address, 0 notsupport       */
+	u8 AdapterID;		/* Adapter scsi ID, default = 7         */
+	u8 first_disk_num;	/* first disk number under BIOS (82->2) */
+	u8 last_disk_num;	/* last disk number under BIOS          */
+	u8 time_factor;	/* used for device scam                 */
+
+	u8 IntrNum;		/* -1 NotSupport, otherwise IRQ         */
+	u16 hw_attr;		/* see eeprom def                       */
+	u16 sw_attr;		/* see eeprom def                       */
+	DEVStruct dev[16];	/* target device structure              */
+	u16 mbx_out_ptr;	/* mail box out pointer                 */
+	u8 HAParam[16];	/* host adapter parameters              */
+	u8 bios_install;	/* adapter has BIOS installed           */
+	u16 scam_type;		/* scam use              */
+	u8 scam_assigned;	/* scam use              */
+	u8 * Signature;	/* BIOS signature & new manager address */
+	u32 mbx_in_base;	/* mbx in base  logical address    */
+	u32 mbx_out_base;	/* mbx out base logical address    */
+	u32 devhdr_base;	/* devhdr base logical address     */
+	u32 taskq_base;	/* taskq base  logical address     */
+	u32 ptaskq_base;	/* taskq base physical address     */
+	u32 pdev_base;		/* taskq base physical address     */
+	u32 pmbi_base;		/* taskq base physical address     */
+	u32 pmbo_base;		/* taskq base physical address     */
+}
+Adapter, *PAdapter;
+
+/*
+   **  adapter information structure reserved for BIOS usage
+ */
+
+typedef struct _dev_parm
+{
+	u8 header;		/* header             */
+	u8 sect_per_track;	/* sector per tarck   */
+}
+target_parm, *ptarget_parm;
+/*
+   **  This structure is for BIOS used and read by driver
+ */
+typedef struct _Ada_data
+{
+	u8 drv_start;		/* first drive           */
+	u8 drv_end;		/* last drive            */
+	u16 timfact;		/* timing factor         */
+	u32 old_int13;		/* old int13 addr        */
+	u8 drive_id[8];	/* index= (8x-drv_start) */
+	u8 drive_num[16];	/* device number         */
+	target_parm dev[16];	/* device parameters     */
+	u8 allow_discon[16];	/* disconnect record     */
+	u16 scam_type;		/* scam use              */
+	u8 scam_assigned;	/* scam use              */
+	u8 adapter_id;	/* scam use              */
+	u32 signature;		/* BIOS signature        */
+}
+HA_data, *PHA_data;
+
+
+typedef struct _ScatGath
+{
+	u32 sg_address;	/* must be physical address */
+	u32 sg_length;		/* sg length     */
+}
+ScatGath, *PScatGath;
+
+/* length must be 32 bytes */
+typedef struct _risc_srb
+{
+	u8 Tag_info;		/* Tag information */
+	u8 SRB_flag;		/* SRB flag */
+	u8 DEV_Status;	/* SRB status */
+	u8 ScsiStatus;	/* scsi command status */
+	u32 CDB;		/* SCSI Command Block */
+	u32 CDBLength;		/* SCSI Command Length */
+	u32 SenseDataPtr;	/* auto sense pointer */
+	u32 Sense_Cmd_Ptr;	/* auto sense pointer */
+	u32 SG_ListPtr;	/* SG list  */
+	u8 SGNum;		/* S/G number */
+	u8 Identify;		/* Identify  message */
+	u8 Sense_LUN;		/* lun               */
+	u8 Sense_len;		/* sense len         */
+	u32 Cmd_sg_addr;	/* cmr sg ptr point to cmd */
+}
+RISC_SRB, *PRISC_SRB;
+
+
+typedef struct _SRB
+{				/* for SCSI */
+	RISC_SRB *risc_srb;	/* structure of SRB in RISC */
+	PAdapter AdapterPtr;	/* a pointer to adapter structure */
+	u8 LUN;		/* lun number */
+	u8 Tag_type;		/* tag type */
+	u8 Request_type;	/* request type */
+}
+SRB, *PSRB;
+
+typedef struct _sync_tbl
+{
+	int period;		/* parameter setting  */
+	int f_factor;		/* fast clock factor  */
+	int s_factor;		/* slow clock factor  */
+}
+sync_tbl;
+
+/*
+   **  total 12 bytes of sg header 
+ */
+typedef struct _dma_hrd
+{
+	u32 size;		/* region size        */
+	u32 offset;		/* offste             */
+	u16 segment;		/* segment            */
+	u16 revsed;		/* reserved           */
+	u16 num_avail;		/* number available   */
+	u16 num_used;		/* number used        */
+}
+DMA_HDR;
+
+/*
+   **  total 60 bytes (for each task in windows)
+ */
+typedef struct _dma_desc
+{
+	DMA_HDR dma_hdr;
+	ScatGath sg_list[6];
+}
+dma_desc, *Pdma_desc;
+
+/* Flags */
+#define SRB_TOHOST    8
+#define SRB_TOTARGET  0x10
+#define SRB_NEEDSDT   0x20
+#define SRB_SENSE     0x40	/* only for OSD      */
+#define SIZE_OF_SG    0x3C	/* size of sg table (60 bytes)  */
+
+/* 2. Target Error == SCSI Status */
+
+/* ============ function definiton ============ 
+   ** 1. INPUT:  PSRB
+   **    Start a scsi command. 
+   * */
+static void StartScsiCmd(PRISC_SRB);
+
+#define  CMD_INPROGRESS      0x01
+#define  CMD_DISCONCTED      0x02
+#define  CMD_DATAXFERED      0x04
+
+#define  TAR_TRUESG          0x01
+#define  NEEDSDTN            0x10
+
+#define  MSG_ABORT           0x06
+#define  MSG_RESET           0x0C
+#define  MSG_ALLOWDISC       0x40
+#define  MSG_IDENTIFY        0x80
+#define  MSG_EXTENDED        0x01
+#define  MSG_NOMSG           0x08
+#define  MSG_CMDCOMP         0x00
+#define  MSG_DISC            0x04
+#define  MSG_IGNWR           0x23
+#define  MSG_RESTPTR         0x03
+#define  MSG_SAVEPTR         0x02
+#define  MSG_REJECTED        0x07
+#define  MSG_INITRECVY       0x0f
+#define  MSG_LNKCMD          0x0a
+#define  MSG_LNKCMDTAG       0x0b
+#define  MSG_SIMPLEQUE       0x20
+#define  MSG_MDFDATPTR       0x00
+#define  MSG_SDTREQ          0x01
+#define  MSG_WDTREQ          0x03
+
+#define  SECOND              18	//ticks per second
+#define  DEV_EMPTY           0xFF
+
+typedef struct _DEVHDR
+{
+	u32 Updatedmap;	/* updated bitmap      */
+	u32 Startedmap;	/* start bitmap        */
+	u32 Currentmap;	/* current bitmap      */
+	u8 Task_Index;	/* current task index  */
+	u8 Request_type;	/* request type        */
+	u8 SpCmddone;		/* special commad done */
+	u8 Srb_loc;		/* location            */
+	u8 TagCmdCnt;		/* Pending task count  */
+	u8 ScsiID;		/* scsi ID             */
+	u8 DeviceNum;		/* device number       */
+	u8 WideMsg;		/* wide bus message    */
+	u8 SyncPeriod;	/* sync period         */
+	u8 SyncOffset;	/* sync offset         */
+	u8 RtnWideMsg;	/* return wide bus msg */
+	u8 RtnSyncPeriod;	/* Rtn sync period     */
+	u8 RtnSyncOffset;	/* rtn sync offset     */
+	u8 ChkSenseTask;	/* check sense task    */
+	u8 SenseCmd[6];	/* sense command       */
+}
+DevHdr, *PDevHdr;
+
+typedef struct _E2Prom
+{
+	u16 hw_parm;
+	u16 sw_parm;
+	u16 dev_parm[16];
+}
+E2prom, *PE2prom;
+
+/* parameter setting for parameter */
+#define		HW_ADAPTER_ID            0x0f
+#define		HW_PARITY_DISABLE        0x10
+#define		HW_TERMPWR_ENABLE        0x20
+#define		HW_FAST_CLOCK            0x40
+#define		HW_DIAG_ENABLE           0x80
+#define		HW_BURST_DISABLE         0x100
+#define		HW_CACHE_LINE_DISABLE    0x200
+#define		HW_MULTI_CACHE_DISABLE   0x400
+#define		HW_SCAM_ENABLE           0x800
+#define		HW_CACHE_LINE_SIZE_4	  0x1000
+#define		HW_CACHE_LINE_SIZE_8	  0x2000
+#define		HW_CACHE_LINE_SIZE_16	  0x3000
+#define		HW_FAST_SELECTION        0x4000
+#define		HW_BIOS_DISABLE          0x8000
+
+
+/* software setting      */
+#define		SW_REMOVABLE_SUPPORT     0x1
+#define		SW_OVER_1GB              0x2
+#define		SW_8_DRIVE_SUPPORT       0x4
+#define		SW_MAX_ID		 0x8
+#define		SW_DEVICE_CHANGED        0x10
+
+/* parameter setting     */
+#define		PM_UNDER_BIOS            0x8000
+#define		PM_BIOSSCAN_DISABLE      0x2000
+#define		PM_NEED_STARTCMD         0x1000
+#define		PM_DISCON_ENABLE         0x800
+#define		PM_SYNC_ENABLE           0x400
+#define		PM_TAG_ENABLE            0x200
+#define		PM_WIDEBUS_ENABLE        0x100
+#define		PM_TRANSFER_RATE         0xE0
+#define		PM_TRANSFER_OFFSET       0x1F
+
+/* ScsiFunc  */
+#define		SUPPORT_MORETHAN16M  0x40
+#define		SUPPORT_RESELECT     0x20
+#define		SUPPORT_SYNC         0x10
+#define		SUPPORT_LINKED       0x08
+#define		SUPPORT_CMDQUEUE     0x02
+#define		SUPPORT_SFTRE        0x01
+#define		SUPPORT_WIDEHOST     0x04
+#define		SUPPORT_PARCHK       0x80
+
+
+static unsigned int port_base = 0;
+static unsigned int CFG_BASE = 0;
+static unsigned int interrupt_level = 0;
+
+/* period table 
+
+   static sync_tbl  period_tbl[8]= {
+   { 0, 12, 12,},
+   { 1, 16, 18,},
+   { 2, 20, 25,},
+   { 3, 25, 31,},
+   { 4, 29, 37,},
+   { 5, 33, 43,},
+   { 6, 50, 50,},
+   { 7, 58, 75,},
+   };
+ */
+
+/* pointer to scsi host struc for each HA */
+/* needs change for multiple HA support */
+
+static struct Scsi_Host *tripace_host;
+
+/* Tc2550 mailbox data structures */
+static unsigned char tcmbdata[Q_FILE_SIZE + DEVHDR_SIZE + MBOX_SIZE + 64];
+/* static alloc of sg table for all tasks */
+/* dynamic memory is giving problems */
+static unsigned char table[8 * MAXSGENT * MAXSRBS * MAXTARGET + 4];
+
+
+/* global variables */
+/* logical addresses of mailbox in/out,dev header base,task que base */
+
+static unsigned char *startsgptr;
+static unsigned long pstartsgptr;
+
+
+static u32 mbx_in_base, mbx_out_base, devhdr_base, taskq_base;
+static u8 TargetID;
+
+
+/* hostadapter structure-as of now we have a single adapter */
+Adapter HostAdapter[1];
+unsigned char ReqType, targetID, HANumber, Index, HostID;
+
+/* variable for term power in case of /T option */
+static unsigned short int EN_TERM_PWR = TERM_PWR_EN;
+static unsigned short fast_clk = 0;
+static unsigned short par_off = 0;
+static unsigned short discon = 1;
+static unsigned short syncflag = 1;
+static unsigned short tagflag = 0;
+
+
+static int makecode(unsigned, unsigned);
+static void Init_struc(int);
+static int download_RISC_code(void);
+static void init_chip_reg(void);
+
+static PRISC_SRB search(PAdapter);
+u32 insert_bit(u32, short int);
+static void Get_Base(Adapter *);
+
+void tc2550_intr(int, void *, struct pt_regs *);
+
+static void internal_done(Scsi_Cmnd *);
+
+int tc2550_command(Scsi_Cmnd *);
+
+static int tc2550_pci_bios_detect(int *irq, int *iobase)
+{
+	int error;
+	unsigned char pci_bus, pci_dev_fn;	/* PCI bus & device function */
+	unsigned char pci_irq;	/* PCI interrupt line */
+	unsigned int pci_base;	/* PCI I/O base address */
+	unsigned short pci_vendor, pci_device;	/* PCI vendor & device IDs */
+
+
+	/* We will have to change this if more than 1 PCI bus is present and the
+	   tripace scsi host is not on the first bus (i.e., a PCI to PCI bridge,
+	   which is not supported by bios32 right now anyway). */
+
+	pci_bus = 0;
+
+	for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++)
+	{
+		pcibios_read_config_word(pci_bus,
+					 pci_dev_fn,
+					 PCI_VENDOR_ID,
+					 &pci_vendor);
+
+		if (pci_vendor == 0x1190)
+		{
+			pcibios_read_config_word(pci_bus,
+						 pci_dev_fn,
+						 PCI_DEVICE_ID,
+						 &pci_device);
+
+			if (pci_device == 0xc731)
+			{
+				/* Break out once we have the correct device.  If othertrip 
+				   PCI devices are added to this driver we will need to add
+				   an or of the other PCI_DEVICE_ID here. */
+				printk(KERN_INFO "Tripace TC-2550x based PCI SCSI Adapter detected\n");
+				break;
+			} else
+			{
+				/* If we can't finl an tripace scsi card we give up. */
+				return 0;
+			}
+		}
+	}
+
+/* vendor id not found */
+
+	if (pci_device != 0xc731)
+	{
+		printk(KERN_INFO "Tripace TC-2550x - No Host Adapter Detected \n");
+		return (0);
+	}
+	/* We now have the appropriate device function for the tripace board so we
+	   just read the PCI config info from the registers.  */
+
+	if ((error = pcibios_read_config_dword(pci_bus,
+					       pci_dev_fn,
+					       PCI_BASE_ADDRESS_0,
+					       &pci_base))
+	    || (error = pcibios_read_config_byte(pci_bus,
+						 pci_dev_fn,
+						 PCI_INTERRUPT_LINE,
+						 &pci_irq)))
+	{
+		printk(KERN_ERR "Tripace TC-2550x not initializing"
+		       " due to error reading configuration space\n");
+		return 0;
+	} else
+	{
+		printk(KERN_INFO "TC-2550x PCI: IRQ = %u, I/O base = %X\n",
+		       pci_irq, pci_base);
+
+		/* Now we have the I/O base address and interrupt from the PCI
+		   configuration registers.  
+		 */
+
+		*irq = pci_irq;
+		*iobase = (pci_base & 0xfff8);
+		CFG_BASE = *iobase;
+
+		printk(KERN_INFO "TC-2550x Driver version 1.00.000 (904)\n");
+		printk(KERN_INFO "TC-2550x: IRQ = %d, I/O base = 0x%X\n", *irq, *iobase);
+		return 1;
+	}
+	return 0;
+}
+
+static void init_chip_reg(void)
+{
+	int i, val, base;
+	unsigned long tick;
+
+	outw(HALT_RISC, CONTROL_REG);
+	base = CFG_BASE + 0x20;
+	for (i = 0; i < 16; i++)
+		outw(0, base + i * 2);
+	outw(EN_TERM_PWR, STATUS_INT_REG);
+	outw(RESET_SCSI_BUS, STATUS_INT_REG);
+
+	udelay(50);		/*wait for 50 micro secs */
+
+	outw(EN_TERM_PWR, STATUS_INT_REG);
+	val = (HALT_RISC | RISC_CHIP_RESET);
+	outw(val, CONTROL_REG);
+	outw(HALT_RISC, CONTROL_REG);
+	val = inw(STATUS_INT_REG);
+	tick = 0;
+	while ((val & 0x40) == 0 && tick < 0x3fff)
+	{
+		val = inw(STATUS_INT_REG);
+		tick += 1;
+	};
+	if (tick == 0x3fff)
+		printk(KERN_DEBUG "val= %x  \n\r", val);
+	outw(EN_TERM_PWR, STATUS_INT_REG);
+	outw(0, SCSI_CONTROL);
+
+/* delay for 50 micro secs */
+	udelay(50);
+}
+
+static int download_RISC_code(void)
+{
+	unsigned short i, j, fast = 0;
+	unsigned short hi, low, base;
+	long tmp;
+	unsigned long start_time;
+
+	i = inw(CONTROL_REG);
+	if (i & 0x40)
+		fast = 1;
+	outw(HALT_RISC, CONTROL_REG);
+
+/* Ravi modified for sanity check dec 17 1998 */
+	start_time = jiffies;
+
+	do
+	{
+		if ((jiffies - start_time) > 5 * HZ)
+		{
+			printk(KERN_ERR "tc2550: Download failure.\n");
+			return 1;
+		}
+		i = inw(STATUS_INT_REG);
+	}
+	while ((i & 0x40) == 0);
+
+	outw(HALT_RISC + EN_MEMORY_WRITE, CONTROL_REG);
+	outw(EN_TERM_PWR + DIS_INTR, STATUS_INT_REG);
+
+	/*  download load RISC code
+	 */
+	outw(0, PC);
+	for (i = 0; i < ucode_size; i++)
+		outl(ucode_instruction[i], CURRENT_INST);
+	/*
+	   //  checksum checking (word)
+	 */
+	base = 0;
+	for (i = 0; i < ucode_size; i++)
+	{
+		outw(i * 4, PC);
+		tmp = inl(PROGRAM_DATA_REG);
+		hi = tmp >> 16;
+		low = (tmp & 0xffff);
+		base = base + (hi + low);
+	}
+	outw(HALT_RISC + RISC_CHIP_RESET, CONTROL_REG);
+	outw(HALT_RISC, CONTROL_REG);
+	if (fast_clk)
+		outw((HALT_RISC | FAST_CLOCK), CONTROL_REG);
+	if (par_off)
+	{
+		i = inw(CONTROL_REG);
+		outw((i | DIS_SCSI_PARITY), CONTROL_REG);
+	}
+	outw(EN_TERM_PWR, STATUS_INT_REG);
+	/*ravi
+	 */
+	if ((unsigned short) (ucode_checksum + base) != 0)
+	{
+		printk(KERN_ERR "tc2550: Checksum Error During Code Download\n");
+		return (1);
+	};
+	/*
+	   load vector table
+	 */
+	j = 0;
+	base = CFG_BASE;
+	for (i = 0, j = 0; i < 15; i++, j = j + 2)
+		outw(ucode_vector[i], (base + j));
+	outw(0, SCSI_CONTROL);
+	return (0);
+}
+
+int tc2550_detect(Scsi_Host_Template * tpnt)
+{
+	int flag = 0;
+	int retcode;
+	struct Scsi_Host *shpnt;
+	unsigned long flags;
+	unsigned int mod4;
+
+
+	flag = tc2550_pci_bios_detect(&interrupt_level, &port_base);
+	if (!flag)
+		return (0);
+
+	init_chip_reg();	/* chip Tc-2550 initialize */
+	flag = download_RISC_code();
+	if (flag == 0)
+	{
+		printk(KERN_INFO "tc2550: Successful F/W download on TC-2550x\n");
+	}
+/* now do a scsi register and get scsi host ptr */
+
+	shpnt = scsi_register(tpnt, 0);
+
+	save_flags(flags);
+	cli();
+	retcode = request_irq(interrupt_level,
+			      tc2550_intr, SA_INTERRUPT, "tripace", NULL);
+	if (retcode)
+	{
+		printk(KERN_ERR "tc2550: Unable to allocate IRQ for Tripace TC-2550x based SCSI Host Adapter.\n");
+		goto unregister;
+	}
+	/* For multiple HA we need to change all this */
+
+
+	tripace_host = shpnt;
+	shpnt->io_port = CFG_BASE;
+	shpnt->n_io_port = 0xfc;	/* Number of bytes of I/O space used */
+	shpnt->dma_channel = 0;
+	shpnt->irq = interrupt_level;
+
+	restore_flags(flags);
+
+
+	/* log i/o ports with the kernel */
+	request_region(port_base, 0xfc, "tripace");
+
+/* when we support multiple HA ,we need to modify */
+	Init_struc(0);		/* init mailboxes for one adapter */
+/* sg table init */
+
+	/*  get physical address */
+	startsgptr = (unsigned char *) table;
+	pstartsgptr = virt_to_phys((unsigned char *) table);
+	mod4 = pstartsgptr % 4;
+	if (mod4)
+	{
+		pstartsgptr += (4 - mod4);
+		startsgptr += (4 - mod4);
+	}
+	return (0);
+
+
+unregister:
+	scsi_unregister(shpnt);
+	return (0);
+}
+
+/****************************************************************************
+**   Init chip registers and allocate required memory space
+****************************************************************************/
+
+static void Init_struc(int id)
+{
+	u32 pmbx_in_base, pmbx_out_base, pdevhdr_base, ptaskq_base;
+	unsigned long paddr;
+	char *laddr;
+	unsigned short modulo;
+
+/* setup ioport address and irq */
+
+	HostAdapter[id].IoPort = (u16) CFG_BASE;
+	HostAdapter[id].IntrNum = (u8) interrupt_level;
+
+	laddr = tcmbdata;
+	paddr = virt_to_phys(tcmbdata);
+/* adjust phys address to 32 byte boundary */
+	modulo = paddr % 32;
+	if (modulo)
+	{
+		paddr = paddr + 32 - modulo;
+		laddr = laddr + 32 - modulo;
+	}
+	/*  logical address  */
+	mbx_in_base = (u32) laddr;
+	pmbx_in_base = paddr;
+	HostAdapter[id].mbx_in_base = mbx_in_base;
+
+	laddr += 32;
+	paddr += 32;
+	mbx_out_base = (u32) laddr;
+	pmbx_out_base = paddr;
+	HostAdapter[id].mbx_out_base = mbx_out_base;
+	memset((char *) mbx_in_base, 0, 48);
+
+	laddr += 32;
+	paddr += 32;
+	devhdr_base = (u32) laddr;
+	pdevhdr_base = paddr;
+	HostAdapter[id].devhdr_base = devhdr_base;
+	memset((char *) devhdr_base, 0, 512);
+
+
+	laddr += 512;
+	paddr += 512;
+
+	taskq_base = (u32) laddr;
+	ptaskq_base = paddr;
+	HostAdapter[id].taskq_base = taskq_base;
+	memset((char *) taskq_base, 0, Q_FILE_SIZE);
+
+	HostAdapter[id].ptaskq_base = (u32) ptaskq_base;
+	HostAdapter[id].pdev_base = (u32) pdevhdr_base;
+	HostAdapter[id].pmbi_base = (u32) pmbx_in_base;
+	HostAdapter[id].pmbo_base = (u32) pmbx_out_base;
+
+	outl(pmbx_in_base, MBX_IN_BASE);
+	outl(pmbx_out_base, MBX_OUT_BASE);
+	outl(pdevhdr_base, DEV_HDR_BASE);
+	outl(ptaskq_base, TASK_Q_BASE);
+	outb(0, MBX_IN_INDEX);
+	outb(0, MBX_OUT_INDEX);
+	/* clear mailbox out pointer */
+	HostAdapter[id].mbx_out_ptr = 0;
+}
+
+
+/***************************************************************************
+**   adjust bitmap position
+**   Input : old bitmap,  new bit location 
+**   Output: return with new  bitmap layout
+****************************************************************************/
+
+extern __inline__ u32 insert_bit(u32 bits, short int loc)
+{
+	u32 lo = 0;
+
+	lo = 1;
+	lo <<= loc;
+
+
+	return ((lo | bits));
+}
+
+
+/***************************************************************************
+**   Get the base address and structures of current host adapter
+**   Input  : adapter structure pointer
+**   Output : none
+****************************************************************************/
+
+static void Get_Base(Adapter * padapter)
+{
+
+	CFG_BASE = padapter->IoPort;
+	interrupt_level = (u16) padapter->IntrNum;
+	mbx_in_base = padapter->mbx_in_base;
+	mbx_out_base = padapter->mbx_out_base;
+	devhdr_base = padapter->devhdr_base;
+	taskq_base = padapter->taskq_base;
+
+}
+
+
+
+/***************************************************************************
+**  name   : search()
+**  Desc   : search an available SRB from taskQ
+**  Input  : adapter structure pointer
+**  Output : 1. a risc structure space pointer or 0 for non available
+**           2. index of task location
+****************************************************************************/
+static PRISC_SRB search(PAdapter pa)
+{
+	PRISC_SRB rsrb;
+	short int i;
+	unsigned long flags;
+
+	Get_Base(pa);
+	rsrb = (PRISC_SRB) (taskq_base + TargetID * 16 * sizeof(RISC_SRB));
+	/* check attrib in case drive doesn't support SYNC xfer */
+
+	if ((pa->dev[TargetID].attrib & DO_SYNC_NEGO) == 0)
+		ReqType = 0;
+	save_flags(flags);
+	cli();
+
+	Index = 0;
+	for (i = 0; i < 16; i++, rsrb++)
+		if (rsrb->SRB_flag == SRB_DONE)
+			break;
+	if (i == 16)
+	{
+		restore_flags(flags);
+		return (0);
+	}
+	Index = i;
+	restore_flags(flags);
+	memset((char *) rsrb, 0, 32);
+	rsrb->SRB_flag = SRB_ASSIGNED;	/* mark for use */
+	if ((pa->dev[TargetID].attrib & 0x44) == 0x44)
+		rsrb->Tag_info = 0x20;
+	return (rsrb);
+}
+
+/***************************************************************************
+**  Name   : StartSCSICmd()
+**  func   : 1. all commands passed through here are regular
+**           2. fill in device structure bitmap && start RISC
+**  Input  : risc srb structure, Index, ReqType
+**  Output : none
+****************************************************************************/
+static void StartScsiCmd(PRISC_SRB rsrb)
+{
+	DevHdr *dev;
+	u16 status;
+	PAdapter pa;
+	unsigned short val;
+	u8 t, find_id, find_last, ch = 0;
+	char *mptr;
+/* Request sense CDB */
+	char RequestSense[6] =
+	{0x03, 0x00, 0x00, 0x00, 0x0e, 0};
+
+	pa = (PAdapter) & HostAdapter[HANumber];
+	pa->dev[TargetID].task[Index].CmdInProcess = 1;		/* command in process */
+	dev = (DevHdr *) (devhdr_base + TargetID * sizeof(DevHdr));
+	dev->Srb_loc = Index;
+	dev->Request_type = ReqType;	/* set request type */
+	dev->Updatedmap = insert_bit(dev->Updatedmap, Index);
+	for (val = 0; val < 6; val++)
+		dev->SenseCmd[val] = RequestSense[val];
+	rsrb->Sense_Cmd_Ptr = virt_to_phys(&dev->SenseCmd[0]);
+
+	if (ReqType >= 2)
+	{
+		if (ReqType & 0x2)
+			dev->WideMsg = 0x1;
+		else
+		{
+/*        printf("firing sync nego");
+   //ravi 10/3/98 -ultra support in parse 
+
+   if(fast_clk)
+   dev->SyncPeriod =   period_tbl[(ultra[TargetID])].f_factor;
+   else
+   dev->SyncPeriod =   period_tbl[(ultra[TargetID])].s_factor;
+ */
+
+			if (pa->dev[TargetID].attrib & 0x1)
+				dev->SyncOffset = W_MAX_OFFSET;
+			else
+				dev->SyncOffset = MAX_OFFSET;
+		}
+	}
+	mptr = (char *) mbx_in_base;
+	find_id = 0xff;
+	find_last = 0xff;
+	for (t = 0; t < 15; t++)
+	{
+		ch = *mptr++;
+		if ((ch & 0xf) == TargetID)
+		{
+			find_id = t;
+			break;
+		}
+	}
+
+	mptr = (char *) mbx_in_base;
+	for (t = 0; t < 15; t++)
+	{
+		ch = *mptr++;
+		if (ch & 0x80)
+		{
+			find_last = t;
+			break;
+		}
+	}
+	val = inw(STATUS_INT_REG);
+	mptr = (char *) mbx_in_base;
+	if (find_id != 0xff && find_last != 0xff)
+	{
+		if (find_id < find_last)
+			*(char *) (mptr + find_id) |= 0x10;
+		else
+		{
+			*(char *) (mptr + find_last) &= 0x7f;
+			*(char *) (mptr + find_id) |= 0x90;
+		}
+	} else if (find_last != 0xff && find_id == 0xff)
+	{
+		*(char *) (mptr + find_last) &= 0x7f;
+		find_last = find_last + 1;
+		*(char *) (mptr + find_last) = (0x90 | TargetID);
+	} else if (find_last == 0xff)
+		*(char *) mptr = (0x90 | TargetID);
+
+
+	ReqType = 0;
+	/*
+	   //  restart the RISC if it is halted before
+	 */
+
+	rsrb->SRB_flag = SRB_READY;
+
+
+	if (val & RISC_HALT)
+	{
+		outw(ucode_start, PC);	/* set pc counter */
+		status = inw(CONTROL_REG);	/* clear halt status */
+		outw((status & ~HALT_RISC), CONTROL_REG);
+	}
+#ifdef DEBUG
+	printk(KERN_DEBUG " start scsi issued \n");
+#endif
+
+}
+
+static void internal_done(Scsi_Cmnd * SCpnt)
+{
+	SCpnt->SCp.Status++;
+}
+
+int tc2550_command(Scsi_Cmnd * SCpnt)
+{
+	tc2550_queue(SCpnt, internal_done);
+
+	SCpnt->SCp.Status = 0;
+	while (!SCpnt->SCp.Status)
+		barrier();
+	return SCpnt->result;
+}
+
+int tc2550_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+
+	PAdapter pa;
+	PRISC_SRB rsrb;
+	int val;
+	struct scatterlist *sgpnt;
+
+
+	ScatGath *riscsgptr;
+
+
+	int i;
+	unsigned int nentries;
+
+	pa = (PAdapter) & HostAdapter[HANumber];
+	Get_Base(pa);
+	val = 0xaa;
+	TargetID = SCpnt->target;
+	HostID = 7;
+	/* the following code is for corel compatibility */
+	if (SCpnt->lun != 0 ||
+	    (TargetID == HostID))
+	{
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return (0);
+	};
+	/* Error if more than 16 tasks /target if no space is available  */
+
+	if ((rsrb = search(pa)) == 0)
+	{
+		SCpnt->result = DID_ERROR << 16;
+		done(SCpnt);
+		return (0);
+	};
+
+/*Ravi -modified for hostid 16/12/98 */
+	outb((u8) ((TargetID << 4) | HostID), SCSI_ID_REG);
+
+
+	rsrb->CDBLength = SCpnt->cmd_len;
+/* get the physical address of CDB */
+	rsrb->CDB = virt_to_phys((unsigned char *) SCpnt->cmnd);
+
+
+	if (discon)
+
+		rsrb->Identify = 0xC0;
+	else
+		rsrb->Identify = 0x80;
+
+/* scatter gather processing */
+
+	nentries = SCpnt->use_sg;
+	if (nentries == 0)
+		nentries = 1;
+	rsrb->SGNum = nentries;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "sgentries = %d\n", nentries);
+#endif
+
+/*allocate mem for scatter gather table at 32bit boundary */
+	SCpnt->host_scribble = startsgptr + 8 * MAXSGENT * MAXSRBS * TargetID;
+
+	/*(unsigned char *)scsi_malloc(4096); */
+
+	sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+
+	riscsgptr = (PScatGath) (SCpnt->host_scribble);
+	if (riscsgptr == NULL)
+		panic("tripace: unable to allocate DMA memory\n");
+
+
+	/* fill physical address of scatter-gather list */
+	rsrb->SG_ListPtr = virt_to_phys(SCpnt->host_scribble);
+	rsrb->Cmd_sg_addr = virt_to_phys(rsrb + 4);
+
+	if (SCpnt->use_sg)
+	{
+		for (i = 0; i < SCpnt->use_sg; i++)
+		{
+			if (sgpnt[i].length == 0 || SCpnt->use_sg > 255)
+			{
+				unsigned char *ptr;
+				printk(KERN_ERR "tc2550: Bad segment list supplied to Tripace.c (%d, %d)\n", SCpnt->use_sg, i);
+				for (i = 0; i < SCpnt->use_sg; i++)
+				{
+					printk(KERN_ERR "%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
+					       sgpnt[i].length);
+				};
+				printk(KERN_ERR "RISCGPTR %x: ", (unsigned int) riscsgptr);
+				ptr = (unsigned char *) &riscsgptr[i];
+				for (i = 0; i < 18; i++)
+					printk("%02x ", ptr[i]);
+				panic("Tripace tc-2550x driver!");
+			};
+
+			riscsgptr[i].sg_address = (u32) sgpnt[i].address;
+			riscsgptr[i].sg_length = sgpnt[i].length;
+		};
+	} else
+	{
+		riscsgptr[0].sg_address = (u32) SCpnt->request_buffer;
+		riscsgptr[0].sg_length = SCpnt->request_bufflen;
+	};
+
+
+/* fill sense data pointer and len */
+
+	rsrb->Sense_len = sizeof(SCpnt->sense_buffer);
+	rsrb->SenseDataPtr = virt_to_phys(SCpnt->sense_buffer);
+
+/* store scsi command pointer for use in intr routine */
+	pa->dev[TargetID].task[Index].REQ_Header = (u8 *) SCpnt;
+	SCpnt->scsi_done = done;
+
+	/* pa->dev[TargetID].task[Index].complete = CompleteIORequest; */
+	ReqType = 0;
+	StartScsiCmd(rsrb);
+	return 0;
+}
+
+int tc2550_reset(Scsi_Cmnd * SCpnt)
+{
+	return 0;
+
+}
+
+#include "sd.h"
+
+int tc2550_biosparam(Scsi_Disk * disk, int dev, int *info_array)
+{
+	return 0;
+
+}
+
+int tc2550_abort(Scsi_Cmnd * SCpnt)
+{
+
+	return 0;
+}
+
+
+const char *tc2550_info(struct Scsi_Host *ignore)
+{
+
+	return 0;
+}
+
+void tc2550_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	void (*my_done) (Scsi_Cmnd *) = NULL;
+
+	int val, id, map = 0, tmap, mbx_out_ptr;
+	u8 loc = 0;
+	PRISC_SRB rsrb;
+	DevHdr *dev;
+	char *ptr0;
+	PAdapter padapter;
+/* 
+   int i ;
+   unsigned long flags ;
+ */
+	unsigned int memsize;
+	Scsi_Cmnd *SCtmp;
+	unsigned devstat = 0;
+	unsigned scsistat = 0;
+	long start_time;
+
+#ifdef DEBUG
+	printk("interrupt registered \n");
+#endif
+
+/*
+   save_flags(flags);
+   cli();
+ */
+
+	/* multiple HA? not supported now! */
+	HANumber = 0;
+	padapter = (PAdapter) & HostAdapter[HANumber];
+	Get_Base(padapter);
+
+/* disable interrupts */
+	val = inw(STATUS_INT_REG);
+
+	udelay(10);
+
+	val |= 0x20;		/* clear interrupt pending */
+	outw(val, STATUS_INT_REG);
+
+	udelay(10);
+
+	val |= 0x22;		/* disable interrupt */
+
+	outw(val, STATUS_INT_REG);
+	/*               
+	   // if RISC is in halt state then find out why ?
+	 */
+	tmap = inw(STATUS_INT_REG);
+/* The following code needs to be added when we intro sync /wide nego */
+/*
+   if(tmap & RISC_HALT) {
+   tmap= risc_halt_check();
+   if(tmap) return(0xff);
+   };
+ */
+
+
+	mbx_out_ptr = padapter->mbx_out_ptr;
+
+	val = *(u16 *) (mbx_out_base + mbx_out_ptr);
+
+	while (val & 0x80)
+	{
+		loc = (char) (val & 0x7f);
+		id = val & 0xff00;
+		id >>= 8;
+		TargetID = id;
+		dev = (DevHdr *) (devhdr_base + TargetID * sizeof(DevHdr));
+		/*(u16  *)(mbx_out_base+ mbx_out_ptr)= (val& 0xff7f); */
+		rsrb = (PRISC_SRB) (taskq_base + (id * 16 + loc) * sizeof(RISC_SRB));
+		Index = loc;
+		devstat = rsrb->DEV_Status;
+		scsistat = rsrb->ScsiStatus;
+
+/*      (*padapter->dev[TargetID].task[loc].complete)(rsrb); */
+
+		*(u16 *) (mbx_out_base + mbx_out_ptr) = (val & 0xff7f);
+
+		padapter->dev[TargetID].task[loc].CmdInProcess = 0;
+		mbx_out_ptr += 2;
+		if (mbx_out_ptr == 32)
+			mbx_out_ptr = 0;
+		padapter->mbx_out_ptr = mbx_out_ptr;
+		/*
+		 *	Clear init bimap if no more tasks are waiting
+		 */
+		map = 1;
+		dev->Updatedmap = (dev->Updatedmap ^ (map << loc));
+		if ((dev->Updatedmap & 0x0000ffff) == 0)
+		{
+			ptr0 = (char *) mbx_in_base;
+			for (map = 0; map < 16; map++)
+				if ((*ptr0 & 0xf) == (char) id)
+				{
+					*ptr0 = (*ptr0 & 0xef);
+					break;
+				} else
+					ptr0++;
+		}
+		val = *(u16 *) (mbx_out_base + mbx_out_ptr);
+
+		rsrb->SRB_flag = SRB_DONE;	/* mark done */
+	}
+
+	/* stop RISC if mailbox is empty  */
+
+	ptr0 = (char *) mbx_in_base;
+	for (map = 0; map < 16; map++)
+		if (*ptr0 & 0x10)
+			break;
+	if (map == 16)
+	{
+		tmap = inw(CONTROL_REG);
+		outw((tmap | HALT_RISC), CONTROL_REG);
+
+/*Ravi modified to introduce sanity check&time out dec 16 1998 */
+
+		start_time = jiffies;
+		
+		do
+		{
+			if ((start_time - jiffies) > 5 * HZ)
+			{
+				printk(KERN_ERR "tc2550: TC-2550x Controller Failure\n");
+				return;
+			}
+			tmap = inw(STATUS_INT_REG);
+		}
+		while((tmap & RISC_HALT) == 0);
+	}
+	SCtmp = (Scsi_Cmnd *) padapter->dev[TargetID].task[loc].REQ_Header;
+
+	if (!SCtmp || !SCtmp->scsi_done)
+	{
+		printk(KERN_ERR "tc2550: Tripace_Intr_Handle: Unexpected Interrupt\n");
+		return;
+	}
+	memsize = 255 * sizeof(struct _ScatGath) + 4;
+	my_done = SCtmp->scsi_done;
+	/*if (SCtmp->host_scribble)
+	   scsi_free(SCtmp->host_scribble,4096); */
+
+
+	padapter->dev[TargetID].task[loc].REQ_Header = NULL;
+	SCtmp->result = makecode(devstat, scsistat);
+/*enable chip interrupt signal */
+	val = inw(STATUS_INT_REG);
+	udelay(25);		/* delay for 25 micros */
+
+	val &= 0xfd;		/* enable interrupt-bit1=0 in status-int reg */
+	outw(val, STATUS_INT_REG);
+
+	my_done(SCtmp);		/* inform mid layer that scsi command is over */
+/*
+   restore_flags(flags);
+ */
+
+}
+
+/* called from init/main.c */
+void tripace_setup(char *str, int *ints)
+{
+	switch (ints[0])
+	{
+
+	case 0:
+
+		printk(KERN_INFO "tc2550: No Arguments In Command Line:Assuming Defaults\n");
+		break;
+
+	case 1:
+		fast_clk = ints[1];
+		break;
+
+	case 2:
+		fast_clk = ints[1];
+		discon = ints[2];
+		break;
+
+	case 3:
+		fast_clk = ints[1];
+		discon = ints[2];
+		syncflag = ints[3];
+		break;
+
+	case 4:
+		fast_clk = ints[1];
+		discon = ints[2];
+		syncflag = ints[3];
+		tagflag = ints[4];
+	}
+
+#ifdef DEBUG
+	printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+	       fast_clk, discon, syncflag, tagflag);
+	printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+	       fast_clk, discon, syncflag, tagflag);
+	printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+	       fast_clk, discon, syncflag, tagflag);
+	printk("fast_clk = %d,discon = %d,syncflag =%d,tagflag=%d\n",
+	       fast_clk, discon, syncflag, tagflag);
+#endif
+
+}
+
+static int makecode(unsigned hosterr, unsigned scsierr)
+{
+	switch (hosterr)
+	{
+	case 0x0:
+		hosterr = 0;
+		break;
+
+	case SEL_TIME_OUT:	/* Selection time out-The initiator selection or target
+				   reselection was not complete within the SCSI Time out period */
+		hosterr = DID_TIME_OUT;
+		break;
+
+	case ERR_PARITY:	/* parity error */
+
+		hosterr = DID_PARITY;
+		break;
+
+	case ERR_OVERRUN:	/* Data overrun/underrun-The target attempted to transfer more data
+				   than was allocated by the Data Length field or the sum of the
+				   Scatter / Gather Data Length fields. */
+
+	case ERR_BUSFREE:	/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+
+	case ERR_PHASE:	/* Target bus phase sequence failure-An invalid bus phase or bus
+				   phase sequence was requested by the target. */
+
+		hosterr = DID_ERROR;	/* Couldn't find any better */
+		break;
+
+	default:
+		hosterr = DID_ERROR;
+		printk(KERN_ERR "tc2550: Makecode: Unknown Hoststatus %x\n", hosterr);
+		break;
+	}
+	return scsierr | (hosterr << 16);
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov