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