xref: /openbmc/linux/drivers/scsi/initio.c (revision a2ba192c)
11da177e4SLinus Torvalds /**************************************************************************
21da177e4SLinus Torvalds  * Initio 9100 device driver for Linux.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 1994-1998 Initio Corporation
51da177e4SLinus Torvalds  * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
61da177e4SLinus Torvalds  * All rights reserved.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
91da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
101da177e4SLinus Torvalds  * the Free Software Foundation; either version 2, or (at your option)
111da177e4SLinus Torvalds  * any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
141da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
151da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161da177e4SLinus Torvalds  * GNU General Public License for more details.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
191da177e4SLinus Torvalds  * along with this program; see the file COPYING.  If not, write to
201da177e4SLinus Torvalds  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * --------------------------------------------------------------------------
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  * Redistribution and use in source and binary forms, with or without
251da177e4SLinus Torvalds  * modification, are permitted provided that the following conditions
261da177e4SLinus Torvalds  * are met:
271da177e4SLinus Torvalds  * 1. Redistributions of source code must retain the above copyright
281da177e4SLinus Torvalds  *    notice, this list of conditions, and the following disclaimer,
291da177e4SLinus Torvalds  *    without modification, immediately at the beginning of the file.
301da177e4SLinus Torvalds  * 2. Redistributions in binary form must reproduce the above copyright
311da177e4SLinus Torvalds  *    notice, this list of conditions and the following disclaimer in the
321da177e4SLinus Torvalds  *    documentation and/or other materials provided with the distribution.
331da177e4SLinus Torvalds  * 3. The name of the author may not be used to endorse or promote products
341da177e4SLinus Torvalds  *    derived from this software without specific prior written permission.
351da177e4SLinus Torvalds  *
361da177e4SLinus Torvalds  * Where this Software is combined with software released under the terms of
371da177e4SLinus Torvalds  * the GNU General Public License ("GPL") and the terms of the GPL would require the
381da177e4SLinus Torvalds  * combined work to also be released under the terms of the GPL, the terms
391da177e4SLinus Torvalds  * and conditions of this License will apply in addition to those of the
401da177e4SLinus Torvalds  * GPL with the exception of any terms or conditions of this License that
411da177e4SLinus Torvalds  * conflict with, or are expressly prohibited by, the GPL.
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
441da177e4SLinus Torvalds  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
451da177e4SLinus Torvalds  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
461da177e4SLinus Torvalds  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
471da177e4SLinus Torvalds  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
481da177e4SLinus Torvalds  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
491da177e4SLinus Torvalds  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
501da177e4SLinus Torvalds  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
511da177e4SLinus Torvalds  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
521da177e4SLinus Torvalds  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
531da177e4SLinus Torvalds  * SUCH DAMAGE.
541da177e4SLinus Torvalds  *
551da177e4SLinus Torvalds  *************************************************************************
561da177e4SLinus Torvalds  *
571da177e4SLinus Torvalds  * DESCRIPTION:
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host
601da177e4SLinus Torvalds  * adapters
611da177e4SLinus Torvalds  *
621da177e4SLinus Torvalds  * 08/06/97 hc	- v1.01h
631da177e4SLinus Torvalds  *		- Support inic-940 and inic-935
641da177e4SLinus Torvalds  * 09/26/97 hc	- v1.01i
651da177e4SLinus Torvalds  *		- Make correction from J.W. Schultz suggestion
661da177e4SLinus Torvalds  * 10/13/97 hc	- Support reset function
671da177e4SLinus Torvalds  * 10/21/97 hc	- v1.01j
681da177e4SLinus Torvalds  *		- Support 32 LUN (SCSI 3)
691da177e4SLinus Torvalds  * 01/14/98 hc	- v1.01k
701da177e4SLinus Torvalds  *		- Fix memory allocation problem
711da177e4SLinus Torvalds  * 03/04/98 hc	- v1.01l
721da177e4SLinus Torvalds  *		- Fix tape rewind which will hang the system problem
731da177e4SLinus Torvalds  *		- Set can_queue to tul_num_scb
741da177e4SLinus Torvalds  * 06/25/98 hc	- v1.01m
751da177e4SLinus Torvalds  *		- Get it work for kernel version >= 2.1.75
761da177e4SLinus Torvalds  *		- Dynamic assign SCSI bus reset holding time in init_tulip()
771da177e4SLinus Torvalds  * 07/02/98 hc	- v1.01n
781da177e4SLinus Torvalds  *		- Support 0002134A
791da177e4SLinus Torvalds  * 08/07/98 hc  - v1.01o
801da177e4SLinus Torvalds  *		- Change the tul_abort_srb routine to use scsi_done. <01>
811da177e4SLinus Torvalds  * 09/07/98 hl  - v1.02
821da177e4SLinus Torvalds  *              - Change the INI9100U define and proc_dir_entry to
831da177e4SLinus Torvalds  *                reflect the newer Kernel 2.1.118, but the v1.o1o
841da177e4SLinus Torvalds  *                should work with Kernel 2.1.118.
851da177e4SLinus Torvalds  * 09/20/98 wh  - v1.02a
861da177e4SLinus Torvalds  *              - Support Abort command.
871da177e4SLinus Torvalds  *              - Handle reset routine.
881da177e4SLinus Torvalds  * 09/21/98 hl  - v1.03
891da177e4SLinus Torvalds  *              - remove comments.
901da177e4SLinus Torvalds  * 12/09/98 bv	- v1.03a
911da177e4SLinus Torvalds  *		- Removed unused code
921da177e4SLinus Torvalds  * 12/13/98 bv	- v1.03b
931da177e4SLinus Torvalds  *		- Remove cli() locking for kernels >= 2.1.95. This uses
941da177e4SLinus Torvalds  *		  spinlocks to serialize access to the pSRB_head and
951da177e4SLinus Torvalds  *		  pSRB_tail members of the HCS structure.
961da177e4SLinus Torvalds  * 09/01/99 bv	- v1.03d
971da177e4SLinus Torvalds  *		- Fixed a deadlock problem in SMP.
981da177e4SLinus Torvalds  * 21/01/99 bv	- v1.03e
991da177e4SLinus Torvalds  *		- Add support for the Domex 3192U PCI SCSI
1001da177e4SLinus Torvalds  *		  This is a slightly modified patch by
1011da177e4SLinus Torvalds  *		  Brian Macy <bmacy@sunshinecomputing.com>
1021da177e4SLinus Torvalds  * 22/02/99 bv	- v1.03f
1031da177e4SLinus Torvalds  *		- Didn't detect the INIC-950 in 2.0.x correctly.
1041da177e4SLinus Torvalds  *		  Now fixed.
1051da177e4SLinus Torvalds  * 05/07/99 bv	- v1.03g
1061da177e4SLinus Torvalds  *		- Changed the assumption that HZ = 100
1071da177e4SLinus Torvalds  * 10/17/03 mc	- v1.04
1081da177e4SLinus Torvalds  *		- added new DMA API support
1091da177e4SLinus Torvalds  * 06/01/04 jmd	- v1.04a
1101da177e4SLinus Torvalds  *		- Re-add reset_bus support
1111da177e4SLinus Torvalds  **************************************************************************/
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds #include <linux/module.h>
1141da177e4SLinus Torvalds #include <linux/errno.h>
1151da177e4SLinus Torvalds #include <linux/delay.h>
1161da177e4SLinus Torvalds #include <linux/pci.h>
1171da177e4SLinus Torvalds #include <linux/init.h>
1181da177e4SLinus Torvalds #include <linux/blkdev.h>
1191da177e4SLinus Torvalds #include <linux/spinlock.h>
1201da177e4SLinus Torvalds #include <linux/stat.h>
1211da177e4SLinus Torvalds #include <linux/config.h>
1221da177e4SLinus Torvalds #include <linux/kernel.h>
1231da177e4SLinus Torvalds #include <linux/proc_fs.h>
1241da177e4SLinus Torvalds #include <linux/string.h>
1251da177e4SLinus Torvalds #include <linux/interrupt.h>
1261da177e4SLinus Torvalds #include <linux/ioport.h>
1271da177e4SLinus Torvalds #include <linux/sched.h>
1281da177e4SLinus Torvalds #include <linux/slab.h>
1291da177e4SLinus Torvalds #include <linux/jiffies.h>
1301da177e4SLinus Torvalds #include <asm/io.h>
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds #include <scsi/scsi.h>
1331da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h>
1341da177e4SLinus Torvalds #include <scsi/scsi_device.h>
1351da177e4SLinus Torvalds #include <scsi/scsi_host.h>
1361da177e4SLinus Torvalds #include <scsi/scsi_tcq.h>
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds #include "initio.h"
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds #define SENSE_SIZE		14
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds #define i91u_MAXQUEUE		2
1431da177e4SLinus Torvalds #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds #define INI_VENDOR_ID   0x1101	/* Initio's PCI vendor ID       */
1461da177e4SLinus Torvalds #define DMX_VENDOR_ID	0x134a	/* Domex's PCI vendor ID	*/
1471da177e4SLinus Torvalds #define I950_DEVICE_ID	0x9500	/* Initio's inic-950 product ID   */
1481da177e4SLinus Torvalds #define I940_DEVICE_ID	0x9400	/* Initio's inic-940 product ID   */
1491da177e4SLinus Torvalds #define I935_DEVICE_ID	0x9401	/* Initio's inic-935 product ID   */
1501da177e4SLinus Torvalds #define I920_DEVICE_ID	0x0002	/* Initio's other product ID      */
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds #ifdef DEBUG_i91u
1531da177e4SLinus Torvalds static unsigned int i91u_debug = DEBUG_DEFAULT;
1541da177e4SLinus Torvalds #endif
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds #define TULSZ(sz)     (sizeof(sz) / sizeof(sz[0]))
1571da177e4SLinus Torvalds #define TUL_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds typedef struct PCI_ID_Struc {
1601da177e4SLinus Torvalds 	unsigned short vendor_id;
1611da177e4SLinus Torvalds 	unsigned short device_id;
1621da177e4SLinus Torvalds } PCI_ID;
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds static int tul_num_ch = 4;	/* Maximum 4 adapters           */
1651da177e4SLinus Torvalds static int tul_num_scb;
1661da177e4SLinus Torvalds static int tul_tag_enable = 1;
1671da177e4SLinus Torvalds static SCB *tul_scb;
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds #ifdef DEBUG_i91u
1701da177e4SLinus Torvalds static int setup_debug = 0;
1711da177e4SLinus Torvalds #endif
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds static const PCI_ID i91u_pci_devices[] = {
1761da177e4SLinus Torvalds 	{ INI_VENDOR_ID, I950_DEVICE_ID },
1771da177e4SLinus Torvalds 	{ INI_VENDOR_ID, I940_DEVICE_ID },
1781da177e4SLinus Torvalds 	{ INI_VENDOR_ID, I935_DEVICE_ID },
1791da177e4SLinus Torvalds 	{ INI_VENDOR_ID, I920_DEVICE_ID },
1801da177e4SLinus Torvalds 	{ DMX_VENDOR_ID, I920_DEVICE_ID },
1811da177e4SLinus Torvalds };
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds #define DEBUG_INTERRUPT 0
1841da177e4SLinus Torvalds #define DEBUG_QUEUE     0
1851da177e4SLinus Torvalds #define DEBUG_STATE     0
1861da177e4SLinus Torvalds #define INT_DISC	0
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds /*--- external functions --*/
1891da177e4SLinus Torvalds static void tul_se2_wait(void);
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds /*--- forward refrence ---*/
1921da177e4SLinus Torvalds static SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun);
1931da177e4SLinus Torvalds static SCB *tul_find_done_scb(HCS * pCurHcb);
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds static int tulip_main(HCS * pCurHcb);
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds static int tul_next_state(HCS * pCurHcb);
1981da177e4SLinus Torvalds static int tul_state_1(HCS * pCurHcb);
1991da177e4SLinus Torvalds static int tul_state_2(HCS * pCurHcb);
2001da177e4SLinus Torvalds static int tul_state_3(HCS * pCurHcb);
2011da177e4SLinus Torvalds static int tul_state_4(HCS * pCurHcb);
2021da177e4SLinus Torvalds static int tul_state_5(HCS * pCurHcb);
2031da177e4SLinus Torvalds static int tul_state_6(HCS * pCurHcb);
2041da177e4SLinus Torvalds static int tul_state_7(HCS * pCurHcb);
2051da177e4SLinus Torvalds static int tul_xfer_data_in(HCS * pCurHcb);
2061da177e4SLinus Torvalds static int tul_xfer_data_out(HCS * pCurHcb);
2071da177e4SLinus Torvalds static int tul_xpad_in(HCS * pCurHcb);
2081da177e4SLinus Torvalds static int tul_xpad_out(HCS * pCurHcb);
2091da177e4SLinus Torvalds static int tul_status_msg(HCS * pCurHcb);
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds static int tul_msgin(HCS * pCurHcb);
2121da177e4SLinus Torvalds static int tul_msgin_sync(HCS * pCurHcb);
2131da177e4SLinus Torvalds static int tul_msgin_accept(HCS * pCurHcb);
2141da177e4SLinus Torvalds static int tul_msgout_reject(HCS * pCurHcb);
2151da177e4SLinus Torvalds static int tul_msgin_extend(HCS * pCurHcb);
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds static int tul_msgout_ide(HCS * pCurHcb);
2181da177e4SLinus Torvalds static int tul_msgout_abort_targ(HCS * pCurHcb);
2191da177e4SLinus Torvalds static int tul_msgout_abort_tag(HCS * pCurHcb);
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds static int tul_bus_device_reset(HCS * pCurHcb);
2221da177e4SLinus Torvalds static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
2231da177e4SLinus Torvalds static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
2241da177e4SLinus Torvalds static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
2251da177e4SLinus Torvalds static int int_tul_busfree(HCS * pCurHcb);
226a2ba192cSAdrian Bunk static int int_tul_scsi_rst(HCS * pCurHcb);
2271da177e4SLinus Torvalds static int int_tul_bad_seq(HCS * pCurHcb);
2281da177e4SLinus Torvalds static int int_tul_resel(HCS * pCurHcb);
2291da177e4SLinus Torvalds static int tul_sync_done(HCS * pCurHcb);
2301da177e4SLinus Torvalds static int wdtr_done(HCS * pCurHcb);
2311da177e4SLinus Torvalds static int wait_tulip(HCS * pCurHcb);
2321da177e4SLinus Torvalds static int tul_wait_done_disc(HCS * pCurHcb);
2331da177e4SLinus Torvalds static int tul_wait_disc(HCS * pCurHcb);
2341da177e4SLinus Torvalds static void tulip_scsi(HCS * pCurHcb);
2351da177e4SLinus Torvalds static int tul_post_scsi_rst(HCS * pCurHcb);
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds static void tul_se2_ew_en(WORD CurBase);
2381da177e4SLinus Torvalds static void tul_se2_ew_ds(WORD CurBase);
2391da177e4SLinus Torvalds static int tul_se2_rd_all(WORD CurBase);
2401da177e4SLinus Torvalds static void tul_se2_update_all(WORD CurBase);	/* setup default pattern */
2411da177e4SLinus Torvalds static void tul_read_eeprom(WORD CurBase);
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 				/* ---- INTERNAL VARIABLES ---- */
244a2ba192cSAdrian Bunk static HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
2451da177e4SLinus Torvalds static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds /*NVRAM nvram, *nvramp = &nvram; */
2481da177e4SLinus Torvalds static NVRAM i91unvram;
2491da177e4SLinus Torvalds static NVRAM *i91unvramp;
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds static UCHAR i91udftNvRam[64] =
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds /*----------- header -----------*/
2561da177e4SLinus Torvalds 	0x25, 0xc9,		/* Signature    */
2571da177e4SLinus Torvalds 	0x40,			/* Size         */
2581da177e4SLinus Torvalds 	0x01,			/* Revision     */
2591da177e4SLinus Torvalds 	/* -- Host Adapter Structure -- */
2601da177e4SLinus Torvalds 	0x95,			/* ModelByte0   */
2611da177e4SLinus Torvalds 	0x00,			/* ModelByte1   */
2621da177e4SLinus Torvalds 	0x00,			/* ModelInfo    */
2631da177e4SLinus Torvalds 	0x01,			/* NumOfCh      */
2641da177e4SLinus Torvalds 	NBC1_DEFAULT,		/* BIOSConfig1  */
2651da177e4SLinus Torvalds 	0,			/* BIOSConfig2  */
2661da177e4SLinus Torvalds 	0,			/* HAConfig1    */
2671da177e4SLinus Torvalds 	0,			/* HAConfig2    */
2681da177e4SLinus Torvalds 	/* SCSI channel 0 and target Structure  */
2691da177e4SLinus Torvalds 	7,			/* SCSIid       */
2701da177e4SLinus Torvalds 	NCC1_DEFAULT,		/* SCSIconfig1  */
2711da177e4SLinus Torvalds 	0,			/* SCSIconfig2  */
2721da177e4SLinus Torvalds 	0x10,			/* NumSCSItarget */
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2751da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2761da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2771da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	/* SCSI channel 1 and target Structure  */
2801da177e4SLinus Torvalds 	7,			/* SCSIid       */
2811da177e4SLinus Torvalds 	NCC1_DEFAULT,		/* SCSIconfig1  */
2821da177e4SLinus Torvalds 	0,			/* SCSIconfig2  */
2831da177e4SLinus Torvalds 	0x10,			/* NumSCSItarget */
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2861da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2871da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2881da177e4SLinus Torvalds 	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
2891da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2901da177e4SLinus Torvalds 	0, 0};			/*      - CheckSum -            */
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds static UCHAR tul_rate_tbl[8] =	/* fast 20      */
2941da177e4SLinus Torvalds {
2951da177e4SLinus Torvalds 				/* nanosecond devide by 4 */
2961da177e4SLinus Torvalds 	12,			/* 50ns,  20M   */
2971da177e4SLinus Torvalds 	18,			/* 75ns,  13.3M */
2981da177e4SLinus Torvalds 	25,			/* 100ns, 10M   */
2991da177e4SLinus Torvalds 	31,			/* 125ns, 8M    */
3001da177e4SLinus Torvalds 	37,			/* 150ns, 6.6M  */
3011da177e4SLinus Torvalds 	43,			/* 175ns, 5.7M  */
3021da177e4SLinus Torvalds 	50,			/* 200ns, 5M    */
3031da177e4SLinus Torvalds 	62			/* 250ns, 4M    */
3041da177e4SLinus Torvalds };
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds static void tul_do_pause(unsigned amount)
3071da177e4SLinus Torvalds {				/* Pause for amount jiffies */
3081da177e4SLinus Torvalds 	unsigned long the_time = jiffies + amount;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	while (time_before_eq(jiffies, the_time));
3111da177e4SLinus Torvalds }
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds /*-- forward reference --*/
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds /*******************************************************************
3161da177e4SLinus Torvalds 	Use memeory refresh time        ~ 15us * 2
3171da177e4SLinus Torvalds ********************************************************************/
3181da177e4SLinus Torvalds void tul_se2_wait(void)
3191da177e4SLinus Torvalds {
3201da177e4SLinus Torvalds #if 1
3211da177e4SLinus Torvalds 	udelay(30);
3221da177e4SLinus Torvalds #else
3231da177e4SLinus Torvalds 	UCHAR readByte;
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	readByte = TUL_RD(0, 0x61);
3261da177e4SLinus Torvalds 	if ((readByte & 0x10) == 0x10) {
3271da177e4SLinus Torvalds 		for (;;) {
3281da177e4SLinus Torvalds 			readByte = TUL_RD(0, 0x61);
3291da177e4SLinus Torvalds 			if ((readByte & 0x10) == 0x10)
3301da177e4SLinus Torvalds 				break;
3311da177e4SLinus Torvalds 		}
3321da177e4SLinus Torvalds 		for (;;) {
3331da177e4SLinus Torvalds 			readByte = TUL_RD(0, 0x61);
3341da177e4SLinus Torvalds 			if ((readByte & 0x10) != 0x10)
3351da177e4SLinus Torvalds 				break;
3361da177e4SLinus Torvalds 		}
3371da177e4SLinus Torvalds 	} else {
3381da177e4SLinus Torvalds 		for (;;) {
3391da177e4SLinus Torvalds 			readByte = TUL_RD(0, 0x61);
3401da177e4SLinus Torvalds 			if ((readByte & 0x10) == 0x10)
3411da177e4SLinus Torvalds 				break;
3421da177e4SLinus Torvalds 		}
3431da177e4SLinus Torvalds 		for (;;) {
3441da177e4SLinus Torvalds 			readByte = TUL_RD(0, 0x61);
3451da177e4SLinus Torvalds 			if ((readByte & 0x10) != 0x10)
3461da177e4SLinus Torvalds 				break;
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 	}
3491da177e4SLinus Torvalds #endif
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds /******************************************************************
3541da177e4SLinus Torvalds  Input: instruction for  Serial E2PROM
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds  EX: se2_rd(0 call se2_instr() to send address and read command
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	 StartBit  OP_Code   Address                Data
3591da177e4SLinus Torvalds 	 --------- --------  ------------------     -------
3601da177e4SLinus Torvalds 	 1         1 , 0     A5,A4,A3,A2,A1,A0      D15-D0
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 		 +-----------------------------------------------------
3631da177e4SLinus Torvalds 		 |
3641da177e4SLinus Torvalds  CS -----+
3651da177e4SLinus Torvalds 			+--+  +--+  +--+  +--+  +--+
3661da177e4SLinus Torvalds 			^  |  ^  |  ^  |  ^  |  ^  |
3671da177e4SLinus Torvalds 			|  |  |  |  |  |  |  |  |  |
3681da177e4SLinus Torvalds  CLK -------+  +--+  +--+  +--+  +--+  +--
3691da177e4SLinus Torvalds  (leading edge trigger)
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 		 +--1-----1--+
3721da177e4SLinus Torvalds 		 | SB    OP  |  OP    A5    A4
3731da177e4SLinus Torvalds  DI  ----+           +--0------------------
3741da177e4SLinus Torvalds  (address and cmd sent to nvram)
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	 -------------------------------------------+
3771da177e4SLinus Torvalds 												|
3781da177e4SLinus Torvalds  DO                                             +---
3791da177e4SLinus Torvalds  (data sent from nvram)
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds ******************************************************************/
383a2ba192cSAdrian Bunk static void tul_se2_instr(WORD CurBase, UCHAR instr)
3841da177e4SLinus Torvalds {
3851da177e4SLinus Torvalds 	int i;
3861da177e4SLinus Torvalds 	UCHAR b;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);	/* cs+start bit */
3891da177e4SLinus Torvalds 	tul_se2_wait();
3901da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK | SE2DO);	/* +CLK */
3911da177e4SLinus Torvalds 	tul_se2_wait();
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	for (i = 0; i < 8; i++) {
3941da177e4SLinus Torvalds 		if (instr & 0x80)
3951da177e4SLinus Torvalds 			b = SE2CS | SE2DO;	/* -CLK+dataBit */
3961da177e4SLinus Torvalds 		else
3971da177e4SLinus Torvalds 			b = SE2CS;	/* -CLK */
3981da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, b);
3991da177e4SLinus Torvalds 		tul_se2_wait();
4001da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, b | SE2CLK);	/* +CLK */
4011da177e4SLinus Torvalds 		tul_se2_wait();
4021da177e4SLinus Torvalds 		instr <<= 1;
4031da177e4SLinus Torvalds 	}
4041da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
4051da177e4SLinus Torvalds 	tul_se2_wait();
4061da177e4SLinus Torvalds 	return;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds /******************************************************************
4111da177e4SLinus Torvalds  Function name  : tul_se2_ew_en
4121da177e4SLinus Torvalds  Description    : Enable erase/write state of serial EEPROM
4131da177e4SLinus Torvalds ******************************************************************/
4141da177e4SLinus Torvalds void tul_se2_ew_en(WORD CurBase)
4151da177e4SLinus Torvalds {
4161da177e4SLinus Torvalds 	tul_se2_instr(CurBase, 0x30);	/* EWEN */
4171da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS  */
4181da177e4SLinus Torvalds 	tul_se2_wait();
4191da177e4SLinus Torvalds 	return;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds /************************************************************************
4241da177e4SLinus Torvalds  Disable erase/write state of serial EEPROM
4251da177e4SLinus Torvalds *************************************************************************/
4261da177e4SLinus Torvalds void tul_se2_ew_ds(WORD CurBase)
4271da177e4SLinus Torvalds {
4281da177e4SLinus Torvalds 	tul_se2_instr(CurBase, 0);	/* EWDS */
4291da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS  */
4301da177e4SLinus Torvalds 	tul_se2_wait();
4311da177e4SLinus Torvalds 	return;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds /******************************************************************
4361da177e4SLinus Torvalds 	Input  :address of Serial E2PROM
4371da177e4SLinus Torvalds 	Output :value stored in  Serial E2PROM
4381da177e4SLinus Torvalds *******************************************************************/
439a2ba192cSAdrian Bunk static USHORT tul_se2_rd(WORD CurBase, ULONG adr)
4401da177e4SLinus Torvalds {
4411da177e4SLinus Torvalds 	UCHAR instr, readByte;
4421da177e4SLinus Torvalds 	USHORT readWord;
4431da177e4SLinus Torvalds 	int i;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	instr = (UCHAR) (adr | 0x80);
4461da177e4SLinus Torvalds 	tul_se2_instr(CurBase, instr);	/* READ INSTR */
4471da177e4SLinus Torvalds 	readWord = 0;
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 	for (i = 15; i >= 0; i--) {
4501da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);	/* +CLK */
4511da177e4SLinus Torvalds 		tul_se2_wait();
4521da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 		/* sample data after the following edge of clock  */
4551da177e4SLinus Torvalds 		readByte = TUL_RD(CurBase, TUL_NVRAM);
4561da177e4SLinus Torvalds 		readByte &= SE2DI;
4571da177e4SLinus Torvalds 		readWord += (readByte << i);
4581da177e4SLinus Torvalds 		tul_se2_wait();	/* 6/20/95 */
4591da177e4SLinus Torvalds 	}
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, 0);		/* no chip select */
4621da177e4SLinus Torvalds 	tul_se2_wait();
4631da177e4SLinus Torvalds 	return readWord;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds /******************************************************************
4681da177e4SLinus Torvalds  Input: new value in  Serial E2PROM, address of Serial E2PROM
4691da177e4SLinus Torvalds *******************************************************************/
470a2ba192cSAdrian Bunk static void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
4711da177e4SLinus Torvalds {
4721da177e4SLinus Torvalds 	UCHAR readByte;
4731da177e4SLinus Torvalds 	UCHAR instr;
4741da177e4SLinus Torvalds 	int i;
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds 	instr = (UCHAR) (adr | 0x40);
4771da177e4SLinus Torvalds 	tul_se2_instr(CurBase, instr);	/* WRITE INSTR */
4781da177e4SLinus Torvalds 	for (i = 15; i >= 0; i--) {
4791da177e4SLinus Torvalds 		if (writeWord & 0x8000)
4801da177e4SLinus Torvalds 			TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);	/* -CLK+dataBit 1 */
4811da177e4SLinus Torvalds 		else
4821da177e4SLinus Torvalds 			TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK+dataBit 0 */
4831da177e4SLinus Torvalds 		tul_se2_wait();
4841da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);	/* +CLK */
4851da177e4SLinus Torvalds 		tul_se2_wait();
4861da177e4SLinus Torvalds 		writeWord <<= 1;
4871da177e4SLinus Torvalds 	}
4881da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
4891da177e4SLinus Torvalds 	tul_se2_wait();
4901da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS  */
4911da177e4SLinus Torvalds 	tul_se2_wait();
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* +CS  */
4941da177e4SLinus Torvalds 	tul_se2_wait();
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	for (;;) {
4971da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);	/* +CLK */
4981da177e4SLinus Torvalds 		tul_se2_wait();
4991da177e4SLinus Torvalds 		TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
5001da177e4SLinus Torvalds 		tul_se2_wait();
5011da177e4SLinus Torvalds 		if ((readByte = TUL_RD(CurBase, TUL_NVRAM)) & SE2DI)
5021da177e4SLinus Torvalds 			break;	/* write complete */
5031da177e4SLinus Torvalds 	}
5041da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS */
5051da177e4SLinus Torvalds 	return;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds /***********************************************************************
5101da177e4SLinus Torvalds  Read SCSI H/A configuration parameters from serial EEPROM
5111da177e4SLinus Torvalds ************************************************************************/
5121da177e4SLinus Torvalds int tul_se2_rd_all(WORD CurBase)
5131da177e4SLinus Torvalds {
5141da177e4SLinus Torvalds 	int i;
5151da177e4SLinus Torvalds 	ULONG chksum = 0;
5161da177e4SLinus Torvalds 	USHORT *np;
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	i91unvramp = &i91unvram;
5191da177e4SLinus Torvalds 	np = (USHORT *) i91unvramp;
5201da177e4SLinus Torvalds 	for (i = 0; i < 32; i++) {
5211da177e4SLinus Torvalds 		*np++ = tul_se2_rd(CurBase, i);
5221da177e4SLinus Torvalds 	}
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds /*--------------------Is signature "ini" ok ? ----------------*/
5251da177e4SLinus Torvalds 	if (i91unvramp->NVM_Signature != INI_SIGNATURE)
5261da177e4SLinus Torvalds 		return -1;
5271da177e4SLinus Torvalds /*---------------------- Is ckecksum ok ? ----------------------*/
5281da177e4SLinus Torvalds 	np = (USHORT *) i91unvramp;
5291da177e4SLinus Torvalds 	for (i = 0; i < 31; i++)
5301da177e4SLinus Torvalds 		chksum += *np++;
5311da177e4SLinus Torvalds 	if (i91unvramp->NVM_CheckSum != (USHORT) chksum)
5321da177e4SLinus Torvalds 		return -1;
5331da177e4SLinus Torvalds 	return 1;
5341da177e4SLinus Torvalds }
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds /***********************************************************************
5381da177e4SLinus Torvalds  Update SCSI H/A configuration parameters from serial EEPROM
5391da177e4SLinus Torvalds ************************************************************************/
5401da177e4SLinus Torvalds void tul_se2_update_all(WORD CurBase)
5411da177e4SLinus Torvalds {				/* setup default pattern */
5421da177e4SLinus Torvalds 	int i;
5431da177e4SLinus Torvalds 	ULONG chksum = 0;
5441da177e4SLinus Torvalds 	USHORT *np, *np1;
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds 	i91unvramp = &i91unvram;
5471da177e4SLinus Torvalds 	/* Calculate checksum first */
5481da177e4SLinus Torvalds 	np = (USHORT *) i91udftNvRam;
5491da177e4SLinus Torvalds 	for (i = 0; i < 31; i++)
5501da177e4SLinus Torvalds 		chksum += *np++;
5511da177e4SLinus Torvalds 	*np = (USHORT) chksum;
5521da177e4SLinus Torvalds 	tul_se2_ew_en(CurBase);	/* Enable write  */
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 	np = (USHORT *) i91udftNvRam;
5551da177e4SLinus Torvalds 	np1 = (USHORT *) i91unvramp;
5561da177e4SLinus Torvalds 	for (i = 0; i < 32; i++, np++, np1++) {
5571da177e4SLinus Torvalds 		if (*np != *np1) {
5581da177e4SLinus Torvalds 			tul_se2_wr(CurBase, i, *np);
5591da177e4SLinus Torvalds 		}
5601da177e4SLinus Torvalds 	}
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	tul_se2_ew_ds(CurBase);	/* Disable write   */
5631da177e4SLinus Torvalds 	return;
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds /*************************************************************************
5671da177e4SLinus Torvalds  Function name  : read_eeprom
5681da177e4SLinus Torvalds **************************************************************************/
5691da177e4SLinus Torvalds void tul_read_eeprom(WORD CurBase)
5701da177e4SLinus Torvalds {
5711da177e4SLinus Torvalds 	UCHAR gctrl;
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	i91unvramp = &i91unvram;
5741da177e4SLinus Torvalds /*------Enable EEProm programming ---*/
5751da177e4SLinus Torvalds 	gctrl = TUL_RD(CurBase, TUL_GCTRL);
5761da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT);
5771da177e4SLinus Torvalds 	if (tul_se2_rd_all(CurBase) != 1) {
5781da177e4SLinus Torvalds 		tul_se2_update_all(CurBase);	/* setup default pattern */
5791da177e4SLinus Torvalds 		tul_se2_rd_all(CurBase);	/* load again  */
5801da177e4SLinus Torvalds 	}
5811da177e4SLinus Torvalds /*------ Disable EEProm programming ---*/
5821da177e4SLinus Torvalds 	gctrl = TUL_RD(CurBase, TUL_GCTRL);
5831da177e4SLinus Torvalds 	TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
5841da177e4SLinus Torvalds }				/* read_eeprom */
5851da177e4SLinus Torvalds 
586a2ba192cSAdrian Bunk static int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
5871da177e4SLinus Torvalds 				      BYTE bBus, BYTE bDevice)
5881da177e4SLinus Torvalds {
5891da177e4SLinus Torvalds 	int i, j;
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
5921da177e4SLinus Torvalds 		if (i91u_adpt[i].ADPT_BIOS < wBIOS)
5931da177e4SLinus Torvalds 			continue;
5941da177e4SLinus Torvalds 		if (i91u_adpt[i].ADPT_BIOS == wBIOS) {
5951da177e4SLinus Torvalds 			if (i91u_adpt[i].ADPT_BASE == wBASE) {
5961da177e4SLinus Torvalds 				if (i91u_adpt[i].ADPT_Bus != 0xFF)
5971da177e4SLinus Torvalds 					return 1;
5981da177e4SLinus Torvalds 			} else if (i91u_adpt[i].ADPT_BASE < wBASE)
5991da177e4SLinus Torvalds 					continue;
6001da177e4SLinus Torvalds 		}
6011da177e4SLinus Torvalds 		for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
6021da177e4SLinus Torvalds 			i91u_adpt[j].ADPT_BASE = i91u_adpt[j - 1].ADPT_BASE;
6031da177e4SLinus Torvalds 			i91u_adpt[j].ADPT_INTR = i91u_adpt[j - 1].ADPT_INTR;
6041da177e4SLinus Torvalds 			i91u_adpt[j].ADPT_BIOS = i91u_adpt[j - 1].ADPT_BIOS;
6051da177e4SLinus Torvalds 			i91u_adpt[j].ADPT_Bus = i91u_adpt[j - 1].ADPT_Bus;
6061da177e4SLinus Torvalds 			i91u_adpt[j].ADPT_Device = i91u_adpt[j - 1].ADPT_Device;
6071da177e4SLinus Torvalds 		}
6081da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_BASE = wBASE;
6091da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_INTR = bInterrupt;
6101da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_BIOS = wBIOS;
6111da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_Bus = bBus;
6121da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_Device = bDevice;
6131da177e4SLinus Torvalds 		return 0;
6141da177e4SLinus Torvalds 	}
6151da177e4SLinus Torvalds 	return 1;
6161da177e4SLinus Torvalds }
6171da177e4SLinus Torvalds 
618a2ba192cSAdrian Bunk static void init_i91uAdapter_table(void)
6191da177e4SLinus Torvalds {
6201da177e4SLinus Torvalds 	int i;
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds 	for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {	/* Initialize adapter structure */
6231da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_BIOS = 0xffff;
6241da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_BASE = 0xffff;
6251da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_INTR = 0xff;
6261da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_Bus = 0xff;
6271da177e4SLinus Torvalds 		i91u_adpt[i].ADPT_Device = 0xff;
6281da177e4SLinus Torvalds 	}
6291da177e4SLinus Torvalds 	return;
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds 
632a2ba192cSAdrian Bunk static void tul_stop_bm(HCS * pCurHcb)
6331da177e4SLinus Torvalds {
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */
6361da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
6371da177e4SLinus Torvalds 		/* wait Abort DMA xfer done */
6381da177e4SLinus Torvalds 		while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
6391da177e4SLinus Torvalds 	}
6401da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
6411da177e4SLinus Torvalds }
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds /***************************************************************************/
644a2ba192cSAdrian Bunk static void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
6451da177e4SLinus Torvalds {
6461da177e4SLinus Torvalds 	pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE;	/* Supply base address  */
6471da177e4SLinus Torvalds 	pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS;	/* Supply BIOS address  */
6481da177e4SLinus Torvalds 	pCurHcb->HCS_Intr = i91u_adpt[ch_idx].ADPT_INTR;	/* Supply interrupt line */
6491da177e4SLinus Torvalds 	return;
6501da177e4SLinus Torvalds }
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds /***************************************************************************/
653a2ba192cSAdrian Bunk static int tul_reset_scsi(HCS * pCurHcb, int seconds)
6541da177e4SLinus Torvalds {
6551da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
6561da177e4SLinus Torvalds 
6571da177e4SLinus Torvalds 	while (!((pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt)) & TSS_SCSIRST_INT));
6581da177e4SLinus Torvalds 	/* reset tulip chip */
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, 0);
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	/* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
6631da177e4SLinus Torvalds 	/* SONY 5200 tape drive won't work if only stall for 1 sec */
6641da177e4SLinus Torvalds 	tul_do_pause(seconds * HZ);
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds 	return (SCSI_RESET_SUCCESS);
6691da177e4SLinus Torvalds }
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds /***************************************************************************/
672a2ba192cSAdrian Bunk static int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb,
673a2ba192cSAdrian Bunk 		      BYTE * pbBiosAdr, int seconds)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds 	int i;
6761da177e4SLinus Torvalds 	BYTE *pwFlags;
6771da177e4SLinus Torvalds 	BYTE *pbHeads;
6781da177e4SLinus Torvalds 	SCB *pTmpScb, *pPrevScb = NULL;
6791da177e4SLinus Torvalds 
6801da177e4SLinus Torvalds 	pCurHcb->HCS_NumScbs = tul_num_scb;
6811da177e4SLinus Torvalds 	pCurHcb->HCS_Semaph = 1;
6821da177e4SLinus Torvalds 	spin_lock_init(&pCurHcb->HCS_SemaphLock);
6831da177e4SLinus Torvalds 	pCurHcb->HCS_JSStatus0 = 0;
6841da177e4SLinus Torvalds 	pCurHcb->HCS_Scb = scbp;
6851da177e4SLinus Torvalds 	pCurHcb->HCS_NxtPend = scbp;
6861da177e4SLinus Torvalds 	pCurHcb->HCS_NxtAvail = scbp;
6871da177e4SLinus Torvalds 	for (i = 0, pTmpScb = scbp; i < tul_num_scb; i++, pTmpScb++) {
6881da177e4SLinus Torvalds 		pTmpScb->SCB_TagId = i;
6891da177e4SLinus Torvalds 		if (i != 0)
6901da177e4SLinus Torvalds 			pPrevScb->SCB_NxtScb = pTmpScb;
6911da177e4SLinus Torvalds 		pPrevScb = pTmpScb;
6921da177e4SLinus Torvalds 	}
6931da177e4SLinus Torvalds 	pPrevScb->SCB_NxtScb = NULL;
6941da177e4SLinus Torvalds 	pCurHcb->HCS_ScbEnd = pTmpScb;
6951da177e4SLinus Torvalds 	pCurHcb->HCS_FirstAvail = scbp;
6961da177e4SLinus Torvalds 	pCurHcb->HCS_LastAvail = pPrevScb;
6971da177e4SLinus Torvalds 	spin_lock_init(&pCurHcb->HCS_AvailLock);
6981da177e4SLinus Torvalds 	pCurHcb->HCS_FirstPend = NULL;
6991da177e4SLinus Torvalds 	pCurHcb->HCS_LastPend = NULL;
7001da177e4SLinus Torvalds 	pCurHcb->HCS_FirstBusy = NULL;
7011da177e4SLinus Torvalds 	pCurHcb->HCS_LastBusy = NULL;
7021da177e4SLinus Torvalds 	pCurHcb->HCS_FirstDone = NULL;
7031da177e4SLinus Torvalds 	pCurHcb->HCS_LastDone = NULL;
7041da177e4SLinus Torvalds 	pCurHcb->HCS_ActScb = NULL;
7051da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = NULL;
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	tul_read_eeprom(pCurHcb->HCS_Base);
7081da177e4SLinus Torvalds /*---------- get H/A configuration -------------*/
7091da177e4SLinus Torvalds 	if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
7101da177e4SLinus Torvalds 		pCurHcb->HCS_MaxTar = 8;
7111da177e4SLinus Torvalds 	else
7121da177e4SLinus Torvalds 		pCurHcb->HCS_MaxTar = 16;
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	pCurHcb->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	pCurHcb->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
7171da177e4SLinus Torvalds 	pCurHcb->HCS_IdMask = ~(1 << pCurHcb->HCS_SCSI_ID);
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds #if CHK_PARITY
7201da177e4SLinus Torvalds 	/* Enable parity error response */
7211da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_PCMD, TUL_RD(pCurHcb->HCS_Base, TUL_PCMD) | 0x40);
7221da177e4SLinus Torvalds #endif
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	/* Mask all the interrupt       */
7251da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	tul_stop_bm(pCurHcb);
7281da177e4SLinus Torvalds 	/* --- Initialize the tulip --- */
7291da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP);
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	/* program HBA's SCSI ID        */
7321da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId, pCurHcb->HCS_SCSI_ID << 4);
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	/* Enable Initiator Mode ,phase latch,alternate sync period mode,
7351da177e4SLinus Torvalds 	   disable SCSI reset */
7361da177e4SLinus Torvalds 	if (pCurHcb->HCS_Config & HCC_EN_PAR)
7371da177e4SLinus Torvalds 		pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
7381da177e4SLinus Torvalds 	else
7391da177e4SLinus Torvalds 		pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT);
7401da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_SConf1);
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds 	/* Enable HW reselect           */
7431da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
7441da177e4SLinus Torvalds 
7451da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, 0);
7461da177e4SLinus Torvalds 
7471da177e4SLinus Torvalds 	/* selection time out = 250 ms */
7481da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_STimeOut, 153);
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds /*--------- Enable SCSI terminator -----*/
7511da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, (pCurHcb->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)));
7521da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_GCTRL1,
7531da177e4SLinus Torvalds 	       ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE));
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	for (i = 0,
7561da177e4SLinus Torvalds 	     pwFlags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
7571da177e4SLinus Torvalds 	     pbHeads = pbBiosAdr + 0x180;
7581da177e4SLinus Torvalds 	     i < pCurHcb->HCS_MaxTar;
7591da177e4SLinus Torvalds 	     i++, pwFlags++) {
7601da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
7611da177e4SLinus Torvalds 		if (pCurHcb->HCS_Tcs[i].TCS_Flags & TCF_EN_255)
7621da177e4SLinus Torvalds 			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
7631da177e4SLinus Torvalds 		else
7641da177e4SLinus Torvalds 			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
7651da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_JS_Period = 0;
7661da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_SConfig0 = pCurHcb->HCS_SConf1;
7671da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_DrvHead = *pbHeads++;
7681da177e4SLinus Torvalds 		if (pCurHcb->HCS_Tcs[i].TCS_DrvHead == 255)
7691da177e4SLinus Torvalds 			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
7701da177e4SLinus Torvalds 		else
7711da177e4SLinus Torvalds 			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
7721da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_DrvSector = *pbHeads++;
7731da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;
7741da177e4SLinus Torvalds 		pCurHcb->HCS_ActTags[i] = 0;
7751da177e4SLinus Torvalds 		pCurHcb->HCS_MaxTags[i] = 0xFF;
7761da177e4SLinus Torvalds 	}			/* for                          */
7771da177e4SLinus Torvalds 	printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
7781da177e4SLinus Torvalds 	       pCurHcb->HCS_Base, pCurHcb->HCS_Intr,
7791da177e4SLinus Torvalds 	       pCurHcb->HCS_BIOS, pCurHcb->HCS_SCSI_ID);
7801da177e4SLinus Torvalds /*------------------- reset SCSI Bus ---------------------------*/
7811da177e4SLinus Torvalds 	if (pCurHcb->HCS_Config & HCC_SCSI_RESET) {
7821da177e4SLinus Torvalds 		printk("i91u: Reset SCSI Bus ... \n");
7831da177e4SLinus Torvalds 		tul_reset_scsi(pCurHcb, seconds);
7841da177e4SLinus Torvalds 	}
7851da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCFG1, 0x17);
7861da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SIntEnable, 0xE9);
7871da177e4SLinus Torvalds 	return (0);
7881da177e4SLinus Torvalds }
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds /***************************************************************************/
791a2ba192cSAdrian Bunk static SCB *tul_alloc_scb(HCS * hcsp)
7921da177e4SLinus Torvalds {
7931da177e4SLinus Torvalds 	SCB *pTmpScb;
7941da177e4SLinus Torvalds 	ULONG flags;
7951da177e4SLinus Torvalds 	spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
7961da177e4SLinus Torvalds 	if ((pTmpScb = hcsp->HCS_FirstAvail) != NULL) {
7971da177e4SLinus Torvalds #if DEBUG_QUEUE
7981da177e4SLinus Torvalds 		printk("find scb at %08lx\n", (ULONG) pTmpScb);
7991da177e4SLinus Torvalds #endif
8001da177e4SLinus Torvalds 		if ((hcsp->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL)
8011da177e4SLinus Torvalds 			hcsp->HCS_LastAvail = NULL;
8021da177e4SLinus Torvalds 		pTmpScb->SCB_NxtScb = NULL;
8031da177e4SLinus Torvalds 		pTmpScb->SCB_Status = SCB_RENT;
8041da177e4SLinus Torvalds 	}
8051da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
8061da177e4SLinus Torvalds 	return (pTmpScb);
8071da177e4SLinus Torvalds }
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds /***************************************************************************/
810a2ba192cSAdrian Bunk static void tul_release_scb(HCS * hcsp, SCB * scbp)
8111da177e4SLinus Torvalds {
8121da177e4SLinus Torvalds 	ULONG flags;
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds #if DEBUG_QUEUE
8151da177e4SLinus Torvalds 	printk("Release SCB %lx; ", (ULONG) scbp);
8161da177e4SLinus Torvalds #endif
8171da177e4SLinus Torvalds 	spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
8181da177e4SLinus Torvalds 	scbp->SCB_Srb = NULL;
8191da177e4SLinus Torvalds 	scbp->SCB_Status = 0;
8201da177e4SLinus Torvalds 	scbp->SCB_NxtScb = NULL;
8211da177e4SLinus Torvalds 	if (hcsp->HCS_LastAvail != NULL) {
8221da177e4SLinus Torvalds 		hcsp->HCS_LastAvail->SCB_NxtScb = scbp;
8231da177e4SLinus Torvalds 		hcsp->HCS_LastAvail = scbp;
8241da177e4SLinus Torvalds 	} else {
8251da177e4SLinus Torvalds 		hcsp->HCS_FirstAvail = scbp;
8261da177e4SLinus Torvalds 		hcsp->HCS_LastAvail = scbp;
8271da177e4SLinus Torvalds 	}
8281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
8291da177e4SLinus Torvalds }
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds /***************************************************************************/
832a2ba192cSAdrian Bunk static void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
8331da177e4SLinus Torvalds {
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds #if DEBUG_QUEUE
8361da177e4SLinus Torvalds 	printk("Append pend SCB %lx; ", (ULONG) scbp);
8371da177e4SLinus Torvalds #endif
8381da177e4SLinus Torvalds 	scbp->SCB_Status = SCB_PEND;
8391da177e4SLinus Torvalds 	scbp->SCB_NxtScb = NULL;
8401da177e4SLinus Torvalds 	if (pCurHcb->HCS_LastPend != NULL) {
8411da177e4SLinus Torvalds 		pCurHcb->HCS_LastPend->SCB_NxtScb = scbp;
8421da177e4SLinus Torvalds 		pCurHcb->HCS_LastPend = scbp;
8431da177e4SLinus Torvalds 	} else {
8441da177e4SLinus Torvalds 		pCurHcb->HCS_FirstPend = scbp;
8451da177e4SLinus Torvalds 		pCurHcb->HCS_LastPend = scbp;
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds }
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds /***************************************************************************/
850a2ba192cSAdrian Bunk static void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
8511da177e4SLinus Torvalds {
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds #if DEBUG_QUEUE
8541da177e4SLinus Torvalds 	printk("Push pend SCB %lx; ", (ULONG) scbp);
8551da177e4SLinus Torvalds #endif
8561da177e4SLinus Torvalds 	scbp->SCB_Status = SCB_PEND;
8571da177e4SLinus Torvalds 	if ((scbp->SCB_NxtScb = pCurHcb->HCS_FirstPend) != NULL) {
8581da177e4SLinus Torvalds 		pCurHcb->HCS_FirstPend = scbp;
8591da177e4SLinus Torvalds 	} else {
8601da177e4SLinus Torvalds 		pCurHcb->HCS_FirstPend = scbp;
8611da177e4SLinus Torvalds 		pCurHcb->HCS_LastPend = scbp;
8621da177e4SLinus Torvalds 	}
8631da177e4SLinus Torvalds }
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds /***************************************************************************/
866a2ba192cSAdrian Bunk static SCB *tul_find_first_pend_scb(HCS * pCurHcb)
8671da177e4SLinus Torvalds {
8681da177e4SLinus Torvalds 	SCB *pFirstPend;
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 
8711da177e4SLinus Torvalds 	pFirstPend = pCurHcb->HCS_FirstPend;
8721da177e4SLinus Torvalds 	while (pFirstPend != NULL) {
8731da177e4SLinus Torvalds 		if (pFirstPend->SCB_Opcode != ExecSCSI) {
8741da177e4SLinus Torvalds 			return (pFirstPend);
8751da177e4SLinus Torvalds 		}
8761da177e4SLinus Torvalds 		if (pFirstPend->SCB_TagMsg == 0) {
8771da177e4SLinus Torvalds 			if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] == 0) &&
8781da177e4SLinus Torvalds 			    !(pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
8791da177e4SLinus Torvalds 				return (pFirstPend);
8801da177e4SLinus Torvalds 			}
8811da177e4SLinus Torvalds 		} else {
8821da177e4SLinus Torvalds 			if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] >=
8831da177e4SLinus Torvalds 			  pCurHcb->HCS_MaxTags[pFirstPend->SCB_Target]) |
8841da177e4SLinus Torvalds 			    (pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
8851da177e4SLinus Torvalds 				pFirstPend = pFirstPend->SCB_NxtScb;
8861da177e4SLinus Torvalds 				continue;
8871da177e4SLinus Torvalds 			}
8881da177e4SLinus Torvalds 			return (pFirstPend);
8891da177e4SLinus Torvalds 		}
8901da177e4SLinus Torvalds 		pFirstPend = pFirstPend->SCB_NxtScb;
8911da177e4SLinus Torvalds 	}
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds 	return (pFirstPend);
8951da177e4SLinus Torvalds }
8961da177e4SLinus Torvalds /***************************************************************************/
897a2ba192cSAdrian Bunk static void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
8981da177e4SLinus Torvalds {
8991da177e4SLinus Torvalds 	SCB *pTmpScb, *pPrevScb;
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds #if DEBUG_QUEUE
9021da177e4SLinus Torvalds 	printk("unlink pend SCB %lx; ", (ULONG) pCurScb);
9031da177e4SLinus Torvalds #endif
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds 	pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;
9061da177e4SLinus Torvalds 	while (pTmpScb != NULL) {
9071da177e4SLinus Torvalds 		if (pCurScb == pTmpScb) {	/* Unlink this SCB              */
9081da177e4SLinus Torvalds 			if (pTmpScb == pCurHcb->HCS_FirstPend) {
9091da177e4SLinus Torvalds 				if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
9101da177e4SLinus Torvalds 					pCurHcb->HCS_LastPend = NULL;
9111da177e4SLinus Torvalds 			} else {
9121da177e4SLinus Torvalds 				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
9131da177e4SLinus Torvalds 				if (pTmpScb == pCurHcb->HCS_LastPend)
9141da177e4SLinus Torvalds 					pCurHcb->HCS_LastPend = pPrevScb;
9151da177e4SLinus Torvalds 			}
9161da177e4SLinus Torvalds 			pTmpScb->SCB_NxtScb = NULL;
9171da177e4SLinus Torvalds 			break;
9181da177e4SLinus Torvalds 		}
9191da177e4SLinus Torvalds 		pPrevScb = pTmpScb;
9201da177e4SLinus Torvalds 		pTmpScb = pTmpScb->SCB_NxtScb;
9211da177e4SLinus Torvalds 	}
9221da177e4SLinus Torvalds 	return;
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds /***************************************************************************/
925a2ba192cSAdrian Bunk static void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
9261da177e4SLinus Torvalds {
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds #if DEBUG_QUEUE
9291da177e4SLinus Torvalds 	printk("append busy SCB %lx; ", (ULONG) scbp);
9301da177e4SLinus Torvalds #endif
9311da177e4SLinus Torvalds 	if (scbp->SCB_TagMsg)
9321da177e4SLinus Torvalds 		pCurHcb->HCS_ActTags[scbp->SCB_Target]++;
9331da177e4SLinus Torvalds 	else
9341da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[scbp->SCB_Target].TCS_Flags |= TCF_BUSY;
9351da177e4SLinus Torvalds 	scbp->SCB_Status = SCB_BUSY;
9361da177e4SLinus Torvalds 	scbp->SCB_NxtScb = NULL;
9371da177e4SLinus Torvalds 	if (pCurHcb->HCS_LastBusy != NULL) {
9381da177e4SLinus Torvalds 		pCurHcb->HCS_LastBusy->SCB_NxtScb = scbp;
9391da177e4SLinus Torvalds 		pCurHcb->HCS_LastBusy = scbp;
9401da177e4SLinus Torvalds 	} else {
9411da177e4SLinus Torvalds 		pCurHcb->HCS_FirstBusy = scbp;
9421da177e4SLinus Torvalds 		pCurHcb->HCS_LastBusy = scbp;
9431da177e4SLinus Torvalds 	}
9441da177e4SLinus Torvalds }
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds /***************************************************************************/
947a2ba192cSAdrian Bunk static SCB *tul_pop_busy_scb(HCS * pCurHcb)
9481da177e4SLinus Torvalds {
9491da177e4SLinus Torvalds 	SCB *pTmpScb;
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 	if ((pTmpScb = pCurHcb->HCS_FirstBusy) != NULL) {
9531da177e4SLinus Torvalds 		if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
9541da177e4SLinus Torvalds 			pCurHcb->HCS_LastBusy = NULL;
9551da177e4SLinus Torvalds 		pTmpScb->SCB_NxtScb = NULL;
9561da177e4SLinus Torvalds 		if (pTmpScb->SCB_TagMsg)
9571da177e4SLinus Torvalds 			pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
9581da177e4SLinus Torvalds 		else
9591da177e4SLinus Torvalds 			pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
9601da177e4SLinus Torvalds 	}
9611da177e4SLinus Torvalds #if DEBUG_QUEUE
9621da177e4SLinus Torvalds 	printk("Pop busy SCB %lx; ", (ULONG) pTmpScb);
9631da177e4SLinus Torvalds #endif
9641da177e4SLinus Torvalds 	return (pTmpScb);
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds /***************************************************************************/
968a2ba192cSAdrian Bunk static void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
9691da177e4SLinus Torvalds {
9701da177e4SLinus Torvalds 	SCB *pTmpScb, *pPrevScb;
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds #if DEBUG_QUEUE
9731da177e4SLinus Torvalds 	printk("unlink busy SCB %lx; ", (ULONG) pCurScb);
9741da177e4SLinus Torvalds #endif
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
9771da177e4SLinus Torvalds 	while (pTmpScb != NULL) {
9781da177e4SLinus Torvalds 		if (pCurScb == pTmpScb) {	/* Unlink this SCB              */
9791da177e4SLinus Torvalds 			if (pTmpScb == pCurHcb->HCS_FirstBusy) {
9801da177e4SLinus Torvalds 				if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
9811da177e4SLinus Torvalds 					pCurHcb->HCS_LastBusy = NULL;
9821da177e4SLinus Torvalds 			} else {
9831da177e4SLinus Torvalds 				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
9841da177e4SLinus Torvalds 				if (pTmpScb == pCurHcb->HCS_LastBusy)
9851da177e4SLinus Torvalds 					pCurHcb->HCS_LastBusy = pPrevScb;
9861da177e4SLinus Torvalds 			}
9871da177e4SLinus Torvalds 			pTmpScb->SCB_NxtScb = NULL;
9881da177e4SLinus Torvalds 			if (pTmpScb->SCB_TagMsg)
9891da177e4SLinus Torvalds 				pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
9901da177e4SLinus Torvalds 			else
9911da177e4SLinus Torvalds 				pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
9921da177e4SLinus Torvalds 			break;
9931da177e4SLinus Torvalds 		}
9941da177e4SLinus Torvalds 		pPrevScb = pTmpScb;
9951da177e4SLinus Torvalds 		pTmpScb = pTmpScb->SCB_NxtScb;
9961da177e4SLinus Torvalds 	}
9971da177e4SLinus Torvalds 	return;
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds /***************************************************************************/
10011da177e4SLinus Torvalds SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
10021da177e4SLinus Torvalds {
10031da177e4SLinus Torvalds 	SCB *pTmpScb, *pPrevScb;
10041da177e4SLinus Torvalds 	WORD scbp_tarlun;
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds 	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
10081da177e4SLinus Torvalds 	while (pTmpScb != NULL) {
10091da177e4SLinus Torvalds 		scbp_tarlun = (pTmpScb->SCB_Lun << 8) | (pTmpScb->SCB_Target);
10101da177e4SLinus Torvalds 		if (scbp_tarlun == tarlun) {	/* Unlink this SCB              */
10111da177e4SLinus Torvalds 			break;
10121da177e4SLinus Torvalds 		}
10131da177e4SLinus Torvalds 		pPrevScb = pTmpScb;
10141da177e4SLinus Torvalds 		pTmpScb = pTmpScb->SCB_NxtScb;
10151da177e4SLinus Torvalds 	}
10161da177e4SLinus Torvalds #if DEBUG_QUEUE
10171da177e4SLinus Torvalds 	printk("find busy SCB %lx; ", (ULONG) pTmpScb);
10181da177e4SLinus Torvalds #endif
10191da177e4SLinus Torvalds 	return (pTmpScb);
10201da177e4SLinus Torvalds }
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds /***************************************************************************/
1023a2ba192cSAdrian Bunk static void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
10241da177e4SLinus Torvalds {
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds #if DEBUG_QUEUE
10271da177e4SLinus Torvalds 	printk("append done SCB %lx; ", (ULONG) scbp);
10281da177e4SLinus Torvalds #endif
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds 	scbp->SCB_Status = SCB_DONE;
10311da177e4SLinus Torvalds 	scbp->SCB_NxtScb = NULL;
10321da177e4SLinus Torvalds 	if (pCurHcb->HCS_LastDone != NULL) {
10331da177e4SLinus Torvalds 		pCurHcb->HCS_LastDone->SCB_NxtScb = scbp;
10341da177e4SLinus Torvalds 		pCurHcb->HCS_LastDone = scbp;
10351da177e4SLinus Torvalds 	} else {
10361da177e4SLinus Torvalds 		pCurHcb->HCS_FirstDone = scbp;
10371da177e4SLinus Torvalds 		pCurHcb->HCS_LastDone = scbp;
10381da177e4SLinus Torvalds 	}
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds /***************************************************************************/
10421da177e4SLinus Torvalds SCB *tul_find_done_scb(HCS * pCurHcb)
10431da177e4SLinus Torvalds {
10441da177e4SLinus Torvalds 	SCB *pTmpScb;
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds 	if ((pTmpScb = pCurHcb->HCS_FirstDone) != NULL) {
10481da177e4SLinus Torvalds 		if ((pCurHcb->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL)
10491da177e4SLinus Torvalds 			pCurHcb->HCS_LastDone = NULL;
10501da177e4SLinus Torvalds 		pTmpScb->SCB_NxtScb = NULL;
10511da177e4SLinus Torvalds 	}
10521da177e4SLinus Torvalds #if DEBUG_QUEUE
10531da177e4SLinus Torvalds 	printk("find done SCB %lx; ", (ULONG) pTmpScb);
10541da177e4SLinus Torvalds #endif
10551da177e4SLinus Torvalds 	return (pTmpScb);
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds /***************************************************************************/
1059a2ba192cSAdrian Bunk static int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
10601da177e4SLinus Torvalds {
10611da177e4SLinus Torvalds 	ULONG flags;
10621da177e4SLinus Torvalds 	SCB *pTmpScb, *pPrevScb;
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
10651da177e4SLinus Torvalds 
10661da177e4SLinus Torvalds 	if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
10671da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
10681da177e4SLinus Torvalds 		/* disable Jasmin SCSI Int        */
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds                 spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds 		tulip_main(pCurHcb);
10731da177e4SLinus Torvalds 
10741da177e4SLinus Torvalds         	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds 		pCurHcb->HCS_Semaph = 1;
10771da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds 		spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds 		return SCSI_ABORT_SNOOZE;
10821da177e4SLinus Torvalds 	}
10831da177e4SLinus Torvalds 	pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;	/* Check Pend queue */
10841da177e4SLinus Torvalds 	while (pTmpScb != NULL) {
10851da177e4SLinus Torvalds 		/* 07/27/98 */
10861da177e4SLinus Torvalds 		if (pTmpScb->SCB_Srb == srbp) {
10871da177e4SLinus Torvalds 			if (pTmpScb == pCurHcb->HCS_ActScb) {
10881da177e4SLinus Torvalds 				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
10891da177e4SLinus Torvalds 				return SCSI_ABORT_BUSY;
10901da177e4SLinus Torvalds 			} else if (pTmpScb == pCurHcb->HCS_FirstPend) {
10911da177e4SLinus Torvalds 				if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
10921da177e4SLinus Torvalds 					pCurHcb->HCS_LastPend = NULL;
10931da177e4SLinus Torvalds 			} else {
10941da177e4SLinus Torvalds 				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
10951da177e4SLinus Torvalds 				if (pTmpScb == pCurHcb->HCS_LastPend)
10961da177e4SLinus Torvalds 					pCurHcb->HCS_LastPend = pPrevScb;
10971da177e4SLinus Torvalds 			}
10981da177e4SLinus Torvalds 			pTmpScb->SCB_HaStat = HOST_ABORTED;
10991da177e4SLinus Torvalds 			pTmpScb->SCB_Flags |= SCF_DONE;
11001da177e4SLinus Torvalds 			if (pTmpScb->SCB_Flags & SCF_POST)
11011da177e4SLinus Torvalds 				(*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
11021da177e4SLinus Torvalds 			spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11031da177e4SLinus Torvalds 			return SCSI_ABORT_SUCCESS;
11041da177e4SLinus Torvalds 		}
11051da177e4SLinus Torvalds 		pPrevScb = pTmpScb;
11061da177e4SLinus Torvalds 		pTmpScb = pTmpScb->SCB_NxtScb;
11071da177e4SLinus Torvalds 	}
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;	/* Check Busy queue */
11101da177e4SLinus Torvalds 	while (pTmpScb != NULL) {
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 		if (pTmpScb->SCB_Srb == srbp) {
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 			if (pTmpScb == pCurHcb->HCS_ActScb) {
11151da177e4SLinus Torvalds 				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11161da177e4SLinus Torvalds 				return SCSI_ABORT_BUSY;
11171da177e4SLinus Torvalds 			} else if (pTmpScb->SCB_TagMsg == 0) {
11181da177e4SLinus Torvalds 				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11191da177e4SLinus Torvalds 				return SCSI_ABORT_BUSY;
11201da177e4SLinus Torvalds 			} else {
11211da177e4SLinus Torvalds 				pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
11221da177e4SLinus Torvalds 				if (pTmpScb == pCurHcb->HCS_FirstBusy) {
11231da177e4SLinus Torvalds 					if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
11241da177e4SLinus Torvalds 						pCurHcb->HCS_LastBusy = NULL;
11251da177e4SLinus Torvalds 				} else {
11261da177e4SLinus Torvalds 					pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
11271da177e4SLinus Torvalds 					if (pTmpScb == pCurHcb->HCS_LastBusy)
11281da177e4SLinus Torvalds 						pCurHcb->HCS_LastBusy = pPrevScb;
11291da177e4SLinus Torvalds 				}
11301da177e4SLinus Torvalds 				pTmpScb->SCB_NxtScb = NULL;
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 				pTmpScb->SCB_HaStat = HOST_ABORTED;
11341da177e4SLinus Torvalds 				pTmpScb->SCB_Flags |= SCF_DONE;
11351da177e4SLinus Torvalds 				if (pTmpScb->SCB_Flags & SCF_POST)
11361da177e4SLinus Torvalds 					(*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
11371da177e4SLinus Torvalds 				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11381da177e4SLinus Torvalds 				return SCSI_ABORT_SUCCESS;
11391da177e4SLinus Torvalds 			}
11401da177e4SLinus Torvalds 		}
11411da177e4SLinus Torvalds 		pPrevScb = pTmpScb;
11421da177e4SLinus Torvalds 		pTmpScb = pTmpScb->SCB_NxtScb;
11431da177e4SLinus Torvalds 	}
11441da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11451da177e4SLinus Torvalds 	return (SCSI_ABORT_NOT_RUNNING);
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds 
11481da177e4SLinus Torvalds /***************************************************************************/
1149a2ba192cSAdrian Bunk static int tul_bad_seq(HCS * pCurHcb)
11501da177e4SLinus Torvalds {
11511da177e4SLinus Torvalds 	SCB *pCurScb;
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 	printk("tul_bad_seg c=%d\n", pCurHcb->HCS_Index);
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
11561da177e4SLinus Torvalds 		tul_unlink_busy_scb(pCurHcb, pCurScb);
11571da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
11581da177e4SLinus Torvalds 		pCurScb->SCB_TaStat = 0;
11591da177e4SLinus Torvalds 		tul_append_done_scb(pCurHcb, pCurScb);
11601da177e4SLinus Torvalds 	}
11611da177e4SLinus Torvalds 	tul_stop_bm(pCurHcb);
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 	tul_reset_scsi(pCurHcb, 8);	/* 7/29/98 */
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds 	return (tul_post_scsi_rst(pCurHcb));
11661da177e4SLinus Torvalds }
11671da177e4SLinus Torvalds 
1168a2ba192cSAdrian Bunk #if 0
1169a2ba192cSAdrian Bunk 
11701da177e4SLinus Torvalds /************************************************************************/
1171a2ba192cSAdrian Bunk static int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
11721da177e4SLinus Torvalds 			    unsigned int target, unsigned int ResetFlags)
11731da177e4SLinus Torvalds {
11741da177e4SLinus Torvalds 	ULONG flags;
11751da177e4SLinus Torvalds 	SCB *pScb;
11761da177e4SLinus Torvalds 	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 	if (ResetFlags & SCSI_RESET_ASYNCHRONOUS) {
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 		if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
11811da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
11821da177e4SLinus Torvalds 			/* disable Jasmin SCSI Int        */
11831da177e4SLinus Torvalds 
11841da177e4SLinus Torvalds         		spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 			tulip_main(pCurHcb);
11871da177e4SLinus Torvalds 
11881da177e4SLinus Torvalds         		spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds 			pCurHcb->HCS_Semaph = 1;
11911da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 			spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 			return SCSI_RESET_SNOOZE;
11961da177e4SLinus Torvalds 		}
11971da177e4SLinus Torvalds 		pScb = pCurHcb->HCS_FirstBusy;	/* Check Busy queue */
11981da177e4SLinus Torvalds 		while (pScb != NULL) {
11991da177e4SLinus Torvalds 			if (pScb->SCB_Srb == pSrb)
12001da177e4SLinus Torvalds 				break;
12011da177e4SLinus Torvalds 			pScb = pScb->SCB_NxtScb;
12021da177e4SLinus Torvalds 		}
12031da177e4SLinus Torvalds 		if (pScb == NULL) {
12041da177e4SLinus Torvalds 			printk("Unable to Reset - No SCB Found\n");
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 			spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12071da177e4SLinus Torvalds 			return SCSI_RESET_NOT_RUNNING;
12081da177e4SLinus Torvalds 		}
12091da177e4SLinus Torvalds 	}
12101da177e4SLinus Torvalds 	if ((pScb = tul_alloc_scb(pCurHcb)) == NULL) {
12111da177e4SLinus Torvalds 		spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12121da177e4SLinus Torvalds 		return SCSI_RESET_NOT_RUNNING;
12131da177e4SLinus Torvalds 	}
12141da177e4SLinus Torvalds 	pScb->SCB_Opcode = BusDevRst;
12151da177e4SLinus Torvalds 	pScb->SCB_Flags = SCF_POST;
12161da177e4SLinus Torvalds 	pScb->SCB_Target = target;
12171da177e4SLinus Torvalds 	pScb->SCB_Mode = 0;
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	pScb->SCB_Srb = NULL;
12201da177e4SLinus Torvalds 	if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
12211da177e4SLinus Torvalds 		pScb->SCB_Srb = pSrb;
12221da177e4SLinus Torvalds 	}
12231da177e4SLinus Torvalds 	tul_push_pend_scb(pCurHcb, pScb);	/* push this SCB to Pending queue */
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds 	if (pCurHcb->HCS_Semaph == 1) {
12261da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
12271da177e4SLinus Torvalds 		/* disable Jasmin SCSI Int        */
12281da177e4SLinus Torvalds 		pCurHcb->HCS_Semaph = 0;
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds         	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 		tulip_main(pCurHcb);
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds                 spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 		pCurHcb->HCS_Semaph = 1;
12371da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
12381da177e4SLinus Torvalds 	}
12391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12401da177e4SLinus Torvalds 	return SCSI_RESET_PENDING;
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
1243a2ba192cSAdrian Bunk static int tul_reset_scsi_bus(HCS * pCurHcb)
12441da177e4SLinus Torvalds {
12451da177e4SLinus Torvalds 	ULONG flags;
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
12481da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
12491da177e4SLinus Torvalds 	pCurHcb->HCS_Semaph = 0;
12501da177e4SLinus Torvalds 
12511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds 	tul_stop_bm(pCurHcb);
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds 	tul_reset_scsi(pCurHcb, 2);	/* 7/29/98 */
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
12581da177e4SLinus Torvalds 	tul_post_scsi_rst(pCurHcb);
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds         spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12611da177e4SLinus Torvalds 
12621da177e4SLinus Torvalds 	tulip_main(pCurHcb);
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds         spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
12651da177e4SLinus Torvalds 
12661da177e4SLinus Torvalds 	pCurHcb->HCS_Semaph = 1;
12671da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
12681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12691da177e4SLinus Torvalds 	return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
12701da177e4SLinus Torvalds }
12711da177e4SLinus Torvalds 
1272a2ba192cSAdrian Bunk #endif  /*  0  */
1273a2ba192cSAdrian Bunk 
12741da177e4SLinus Torvalds /************************************************************************/
1275a2ba192cSAdrian Bunk static void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
12761da177e4SLinus Torvalds {
12771da177e4SLinus Torvalds 	ULONG flags;
12781da177e4SLinus Torvalds 
12791da177e4SLinus Torvalds 	pCurScb->SCB_Mode = 0;
12801da177e4SLinus Torvalds 
12811da177e4SLinus Torvalds 	pCurScb->SCB_SGIdx = 0;
12821da177e4SLinus Torvalds 	pCurScb->SCB_SGMax = pCurScb->SCB_SGLen;
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds 	tul_append_pend_scb(pCurHcb, pCurScb);	/* Append this SCB to Pending queue */
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds /* VVVVV 07/21/98 */
12891da177e4SLinus Torvalds 	if (pCurHcb->HCS_Semaph == 1) {
12901da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
12911da177e4SLinus Torvalds 		/* disable Jasmin SCSI Int        */
12921da177e4SLinus Torvalds 		pCurHcb->HCS_Semaph = 0;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds         	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds 		tulip_main(pCurHcb);
12971da177e4SLinus Torvalds 
12981da177e4SLinus Torvalds         	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
12991da177e4SLinus Torvalds 
13001da177e4SLinus Torvalds 		pCurHcb->HCS_Semaph = 1;
13011da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
13021da177e4SLinus Torvalds 	}
13031da177e4SLinus Torvalds 	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
13041da177e4SLinus Torvalds 	return;
13051da177e4SLinus Torvalds }
13061da177e4SLinus Torvalds 
13071da177e4SLinus Torvalds /***************************************************************************/
1308a2ba192cSAdrian Bunk static int tul_isr(HCS * pCurHcb)
13091da177e4SLinus Torvalds {
13101da177e4SLinus Torvalds 	/* Enter critical section       */
13111da177e4SLinus Torvalds 
13121da177e4SLinus Torvalds 	if (TUL_RD(pCurHcb->HCS_Base, TUL_Int) & TSS_INT_PENDING) {
13131da177e4SLinus Torvalds 		if (pCurHcb->HCS_Semaph == 1) {
13141da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
13151da177e4SLinus Torvalds 			/* Disable Tulip SCSI Int */
13161da177e4SLinus Torvalds 			pCurHcb->HCS_Semaph = 0;
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 			tulip_main(pCurHcb);
13191da177e4SLinus Torvalds 
13201da177e4SLinus Torvalds 			pCurHcb->HCS_Semaph = 1;
13211da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
13221da177e4SLinus Torvalds 			return (1);
13231da177e4SLinus Torvalds 		}
13241da177e4SLinus Torvalds 	}
13251da177e4SLinus Torvalds 	return (0);
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds /***************************************************************************/
13291da177e4SLinus Torvalds int tulip_main(HCS * pCurHcb)
13301da177e4SLinus Torvalds {
13311da177e4SLinus Torvalds 	SCB *pCurScb;
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	for (;;) {
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds 		tulip_scsi(pCurHcb);	/* Call tulip_scsi              */
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 		while ((pCurScb = tul_find_done_scb(pCurHcb)) != NULL) {	/* find done entry */
13381da177e4SLinus Torvalds 			if (pCurScb->SCB_TaStat == INI_QUEUE_FULL) {
13391da177e4SLinus Torvalds 				pCurHcb->HCS_MaxTags[pCurScb->SCB_Target] =
13401da177e4SLinus Torvalds 				    pCurHcb->HCS_ActTags[pCurScb->SCB_Target] - 1;
13411da177e4SLinus Torvalds 				pCurScb->SCB_TaStat = 0;
13421da177e4SLinus Torvalds 				tul_append_pend_scb(pCurHcb, pCurScb);
13431da177e4SLinus Torvalds 				continue;
13441da177e4SLinus Torvalds 			}
13451da177e4SLinus Torvalds 			if (!(pCurScb->SCB_Mode & SCM_RSENS)) {		/* not in auto req. sense mode */
13461da177e4SLinus Torvalds 				if (pCurScb->SCB_TaStat == 2) {
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 					/* clr sync. nego flag */
13491da177e4SLinus Torvalds 
13501da177e4SLinus Torvalds 					if (pCurScb->SCB_Flags & SCF_SENSE) {
13511da177e4SLinus Torvalds 						BYTE len;
13521da177e4SLinus Torvalds 						len = pCurScb->SCB_SenseLen;
13531da177e4SLinus Torvalds 						if (len == 0)
13541da177e4SLinus Torvalds 							len = 1;
13551da177e4SLinus Torvalds 						pCurScb->SCB_BufLen = pCurScb->SCB_SenseLen;
13561da177e4SLinus Torvalds 						pCurScb->SCB_BufPtr = pCurScb->SCB_SensePtr;
13571da177e4SLinus Torvalds 						pCurScb->SCB_Flags &= ~(SCF_SG | SCF_DIR);	/* for xfer_data_in */
13581da177e4SLinus Torvalds /*                      pCurScb->SCB_Flags |= SCF_NO_DCHK;      */
13591da177e4SLinus Torvalds 						/* so, we won't report worng direction in xfer_data_in,
13601da177e4SLinus Torvalds 						   and won't report HOST_DO_DU in state_6 */
13611da177e4SLinus Torvalds 						pCurScb->SCB_Mode = SCM_RSENS;
13621da177e4SLinus Torvalds 						pCurScb->SCB_Ident &= 0xBF;	/* Disable Disconnect */
13631da177e4SLinus Torvalds 						pCurScb->SCB_TagMsg = 0;
13641da177e4SLinus Torvalds 						pCurScb->SCB_TaStat = 0;
13651da177e4SLinus Torvalds 						pCurScb->SCB_CDBLen = 6;
13661da177e4SLinus Torvalds 						pCurScb->SCB_CDB[0] = SCSICMD_RequestSense;
13671da177e4SLinus Torvalds 						pCurScb->SCB_CDB[1] = 0;
13681da177e4SLinus Torvalds 						pCurScb->SCB_CDB[2] = 0;
13691da177e4SLinus Torvalds 						pCurScb->SCB_CDB[3] = 0;
13701da177e4SLinus Torvalds 						pCurScb->SCB_CDB[4] = len;
13711da177e4SLinus Torvalds 						pCurScb->SCB_CDB[5] = 0;
13721da177e4SLinus Torvalds 						tul_push_pend_scb(pCurHcb, pCurScb);
13731da177e4SLinus Torvalds 						break;
13741da177e4SLinus Torvalds 					}
13751da177e4SLinus Torvalds 				}
13761da177e4SLinus Torvalds 			} else {	/* in request sense mode */
13771da177e4SLinus Torvalds 
13781da177e4SLinus Torvalds 				if (pCurScb->SCB_TaStat == 2) {		/* check contition status again after sending
13791da177e4SLinus Torvalds 									   requset sense cmd 0x3 */
13801da177e4SLinus Torvalds 					pCurScb->SCB_HaStat = HOST_BAD_PHAS;
13811da177e4SLinus Torvalds 				}
13821da177e4SLinus Torvalds 				pCurScb->SCB_TaStat = 2;
13831da177e4SLinus Torvalds 			}
13841da177e4SLinus Torvalds 			pCurScb->SCB_Flags |= SCF_DONE;
13851da177e4SLinus Torvalds 			if (pCurScb->SCB_Flags & SCF_POST) {
13861da177e4SLinus Torvalds 				(*pCurScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pCurScb);
13871da177e4SLinus Torvalds 			}
13881da177e4SLinus Torvalds 		}		/* while */
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 		/* find_active: */
13911da177e4SLinus Torvalds 		if (TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0) & TSS_INT_PENDING)
13921da177e4SLinus Torvalds 			continue;
13931da177e4SLinus Torvalds 
13941da177e4SLinus Torvalds 		if (pCurHcb->HCS_ActScb) {	/* return to OS and wait for xfer_done_ISR/Selected_ISR */
13951da177e4SLinus Torvalds 			return 1;	/* return to OS, enable interrupt */
13961da177e4SLinus Torvalds 		}
13971da177e4SLinus Torvalds 		/* Check pending SCB            */
13981da177e4SLinus Torvalds 		if (tul_find_first_pend_scb(pCurHcb) == NULL) {
13991da177e4SLinus Torvalds 			return 1;	/* return to OS, enable interrupt */
14001da177e4SLinus Torvalds 		}
14011da177e4SLinus Torvalds 	}			/* End of for loop */
14021da177e4SLinus Torvalds 	/* statement won't reach here */
14031da177e4SLinus Torvalds }
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 
14061da177e4SLinus Torvalds 
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
14091da177e4SLinus Torvalds /***************************************************************************/
14101da177e4SLinus Torvalds /***************************************************************************/
14111da177e4SLinus Torvalds /***************************************************************************/
14121da177e4SLinus Torvalds /***************************************************************************/
14131da177e4SLinus Torvalds 
14141da177e4SLinus Torvalds /***************************************************************************/
14151da177e4SLinus Torvalds void tulip_scsi(HCS * pCurHcb)
14161da177e4SLinus Torvalds {
14171da177e4SLinus Torvalds 	SCB *pCurScb;
14181da177e4SLinus Torvalds 	TCS *pCurTcb;
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 	/* make sure to service interrupt asap */
14211da177e4SLinus Torvalds 
14221da177e4SLinus Torvalds 	if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 		pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
14251da177e4SLinus Torvalds 		pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
14261da177e4SLinus Torvalds 		pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
14271da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* SCSI bus reset detected      */
14281da177e4SLinus Torvalds 			int_tul_scsi_rst(pCurHcb);
14291da177e4SLinus Torvalds 			return;
14301da177e4SLinus Torvalds 		}
14311da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {	/* if selected/reselected interrupt */
14321da177e4SLinus Torvalds 			if (int_tul_resel(pCurHcb) == 0)
14331da177e4SLinus Torvalds 				tul_next_state(pCurHcb);
14341da177e4SLinus Torvalds 			return;
14351da177e4SLinus Torvalds 		}
14361da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {
14371da177e4SLinus Torvalds 			int_tul_busfree(pCurHcb);
14381da177e4SLinus Torvalds 			return;
14391da177e4SLinus Torvalds 		}
14401da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
14411da177e4SLinus Torvalds 			int_tul_busfree(pCurHcb);	/* unexpected bus free or sel timeout */
14421da177e4SLinus Torvalds 			return;
14431da177e4SLinus Torvalds 		}
14441da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {	/* func complete or Bus service */
14451da177e4SLinus Torvalds 			if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)
14461da177e4SLinus Torvalds 				tul_next_state(pCurHcb);
14471da177e4SLinus Torvalds 			return;
14481da177e4SLinus Torvalds 		}
14491da177e4SLinus Torvalds 	}
14501da177e4SLinus Torvalds 	if (pCurHcb->HCS_ActScb != NULL)
14511da177e4SLinus Torvalds 		return;
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 	if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)
14541da177e4SLinus Torvalds 		return;
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds 	/* program HBA's SCSI ID & target SCSI ID */
14571da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,
14581da177e4SLinus Torvalds 	     (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));
14591da177e4SLinus Torvalds 	if (pCurScb->SCB_Opcode == ExecSCSI) {
14601da177e4SLinus Torvalds 		pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 		if (pCurScb->SCB_TagMsg)
14631da177e4SLinus Torvalds 			pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;
14641da177e4SLinus Torvalds 		else
14651da177e4SLinus Torvalds 			pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
14681da177e4SLinus Torvalds 		if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {	/* do wdtr negotiation          */
14691da177e4SLinus Torvalds 			tul_select_atn_stop(pCurHcb, pCurScb);
14701da177e4SLinus Torvalds 		} else {
14711da177e4SLinus Torvalds 			if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {	/* do sync negotiation          */
14721da177e4SLinus Torvalds 				tul_select_atn_stop(pCurHcb, pCurScb);
14731da177e4SLinus Torvalds 			} else {
14741da177e4SLinus Torvalds 				if (pCurScb->SCB_TagMsg)
14751da177e4SLinus Torvalds 					tul_select_atn3(pCurHcb, pCurScb);
14761da177e4SLinus Torvalds 				else
14771da177e4SLinus Torvalds 					tul_select_atn(pCurHcb, pCurScb);
14781da177e4SLinus Torvalds 			}
14791da177e4SLinus Torvalds 		}
14801da177e4SLinus Torvalds 		if (pCurScb->SCB_Flags & SCF_POLL) {
14811da177e4SLinus Torvalds 			while (wait_tulip(pCurHcb) != -1) {
14821da177e4SLinus Torvalds 				if (tul_next_state(pCurHcb) == -1)
14831da177e4SLinus Torvalds 					break;
14841da177e4SLinus Torvalds 			}
14851da177e4SLinus Torvalds 		}
14861da177e4SLinus Torvalds 	} else if (pCurScb->SCB_Opcode == BusDevRst) {
14871da177e4SLinus Torvalds 		tul_select_atn_stop(pCurHcb, pCurScb);
14881da177e4SLinus Torvalds 		pCurScb->SCB_NxtStat = 8;
14891da177e4SLinus Torvalds 		if (pCurScb->SCB_Flags & SCF_POLL) {
14901da177e4SLinus Torvalds 			while (wait_tulip(pCurHcb) != -1) {
14911da177e4SLinus Torvalds 				if (tul_next_state(pCurHcb) == -1)
14921da177e4SLinus Torvalds 					break;
14931da177e4SLinus Torvalds 			}
14941da177e4SLinus Torvalds 		}
14951da177e4SLinus Torvalds 	} else if (pCurScb->SCB_Opcode == AbortCmd) {
14961da177e4SLinus Torvalds 		if (tul_abort_srb(pCurHcb, pCurScb->SCB_Srb) != 0) {
14971da177e4SLinus Torvalds 
14981da177e4SLinus Torvalds 
14991da177e4SLinus Torvalds 			tul_unlink_pend_scb(pCurHcb, pCurScb);
15001da177e4SLinus Torvalds 
15011da177e4SLinus Torvalds 			tul_release_scb(pCurHcb, pCurScb);
15021da177e4SLinus Torvalds 		} else {
15031da177e4SLinus Torvalds 			pCurScb->SCB_Opcode = BusDevRst;
15041da177e4SLinus Torvalds 			tul_select_atn_stop(pCurHcb, pCurScb);
15051da177e4SLinus Torvalds 			pCurScb->SCB_NxtStat = 8;
15061da177e4SLinus Torvalds 		}
15071da177e4SLinus Torvalds 
15081da177e4SLinus Torvalds /* 08/03/98 */
15091da177e4SLinus Torvalds 	} else {
15101da177e4SLinus Torvalds 		tul_unlink_pend_scb(pCurHcb, pCurScb);
15111da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = 0x16;	/* bad command */
15121da177e4SLinus Torvalds 		tul_append_done_scb(pCurHcb, pCurScb);
15131da177e4SLinus Torvalds 	}
15141da177e4SLinus Torvalds 	return;
15151da177e4SLinus Torvalds }
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds 
15181da177e4SLinus Torvalds /***************************************************************************/
15191da177e4SLinus Torvalds int tul_next_state(HCS * pCurHcb)
15201da177e4SLinus Torvalds {
15211da177e4SLinus Torvalds 	int next;
15221da177e4SLinus Torvalds 
15231da177e4SLinus Torvalds 	next = pCurHcb->HCS_ActScb->SCB_NxtStat;
15241da177e4SLinus Torvalds 	for (;;) {
15251da177e4SLinus Torvalds 		switch (next) {
15261da177e4SLinus Torvalds 		case 1:
15271da177e4SLinus Torvalds 			next = tul_state_1(pCurHcb);
15281da177e4SLinus Torvalds 			break;
15291da177e4SLinus Torvalds 		case 2:
15301da177e4SLinus Torvalds 			next = tul_state_2(pCurHcb);
15311da177e4SLinus Torvalds 			break;
15321da177e4SLinus Torvalds 		case 3:
15331da177e4SLinus Torvalds 			next = tul_state_3(pCurHcb);
15341da177e4SLinus Torvalds 			break;
15351da177e4SLinus Torvalds 		case 4:
15361da177e4SLinus Torvalds 			next = tul_state_4(pCurHcb);
15371da177e4SLinus Torvalds 			break;
15381da177e4SLinus Torvalds 		case 5:
15391da177e4SLinus Torvalds 			next = tul_state_5(pCurHcb);
15401da177e4SLinus Torvalds 			break;
15411da177e4SLinus Torvalds 		case 6:
15421da177e4SLinus Torvalds 			next = tul_state_6(pCurHcb);
15431da177e4SLinus Torvalds 			break;
15441da177e4SLinus Torvalds 		case 7:
15451da177e4SLinus Torvalds 			next = tul_state_7(pCurHcb);
15461da177e4SLinus Torvalds 			break;
15471da177e4SLinus Torvalds 		case 8:
15481da177e4SLinus Torvalds 			return (tul_bus_device_reset(pCurHcb));
15491da177e4SLinus Torvalds 		default:
15501da177e4SLinus Torvalds 			return (tul_bad_seq(pCurHcb));
15511da177e4SLinus Torvalds 		}
15521da177e4SLinus Torvalds 		if (next <= 0)
15531da177e4SLinus Torvalds 			return next;
15541da177e4SLinus Torvalds 	}
15551da177e4SLinus Torvalds }
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds /***************************************************************************/
15591da177e4SLinus Torvalds /* sTate after selection with attention & stop */
15601da177e4SLinus Torvalds int tul_state_1(HCS * pCurHcb)
15611da177e4SLinus Torvalds {
15621da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
15631da177e4SLinus Torvalds 	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
15641da177e4SLinus Torvalds #if DEBUG_STATE
15651da177e4SLinus Torvalds 	printk("-s1-");
15661da177e4SLinus Torvalds #endif
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds 	tul_unlink_pend_scb(pCurHcb, pCurScb);
15691da177e4SLinus Torvalds 	tul_append_busy_scb(pCurHcb, pCurScb);
15701da177e4SLinus Torvalds 
15711da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
15721da177e4SLinus Torvalds 	/* ATN on */
15731da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase == MSG_OUT) {
15741da177e4SLinus Torvalds 
15751da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));
15761da177e4SLinus Torvalds 
15771da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
15781da177e4SLinus Torvalds 
15791da177e4SLinus Torvalds 		if (pCurScb->SCB_TagMsg) {
15801da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
15811da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
15821da177e4SLinus Torvalds 		}
15831da177e4SLinus Torvalds 		if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
15841da177e4SLinus Torvalds 
15851da177e4SLinus Torvalds 			pCurTcb->TCS_Flags |= TCF_WDTR_DONE;
15861da177e4SLinus Torvalds 
15871da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
15881da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);	/* Extended msg length */
15891da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* Sync request */
15901da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* Start from 16 bits */
15911da177e4SLinus Torvalds 		} else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds 			pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
15941da177e4SLinus Torvalds 
15951da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
15961da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* extended msg length */
15971da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* sync request */
15981da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
15991da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);	/* REQ/ACK offset */
16001da177e4SLinus Torvalds 		}
16011da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
16021da177e4SLinus Torvalds 		if (wait_tulip(pCurHcb) == -1)
16031da177e4SLinus Torvalds 			return (-1);
16041da177e4SLinus Torvalds 	}
16051da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
16061da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
16071da177e4SLinus Torvalds 	return (3);
16081da177e4SLinus Torvalds }
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 
16111da177e4SLinus Torvalds /***************************************************************************/
16121da177e4SLinus Torvalds /* state after selection with attention */
16131da177e4SLinus Torvalds /* state after selection with attention3 */
16141da177e4SLinus Torvalds int tul_state_2(HCS * pCurHcb)
16151da177e4SLinus Torvalds {
16161da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
16171da177e4SLinus Torvalds 	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
16181da177e4SLinus Torvalds #if DEBUG_STATE
16191da177e4SLinus Torvalds 	printk("-s2-");
16201da177e4SLinus Torvalds #endif
16211da177e4SLinus Torvalds 
16221da177e4SLinus Torvalds 	tul_unlink_pend_scb(pCurHcb, pCurScb);
16231da177e4SLinus Torvalds 	tul_append_busy_scb(pCurHcb, pCurScb);
16241da177e4SLinus Torvalds 
16251da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
16261da177e4SLinus Torvalds 
16271da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {
16281da177e4SLinus Torvalds 		return (4);
16291da177e4SLinus Torvalds 	}
16301da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
16311da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
16321da177e4SLinus Torvalds 	return (3);
16331da177e4SLinus Torvalds }
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds /***************************************************************************/
16361da177e4SLinus Torvalds /* state before CDB xfer is done */
16371da177e4SLinus Torvalds int tul_state_3(HCS * pCurHcb)
16381da177e4SLinus Torvalds {
16391da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
16401da177e4SLinus Torvalds 	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
16411da177e4SLinus Torvalds 	int i;
16421da177e4SLinus Torvalds 
16431da177e4SLinus Torvalds #if DEBUG_STATE
16441da177e4SLinus Torvalds 	printk("-s3-");
16451da177e4SLinus Torvalds #endif
16461da177e4SLinus Torvalds 	for (;;) {
16471da177e4SLinus Torvalds 		switch (pCurHcb->HCS_Phase) {
16481da177e4SLinus Torvalds 		case CMD_OUT:	/* Command out phase            */
16491da177e4SLinus Torvalds 			for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
16501da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
16511da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
16521da177e4SLinus Torvalds 			if (wait_tulip(pCurHcb) == -1)
16531da177e4SLinus Torvalds 				return (-1);
16541da177e4SLinus Torvalds 			if (pCurHcb->HCS_Phase == CMD_OUT) {
16551da177e4SLinus Torvalds 				return (tul_bad_seq(pCurHcb));
16561da177e4SLinus Torvalds 			}
16571da177e4SLinus Torvalds 			return (4);
16581da177e4SLinus Torvalds 
16591da177e4SLinus Torvalds 		case MSG_IN:	/* Message in phase             */
16601da177e4SLinus Torvalds 			pCurScb->SCB_NxtStat = 3;
16611da177e4SLinus Torvalds 			if (tul_msgin(pCurHcb) == -1)
16621da177e4SLinus Torvalds 				return (-1);
16631da177e4SLinus Torvalds 			break;
16641da177e4SLinus Torvalds 
16651da177e4SLinus Torvalds 		case STATUS_IN:	/* Status phase                 */
16661da177e4SLinus Torvalds 			if (tul_status_msg(pCurHcb) == -1)
16671da177e4SLinus Torvalds 				return (-1);
16681da177e4SLinus Torvalds 			break;
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 		case MSG_OUT:	/* Message out phase            */
16711da177e4SLinus Torvalds 			if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
16721da177e4SLinus Torvalds 
16731da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */
16741da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
16751da177e4SLinus Torvalds 				if (wait_tulip(pCurHcb) == -1)
16761da177e4SLinus Torvalds 					return (-1);
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 			} else {
16791da177e4SLinus Torvalds 				pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
16801da177e4SLinus Torvalds 
16811da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
16821da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* ext. msg len */
16831da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* sync request */
16841da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
16851da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);	/* REQ/ACK offset */
16861da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
16871da177e4SLinus Torvalds 				if (wait_tulip(pCurHcb) == -1)
16881da177e4SLinus Torvalds 					return (-1);
16891da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
16901da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));
16911da177e4SLinus Torvalds 
16921da177e4SLinus Torvalds 			}
16931da177e4SLinus Torvalds 			break;
16941da177e4SLinus Torvalds 
16951da177e4SLinus Torvalds 		default:
16961da177e4SLinus Torvalds 			return (tul_bad_seq(pCurHcb));
16971da177e4SLinus Torvalds 		}
16981da177e4SLinus Torvalds 	}
16991da177e4SLinus Torvalds }
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 
17021da177e4SLinus Torvalds /***************************************************************************/
17031da177e4SLinus Torvalds int tul_state_4(HCS * pCurHcb)
17041da177e4SLinus Torvalds {
17051da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
17061da177e4SLinus Torvalds 
17071da177e4SLinus Torvalds #if DEBUG_STATE
17081da177e4SLinus Torvalds 	printk("-s4-");
17091da177e4SLinus Torvalds #endif
17101da177e4SLinus Torvalds 	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {
17111da177e4SLinus Torvalds 		return (6);	/* Go to state 6                */
17121da177e4SLinus Torvalds 	}
17131da177e4SLinus Torvalds 	for (;;) {
17141da177e4SLinus Torvalds 		if (pCurScb->SCB_BufLen == 0)
17151da177e4SLinus Torvalds 			return (6);	/* Go to state 6                */
17161da177e4SLinus Torvalds 
17171da177e4SLinus Torvalds 		switch (pCurHcb->HCS_Phase) {
17181da177e4SLinus Torvalds 
17191da177e4SLinus Torvalds 		case STATUS_IN:	/* Status phase                 */
17201da177e4SLinus Torvalds 			if ((pCurScb->SCB_Flags & SCF_DIR) != 0) {	/* if direction bit set then report data underrun */
17211da177e4SLinus Torvalds 				pCurScb->SCB_HaStat = HOST_DO_DU;
17221da177e4SLinus Torvalds 			}
17231da177e4SLinus Torvalds 			if ((tul_status_msg(pCurHcb)) == -1)
17241da177e4SLinus Torvalds 				return (-1);
17251da177e4SLinus Torvalds 			break;
17261da177e4SLinus Torvalds 
17271da177e4SLinus Torvalds 		case MSG_IN:	/* Message in phase             */
17281da177e4SLinus Torvalds 			pCurScb->SCB_NxtStat = 0x4;
17291da177e4SLinus Torvalds 			if (tul_msgin(pCurHcb) == -1)
17301da177e4SLinus Torvalds 				return (-1);
17311da177e4SLinus Torvalds 			break;
17321da177e4SLinus Torvalds 
17331da177e4SLinus Torvalds 		case MSG_OUT:	/* Message out phase            */
17341da177e4SLinus Torvalds 			if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
17351da177e4SLinus Torvalds 				pCurScb->SCB_BufLen = 0;
17361da177e4SLinus Torvalds 				pCurScb->SCB_HaStat = HOST_DO_DU;
17371da177e4SLinus Torvalds 				if (tul_msgout_ide(pCurHcb) == -1)
17381da177e4SLinus Torvalds 					return (-1);
17391da177e4SLinus Torvalds 				return (6);	/* Go to state 6                */
17401da177e4SLinus Torvalds 			} else {
17411da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */
17421da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
17431da177e4SLinus Torvalds 				if (wait_tulip(pCurHcb) == -1)
17441da177e4SLinus Torvalds 					return (-1);
17451da177e4SLinus Torvalds 			}
17461da177e4SLinus Torvalds 			break;
17471da177e4SLinus Torvalds 
17481da177e4SLinus Torvalds 		case DATA_IN:	/* Data in phase                */
17491da177e4SLinus Torvalds 			return (tul_xfer_data_in(pCurHcb));
17501da177e4SLinus Torvalds 
17511da177e4SLinus Torvalds 		case DATA_OUT:	/* Data out phase               */
17521da177e4SLinus Torvalds 			return (tul_xfer_data_out(pCurHcb));
17531da177e4SLinus Torvalds 
17541da177e4SLinus Torvalds 		default:
17551da177e4SLinus Torvalds 			return (tul_bad_seq(pCurHcb));
17561da177e4SLinus Torvalds 		}
17571da177e4SLinus Torvalds 	}
17581da177e4SLinus Torvalds }
17591da177e4SLinus Torvalds 
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds /***************************************************************************/
17621da177e4SLinus Torvalds /* state after dma xfer done or phase change before xfer done */
17631da177e4SLinus Torvalds int tul_state_5(HCS * pCurHcb)
17641da177e4SLinus Torvalds {
17651da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
17661da177e4SLinus Torvalds 	long cnt, xcnt;		/* cannot use unsigned !! code: if (xcnt < 0) */
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds #if DEBUG_STATE
17691da177e4SLinus Torvalds 	printk("-s5-");
17701da177e4SLinus Torvalds #endif
17711da177e4SLinus Torvalds /*------ get remaining count -------*/
17721da177e4SLinus Torvalds 
17731da177e4SLinus Torvalds 	cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;
17741da177e4SLinus Torvalds 
17751da177e4SLinus Torvalds 	if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {
17761da177e4SLinus Torvalds 		/* ----------------------- DATA_IN ----------------------------- */
17771da177e4SLinus Torvalds 		/* check scsi parity error */
17781da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
17791da177e4SLinus Torvalds 			pCurScb->SCB_HaStat = HOST_DO_DU;
17801da177e4SLinus Torvalds 		}
17811da177e4SLinus Torvalds 		if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* DMA xfer pending, Send STOP  */
17821da177e4SLinus Torvalds 			/* tell Hardware  scsi xfer has been terminated */
17831da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);
17841da177e4SLinus Torvalds 			/* wait until DMA xfer not pending */
17851da177e4SLinus Torvalds 			while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);
17861da177e4SLinus Torvalds 		}
17871da177e4SLinus Torvalds 	} else {
17881da177e4SLinus Torvalds /*-------- DATA OUT -----------*/
17891da177e4SLinus Torvalds 		if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {
17901da177e4SLinus Torvalds 			if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)
17911da177e4SLinus Torvalds 				cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;
17921da177e4SLinus Torvalds 			else
17931da177e4SLinus Torvalds 				cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);
17941da177e4SLinus Torvalds 		}
17951da177e4SLinus Torvalds 		if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */
17961da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);
17971da177e4SLinus Torvalds 			/* wait Abort DMA xfer done */
17981da177e4SLinus Torvalds 			while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
17991da177e4SLinus Torvalds 		}
18001da177e4SLinus Torvalds 		if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {
18011da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
18021da177e4SLinus Torvalds 			if (wait_tulip(pCurHcb) == -1) {
18031da177e4SLinus Torvalds 				return (-1);
18041da177e4SLinus Torvalds 			}
18051da177e4SLinus Torvalds 			cnt = 0;
18061da177e4SLinus Torvalds 		} else {
18071da177e4SLinus Torvalds 			if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)
18081da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
18091da177e4SLinus Torvalds 		}
18101da177e4SLinus Torvalds 	}
18111da177e4SLinus Torvalds 
18121da177e4SLinus Torvalds 	if (cnt == 0) {
18131da177e4SLinus Torvalds 		pCurScb->SCB_BufLen = 0;
18141da177e4SLinus Torvalds 		return (6);	/* Go to state 6                */
18151da177e4SLinus Torvalds 	}
18161da177e4SLinus Torvalds 	/* Update active data pointer */
18171da177e4SLinus Torvalds 	xcnt = (long) pCurScb->SCB_BufLen - cnt;	/* xcnt== bytes already xferred */
18181da177e4SLinus Torvalds 	pCurScb->SCB_BufLen = (U32) cnt;	/* cnt == bytes left to be xferred */
18191da177e4SLinus Torvalds 	if (pCurScb->SCB_Flags & SCF_SG) {
18201da177e4SLinus Torvalds 		register SG *sgp;
18211da177e4SLinus Torvalds 		ULONG i;
18221da177e4SLinus Torvalds 
18231da177e4SLinus Torvalds 		sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];
18241da177e4SLinus Torvalds 		for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {
18251da177e4SLinus Torvalds 			xcnt -= (long) sgp->SG_Len;
18261da177e4SLinus Torvalds 			if (xcnt < 0) {		/* this sgp xfer half done */
18271da177e4SLinus Torvalds 				xcnt += (long) sgp->SG_Len;	/* xcnt == bytes xferred in this sgp */
18281da177e4SLinus Torvalds 				sgp->SG_Ptr += (U32) xcnt;	/* new ptr to be xfer */
18291da177e4SLinus Torvalds 				sgp->SG_Len -= (U32) xcnt;	/* new len to be xfer */
18301da177e4SLinus Torvalds 				pCurScb->SCB_BufPtr += ((U32) (i - pCurScb->SCB_SGIdx) << 3);
18311da177e4SLinus Torvalds 				/* new SG table ptr */
18321da177e4SLinus Torvalds 				pCurScb->SCB_SGLen = (BYTE) (pCurScb->SCB_SGMax - i);
18331da177e4SLinus Torvalds 				/* new SG table len */
18341da177e4SLinus Torvalds 				pCurScb->SCB_SGIdx = (WORD) i;
18351da177e4SLinus Torvalds 				/* for next disc and come in this loop */
18361da177e4SLinus Torvalds 				return (4);	/* Go to state 4                */
18371da177e4SLinus Torvalds 			}
18381da177e4SLinus Torvalds 			/* else (xcnt >= 0 , i.e. this sgp already xferred */
18391da177e4SLinus Torvalds 		}		/* for */
18401da177e4SLinus Torvalds 		return (6);	/* Go to state 6                */
18411da177e4SLinus Torvalds 	} else {
18421da177e4SLinus Torvalds 		pCurScb->SCB_BufPtr += (U32) xcnt;
18431da177e4SLinus Torvalds 	}
18441da177e4SLinus Torvalds 	return (4);		/* Go to state 4                */
18451da177e4SLinus Torvalds }
18461da177e4SLinus Torvalds 
18471da177e4SLinus Torvalds /***************************************************************************/
18481da177e4SLinus Torvalds /* state after Data phase */
18491da177e4SLinus Torvalds int tul_state_6(HCS * pCurHcb)
18501da177e4SLinus Torvalds {
18511da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
18521da177e4SLinus Torvalds 
18531da177e4SLinus Torvalds #if DEBUG_STATE
18541da177e4SLinus Torvalds 	printk("-s6-");
18551da177e4SLinus Torvalds #endif
18561da177e4SLinus Torvalds 	for (;;) {
18571da177e4SLinus Torvalds 		switch (pCurHcb->HCS_Phase) {
18581da177e4SLinus Torvalds 		case STATUS_IN:	/* Status phase                 */
18591da177e4SLinus Torvalds 			if ((tul_status_msg(pCurHcb)) == -1)
18601da177e4SLinus Torvalds 				return (-1);
18611da177e4SLinus Torvalds 			break;
18621da177e4SLinus Torvalds 
18631da177e4SLinus Torvalds 		case MSG_IN:	/* Message in phase             */
18641da177e4SLinus Torvalds 			pCurScb->SCB_NxtStat = 6;
18651da177e4SLinus Torvalds 			if ((tul_msgin(pCurHcb)) == -1)
18661da177e4SLinus Torvalds 				return (-1);
18671da177e4SLinus Torvalds 			break;
18681da177e4SLinus Torvalds 
18691da177e4SLinus Torvalds 		case MSG_OUT:	/* Message out phase            */
18701da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */
18711da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
18721da177e4SLinus Torvalds 			if (wait_tulip(pCurHcb) == -1)
18731da177e4SLinus Torvalds 				return (-1);
18741da177e4SLinus Torvalds 			break;
18751da177e4SLinus Torvalds 
18761da177e4SLinus Torvalds 		case DATA_IN:	/* Data in phase                */
18771da177e4SLinus Torvalds 			return (tul_xpad_in(pCurHcb));
18781da177e4SLinus Torvalds 
18791da177e4SLinus Torvalds 		case DATA_OUT:	/* Data out phase               */
18801da177e4SLinus Torvalds 			return (tul_xpad_out(pCurHcb));
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 		default:
18831da177e4SLinus Torvalds 			return (tul_bad_seq(pCurHcb));
18841da177e4SLinus Torvalds 		}
18851da177e4SLinus Torvalds 	}
18861da177e4SLinus Torvalds }
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds /***************************************************************************/
18891da177e4SLinus Torvalds int tul_state_7(HCS * pCurHcb)
18901da177e4SLinus Torvalds {
18911da177e4SLinus Torvalds 	int cnt, i;
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds #if DEBUG_STATE
18941da177e4SLinus Torvalds 	printk("-s7-");
18951da177e4SLinus Torvalds #endif
18961da177e4SLinus Torvalds 	/* flush SCSI FIFO */
18971da177e4SLinus Torvalds 	cnt = TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F;
18981da177e4SLinus Torvalds 	if (cnt) {
18991da177e4SLinus Torvalds 		for (i = 0; i < cnt; i++)
19001da177e4SLinus Torvalds 			TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
19011da177e4SLinus Torvalds 	}
19021da177e4SLinus Torvalds 	switch (pCurHcb->HCS_Phase) {
19031da177e4SLinus Torvalds 	case DATA_IN:		/* Data in phase                */
19041da177e4SLinus Torvalds 	case DATA_OUT:		/* Data out phase               */
19051da177e4SLinus Torvalds 		return (tul_bad_seq(pCurHcb));
19061da177e4SLinus Torvalds 	default:
19071da177e4SLinus Torvalds 		return (6);	/* Go to state 6                */
19081da177e4SLinus Torvalds 	}
19091da177e4SLinus Torvalds }
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds /***************************************************************************/
19121da177e4SLinus Torvalds int tul_xfer_data_in(HCS * pCurHcb)
19131da177e4SLinus Torvalds {
19141da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds 	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DOUT) {
19171da177e4SLinus Torvalds 		return (6);	/* wrong direction */
19181da177e4SLinus Torvalds 	}
19191da177e4SLinus Torvalds 	TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
19201da177e4SLinus Torvalds 
19211da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_IN);	/* 7/25/95 */
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds 	if (pCurScb->SCB_Flags & SCF_SG) {	/* S/G xfer */
19241da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
19251da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
19261da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_IN);
19271da177e4SLinus Torvalds 	} else {
19281da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
19291da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
19301da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_IN);
19311da177e4SLinus Torvalds 	}
19321da177e4SLinus Torvalds 	pCurScb->SCB_NxtStat = 0x5;
19331da177e4SLinus Torvalds 	return (0);		/* return to OS, wait xfer done , let jas_isr come in */
19341da177e4SLinus Torvalds }
19351da177e4SLinus Torvalds 
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds /***************************************************************************/
19381da177e4SLinus Torvalds int tul_xfer_data_out(HCS * pCurHcb)
19391da177e4SLinus Torvalds {
19401da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
19411da177e4SLinus Torvalds 
19421da177e4SLinus Torvalds 	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DIN) {
19431da177e4SLinus Torvalds 		return (6);	/* wrong direction */
19441da177e4SLinus Torvalds 	}
19451da177e4SLinus Torvalds 	TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
19461da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_OUT);
19471da177e4SLinus Torvalds 
19481da177e4SLinus Torvalds 	if (pCurScb->SCB_Flags & SCF_SG) {	/* S/G xfer */
19491da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
19501da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
19511da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_OUT);
19521da177e4SLinus Torvalds 	} else {
19531da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
19541da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
19551da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_OUT);
19561da177e4SLinus Torvalds 	}
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 	pCurScb->SCB_NxtStat = 0x5;
19591da177e4SLinus Torvalds 	return (0);		/* return to OS, wait xfer done , let jas_isr come in */
19601da177e4SLinus Torvalds }
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds /***************************************************************************/
19641da177e4SLinus Torvalds int tul_xpad_in(HCS * pCurHcb)
19651da177e4SLinus Torvalds {
19661da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
19671da177e4SLinus Torvalds 	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
19681da177e4SLinus Torvalds 
19691da177e4SLinus Torvalds 	if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
19701da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = HOST_DO_DU;	/* over run             */
19711da177e4SLinus Torvalds 	}
19721da177e4SLinus Torvalds 	for (;;) {
19731da177e4SLinus Torvalds 		if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
19741da177e4SLinus Torvalds 			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
19751da177e4SLinus Torvalds 		else
19761da177e4SLinus Torvalds 			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
19771da177e4SLinus Torvalds 
19781da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
19791da177e4SLinus Torvalds 		if ((wait_tulip(pCurHcb)) == -1) {
19801da177e4SLinus Torvalds 			return (-1);
19811da177e4SLinus Torvalds 		}
19821da177e4SLinus Torvalds 		if (pCurHcb->HCS_Phase != DATA_IN) {
19831da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
19841da177e4SLinus Torvalds 			return (6);
19851da177e4SLinus Torvalds 		}
19861da177e4SLinus Torvalds 		TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
19871da177e4SLinus Torvalds 	}
19881da177e4SLinus Torvalds }
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds int tul_xpad_out(HCS * pCurHcb)
19911da177e4SLinus Torvalds {
19921da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
19931da177e4SLinus Torvalds 	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds 	if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
19961da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = HOST_DO_DU;	/* over run             */
19971da177e4SLinus Torvalds 	}
19981da177e4SLinus Torvalds 	for (;;) {
19991da177e4SLinus Torvalds 		if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
20001da177e4SLinus Torvalds 			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
20011da177e4SLinus Torvalds 		else
20021da177e4SLinus Torvalds 			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
20031da177e4SLinus Torvalds 
20041da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);
20051da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
20061da177e4SLinus Torvalds 		if ((wait_tulip(pCurHcb)) == -1) {
20071da177e4SLinus Torvalds 			return (-1);
20081da177e4SLinus Torvalds 		}
20091da177e4SLinus Torvalds 		if (pCurHcb->HCS_Phase != DATA_OUT) {	/* Disable wide CPU to allow read 16 bits */
20101da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
20111da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
20121da177e4SLinus Torvalds 			return (6);
20131da177e4SLinus Torvalds 		}
20141da177e4SLinus Torvalds 	}
20151da177e4SLinus Torvalds }
20161da177e4SLinus Torvalds 
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds /***************************************************************************/
20191da177e4SLinus Torvalds int tul_status_msg(HCS * pCurHcb)
20201da177e4SLinus Torvalds {				/* status & MSG_IN */
20211da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
20221da177e4SLinus Torvalds 	BYTE msg;
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_CMD_COMP);
20251da177e4SLinus Torvalds 	if ((wait_tulip(pCurHcb)) == -1) {
20261da177e4SLinus Torvalds 		return (-1);
20271da177e4SLinus Torvalds 	}
20281da177e4SLinus Torvalds 	/* get status */
20291da177e4SLinus Torvalds 	pCurScb->SCB_TaStat = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
20301da177e4SLinus Torvalds 
20311da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase == MSG_OUT) {
20321da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
20331da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
20341da177e4SLinus Torvalds 		} else {
20351da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);
20361da177e4SLinus Torvalds 		}
20371da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
20381da177e4SLinus Torvalds 		return (wait_tulip(pCurHcb));
20391da177e4SLinus Torvalds 	}
20401da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase == MSG_IN) {
20411da177e4SLinus Torvalds 		msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
20421da177e4SLinus Torvalds 		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {	/* Parity error                 */
20431da177e4SLinus Torvalds 			if ((tul_msgin_accept(pCurHcb)) == -1)
20441da177e4SLinus Torvalds 				return (-1);
20451da177e4SLinus Torvalds 			if (pCurHcb->HCS_Phase != MSG_OUT)
20461da177e4SLinus Torvalds 				return (tul_bad_seq(pCurHcb));
20471da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
20481da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
20491da177e4SLinus Torvalds 			return (wait_tulip(pCurHcb));
20501da177e4SLinus Torvalds 		}
20511da177e4SLinus Torvalds 		if (msg == 0) {	/* Command complete             */
20521da177e4SLinus Torvalds 
20531da177e4SLinus Torvalds 			if ((pCurScb->SCB_TaStat & 0x18) == 0x10) {	/* No link support              */
20541da177e4SLinus Torvalds 				return (tul_bad_seq(pCurHcb));
20551da177e4SLinus Torvalds 			}
20561da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
20571da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
20581da177e4SLinus Torvalds 			return tul_wait_done_disc(pCurHcb);
20591da177e4SLinus Torvalds 
20601da177e4SLinus Torvalds 		}
20611da177e4SLinus Torvalds 		if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) {
20621da177e4SLinus Torvalds 			if ((pCurScb->SCB_TaStat & 0x18) == 0x10)
20631da177e4SLinus Torvalds 				return (tul_msgin_accept(pCurHcb));
20641da177e4SLinus Torvalds 		}
20651da177e4SLinus Torvalds 	}
20661da177e4SLinus Torvalds 	return (tul_bad_seq(pCurHcb));
20671da177e4SLinus Torvalds }
20681da177e4SLinus Torvalds 
20691da177e4SLinus Torvalds 
20701da177e4SLinus Torvalds /***************************************************************************/
20711da177e4SLinus Torvalds /* scsi bus free */
20721da177e4SLinus Torvalds int int_tul_busfree(HCS * pCurHcb)
20731da177e4SLinus Torvalds {
20741da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
20751da177e4SLinus Torvalds 
20761da177e4SLinus Torvalds 	if (pCurScb != NULL) {
20771da177e4SLinus Torvalds 		if (pCurScb->SCB_Status & SCB_SELECT) {		/* selection timeout */
20781da177e4SLinus Torvalds 			tul_unlink_pend_scb(pCurHcb, pCurScb);
20791da177e4SLinus Torvalds 			pCurScb->SCB_HaStat = HOST_SEL_TOUT;
20801da177e4SLinus Torvalds 			tul_append_done_scb(pCurHcb, pCurScb);
20811da177e4SLinus Torvalds 		} else {	/* Unexpected bus free          */
20821da177e4SLinus Torvalds 			tul_unlink_busy_scb(pCurHcb, pCurScb);
20831da177e4SLinus Torvalds 			pCurScb->SCB_HaStat = HOST_BUS_FREE;
20841da177e4SLinus Torvalds 			tul_append_done_scb(pCurHcb, pCurScb);
20851da177e4SLinus Torvalds 		}
20861da177e4SLinus Torvalds 		pCurHcb->HCS_ActScb = NULL;
20871da177e4SLinus Torvalds 		pCurHcb->HCS_ActTcs = NULL;
20881da177e4SLinus Torvalds 	}
20891da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
20901da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
20911da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
20921da177e4SLinus Torvalds 	return (-1);
20931da177e4SLinus Torvalds }
20941da177e4SLinus Torvalds 
20951da177e4SLinus Torvalds 
20961da177e4SLinus Torvalds /***************************************************************************/
20971da177e4SLinus Torvalds /* scsi bus reset */
2098a2ba192cSAdrian Bunk static int int_tul_scsi_rst(HCS * pCurHcb)
20991da177e4SLinus Torvalds {
21001da177e4SLinus Torvalds 	SCB *pCurScb;
21011da177e4SLinus Torvalds 	int i;
21021da177e4SLinus Torvalds 
21031da177e4SLinus Torvalds 	/* if DMA xfer is pending, abort DMA xfer */
21041da177e4SLinus Torvalds 	if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & 0x01) {
21051da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
21061da177e4SLinus Torvalds 		/* wait Abort DMA xfer done */
21071da177e4SLinus Torvalds 		while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & 0x04) == 0);
21081da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
21091da177e4SLinus Torvalds 	}
21101da177e4SLinus Torvalds 	/* Abort all active & disconnected scb */
21111da177e4SLinus Torvalds 	while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
21121da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
21131da177e4SLinus Torvalds 		tul_append_done_scb(pCurHcb, pCurScb);
21141da177e4SLinus Torvalds 	}
21151da177e4SLinus Torvalds 	pCurHcb->HCS_ActScb = NULL;
21161da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = NULL;
21171da177e4SLinus Torvalds 
21181da177e4SLinus Torvalds 	/* clr sync nego. done flag */
21191da177e4SLinus Torvalds 	for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
21201da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
21211da177e4SLinus Torvalds 	}
21221da177e4SLinus Torvalds 	return (-1);
21231da177e4SLinus Torvalds }
21241da177e4SLinus Torvalds 
21251da177e4SLinus Torvalds 
21261da177e4SLinus Torvalds /***************************************************************************/
21271da177e4SLinus Torvalds /* scsi reselection */
21281da177e4SLinus Torvalds int int_tul_resel(HCS * pCurHcb)
21291da177e4SLinus Torvalds {
21301da177e4SLinus Torvalds 	SCB *pCurScb;
21311da177e4SLinus Torvalds 	TCS *pCurTcb;
21321da177e4SLinus Torvalds 	BYTE tag, msg = 0;
21331da177e4SLinus Torvalds 	BYTE tar, lun;
21341da177e4SLinus Torvalds 
21351da177e4SLinus Torvalds 	if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
21361da177e4SLinus Torvalds 		if (pCurScb->SCB_Status & SCB_SELECT) {		/* if waiting for selection complete */
21371da177e4SLinus Torvalds 			pCurScb->SCB_Status &= ~SCB_SELECT;
21381da177e4SLinus Torvalds 		}
21391da177e4SLinus Torvalds 		pCurHcb->HCS_ActScb = NULL;
21401da177e4SLinus Torvalds 	}
21411da177e4SLinus Torvalds 	/* --------- get target id---------------------- */
21421da177e4SLinus Torvalds 	tar = TUL_RD(pCurHcb->HCS_Base, TUL_SBusId);
21431da177e4SLinus Torvalds 	/* ------ get LUN from Identify message----------- */
21441da177e4SLinus Torvalds 	lun = TUL_RD(pCurHcb->HCS_Base, TUL_SIdent) & 0x0F;
21451da177e4SLinus Torvalds 	/* 07/22/98 from 0x1F -> 0x0F */
21461da177e4SLinus Torvalds 	pCurTcb = &pCurHcb->HCS_Tcs[tar];
21471da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = pCurTcb;
21481da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
21491da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
21501da177e4SLinus Torvalds 
21511da177e4SLinus Torvalds 
21521da177e4SLinus Torvalds 	/* ------------- tag queueing ? ------------------- */
21531da177e4SLinus Torvalds 	if (pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG) {
21541da177e4SLinus Torvalds 		if ((tul_msgin_accept(pCurHcb)) == -1)
21551da177e4SLinus Torvalds 			return (-1);
21561da177e4SLinus Torvalds 		if (pCurHcb->HCS_Phase != MSG_IN)
21571da177e4SLinus Torvalds 			goto no_tag;
21581da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
21591da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
21601da177e4SLinus Torvalds 		if ((wait_tulip(pCurHcb)) == -1)
21611da177e4SLinus Torvalds 			return (-1);
21621da177e4SLinus Torvalds 		msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* Read Tag Message    */
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 		if ((msg < MSG_STAG) || (msg > MSG_OTAG))	/* Is simple Tag      */
21651da177e4SLinus Torvalds 			goto no_tag;
21661da177e4SLinus Torvalds 
21671da177e4SLinus Torvalds 		if ((tul_msgin_accept(pCurHcb)) == -1)
21681da177e4SLinus Torvalds 			return (-1);
21691da177e4SLinus Torvalds 
21701da177e4SLinus Torvalds 		if (pCurHcb->HCS_Phase != MSG_IN)
21711da177e4SLinus Torvalds 			goto no_tag;
21721da177e4SLinus Torvalds 
21731da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
21741da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
21751da177e4SLinus Torvalds 		if ((wait_tulip(pCurHcb)) == -1)
21761da177e4SLinus Torvalds 			return (-1);
21771da177e4SLinus Torvalds 		tag = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* Read Tag ID       */
21781da177e4SLinus Torvalds 		pCurScb = pCurHcb->HCS_Scb + tag;
21791da177e4SLinus Torvalds 		if ((pCurScb->SCB_Target != tar) || (pCurScb->SCB_Lun != lun)) {
21801da177e4SLinus Torvalds 			return tul_msgout_abort_tag(pCurHcb);
21811da177e4SLinus Torvalds 		}
21821da177e4SLinus Torvalds 		if (pCurScb->SCB_Status != SCB_BUSY) {	/* 03/24/95             */
21831da177e4SLinus Torvalds 			return tul_msgout_abort_tag(pCurHcb);
21841da177e4SLinus Torvalds 		}
21851da177e4SLinus Torvalds 		pCurHcb->HCS_ActScb = pCurScb;
21861da177e4SLinus Torvalds 		if ((tul_msgin_accept(pCurHcb)) == -1)
21871da177e4SLinus Torvalds 			return (-1);
21881da177e4SLinus Torvalds 	} else {		/* No tag               */
21891da177e4SLinus Torvalds 	      no_tag:
21901da177e4SLinus Torvalds 		if ((pCurScb = tul_find_busy_scb(pCurHcb, tar | (lun << 8))) == NULL) {
21911da177e4SLinus Torvalds 			return tul_msgout_abort_targ(pCurHcb);
21921da177e4SLinus Torvalds 		}
21931da177e4SLinus Torvalds 		pCurHcb->HCS_ActScb = pCurScb;
21941da177e4SLinus Torvalds 		if (!(pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG)) {
21951da177e4SLinus Torvalds 			if ((tul_msgin_accept(pCurHcb)) == -1)
21961da177e4SLinus Torvalds 				return (-1);
21971da177e4SLinus Torvalds 		}
21981da177e4SLinus Torvalds 	}
21991da177e4SLinus Torvalds 	return 0;
22001da177e4SLinus Torvalds }
22011da177e4SLinus Torvalds 
22021da177e4SLinus Torvalds 
22031da177e4SLinus Torvalds /***************************************************************************/
2204a2ba192cSAdrian Bunk static int int_tul_bad_seq(HCS * pCurHcb)
22051da177e4SLinus Torvalds {				/* target wrong phase           */
22061da177e4SLinus Torvalds 	SCB *pCurScb;
22071da177e4SLinus Torvalds 	int i;
22081da177e4SLinus Torvalds 
22091da177e4SLinus Torvalds 	tul_reset_scsi(pCurHcb, 10);
22101da177e4SLinus Torvalds 
22111da177e4SLinus Torvalds 	while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
22121da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
22131da177e4SLinus Torvalds 		tul_append_done_scb(pCurHcb, pCurScb);
22141da177e4SLinus Torvalds 	}
22151da177e4SLinus Torvalds 	for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
22161da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
22171da177e4SLinus Torvalds 	}
22181da177e4SLinus Torvalds 	return (-1);
22191da177e4SLinus Torvalds }
22201da177e4SLinus Torvalds 
22211da177e4SLinus Torvalds 
22221da177e4SLinus Torvalds /***************************************************************************/
22231da177e4SLinus Torvalds int tul_msgout_abort_targ(HCS * pCurHcb)
22241da177e4SLinus Torvalds {
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
22271da177e4SLinus Torvalds 	if (tul_msgin_accept(pCurHcb) == -1)
22281da177e4SLinus Torvalds 		return (-1);
22291da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase != MSG_OUT)
22301da177e4SLinus Torvalds 		return (tul_bad_seq(pCurHcb));
22311da177e4SLinus Torvalds 
22321da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT);
22331da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
22341da177e4SLinus Torvalds 
22351da177e4SLinus Torvalds 	return tul_wait_disc(pCurHcb);
22361da177e4SLinus Torvalds }
22371da177e4SLinus Torvalds 
22381da177e4SLinus Torvalds /***************************************************************************/
22391da177e4SLinus Torvalds int tul_msgout_abort_tag(HCS * pCurHcb)
22401da177e4SLinus Torvalds {
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
22431da177e4SLinus Torvalds 	if (tul_msgin_accept(pCurHcb) == -1)
22441da177e4SLinus Torvalds 		return (-1);
22451da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase != MSG_OUT)
22461da177e4SLinus Torvalds 		return (tul_bad_seq(pCurHcb));
22471da177e4SLinus Torvalds 
22481da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT_TAG);
22491da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds 	return tul_wait_disc(pCurHcb);
22521da177e4SLinus Torvalds 
22531da177e4SLinus Torvalds }
22541da177e4SLinus Torvalds 
22551da177e4SLinus Torvalds /***************************************************************************/
22561da177e4SLinus Torvalds int tul_msgin(HCS * pCurHcb)
22571da177e4SLinus Torvalds {
22581da177e4SLinus Torvalds 	TCS *pCurTcb;
22591da177e4SLinus Torvalds 
22601da177e4SLinus Torvalds 	for (;;) {
22611da177e4SLinus Torvalds 
22621da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
22631da177e4SLinus Torvalds 
22641da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
22651da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
22661da177e4SLinus Torvalds 		if ((wait_tulip(pCurHcb)) == -1)
22671da177e4SLinus Torvalds 			return (-1);
22681da177e4SLinus Torvalds 
22691da177e4SLinus Torvalds 		switch (TUL_RD(pCurHcb->HCS_Base, TUL_SFifo)) {
22701da177e4SLinus Torvalds 		case MSG_DISC:	/* Disconnect msg */
22711da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
22721da177e4SLinus Torvalds 
22731da177e4SLinus Torvalds 			return tul_wait_disc(pCurHcb);
22741da177e4SLinus Torvalds 
22751da177e4SLinus Torvalds 		case MSG_SDP:
22761da177e4SLinus Torvalds 		case MSG_RESTORE:
22771da177e4SLinus Torvalds 		case MSG_NOP:
22781da177e4SLinus Torvalds 			tul_msgin_accept(pCurHcb);
22791da177e4SLinus Torvalds 			break;
22801da177e4SLinus Torvalds 
22811da177e4SLinus Torvalds 		case MSG_REJ:	/* Clear ATN first              */
22821da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SSignal,
22831da177e4SLinus Torvalds 			       (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
22841da177e4SLinus Torvalds 			pCurTcb = pCurHcb->HCS_ActTcs;
22851da177e4SLinus Torvalds 			if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {	/* do sync nego */
22861da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
22871da177e4SLinus Torvalds 			}
22881da177e4SLinus Torvalds 			tul_msgin_accept(pCurHcb);
22891da177e4SLinus Torvalds 			break;
22901da177e4SLinus Torvalds 
22911da177e4SLinus Torvalds 		case MSG_EXTEND:	/* extended msg */
22921da177e4SLinus Torvalds 			tul_msgin_extend(pCurHcb);
22931da177e4SLinus Torvalds 			break;
22941da177e4SLinus Torvalds 
22951da177e4SLinus Torvalds 		case MSG_IGNOREWIDE:
22961da177e4SLinus Torvalds 			tul_msgin_accept(pCurHcb);
22971da177e4SLinus Torvalds 			break;
22981da177e4SLinus Torvalds 
22991da177e4SLinus Torvalds 			/* get */
23001da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
23011da177e4SLinus Torvalds 			if (wait_tulip(pCurHcb) == -1)
23021da177e4SLinus Torvalds 				return -1;
23031da177e4SLinus Torvalds 
23041da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);	/* put pad  */
23051da177e4SLinus Torvalds 			TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* get IGNORE field */
23061da177e4SLinus Torvalds 			TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* get pad */
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds 			tul_msgin_accept(pCurHcb);
23091da177e4SLinus Torvalds 			break;
23101da177e4SLinus Torvalds 
23111da177e4SLinus Torvalds 		case MSG_COMP:
23121da177e4SLinus Torvalds 			{
23131da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
23141da177e4SLinus Torvalds 				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
23151da177e4SLinus Torvalds 				return tul_wait_done_disc(pCurHcb);
23161da177e4SLinus Torvalds 			}
23171da177e4SLinus Torvalds 		default:
23181da177e4SLinus Torvalds 			tul_msgout_reject(pCurHcb);
23191da177e4SLinus Torvalds 			break;
23201da177e4SLinus Torvalds 		}
23211da177e4SLinus Torvalds 		if (pCurHcb->HCS_Phase != MSG_IN)
23221da177e4SLinus Torvalds 			return (pCurHcb->HCS_Phase);
23231da177e4SLinus Torvalds 	}
23241da177e4SLinus Torvalds 	/* statement won't reach here */
23251da177e4SLinus Torvalds }
23261da177e4SLinus Torvalds 
23271da177e4SLinus Torvalds 
23281da177e4SLinus Torvalds 
23291da177e4SLinus Torvalds 
23301da177e4SLinus Torvalds /***************************************************************************/
23311da177e4SLinus Torvalds int tul_msgout_reject(HCS * pCurHcb)
23321da177e4SLinus Torvalds {
23331da177e4SLinus Torvalds 
23341da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
23351da177e4SLinus Torvalds 
23361da177e4SLinus Torvalds 	if ((tul_msgin_accept(pCurHcb)) == -1)
23371da177e4SLinus Torvalds 		return (-1);
23381da177e4SLinus Torvalds 
23391da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase == MSG_OUT) {
23401da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_REJ);		/* Msg reject           */
23411da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
23421da177e4SLinus Torvalds 		return (wait_tulip(pCurHcb));
23431da177e4SLinus Torvalds 	}
23441da177e4SLinus Torvalds 	return (pCurHcb->HCS_Phase);
23451da177e4SLinus Torvalds }
23461da177e4SLinus Torvalds 
23471da177e4SLinus Torvalds 
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds /***************************************************************************/
23501da177e4SLinus Torvalds int tul_msgout_ide(HCS * pCurHcb)
23511da177e4SLinus Torvalds {
23521da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_IDE);		/* Initiator Detected Error */
23531da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
23541da177e4SLinus Torvalds 	return (wait_tulip(pCurHcb));
23551da177e4SLinus Torvalds }
23561da177e4SLinus Torvalds 
23571da177e4SLinus Torvalds 
23581da177e4SLinus Torvalds /***************************************************************************/
23591da177e4SLinus Torvalds int tul_msgin_extend(HCS * pCurHcb)
23601da177e4SLinus Torvalds {
23611da177e4SLinus Torvalds 	BYTE len, idx;
23621da177e4SLinus Torvalds 
23631da177e4SLinus Torvalds 	if (tul_msgin_accept(pCurHcb) != MSG_IN)
23641da177e4SLinus Torvalds 		return (pCurHcb->HCS_Phase);
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 	/* Get extended msg length      */
23671da177e4SLinus Torvalds 	TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
23681da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
23691da177e4SLinus Torvalds 	if (wait_tulip(pCurHcb) == -1)
23701da177e4SLinus Torvalds 		return (-1);
23711da177e4SLinus Torvalds 
23721da177e4SLinus Torvalds 	len = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
23731da177e4SLinus Torvalds 	pCurHcb->HCS_Msg[0] = len;
23741da177e4SLinus Torvalds 	for (idx = 1; len != 0; len--) {
23751da177e4SLinus Torvalds 
23761da177e4SLinus Torvalds 		if ((tul_msgin_accept(pCurHcb)) != MSG_IN)
23771da177e4SLinus Torvalds 			return (pCurHcb->HCS_Phase);
23781da177e4SLinus Torvalds 		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
23791da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
23801da177e4SLinus Torvalds 		if (wait_tulip(pCurHcb) == -1)
23811da177e4SLinus Torvalds 			return (-1);
23821da177e4SLinus Torvalds 		pCurHcb->HCS_Msg[idx++] = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
23831da177e4SLinus Torvalds 	}
23841da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[1] == 1) {		/* if it's synchronous data transfer request */
23851da177e4SLinus Torvalds 		if (pCurHcb->HCS_Msg[0] != 3)	/* if length is not right */
23861da177e4SLinus Torvalds 			return (tul_msgout_reject(pCurHcb));
23871da177e4SLinus Torvalds 		if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) {	/* Set OFFSET=0 to do async, nego back */
23881da177e4SLinus Torvalds 			pCurHcb->HCS_Msg[3] = 0;
23891da177e4SLinus Torvalds 		} else {
23901da177e4SLinus Torvalds 			if ((tul_msgin_sync(pCurHcb) == 0) &&
23911da177e4SLinus Torvalds 			    (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) {
23921da177e4SLinus Torvalds 				tul_sync_done(pCurHcb);
23931da177e4SLinus Torvalds 				return (tul_msgin_accept(pCurHcb));
23941da177e4SLinus Torvalds 			}
23951da177e4SLinus Torvalds 		}
23961da177e4SLinus Torvalds 
23971da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
23981da177e4SLinus Torvalds 		if ((tul_msgin_accept(pCurHcb)) != MSG_OUT)
23991da177e4SLinus Torvalds 			return (pCurHcb->HCS_Phase);
24001da177e4SLinus Torvalds 		/* sync msg out */
24011da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
24021da177e4SLinus Torvalds 
24031da177e4SLinus Torvalds 		tul_sync_done(pCurHcb);
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
24061da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
24071da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);
24081da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
24091da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[3]);
24101da177e4SLinus Torvalds 
24111da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
24121da177e4SLinus Torvalds 		return (wait_tulip(pCurHcb));
24131da177e4SLinus Torvalds 	}
24141da177e4SLinus Torvalds 	if ((pCurHcb->HCS_Msg[0] != 2) || (pCurHcb->HCS_Msg[1] != 3))
24151da177e4SLinus Torvalds 		return (tul_msgout_reject(pCurHcb));
24161da177e4SLinus Torvalds 	/* if it's WIDE DATA XFER REQ   */
24171da177e4SLinus Torvalds 	if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) {
24181da177e4SLinus Torvalds 		pCurHcb->HCS_Msg[2] = 0;
24191da177e4SLinus Torvalds 	} else {
24201da177e4SLinus Torvalds 		if (pCurHcb->HCS_Msg[2] > 2)	/* > 32 bits            */
24211da177e4SLinus Torvalds 			return (tul_msgout_reject(pCurHcb));
24221da177e4SLinus Torvalds 		if (pCurHcb->HCS_Msg[2] == 2) {		/* == 32                */
24231da177e4SLinus Torvalds 			pCurHcb->HCS_Msg[2] = 1;
24241da177e4SLinus Torvalds 		} else {
24251da177e4SLinus Torvalds 			if ((pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) {
24261da177e4SLinus Torvalds 				wdtr_done(pCurHcb);
24271da177e4SLinus Torvalds 				if ((pCurHcb->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
24281da177e4SLinus Torvalds 					TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
24291da177e4SLinus Torvalds 				return (tul_msgin_accept(pCurHcb));
24301da177e4SLinus Torvalds 			}
24311da177e4SLinus Torvalds 		}
24321da177e4SLinus Torvalds 	}
24331da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
24341da177e4SLinus Torvalds 
24351da177e4SLinus Torvalds 	if (tul_msgin_accept(pCurHcb) != MSG_OUT)
24361da177e4SLinus Torvalds 		return (pCurHcb->HCS_Phase);
24371da177e4SLinus Torvalds 	/* WDTR msg out                 */
24381da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
24391da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);
24401da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
24411da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
24421da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
24431da177e4SLinus Torvalds 	return (wait_tulip(pCurHcb));
24441da177e4SLinus Torvalds }
24451da177e4SLinus Torvalds 
24461da177e4SLinus Torvalds /***************************************************************************/
24471da177e4SLinus Torvalds int tul_msgin_sync(HCS * pCurHcb)
24481da177e4SLinus Torvalds {
24491da177e4SLinus Torvalds 	char default_period;
24501da177e4SLinus Torvalds 
24511da177e4SLinus Torvalds 	default_period = tul_rate_tbl[pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE];
24521da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[3] > MAX_OFFSET) {
24531da177e4SLinus Torvalds 		pCurHcb->HCS_Msg[3] = MAX_OFFSET;
24541da177e4SLinus Torvalds 		if (pCurHcb->HCS_Msg[2] < default_period) {
24551da177e4SLinus Torvalds 			pCurHcb->HCS_Msg[2] = default_period;
24561da177e4SLinus Torvalds 			return 1;
24571da177e4SLinus Torvalds 		}
24581da177e4SLinus Torvalds 		if (pCurHcb->HCS_Msg[2] >= 59) {	/* Change to async              */
24591da177e4SLinus Torvalds 			pCurHcb->HCS_Msg[3] = 0;
24601da177e4SLinus Torvalds 		}
24611da177e4SLinus Torvalds 		return 1;
24621da177e4SLinus Torvalds 	}
24631da177e4SLinus Torvalds 	/* offset requests asynchronous transfers ? */
24641da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[3] == 0) {
24651da177e4SLinus Torvalds 		return 0;
24661da177e4SLinus Torvalds 	}
24671da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[2] < default_period) {
24681da177e4SLinus Torvalds 		pCurHcb->HCS_Msg[2] = default_period;
24691da177e4SLinus Torvalds 		return 1;
24701da177e4SLinus Torvalds 	}
24711da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[2] >= 59) {
24721da177e4SLinus Torvalds 		pCurHcb->HCS_Msg[3] = 0;
24731da177e4SLinus Torvalds 		return 1;
24741da177e4SLinus Torvalds 	}
24751da177e4SLinus Torvalds 	return 0;
24761da177e4SLinus Torvalds }
24771da177e4SLinus Torvalds 
24781da177e4SLinus Torvalds 
24791da177e4SLinus Torvalds /***************************************************************************/
24801da177e4SLinus Torvalds int wdtr_done(HCS * pCurHcb)
24811da177e4SLinus Torvalds {
24821da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE;
24831da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE;
24841da177e4SLinus Torvalds 
24851da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs->TCS_JS_Period = 0;
24861da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[2]) {	/* if 16 bit */
24871da177e4SLinus Torvalds 		pCurHcb->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI;
24881da177e4SLinus Torvalds 	}
24891da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD;
24901da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
24911da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
24921da177e4SLinus Torvalds 
24931da177e4SLinus Torvalds 	return 1;
24941da177e4SLinus Torvalds }
24951da177e4SLinus Torvalds 
24961da177e4SLinus Torvalds /***************************************************************************/
24971da177e4SLinus Torvalds int tul_sync_done(HCS * pCurHcb)
24981da177e4SLinus Torvalds {
24991da177e4SLinus Torvalds 	int i;
25001da177e4SLinus Torvalds 
25011da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE;
25021da177e4SLinus Torvalds 
25031da177e4SLinus Torvalds 	if (pCurHcb->HCS_Msg[3]) {
25041da177e4SLinus Torvalds 		pCurHcb->HCS_ActTcs->TCS_JS_Period |= pCurHcb->HCS_Msg[3];
25051da177e4SLinus Torvalds 		for (i = 0; i < 8; i++) {
25061da177e4SLinus Torvalds 			if (tul_rate_tbl[i] >= pCurHcb->HCS_Msg[2])	/* pick the big one */
25071da177e4SLinus Torvalds 				break;
25081da177e4SLinus Torvalds 		}
25091da177e4SLinus Torvalds 		pCurHcb->HCS_ActTcs->TCS_JS_Period |= (i << 4);
25101da177e4SLinus Torvalds 		pCurHcb->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD;
25111da177e4SLinus Torvalds 	}
25121da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
25131da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
25141da177e4SLinus Torvalds 
25151da177e4SLinus Torvalds 	return (-1);
25161da177e4SLinus Torvalds }
25171da177e4SLinus Torvalds 
25181da177e4SLinus Torvalds 
25191da177e4SLinus Torvalds int tul_post_scsi_rst(HCS * pCurHcb)
25201da177e4SLinus Torvalds {
25211da177e4SLinus Torvalds 	SCB *pCurScb;
25221da177e4SLinus Torvalds 	TCS *pCurTcb;
25231da177e4SLinus Torvalds 	int i;
25241da177e4SLinus Torvalds 
25251da177e4SLinus Torvalds 	pCurHcb->HCS_ActScb = NULL;
25261da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = NULL;
25271da177e4SLinus Torvalds 	pCurHcb->HCS_Flags = 0;
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds 	while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
25301da177e4SLinus Torvalds 		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
25311da177e4SLinus Torvalds 		tul_append_done_scb(pCurHcb, pCurScb);
25321da177e4SLinus Torvalds 	}
25331da177e4SLinus Torvalds 	/* clear sync done flag         */
25341da177e4SLinus Torvalds 	pCurTcb = &pCurHcb->HCS_Tcs[0];
25351da177e4SLinus Torvalds 	for (i = 0; i < pCurHcb->HCS_MaxTar; pCurTcb++, i++) {
25361da177e4SLinus Torvalds 		pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
25371da177e4SLinus Torvalds 		/* Initialize the sync. xfer register values to an asyn xfer */
25381da177e4SLinus Torvalds 		pCurTcb->TCS_JS_Period = 0;
25391da177e4SLinus Torvalds 		pCurTcb->TCS_SConfig0 = pCurHcb->HCS_SConf1;
25401da177e4SLinus Torvalds 		pCurHcb->HCS_ActTags[0] = 0;	/* 07/22/98 */
25411da177e4SLinus Torvalds 		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;	/* 07/22/98 */
25421da177e4SLinus Torvalds 	}			/* for */
25431da177e4SLinus Torvalds 
25441da177e4SLinus Torvalds 	return (-1);
25451da177e4SLinus Torvalds }
25461da177e4SLinus Torvalds 
25471da177e4SLinus Torvalds /***************************************************************************/
25481da177e4SLinus Torvalds void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb)
25491da177e4SLinus Torvalds {
25501da177e4SLinus Torvalds 	pCurScb->SCB_Status |= SCB_SELECT;
25511da177e4SLinus Torvalds 	pCurScb->SCB_NxtStat = 0x1;
25521da177e4SLinus Torvalds 	pCurHcb->HCS_ActScb = pCurScb;
25531da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
25541da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SELATNSTOP);
25551da177e4SLinus Torvalds 	return;
25561da177e4SLinus Torvalds }
25571da177e4SLinus Torvalds 
25581da177e4SLinus Torvalds 
25591da177e4SLinus Torvalds /***************************************************************************/
25601da177e4SLinus Torvalds void tul_select_atn(HCS * pCurHcb, SCB * pCurScb)
25611da177e4SLinus Torvalds {
25621da177e4SLinus Torvalds 	int i;
25631da177e4SLinus Torvalds 
25641da177e4SLinus Torvalds 	pCurScb->SCB_Status |= SCB_SELECT;
25651da177e4SLinus Torvalds 	pCurScb->SCB_NxtStat = 0x2;
25661da177e4SLinus Torvalds 
25671da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
25681da177e4SLinus Torvalds 	for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
25691da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
25701da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
25711da177e4SLinus Torvalds 	pCurHcb->HCS_ActScb = pCurScb;
25721da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN);
25731da177e4SLinus Torvalds 	return;
25741da177e4SLinus Torvalds }
25751da177e4SLinus Torvalds 
25761da177e4SLinus Torvalds /***************************************************************************/
25771da177e4SLinus Torvalds void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb)
25781da177e4SLinus Torvalds {
25791da177e4SLinus Torvalds 	int i;
25801da177e4SLinus Torvalds 
25811da177e4SLinus Torvalds 	pCurScb->SCB_Status |= SCB_SELECT;
25821da177e4SLinus Torvalds 	pCurScb->SCB_NxtStat = 0x2;
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
25851da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
25861da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
25871da177e4SLinus Torvalds 	for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
25881da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
25891da177e4SLinus Torvalds 	pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
25901da177e4SLinus Torvalds 	pCurHcb->HCS_ActScb = pCurScb;
25911da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN3);
25921da177e4SLinus Torvalds 	return;
25931da177e4SLinus Torvalds }
25941da177e4SLinus Torvalds 
25951da177e4SLinus Torvalds /***************************************************************************/
25961da177e4SLinus Torvalds /* SCSI Bus Device Reset */
25971da177e4SLinus Torvalds int tul_bus_device_reset(HCS * pCurHcb)
25981da177e4SLinus Torvalds {
25991da177e4SLinus Torvalds 	SCB *pCurScb = pCurHcb->HCS_ActScb;
26001da177e4SLinus Torvalds 	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
26011da177e4SLinus Torvalds 	SCB *pTmpScb, *pPrevScb;
26021da177e4SLinus Torvalds 	BYTE tar;
26031da177e4SLinus Torvalds 
26041da177e4SLinus Torvalds 	if (pCurHcb->HCS_Phase != MSG_OUT) {
26051da177e4SLinus Torvalds 		return (int_tul_bad_seq(pCurHcb));	/* Unexpected phase             */
26061da177e4SLinus Torvalds 	}
26071da177e4SLinus Torvalds 	tul_unlink_pend_scb(pCurHcb, pCurScb);
26081da177e4SLinus Torvalds 	tul_release_scb(pCurHcb, pCurScb);
26091da177e4SLinus Torvalds 
26101da177e4SLinus Torvalds 
26111da177e4SLinus Torvalds 	tar = pCurScb->SCB_Target;	/* target                       */
26121da177e4SLinus Torvalds 	pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
26131da177e4SLinus Torvalds 	/* clr sync. nego & WDTR flags  07/22/98 */
26141da177e4SLinus Torvalds 
26151da177e4SLinus Torvalds 	/* abort all SCB with same target */
26161da177e4SLinus Torvalds 	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;	/* Check Busy queue */
26171da177e4SLinus Torvalds 	while (pTmpScb != NULL) {
26181da177e4SLinus Torvalds 
26191da177e4SLinus Torvalds 		if (pTmpScb->SCB_Target == tar) {
26201da177e4SLinus Torvalds 			/* unlink it */
26211da177e4SLinus Torvalds 			if (pTmpScb == pCurHcb->HCS_FirstBusy) {
26221da177e4SLinus Torvalds 				if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
26231da177e4SLinus Torvalds 					pCurHcb->HCS_LastBusy = NULL;
26241da177e4SLinus Torvalds 			} else {
26251da177e4SLinus Torvalds 				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
26261da177e4SLinus Torvalds 				if (pTmpScb == pCurHcb->HCS_LastBusy)
26271da177e4SLinus Torvalds 					pCurHcb->HCS_LastBusy = pPrevScb;
26281da177e4SLinus Torvalds 			}
26291da177e4SLinus Torvalds 			pTmpScb->SCB_HaStat = HOST_ABORTED;
26301da177e4SLinus Torvalds 			tul_append_done_scb(pCurHcb, pTmpScb);
26311da177e4SLinus Torvalds 		}
26321da177e4SLinus Torvalds 		/* Previous haven't change      */
26331da177e4SLinus Torvalds 		else {
26341da177e4SLinus Torvalds 			pPrevScb = pTmpScb;
26351da177e4SLinus Torvalds 		}
26361da177e4SLinus Torvalds 		pTmpScb = pTmpScb->SCB_NxtScb;
26371da177e4SLinus Torvalds 	}
26381da177e4SLinus Torvalds 
26391da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_DEVRST);
26401da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds 	return tul_wait_disc(pCurHcb);
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds }
26451da177e4SLinus Torvalds 
26461da177e4SLinus Torvalds /***************************************************************************/
26471da177e4SLinus Torvalds int tul_msgin_accept(HCS * pCurHcb)
26481da177e4SLinus Torvalds {
26491da177e4SLinus Torvalds 	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
26501da177e4SLinus Torvalds 	return (wait_tulip(pCurHcb));
26511da177e4SLinus Torvalds }
26521da177e4SLinus Torvalds 
26531da177e4SLinus Torvalds /***************************************************************************/
26541da177e4SLinus Torvalds int wait_tulip(HCS * pCurHcb)
26551da177e4SLinus Torvalds {
26561da177e4SLinus Torvalds 
26571da177e4SLinus Torvalds 	while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
26581da177e4SLinus Torvalds 		 & TSS_INT_PENDING));
26591da177e4SLinus Torvalds 
26601da177e4SLinus Torvalds 	pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
26611da177e4SLinus Torvalds 	pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
26621da177e4SLinus Torvalds 	pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
26631da177e4SLinus Torvalds 
26641da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {	/* if SCSI bus reset detected   */
26651da177e4SLinus Torvalds 		return (int_tul_resel(pCurHcb));
26661da177e4SLinus Torvalds 	}
26671da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {	/* if selected/reselected timeout interrupt */
26681da177e4SLinus Torvalds 		return (int_tul_busfree(pCurHcb));
26691da177e4SLinus Torvalds 	}
26701da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* if SCSI bus reset detected   */
26711da177e4SLinus Torvalds 		return (int_tul_scsi_rst(pCurHcb));
26721da177e4SLinus Torvalds 	}
26731da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
26741da177e4SLinus Torvalds 		if (pCurHcb->HCS_Flags & HCF_EXPECT_DONE_DISC) {
26751da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
26761da177e4SLinus Torvalds 			tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
26771da177e4SLinus Torvalds 			pCurHcb->HCS_ActScb->SCB_HaStat = 0;
26781da177e4SLinus Torvalds 			tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
26791da177e4SLinus Torvalds 			pCurHcb->HCS_ActScb = NULL;
26801da177e4SLinus Torvalds 			pCurHcb->HCS_ActTcs = NULL;
26811da177e4SLinus Torvalds 			pCurHcb->HCS_Flags &= ~HCF_EXPECT_DONE_DISC;
26821da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
26831da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
26841da177e4SLinus Torvalds 			return (-1);
26851da177e4SLinus Torvalds 		}
26861da177e4SLinus Torvalds 		if (pCurHcb->HCS_Flags & HCF_EXPECT_DISC) {
26871da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
26881da177e4SLinus Torvalds 			pCurHcb->HCS_ActScb = NULL;
26891da177e4SLinus Torvalds 			pCurHcb->HCS_ActTcs = NULL;
26901da177e4SLinus Torvalds 			pCurHcb->HCS_Flags &= ~HCF_EXPECT_DISC;
26911da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
26921da177e4SLinus Torvalds 			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
26931da177e4SLinus Torvalds 			return (-1);
26941da177e4SLinus Torvalds 		}
26951da177e4SLinus Torvalds 		return (int_tul_busfree(pCurHcb));
26961da177e4SLinus Torvalds 	}
26971da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {
26981da177e4SLinus Torvalds 		return (pCurHcb->HCS_Phase);
26991da177e4SLinus Torvalds 	}
27001da177e4SLinus Torvalds 	return (pCurHcb->HCS_Phase);
27011da177e4SLinus Torvalds }
27021da177e4SLinus Torvalds /***************************************************************************/
27031da177e4SLinus Torvalds int tul_wait_disc(HCS * pCurHcb)
27041da177e4SLinus Torvalds {
27051da177e4SLinus Torvalds 
27061da177e4SLinus Torvalds 	while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
27071da177e4SLinus Torvalds 		 & TSS_INT_PENDING));
27081da177e4SLinus Torvalds 
27091da177e4SLinus Torvalds 
27101da177e4SLinus Torvalds 	pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
27111da177e4SLinus Torvalds 
27121da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* if SCSI bus reset detected   */
27131da177e4SLinus Torvalds 		return (int_tul_scsi_rst(pCurHcb));
27141da177e4SLinus Torvalds 	}
27151da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
27161da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
27171da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
27181da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
27191da177e4SLinus Torvalds 		pCurHcb->HCS_ActScb = NULL;
27201da177e4SLinus Torvalds 		return (-1);
27211da177e4SLinus Torvalds 	}
27221da177e4SLinus Torvalds 	return (tul_bad_seq(pCurHcb));
27231da177e4SLinus Torvalds }
27241da177e4SLinus Torvalds 
27251da177e4SLinus Torvalds /***************************************************************************/
27261da177e4SLinus Torvalds int tul_wait_done_disc(HCS * pCurHcb)
27271da177e4SLinus Torvalds {
27281da177e4SLinus Torvalds 
27291da177e4SLinus Torvalds 
27301da177e4SLinus Torvalds 	while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
27311da177e4SLinus Torvalds 		 & TSS_INT_PENDING));
27321da177e4SLinus Torvalds 
27331da177e4SLinus Torvalds 	pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
27341da177e4SLinus Torvalds 
27351da177e4SLinus Torvalds 
27361da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* if SCSI bus reset detected   */
27371da177e4SLinus Torvalds 		return (int_tul_scsi_rst(pCurHcb));
27381da177e4SLinus Torvalds 	}
27391da177e4SLinus Torvalds 	if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
27401da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
27411da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
27421da177e4SLinus Torvalds 		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
27431da177e4SLinus Torvalds 		tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
27441da177e4SLinus Torvalds 
27451da177e4SLinus Torvalds 		tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
27461da177e4SLinus Torvalds 		pCurHcb->HCS_ActScb = NULL;
27471da177e4SLinus Torvalds 		return (-1);
27481da177e4SLinus Torvalds 	}
27491da177e4SLinus Torvalds 	return (tul_bad_seq(pCurHcb));
27501da177e4SLinus Torvalds }
27511da177e4SLinus Torvalds 
27521da177e4SLinus Torvalds static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs)
27531da177e4SLinus Torvalds {
27541da177e4SLinus Torvalds 	struct Scsi_Host *dev = dev_id;
27551da177e4SLinus Torvalds 	unsigned long flags;
27561da177e4SLinus Torvalds 
27571da177e4SLinus Torvalds 	spin_lock_irqsave(dev->host_lock, flags);
27581da177e4SLinus Torvalds 	tul_isr((HCS *)dev->base);
27591da177e4SLinus Torvalds 	spin_unlock_irqrestore(dev->host_lock, flags);
27601da177e4SLinus Torvalds 	return IRQ_HANDLED;
27611da177e4SLinus Torvalds }
27621da177e4SLinus Torvalds 
27631da177e4SLinus Torvalds static int tul_NewReturnNumberOfAdapters(void)
27641da177e4SLinus Torvalds {
27651da177e4SLinus Torvalds 	struct pci_dev *pDev = NULL;	/* Start from none              */
27661da177e4SLinus Torvalds 	int iAdapters = 0;
27671da177e4SLinus Torvalds 	long dRegValue;
27681da177e4SLinus Torvalds 	WORD wBIOS;
27691da177e4SLinus Torvalds 	int i = 0;
27701da177e4SLinus Torvalds 
27711da177e4SLinus Torvalds 	init_i91uAdapter_table();
27721da177e4SLinus Torvalds 
27731da177e4SLinus Torvalds 	for (i = 0; i < TULSZ(i91u_pci_devices); i++)
27741da177e4SLinus Torvalds 	{
27751da177e4SLinus Torvalds 		while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
27761da177e4SLinus Torvalds 			if (pci_enable_device(pDev))
27771da177e4SLinus Torvalds 				continue;
27781da177e4SLinus Torvalds 			pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
27791da177e4SLinus Torvalds 			wBIOS = (UWORD) (dRegValue & 0xFF);
27801da177e4SLinus Torvalds 			if (((dRegValue & 0xFF00) >> 8) == 0xFF)
27811da177e4SLinus Torvalds 				dRegValue = 0;
27821da177e4SLinus Torvalds 			wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
27831da177e4SLinus Torvalds 			if (pci_set_dma_mask(pDev, 0xffffffff)) {
27841da177e4SLinus Torvalds 				printk(KERN_WARNING
27851da177e4SLinus Torvalds 				       "i91u: Could not set 32 bit DMA mask\n");
27861da177e4SLinus Torvalds 				continue;
27871da177e4SLinus Torvalds 			}
27881da177e4SLinus Torvalds 
27891da177e4SLinus Torvalds 			if (Addi91u_into_Adapter_table(wBIOS,
27901da177e4SLinus Torvalds 							(pDev->resource[0].start),
27911da177e4SLinus Torvalds 						       	pDev->irq,
27921da177e4SLinus Torvalds 						       	pDev->bus->number,
27931da177e4SLinus Torvalds 					       		(pDev->devfn >> 3)
27941da177e4SLinus Torvalds 		    		) == 0)
27951da177e4SLinus Torvalds 				iAdapters++;
27961da177e4SLinus Torvalds 		}
27971da177e4SLinus Torvalds 	}
27981da177e4SLinus Torvalds 
27991da177e4SLinus Torvalds 	return (iAdapters);
28001da177e4SLinus Torvalds }
28011da177e4SLinus Torvalds 
28021da177e4SLinus Torvalds static int i91u_detect(struct scsi_host_template * tpnt)
28031da177e4SLinus Torvalds {
28041da177e4SLinus Torvalds 	HCS *pHCB;
28051da177e4SLinus Torvalds 	struct Scsi_Host *hreg;
28061da177e4SLinus Torvalds 	unsigned long i;	/* 01/14/98                     */
28071da177e4SLinus Torvalds 	int ok = 0, iAdapters;
28081da177e4SLinus Torvalds 	ULONG dBiosAdr;
28091da177e4SLinus Torvalds 	BYTE *pbBiosAdr;
28101da177e4SLinus Torvalds 
28111da177e4SLinus Torvalds 	/* Get total number of adapters in the motherboard */
28121da177e4SLinus Torvalds 	iAdapters = tul_NewReturnNumberOfAdapters();
28131da177e4SLinus Torvalds 	if (iAdapters == 0)	/* If no tulip founded, return */
28141da177e4SLinus Torvalds 		return (0);
28151da177e4SLinus Torvalds 
28161da177e4SLinus Torvalds 	tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
28171da177e4SLinus Torvalds 	/* Update actually channel number */
28181da177e4SLinus Torvalds 	if (tul_tag_enable) {	/* 1.01i                  */
28191da177e4SLinus Torvalds 		tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
28201da177e4SLinus Torvalds 	} else {
28211da177e4SLinus Torvalds 		tul_num_scb = MAX_TARGETS + 3;	/* 1-tape, 1-CD_ROM, 1- extra */
28221da177e4SLinus Torvalds 	}			/* Update actually SCBs per adapter */
28231da177e4SLinus Torvalds 
28241da177e4SLinus Torvalds 	/* Get total memory needed for HCS */
28251da177e4SLinus Torvalds 	i = tul_num_ch * sizeof(HCS);
28261da177e4SLinus Torvalds 	memset((unsigned char *) &tul_hcs[0], 0, i);	/* Initialize tul_hcs 0 */
28271da177e4SLinus Torvalds 	/* Get total memory needed for SCB */
28281da177e4SLinus Torvalds 
28291da177e4SLinus Torvalds 	for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
28301da177e4SLinus Torvalds 		i = tul_num_ch * tul_num_scb * sizeof(SCB);
28311da177e4SLinus Torvalds 		if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
28321da177e4SLinus Torvalds 			break;
28331da177e4SLinus Torvalds 	}
28341da177e4SLinus Torvalds 	if (tul_scb == NULL) {
28351da177e4SLinus Torvalds 		printk("i91u: SCB memory allocation error\n");
28361da177e4SLinus Torvalds 		return (0);
28371da177e4SLinus Torvalds 	}
28381da177e4SLinus Torvalds 	memset((unsigned char *) tul_scb, 0, i);
28391da177e4SLinus Torvalds 
28401da177e4SLinus Torvalds 	for (i = 0, pHCB = &tul_hcs[0];		/* Get pointer for control block */
28411da177e4SLinus Torvalds 	     i < tul_num_ch;
28421da177e4SLinus Torvalds 	     i++, pHCB++) {
28431da177e4SLinus Torvalds 		get_tulipPCIConfig(pHCB, i);
28441da177e4SLinus Torvalds 
28451da177e4SLinus Torvalds 		dBiosAdr = pHCB->HCS_BIOS;
28461da177e4SLinus Torvalds 		dBiosAdr = (dBiosAdr << 4);
28471da177e4SLinus Torvalds 
28481da177e4SLinus Torvalds 		pbBiosAdr = phys_to_virt(dBiosAdr);
28491da177e4SLinus Torvalds 
28501da177e4SLinus Torvalds 		init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
28511da177e4SLinus Torvalds 		request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */
28521da177e4SLinus Torvalds 
28531da177e4SLinus Torvalds 		pHCB->HCS_Index = i;	/* 7/29/98 */
28541da177e4SLinus Torvalds 		hreg = scsi_register(tpnt, sizeof(HCS));
28551da177e4SLinus Torvalds 		if(hreg == NULL) {
28561da177e4SLinus Torvalds 			release_region(pHCB->HCS_Base, 256);
28571da177e4SLinus Torvalds 			return 0;
28581da177e4SLinus Torvalds 		}
28591da177e4SLinus Torvalds 		hreg->io_port = pHCB->HCS_Base;
28601da177e4SLinus Torvalds 		hreg->n_io_port = 0xff;
28611da177e4SLinus Torvalds 		hreg->can_queue = tul_num_scb;	/* 03/05/98                      */
28621da177e4SLinus Torvalds 		hreg->unique_id = pHCB->HCS_Base;
28631da177e4SLinus Torvalds 		hreg->max_id = pHCB->HCS_MaxTar;
28641da177e4SLinus Torvalds 		hreg->max_lun = 32;	/* 10/21/97                     */
28651da177e4SLinus Torvalds 		hreg->irq = pHCB->HCS_Intr;
28661da177e4SLinus Torvalds 		hreg->this_id = pHCB->HCS_SCSI_ID;	/* Assign HCS index           */
28671da177e4SLinus Torvalds 		hreg->base = (unsigned long)pHCB;
28681da177e4SLinus Torvalds 		hreg->sg_tablesize = TOTAL_SG_ENTRY;	/* Maximun support is 32 */
28691da177e4SLinus Torvalds 
28701da177e4SLinus Torvalds 		/* Initial tulip chip           */
28711da177e4SLinus Torvalds 		ok = request_irq(pHCB->HCS_Intr, i91u_intr, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
28721da177e4SLinus Torvalds 		if (ok < 0) {
28731da177e4SLinus Torvalds 			printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
28741da177e4SLinus Torvalds 			return 0;
28751da177e4SLinus Torvalds 		}
28761da177e4SLinus Torvalds 	}
28771da177e4SLinus Torvalds 
28781da177e4SLinus Torvalds 	tpnt->this_id = -1;
28791da177e4SLinus Torvalds 	tpnt->can_queue = 1;
28801da177e4SLinus Torvalds 
28811da177e4SLinus Torvalds 	return 1;
28821da177e4SLinus Torvalds }
28831da177e4SLinus Torvalds 
28841da177e4SLinus Torvalds static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, struct scsi_cmnd * SCpnt)
28851da177e4SLinus Torvalds {				/* Create corresponding SCB     */
28861da177e4SLinus Torvalds 	struct scatterlist *pSrbSG;
28871da177e4SLinus Torvalds 	SG *pSG;		/* Pointer to SG list           */
28881da177e4SLinus Torvalds 	int i;
28891da177e4SLinus Torvalds 	long TotalLen;
28901da177e4SLinus Torvalds 	dma_addr_t dma_addr;
28911da177e4SLinus Torvalds 
28921da177e4SLinus Torvalds 	pSCB->SCB_Post = i91uSCBPost;	/* i91u's callback routine      */
28931da177e4SLinus Torvalds 	pSCB->SCB_Srb = SCpnt;
28941da177e4SLinus Torvalds 	pSCB->SCB_Opcode = ExecSCSI;
28951da177e4SLinus Torvalds 	pSCB->SCB_Flags = SCF_POST;	/* After SCSI done, call post routine */
28961da177e4SLinus Torvalds 	pSCB->SCB_Target = SCpnt->device->id;
28971da177e4SLinus Torvalds 	pSCB->SCB_Lun = SCpnt->device->lun;
28981da177e4SLinus Torvalds 	pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
28991da177e4SLinus Torvalds 
29001da177e4SLinus Torvalds 	pSCB->SCB_Flags |= SCF_SENSE;	/* Turn on auto request sense   */
29011da177e4SLinus Torvalds 	dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->sense_buffer,
29021da177e4SLinus Torvalds 				  SENSE_SIZE, DMA_FROM_DEVICE);
29031da177e4SLinus Torvalds 	pSCB->SCB_SensePtr = cpu_to_le32((u32)dma_addr);
29041da177e4SLinus Torvalds 	pSCB->SCB_SenseLen = cpu_to_le32(SENSE_SIZE);
29051da177e4SLinus Torvalds 	SCpnt->SCp.ptr = (char *)(unsigned long)dma_addr;
29061da177e4SLinus Torvalds 
29071da177e4SLinus Torvalds 	pSCB->SCB_CDBLen = SCpnt->cmd_len;
29081da177e4SLinus Torvalds 	pSCB->SCB_HaStat = 0;
29091da177e4SLinus Torvalds 	pSCB->SCB_TaStat = 0;
29101da177e4SLinus Torvalds 	memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
29111da177e4SLinus Torvalds 
29121da177e4SLinus Torvalds 	if (SCpnt->device->tagged_supported) {	/* Tag Support                  */
29131da177e4SLinus Torvalds 		pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;	/* Do simple tag only   */
29141da177e4SLinus Torvalds 	} else {
29151da177e4SLinus Torvalds 		pSCB->SCB_TagMsg = 0;	/* No tag support               */
29161da177e4SLinus Torvalds 	}
29171da177e4SLinus Torvalds 	/* todo handle map_sg error */
29181da177e4SLinus Torvalds 	if (SCpnt->use_sg) {
29191da177e4SLinus Torvalds 		dma_addr = dma_map_single(&pHCB->pci_dev->dev, &pSCB->SCB_SGList[0],
29201da177e4SLinus Torvalds 					  sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
29211da177e4SLinus Torvalds 					  DMA_BIDIRECTIONAL);
29221da177e4SLinus Torvalds 		pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
29231da177e4SLinus Torvalds 		SCpnt->SCp.dma_handle = dma_addr;
29241da177e4SLinus Torvalds 
29251da177e4SLinus Torvalds 		pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
29261da177e4SLinus Torvalds 		pSCB->SCB_SGLen = dma_map_sg(&pHCB->pci_dev->dev, pSrbSG,
29271da177e4SLinus Torvalds 					     SCpnt->use_sg, SCpnt->sc_data_direction);
29281da177e4SLinus Torvalds 
29291da177e4SLinus Torvalds 		pSCB->SCB_Flags |= SCF_SG;	/* Turn on SG list flag       */
29301da177e4SLinus Torvalds 		for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0];	/* 1.01g */
29311da177e4SLinus Torvalds 		     i < pSCB->SCB_SGLen; i++, pSG++, pSrbSG++) {
29321da177e4SLinus Torvalds 			pSG->SG_Ptr = cpu_to_le32((u32)sg_dma_address(pSrbSG));
29331da177e4SLinus Torvalds 			TotalLen += pSG->SG_Len = cpu_to_le32((u32)sg_dma_len(pSrbSG));
29341da177e4SLinus Torvalds 		}
29351da177e4SLinus Torvalds 
29361da177e4SLinus Torvalds 		pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
29371da177e4SLinus Torvalds 		    TotalLen : SCpnt->request_bufflen;
29381da177e4SLinus Torvalds 	} else if (SCpnt->request_bufflen) {		/* Non SG */
29391da177e4SLinus Torvalds 		dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->request_buffer,
29401da177e4SLinus Torvalds 					  SCpnt->request_bufflen,
29411da177e4SLinus Torvalds 					  SCpnt->sc_data_direction);
29421da177e4SLinus Torvalds 		SCpnt->SCp.dma_handle = dma_addr;
29431da177e4SLinus Torvalds 		pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
29441da177e4SLinus Torvalds 		pSCB->SCB_BufLen = cpu_to_le32((u32)SCpnt->request_bufflen);
29451da177e4SLinus Torvalds 		pSCB->SCB_SGLen = 0;
29461da177e4SLinus Torvalds 	} else {
29471da177e4SLinus Torvalds 		pSCB->SCB_BufLen = 0;
29481da177e4SLinus Torvalds 		pSCB->SCB_SGLen = 0;
29491da177e4SLinus Torvalds 	}
29501da177e4SLinus Torvalds }
29511da177e4SLinus Torvalds 
29521da177e4SLinus Torvalds static int i91u_queuecommand(struct scsi_cmnd *cmd,
29531da177e4SLinus Torvalds 		void (*done)(struct scsi_cmnd *))
29541da177e4SLinus Torvalds {
29551da177e4SLinus Torvalds 	HCS *pHCB = (HCS *) cmd->device->host->base;
29561da177e4SLinus Torvalds 	register SCB *pSCB;
29571da177e4SLinus Torvalds 
29581da177e4SLinus Torvalds 	cmd->scsi_done = done;
29591da177e4SLinus Torvalds 
29601da177e4SLinus Torvalds 	pSCB = tul_alloc_scb(pHCB);
29611da177e4SLinus Torvalds 	if (!pSCB)
29621da177e4SLinus Torvalds 		return SCSI_MLQUEUE_HOST_BUSY;
29631da177e4SLinus Torvalds 
29641da177e4SLinus Torvalds 	i91uBuildSCB(pHCB, pSCB, cmd);
29651da177e4SLinus Torvalds 	tul_exec_scb(pHCB, pSCB);
29661da177e4SLinus Torvalds 	return 0;
29671da177e4SLinus Torvalds }
29681da177e4SLinus Torvalds 
29691da177e4SLinus Torvalds #if 0 /* no new EH yet */
29701da177e4SLinus Torvalds /*
29711da177e4SLinus Torvalds  *  Abort a queued command
29721da177e4SLinus Torvalds  *  (commands that are on the bus can't be aborted easily)
29731da177e4SLinus Torvalds  */
29741da177e4SLinus Torvalds static int i91u_abort(struct scsi_cmnd * SCpnt)
29751da177e4SLinus Torvalds {
29761da177e4SLinus Torvalds 	HCS *pHCB;
29771da177e4SLinus Torvalds 
29781da177e4SLinus Torvalds 	pHCB = (HCS *) SCpnt->device->host->base;
29791da177e4SLinus Torvalds 	return tul_abort_srb(pHCB, SCpnt);
29801da177e4SLinus Torvalds }
29811da177e4SLinus Torvalds 
29821da177e4SLinus Torvalds /*
29831da177e4SLinus Torvalds  *  Reset registers, reset a hanging bus and
29841da177e4SLinus Torvalds  *  kill active and disconnected commands for target w/o soft reset
29851da177e4SLinus Torvalds  */
29861da177e4SLinus Torvalds static int i91u_reset(struct scsi_cmnd * SCpnt, unsigned int reset_flags)
29871da177e4SLinus Torvalds {				/* I need Host Control Block Information */
29881da177e4SLinus Torvalds 	HCS *pHCB;
29891da177e4SLinus Torvalds 
29901da177e4SLinus Torvalds 	pHCB = (HCS *) SCpnt->device->host->base;
29911da177e4SLinus Torvalds 
29921da177e4SLinus Torvalds 	if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
29931da177e4SLinus Torvalds 		return tul_reset_scsi_bus(pHCB);
29941da177e4SLinus Torvalds 	else
29951da177e4SLinus Torvalds 		return tul_device_reset(pHCB, SCpnt, SCpnt->device->id, reset_flags);
29961da177e4SLinus Torvalds }
29971da177e4SLinus Torvalds #endif
29981da177e4SLinus Torvalds 
29991da177e4SLinus Torvalds static int i91u_bus_reset(struct scsi_cmnd * SCpnt)
30001da177e4SLinus Torvalds {
30011da177e4SLinus Torvalds 	HCS *pHCB;
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds 	pHCB = (HCS *) SCpnt->device->host->base;
300468b3aa7cSJeff Garzik  
300568b3aa7cSJeff Garzik  	spin_lock_irq(SCpnt->device->host->host_lock);
30061da177e4SLinus Torvalds 	tul_reset_scsi(pHCB, 0);
300768b3aa7cSJeff Garzik  	spin_unlock_irq(SCpnt->device->host->host_lock);
300868b3aa7cSJeff Garzik  
30091da177e4SLinus Torvalds 	return SUCCESS;
30101da177e4SLinus Torvalds }
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds /*
30131da177e4SLinus Torvalds  * Return the "logical geometry"
30141da177e4SLinus Torvalds  */
30151da177e4SLinus Torvalds static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
30161da177e4SLinus Torvalds 		sector_t capacity, int *info_array)
30171da177e4SLinus Torvalds {
30181da177e4SLinus Torvalds 	HCS *pHcb;		/* Point to Host adapter control block */
30191da177e4SLinus Torvalds 	TCS *pTcb;
30201da177e4SLinus Torvalds 
30211da177e4SLinus Torvalds 	pHcb = (HCS *) sdev->host->base;
30221da177e4SLinus Torvalds 	pTcb = &pHcb->HCS_Tcs[sdev->id];
30231da177e4SLinus Torvalds 
30241da177e4SLinus Torvalds 	if (pTcb->TCS_DrvHead) {
30251da177e4SLinus Torvalds 		info_array[0] = pTcb->TCS_DrvHead;
30261da177e4SLinus Torvalds 		info_array[1] = pTcb->TCS_DrvSector;
30271da177e4SLinus Torvalds 		info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
30281da177e4SLinus Torvalds 	} else {
30291da177e4SLinus Torvalds 		if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
30301da177e4SLinus Torvalds 			info_array[0] = 255;
30311da177e4SLinus Torvalds 			info_array[1] = 63;
30321da177e4SLinus Torvalds 			info_array[2] = (unsigned long)capacity / 255 / 63;
30331da177e4SLinus Torvalds 		} else {
30341da177e4SLinus Torvalds 			info_array[0] = 64;
30351da177e4SLinus Torvalds 			info_array[1] = 32;
30361da177e4SLinus Torvalds 			info_array[2] = (unsigned long)capacity >> 11;
30371da177e4SLinus Torvalds 		}
30381da177e4SLinus Torvalds 	}
30391da177e4SLinus Torvalds 
30401da177e4SLinus Torvalds #if defined(DEBUG_BIOSPARAM)
30411da177e4SLinus Torvalds 	if (i91u_debug & debug_biosparam) {
30421da177e4SLinus Torvalds 		printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
30431da177e4SLinus Torvalds 		       info_array[0], info_array[1], info_array[2]);
30441da177e4SLinus Torvalds 		printk("WARNING: check, if the bios geometry is correct.\n");
30451da177e4SLinus Torvalds 	}
30461da177e4SLinus Torvalds #endif
30471da177e4SLinus Torvalds 
30481da177e4SLinus Torvalds 	return 0;
30491da177e4SLinus Torvalds }
30501da177e4SLinus Torvalds 
30511da177e4SLinus Torvalds static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
30521da177e4SLinus Torvalds {
30531da177e4SLinus Torvalds 	/* auto sense buffer */
30541da177e4SLinus Torvalds 	if (cmnd->SCp.ptr) {
30551da177e4SLinus Torvalds 		dma_unmap_single(&pci_dev->dev,
30561da177e4SLinus Torvalds 				 (dma_addr_t)((unsigned long)cmnd->SCp.ptr),
30571da177e4SLinus Torvalds 				 SENSE_SIZE, DMA_FROM_DEVICE);
30581da177e4SLinus Torvalds 		cmnd->SCp.ptr = NULL;
30591da177e4SLinus Torvalds 	}
30601da177e4SLinus Torvalds 
30611da177e4SLinus Torvalds 	/* request buffer */
30621da177e4SLinus Torvalds 	if (cmnd->use_sg) {
30631da177e4SLinus Torvalds 		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
30641da177e4SLinus Torvalds 				 sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
30651da177e4SLinus Torvalds 				 DMA_BIDIRECTIONAL);
30661da177e4SLinus Torvalds 
30671da177e4SLinus Torvalds 		dma_unmap_sg(&pci_dev->dev, cmnd->request_buffer,
30681da177e4SLinus Torvalds 			     cmnd->use_sg,
30691da177e4SLinus Torvalds 			     cmnd->sc_data_direction);
30701da177e4SLinus Torvalds 	} else if (cmnd->request_bufflen) {
30711da177e4SLinus Torvalds 		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
30721da177e4SLinus Torvalds 				 cmnd->request_bufflen,
30731da177e4SLinus Torvalds 				 cmnd->sc_data_direction);
30741da177e4SLinus Torvalds 	}
30751da177e4SLinus Torvalds }
30761da177e4SLinus Torvalds 
30771da177e4SLinus Torvalds /*****************************************************************************
30781da177e4SLinus Torvalds  Function name  : i91uSCBPost
30791da177e4SLinus Torvalds  Description    : This is callback routine be called when tulip finish one
30801da177e4SLinus Torvalds 			SCSI command.
30811da177e4SLinus Torvalds  Input          : pHCB  -       Pointer to host adapter control block.
30821da177e4SLinus Torvalds 		  pSCB  -       Pointer to SCSI control block.
30831da177e4SLinus Torvalds  Output         : None.
30841da177e4SLinus Torvalds  Return         : None.
30851da177e4SLinus Torvalds *****************************************************************************/
30861da177e4SLinus Torvalds static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
30871da177e4SLinus Torvalds {
30881da177e4SLinus Torvalds 	struct scsi_cmnd *pSRB;	/* Pointer to SCSI request block */
30891da177e4SLinus Torvalds 	HCS *pHCB;
30901da177e4SLinus Torvalds 	SCB *pSCB;
30911da177e4SLinus Torvalds 
30921da177e4SLinus Torvalds 	pHCB = (HCS *) pHcb;
30931da177e4SLinus Torvalds 	pSCB = (SCB *) pScb;
30941da177e4SLinus Torvalds 	if ((pSRB = pSCB->SCB_Srb) == 0) {
30951da177e4SLinus Torvalds 		printk("i91uSCBPost: SRB pointer is empty\n");
30961da177e4SLinus Torvalds 
30971da177e4SLinus Torvalds 		tul_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
30981da177e4SLinus Torvalds 		return;
30991da177e4SLinus Torvalds 	}
31001da177e4SLinus Torvalds 	switch (pSCB->SCB_HaStat) {
31011da177e4SLinus Torvalds 	case 0x0:
31021da177e4SLinus Torvalds 	case 0xa:		/* Linked command complete without error and linked normally */
31031da177e4SLinus Torvalds 	case 0xb:		/* Linked command complete without error interrupt generated */
31041da177e4SLinus Torvalds 		pSCB->SCB_HaStat = 0;
31051da177e4SLinus Torvalds 		break;
31061da177e4SLinus Torvalds 
31071da177e4SLinus Torvalds 	case 0x11:		/* Selection time out-The initiator selection or target
31081da177e4SLinus Torvalds 				   reselection was not complete within the SCSI Time out period */
31091da177e4SLinus Torvalds 		pSCB->SCB_HaStat = DID_TIME_OUT;
31101da177e4SLinus Torvalds 		break;
31111da177e4SLinus Torvalds 
31121da177e4SLinus Torvalds 	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
31131da177e4SLinus Torvalds 				   phase sequence was requested by the target. The host adapter
31141da177e4SLinus Torvalds 				   will generate a SCSI Reset Condition, notifying the host with
31151da177e4SLinus Torvalds 				   a SCRD interrupt */
31161da177e4SLinus Torvalds 		pSCB->SCB_HaStat = DID_RESET;
31171da177e4SLinus Torvalds 		break;
31181da177e4SLinus Torvalds 
31191da177e4SLinus Torvalds 	case 0x1a:		/* SCB Aborted. 07/21/98 */
31201da177e4SLinus Torvalds 		pSCB->SCB_HaStat = DID_ABORT;
31211da177e4SLinus Torvalds 		break;
31221da177e4SLinus Torvalds 
31231da177e4SLinus Torvalds 	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
31241da177e4SLinus Torvalds 				   than was allocated by the Data Length field or the sum of the
31251da177e4SLinus Torvalds 				   Scatter / Gather Data Length fields. */
31261da177e4SLinus Torvalds 	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
31271da177e4SLinus Torvalds 	case 0x16:		/* Invalid SCB Operation Code. */
31281da177e4SLinus Torvalds 
31291da177e4SLinus Torvalds 	default:
31301da177e4SLinus Torvalds 		printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
31311da177e4SLinus Torvalds 		pSCB->SCB_HaStat = DID_ERROR;	/* Couldn't find any better */
31321da177e4SLinus Torvalds 		break;
31331da177e4SLinus Torvalds 	}
31341da177e4SLinus Torvalds 
31351da177e4SLinus Torvalds 	pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
31361da177e4SLinus Torvalds 
31371da177e4SLinus Torvalds 	if (pSRB == NULL) {
31381da177e4SLinus Torvalds 		printk("pSRB is NULL\n");
31391da177e4SLinus Torvalds 	}
31401da177e4SLinus Torvalds 
31411da177e4SLinus Torvalds 	i91u_unmap_cmnd(pHCB->pci_dev, pSRB);
31421da177e4SLinus Torvalds 	pSRB->scsi_done(pSRB);	/* Notify system DONE           */
31431da177e4SLinus Torvalds 
31441da177e4SLinus Torvalds 	tul_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
31451da177e4SLinus Torvalds }
31461da177e4SLinus Torvalds 
31471da177e4SLinus Torvalds /*
31481da177e4SLinus Torvalds  * Release ressources
31491da177e4SLinus Torvalds  */
31501da177e4SLinus Torvalds static int i91u_release(struct Scsi_Host *hreg)
31511da177e4SLinus Torvalds {
31521da177e4SLinus Torvalds 	free_irq(hreg->irq, hreg);
31531da177e4SLinus Torvalds 	release_region(hreg->io_port, 256);
31541da177e4SLinus Torvalds 	return 0;
31551da177e4SLinus Torvalds }
31561da177e4SLinus Torvalds MODULE_LICENSE("Dual BSD/GPL");
31571da177e4SLinus Torvalds 
31581da177e4SLinus Torvalds static struct scsi_host_template driver_template = {
31591da177e4SLinus Torvalds 	.proc_name	= "INI9100U",
31601da177e4SLinus Torvalds 	.name		= i91u_REVID,
31611da177e4SLinus Torvalds 	.detect		= i91u_detect,
31621da177e4SLinus Torvalds 	.release	= i91u_release,
31631da177e4SLinus Torvalds 	.queuecommand	= i91u_queuecommand,
31641da177e4SLinus Torvalds //	.abort		= i91u_abort,
31651da177e4SLinus Torvalds //	.reset		= i91u_reset,
31661da177e4SLinus Torvalds 	.eh_bus_reset_handler = i91u_bus_reset,
31671da177e4SLinus Torvalds 	.bios_param	= i91u_biosparam,
31681da177e4SLinus Torvalds 	.can_queue	= 1,
31691da177e4SLinus Torvalds 	.this_id	= 1,
31701da177e4SLinus Torvalds 	.sg_tablesize	= SG_ALL,
31711da177e4SLinus Torvalds 	.cmd_per_lun 	= 1,
31721da177e4SLinus Torvalds 	.use_clustering	= ENABLE_CLUSTERING,
31731da177e4SLinus Torvalds };
31741da177e4SLinus Torvalds #include "scsi_module.c"
31751da177e4SLinus Torvalds 
3176