xref: /openbmc/linux/drivers/scsi/aha152x.c (revision 3c011793aca71edf8dd40d1201935b51b3acd855)
13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /* aha152x.c -- Adaptec AHA-152x driver
396de0e25SJan Engelhardt  * Author: Jürgen E. Fischer, fischer@norbit.de
496de0e25SJan Engelhardt  * Copyright 1993-2004 Jürgen E. Fischer
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * $Log: aha152x.c,v $
91da177e4SLinus Torvalds  * Revision 2.7  2004/01/24 11:42:59  fischer
101da177e4SLinus Torvalds  * - gather code that is not used by PCMCIA at the end
111da177e4SLinus Torvalds  * - move request_region for !PCMCIA case to detection
121da177e4SLinus Torvalds  * - migration to new scsi host api (remove legacy code)
131da177e4SLinus Torvalds  * - free host scribble before scsi_done
141da177e4SLinus Torvalds  * - fix error handling
151da177e4SLinus Torvalds  * - one isapnp device added to id_table
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * Revision 2.6  2003/10/30 20:52:47  fischer
181da177e4SLinus Torvalds  * - interfaces changes for kernel 2.6
191da177e4SLinus Torvalds  * - aha152x_probe_one introduced for pcmcia stub
201da177e4SLinus Torvalds  * - fixed pnpdev handling
211da177e4SLinus Torvalds  * - instead of allocation a new one, reuse command for request sense after check condition and reset
221da177e4SLinus Torvalds  * - fixes race in is_complete
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  * Revision 2.5  2002/04/14 11:24:53  fischer
251da177e4SLinus Torvalds  * - isapnp support
261da177e4SLinus Torvalds  * - abort fixed
271da177e4SLinus Torvalds  * - 2.5 support
281da177e4SLinus Torvalds  *
291da177e4SLinus Torvalds  * Revision 2.4  2000/12/16 12:53:56  fischer
301da177e4SLinus Torvalds  * - allow REQUEST SENSE to be queued
311da177e4SLinus Torvalds  * - handle shared PCI interrupts
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * Revision 2.3  2000/11/04 16:40:26  fischer
341da177e4SLinus Torvalds  * - handle data overruns
351da177e4SLinus Torvalds  * - extend timeout for data phases
361da177e4SLinus Torvalds  *
371da177e4SLinus Torvalds  * Revision 2.2  2000/08/08 19:54:53  fischer
381da177e4SLinus Torvalds  * - minor changes
391da177e4SLinus Torvalds  *
401da177e4SLinus Torvalds  * Revision 2.1  2000/05/17 16:23:17  fischer
411da177e4SLinus Torvalds  * - signature update
421da177e4SLinus Torvalds  * - fix for data out w/o scatter gather
431da177e4SLinus Torvalds  *
441da177e4SLinus Torvalds  * Revision 2.0  1999/12/25 15:07:32  fischer
451da177e4SLinus Torvalds  * - interrupt routine completly reworked
461da177e4SLinus Torvalds  * - basic support for new eh code
471da177e4SLinus Torvalds  *
481da177e4SLinus Torvalds  * Revision 1.21  1999/11/10 23:46:36  fischer
491da177e4SLinus Torvalds  * - default to synchronous operation
501da177e4SLinus Torvalds  * - synchronous negotiation fixed
511da177e4SLinus Torvalds  * - added timeout to loops
521da177e4SLinus Torvalds  * - debugging output can be controlled through procfs
531da177e4SLinus Torvalds  *
541da177e4SLinus Torvalds  * Revision 1.20  1999/11/07 18:37:31  fischer
551da177e4SLinus Torvalds  * - synchronous operation works
561da177e4SLinus Torvalds  * - resid support for sg driver
571da177e4SLinus Torvalds  *
581da177e4SLinus Torvalds  * Revision 1.19  1999/11/02 22:39:59  fischer
591da177e4SLinus Torvalds  * - moved leading comments to README.aha152x
601da177e4SLinus Torvalds  * - new additional module parameters
611da177e4SLinus Torvalds  * - updates for 2.3
621da177e4SLinus Torvalds  * - support for the Tripace TC1550 controller
631da177e4SLinus Torvalds  * - interrupt handling changed
641da177e4SLinus Torvalds  *
651da177e4SLinus Torvalds  * Revision 1.18  1996/09/07 20:10:40  fischer
661da177e4SLinus Torvalds  * - fixed can_queue handling (multiple outstanding commands working again)
671da177e4SLinus Torvalds  *
681da177e4SLinus Torvalds  * Revision 1.17  1996/08/17 16:05:14  fischer
691da177e4SLinus Torvalds  * - biosparam improved
701da177e4SLinus Torvalds  * - interrupt verification
711da177e4SLinus Torvalds  * - updated documentation
721da177e4SLinus Torvalds  * - cleanups
731da177e4SLinus Torvalds  *
741da177e4SLinus Torvalds  * Revision 1.16  1996/06/09 00:04:56  root
751da177e4SLinus Torvalds  * - added configuration symbols for insmod (aha152x/aha152x1)
761da177e4SLinus Torvalds  *
771da177e4SLinus Torvalds  * Revision 1.15  1996/04/30 14:52:06  fischer
781da177e4SLinus Torvalds  * - proc info fixed
791da177e4SLinus Torvalds  * - support for extended translation for >1GB disks
801da177e4SLinus Torvalds  *
811da177e4SLinus Torvalds  * Revision 1.14  1996/01/17  15:11:20  fischer
821da177e4SLinus Torvalds  * - fixed lockup in MESSAGE IN phase after reconnection
831da177e4SLinus Torvalds  *
841da177e4SLinus Torvalds  * Revision 1.13  1996/01/09  02:15:53  fischer
851da177e4SLinus Torvalds  * - some cleanups
861da177e4SLinus Torvalds  * - moved request_irq behind controller initialization
871da177e4SLinus Torvalds  *   (to avoid spurious interrupts)
881da177e4SLinus Torvalds  *
891da177e4SLinus Torvalds  * Revision 1.12  1995/12/16  12:26:07  fischer
901da177e4SLinus Torvalds  * - barrier()s added
911da177e4SLinus Torvalds  * - configurable RESET delay added
921da177e4SLinus Torvalds  *
931da177e4SLinus Torvalds  * Revision 1.11  1995/12/06  21:18:35  fischer
941da177e4SLinus Torvalds  * - some minor updates
951da177e4SLinus Torvalds  *
961da177e4SLinus Torvalds  * Revision 1.10  1995/07/22  19:18:45  fischer
971da177e4SLinus Torvalds  * - support for 2 controllers
981da177e4SLinus Torvalds  * - started synchronous data transfers (not working yet)
991da177e4SLinus Torvalds  *
1001da177e4SLinus Torvalds  * Revision 1.9  1995/03/18  09:20:24  root
1011da177e4SLinus Torvalds  * - patches for PCMCIA and modules
1021da177e4SLinus Torvalds  *
1031da177e4SLinus Torvalds  * Revision 1.8  1995/01/21  22:07:19  root
1041da177e4SLinus Torvalds  * - snarf_region => request_region
1051da177e4SLinus Torvalds  * - aha152x_intr interface change
1061da177e4SLinus Torvalds  *
1071da177e4SLinus Torvalds  * Revision 1.7  1995/01/02  23:19:36  root
1081da177e4SLinus Torvalds  * - updated COMMAND_SIZE to cmd_len
1091da177e4SLinus Torvalds  * - changed sti() to restore_flags()
1101da177e4SLinus Torvalds  * - fixed some #ifdef which generated warnings
1111da177e4SLinus Torvalds  *
1121da177e4SLinus Torvalds  * Revision 1.6  1994/11/24  20:35:27  root
1131da177e4SLinus Torvalds  * - problem with odd number of bytes in fifo fixed
1141da177e4SLinus Torvalds  *
1151da177e4SLinus Torvalds  * Revision 1.5  1994/10/30  14:39:56  root
1161da177e4SLinus Torvalds  * - abort code fixed
1171da177e4SLinus Torvalds  * - debugging improved
1181da177e4SLinus Torvalds  *
1191da177e4SLinus Torvalds  * Revision 1.4  1994/09/12  11:33:01  root
1201da177e4SLinus Torvalds  * - irqaction to request_irq
1211da177e4SLinus Torvalds  * - abortion updated
1221da177e4SLinus Torvalds  *
1231da177e4SLinus Torvalds  * Revision 1.3  1994/08/04  13:53:05  root
1241da177e4SLinus Torvalds  * - updates for mid-level-driver changes
1251da177e4SLinus Torvalds  * - accept unexpected BUSFREE phase as error condition
1261da177e4SLinus Torvalds  * - parity check now configurable
1271da177e4SLinus Torvalds  *
1281da177e4SLinus Torvalds  * Revision 1.2  1994/07/03  12:56:36  root
1291da177e4SLinus Torvalds  * - cleaned up debugging code
1301da177e4SLinus Torvalds  * - more tweaking on reset delays
1311da177e4SLinus Torvalds  * - updated abort/reset code (pretty untested...)
1321da177e4SLinus Torvalds  *
1331da177e4SLinus Torvalds  * Revision 1.1  1994/05/28  21:18:49  root
1341da177e4SLinus Torvalds  * - update for mid-level interface change (abort-reset)
1351da177e4SLinus Torvalds  * - delays after resets adjusted for some slow devices
1361da177e4SLinus Torvalds  *
1371da177e4SLinus Torvalds  * Revision 1.0  1994/03/25  12:52:00  root
1381da177e4SLinus Torvalds  * - Fixed "more data than expected" problem
1391da177e4SLinus Torvalds  * - added new BIOS signatures
1401da177e4SLinus Torvalds  *
1411da177e4SLinus Torvalds  * Revision 0.102  1994/01/31  20:44:12  root
1421da177e4SLinus Torvalds  * - minor changes in insw/outsw handling
1431da177e4SLinus Torvalds  *
1441da177e4SLinus Torvalds  * Revision 0.101  1993/12/13  01:16:27  root
1451da177e4SLinus Torvalds  * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
1461da177e4SLinus Torvalds  *   fixes problems with CD-ROM sector size detection & media change)
1471da177e4SLinus Torvalds  *
1481da177e4SLinus Torvalds  * Revision 0.100  1993/12/10  16:58:47  root
1491da177e4SLinus Torvalds  * - fix for unsuccessful selections in case of non-continuous id assignments
1501da177e4SLinus Torvalds  *   on the scsi bus.
1511da177e4SLinus Torvalds  *
1521da177e4SLinus Torvalds  * Revision 0.99  1993/10/24  16:19:59  root
1531da177e4SLinus Torvalds  * - fixed DATA IN (rare read errors gone)
1541da177e4SLinus Torvalds  *
1551da177e4SLinus Torvalds  * Revision 0.98  1993/10/17  12:54:44  root
1561da177e4SLinus Torvalds  * - fixed some recent fixes (shame on me)
1571da177e4SLinus Torvalds  * - moved initialization of scratch area to aha152x_queue
1581da177e4SLinus Torvalds  *
1591da177e4SLinus Torvalds  * Revision 0.97  1993/10/09  18:53:53  root
1601da177e4SLinus Torvalds  * - DATA IN fixed. Rarely left data in the fifo.
1611da177e4SLinus Torvalds  *
1621da177e4SLinus Torvalds  * Revision 0.96  1993/10/03  00:53:59  root
1631da177e4SLinus Torvalds  * - minor changes on DATA IN
1641da177e4SLinus Torvalds  *
1651da177e4SLinus Torvalds  * Revision 0.95  1993/09/24  10:36:01  root
1661da177e4SLinus Torvalds  * - change handling of MSGI after reselection
1671da177e4SLinus Torvalds  * - fixed sti/cli
1681da177e4SLinus Torvalds  * - minor changes
1691da177e4SLinus Torvalds  *
1701da177e4SLinus Torvalds  * Revision 0.94  1993/09/18  14:08:22  root
1711da177e4SLinus Torvalds  * - fixed bug in multiple outstanding command code
1721da177e4SLinus Torvalds  * - changed detection
1731da177e4SLinus Torvalds  * - support for kernel command line configuration
1741da177e4SLinus Torvalds  * - reset corrected
1751da177e4SLinus Torvalds  * - changed message handling
1761da177e4SLinus Torvalds  *
1771da177e4SLinus Torvalds  * Revision 0.93  1993/09/15  20:41:19  root
1781da177e4SLinus Torvalds  * - fixed bugs with multiple outstanding commands
1791da177e4SLinus Torvalds  *
1801da177e4SLinus Torvalds  * Revision 0.92  1993/09/13  02:46:33  root
1811da177e4SLinus Torvalds  * - multiple outstanding commands work (no problems with IBM drive)
1821da177e4SLinus Torvalds  *
1831da177e4SLinus Torvalds  * Revision 0.91  1993/09/12  20:51:46  root
1841da177e4SLinus Torvalds  * added multiple outstanding commands
1851da177e4SLinus Torvalds  * (some problem with this $%&? IBM device remain)
1861da177e4SLinus Torvalds  *
1871da177e4SLinus Torvalds  * Revision 0.9  1993/09/12  11:11:22  root
1881da177e4SLinus Torvalds  * - corrected auto-configuration
1891da177e4SLinus Torvalds  * - changed the auto-configuration (added some '#define's)
1901da177e4SLinus Torvalds  * - added support for dis-/reconnection
1911da177e4SLinus Torvalds  *
1921da177e4SLinus Torvalds  * Revision 0.8  1993/09/06  23:09:39  root
1931da177e4SLinus Torvalds  * - added support for the drive activity light
1941da177e4SLinus Torvalds  * - minor changes
1951da177e4SLinus Torvalds  *
1961da177e4SLinus Torvalds  * Revision 0.7  1993/09/05  14:30:15  root
1971da177e4SLinus Torvalds  * - improved phase detection
1981da177e4SLinus Torvalds  * - now using the new snarf_region code of 0.99pl13
1991da177e4SLinus Torvalds  *
2001da177e4SLinus Torvalds  * Revision 0.6  1993/09/02  11:01:38  root
2011da177e4SLinus Torvalds  * first public release; added some signatures and biosparam()
2021da177e4SLinus Torvalds  *
2031da177e4SLinus Torvalds  * Revision 0.5  1993/08/30  10:23:30  root
2041da177e4SLinus Torvalds  * fixed timing problems with my IBM drive
2051da177e4SLinus Torvalds  *
2061da177e4SLinus Torvalds  * Revision 0.4  1993/08/29  14:06:52  root
2071da177e4SLinus Torvalds  * fixed some problems with timeouts due incomplete commands
2081da177e4SLinus Torvalds  *
2091da177e4SLinus Torvalds  * Revision 0.3  1993/08/28  15:55:03  root
2101da177e4SLinus Torvalds  * writing data works too.  mounted and worked on a dos partition
2111da177e4SLinus Torvalds  *
2121da177e4SLinus Torvalds  * Revision 0.2  1993/08/27  22:42:07  root
2131da177e4SLinus Torvalds  * reading data works.  Mounted a msdos partition.
2141da177e4SLinus Torvalds  *
2151da177e4SLinus Torvalds  * Revision 0.1  1993/08/25  13:38:30  root
2161da177e4SLinus Torvalds  * first "damn thing doesn't work" version
2171da177e4SLinus Torvalds  *
2181da177e4SLinus Torvalds  * Revision 0.0  1993/08/14  19:54:25  root
2191da177e4SLinus Torvalds  * empty function bodies; detect() works.
2201da177e4SLinus Torvalds  *
2211da177e4SLinus Torvalds  **************************************************************************
2221da177e4SLinus Torvalds 
22394b5530fSMauro Carvalho Chehab  see Documentation/scsi/aha152x.rst for configuration details
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds  **************************************************************************/
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds #include <linux/module.h>
2281da177e4SLinus Torvalds #include <asm/irq.h>
22953d5ed62SMatthew Wilcox #include <linux/io.h>
2301da177e4SLinus Torvalds #include <linux/blkdev.h>
2310f06bb34SChristoph Hellwig #include <linux/completion.h>
2321da177e4SLinus Torvalds #include <linux/errno.h>
2331da177e4SLinus Torvalds #include <linux/string.h>
2341da177e4SLinus Torvalds #include <linux/wait.h>
2351da177e4SLinus Torvalds #include <linux/ioport.h>
2361da177e4SLinus Torvalds #include <linux/delay.h>
2371da177e4SLinus Torvalds #include <linux/proc_fs.h>
2381da177e4SLinus Torvalds #include <linux/interrupt.h>
2391da177e4SLinus Torvalds #include <linux/init.h>
2401da177e4SLinus Torvalds #include <linux/kernel.h>
2411da177e4SLinus Torvalds #include <linux/isapnp.h>
2421da177e4SLinus Torvalds #include <linux/spinlock.h>
2431da177e4SLinus Torvalds #include <linux/workqueue.h>
2445fcda422SJames Bottomley #include <linux/list.h>
2455a0e3ad6STejun Heo #include <linux/slab.h>
2461da177e4SLinus Torvalds #include <scsi/scsicam.h>
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds #include "scsi.h"
249db9dff36S #include <scsi/scsi_dbg.h>
2501da177e4SLinus Torvalds #include <scsi/scsi_host.h>
2511abfd370SMatthew Wilcox #include <scsi/scsi_transport_spi.h>
25273d2cb16SBoaz Harrosh #include <scsi/scsi_eh.h>
2531da177e4SLinus Torvalds #include "aha152x.h"
2541da177e4SLinus Torvalds 
2555fcda422SJames Bottomley static LIST_HEAD(aha152x_host_list);
2565fcda422SJames Bottomley 
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds /* DEFINES */
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds /* For PCMCIA cards, always use AUTOCONF */
2613eb2ebcbSChristoph Hellwig #if defined(AHA152X_PCMCIA) || defined(MODULE)
2621da177e4SLinus Torvalds #if !defined(AUTOCONF)
2631da177e4SLinus Torvalds #define AUTOCONF
2641da177e4SLinus Torvalds #endif
2651da177e4SLinus Torvalds #endif
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds #if !defined(AUTOCONF) && !defined(SETUP0)
2681da177e4SLinus Torvalds #error define AUTOCONF or SETUP0
2691da177e4SLinus Torvalds #endif
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds #define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
2721da177e4SLinus Torvalds #define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds #define LEAD		"(scsi%d:%d:%d) "
2751da177e4SLinus Torvalds #define INFO_LEAD	KERN_INFO	LEAD
2761da177e4SLinus Torvalds #define CMDINFO(cmd) \
2771da177e4SLinus Torvalds 			(cmd) ? ((cmd)->device->host->host_no) : -1, \
2781da177e4SLinus Torvalds                         (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
2799cb78c16SHannes Reinecke 			(cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1
2801da177e4SLinus Torvalds 
2812338545aSBoaz Harrosh static inline void
2822338545aSBoaz Harrosh CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
2832338545aSBoaz Harrosh {
2842338545aSBoaz Harrosh 	scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
2852338545aSBoaz Harrosh }
2862338545aSBoaz Harrosh 
2871da177e4SLinus Torvalds #define DELAY_DEFAULT 1000
2881da177e4SLinus Torvalds 
2893eb2ebcbSChristoph Hellwig #if defined(AHA152X_PCMCIA)
2901da177e4SLinus Torvalds #define IRQ_MIN 0
2911da177e4SLinus Torvalds #define IRQ_MAX 16
2921da177e4SLinus Torvalds #else
2931da177e4SLinus Torvalds #define IRQ_MIN 9
2941da177e4SLinus Torvalds #if defined(__PPC)
295171ac6aeSYinghai Lu #define IRQ_MAX (nr_irqs-1)
2961da177e4SLinus Torvalds #else
2971da177e4SLinus Torvalds #define IRQ_MAX 12
2981da177e4SLinus Torvalds #endif
2991da177e4SLinus Torvalds #endif
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds enum {
3021da177e4SLinus Torvalds 	not_issued	= 0x0001,	/* command not yet issued */
303f75ae8edSHannes Reinecke 	selecting	= 0x0002,	/* target is being selected */
3041da177e4SLinus Torvalds 	identified	= 0x0004,	/* IDENTIFY was sent */
3051da177e4SLinus Torvalds 	disconnected	= 0x0008,	/* target disconnected */
3061da177e4SLinus Torvalds 	completed	= 0x0010,	/* target sent COMMAND COMPLETE */
3071da177e4SLinus Torvalds 	aborted		= 0x0020,	/* ABORT was sent */
3081da177e4SLinus Torvalds 	resetted	= 0x0040,	/* BUS DEVICE RESET was sent */
3091da177e4SLinus Torvalds 	spiordy		= 0x0080,	/* waiting for SPIORDY to raise */
3101da177e4SLinus Torvalds 	syncneg		= 0x0100,	/* synchronous negotiation in progress */
3111da177e4SLinus Torvalds 	aborting	= 0x0200,	/* ABORT is pending */
3121da177e4SLinus Torvalds 	resetting	= 0x0400,	/* BUS DEVICE RESET is pending */
3131da177e4SLinus Torvalds 	check_condition = 0x0800,	/* requesting sense after CHECK CONDITION */
3141da177e4SLinus Torvalds };
3151da177e4SLinus Torvalds 
31696de0e25SJan Engelhardt MODULE_AUTHOR("Jürgen Fischer");
3171da177e4SLinus Torvalds MODULE_DESCRIPTION(AHA152X_REVID);
3181da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3191da177e4SLinus Torvalds 
3203eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA)
3211da177e4SLinus Torvalds #if defined(MODULE)
3221da177e4SLinus Torvalds static int io[] = {0, 0};
32388f06b76SDavid Howells module_param_hw_array(io, int, ioport, NULL, 0);
3241da177e4SLinus Torvalds MODULE_PARM_DESC(io,"base io address of controller");
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds static int irq[] = {0, 0};
32788f06b76SDavid Howells module_param_hw_array(irq, int, irq, NULL, 0);
3281da177e4SLinus Torvalds MODULE_PARM_DESC(irq,"interrupt for controller");
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds static int scsiid[] = {7, 7};
3311da177e4SLinus Torvalds module_param_array(scsiid, int, NULL, 0);
3321da177e4SLinus Torvalds MODULE_PARM_DESC(scsiid,"scsi id of controller");
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds static int reconnect[] = {1, 1};
3351da177e4SLinus Torvalds module_param_array(reconnect, int, NULL, 0);
3361da177e4SLinus Torvalds MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds static int parity[] = {1, 1};
3391da177e4SLinus Torvalds module_param_array(parity, int, NULL, 0);
3401da177e4SLinus Torvalds MODULE_PARM_DESC(parity,"use scsi parity");
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static int sync[] = {1, 1};
3431da177e4SLinus Torvalds module_param_array(sync, int, NULL, 0);
3441da177e4SLinus Torvalds MODULE_PARM_DESC(sync,"use synchronous transfers");
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
3471da177e4SLinus Torvalds module_param_array(delay, int, NULL, 0);
3481da177e4SLinus Torvalds MODULE_PARM_DESC(delay,"scsi reset delay");
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds static int exttrans[] = {0, 0};
3511da177e4SLinus Torvalds module_param_array(exttrans, int, NULL, 0);
3521da177e4SLinus Torvalds MODULE_PARM_DESC(exttrans,"use extended translation");
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
3551da177e4SLinus Torvalds module_param_array(aha152x, int, NULL, 0);
3561da177e4SLinus Torvalds MODULE_PARM_DESC(aha152x, "parameters for first controller");
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
3591da177e4SLinus Torvalds module_param_array(aha152x1, int, NULL, 0);
3601da177e4SLinus Torvalds MODULE_PARM_DESC(aha152x1, "parameters for second controller");
3611da177e4SLinus Torvalds #endif /* MODULE */
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds #ifdef __ISAPNP__
3646f039790SGreg Kroah-Hartman static struct isapnp_device_id id_table[] = {
36550f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
36650f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
36750f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
36850f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 },
36950f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 },
37050f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 },
37150f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 },
37250f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 },
37350f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 },
37450f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 },
37550f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 },
37650f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 },
37750f87f91SOndrej Zary 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 },
3781da177e4SLinus Torvalds 	{ ISAPNP_DEVICE_SINGLE_END, }
3791da177e4SLinus Torvalds };
3801da177e4SLinus Torvalds MODULE_DEVICE_TABLE(isapnp, id_table);
3811da177e4SLinus Torvalds #endif /* ISAPNP */
3821da177e4SLinus Torvalds 
3833eb2ebcbSChristoph Hellwig #endif /* !AHA152X_PCMCIA */
3841da177e4SLinus Torvalds 
385d0be4a7dSChristoph Hellwig static struct scsi_host_template aha152x_driver_template;
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds /*
3881da177e4SLinus Torvalds  * internal states of the host
3891da177e4SLinus Torvalds  *
3901da177e4SLinus Torvalds  */
3911da177e4SLinus Torvalds enum aha152x_state {
3921da177e4SLinus Torvalds 	idle=0,
3931da177e4SLinus Torvalds 	unknown,
3941da177e4SLinus Torvalds 	seldo,
3951da177e4SLinus Torvalds 	seldi,
3961da177e4SLinus Torvalds 	selto,
3971da177e4SLinus Torvalds 	busfree,
3981da177e4SLinus Torvalds 	msgo,
3991da177e4SLinus Torvalds 	cmd,
4001da177e4SLinus Torvalds 	msgi,
4011da177e4SLinus Torvalds 	status,
4021da177e4SLinus Torvalds 	datai,
4031da177e4SLinus Torvalds 	datao,
4041da177e4SLinus Torvalds 	parerr,
4051da177e4SLinus Torvalds 	rsti,
4061da177e4SLinus Torvalds 	maxstate
4071da177e4SLinus Torvalds };
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds /*
4101da177e4SLinus Torvalds  * current state information of the host
4111da177e4SLinus Torvalds  *
4121da177e4SLinus Torvalds  */
4131da177e4SLinus Torvalds struct aha152x_hostdata {
41491ebc1faSJohannes Thumshirn 	struct scsi_cmnd *issue_SC;
4151da177e4SLinus Torvalds 		/* pending commands to issue */
4161da177e4SLinus Torvalds 
41791ebc1faSJohannes Thumshirn 	struct scsi_cmnd *current_SC;
4181da177e4SLinus Torvalds 		/* current command on the bus */
4191da177e4SLinus Torvalds 
42091ebc1faSJohannes Thumshirn 	struct scsi_cmnd *disconnected_SC;
4211da177e4SLinus Torvalds 		/* commands that disconnected */
4221da177e4SLinus Torvalds 
42391ebc1faSJohannes Thumshirn 	struct scsi_cmnd *done_SC;
4241da177e4SLinus Torvalds 		/* command that was completed */
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	spinlock_t lock;
4271da177e4SLinus Torvalds 		/* host lock */
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds #if defined(AHA152X_STAT)
4301da177e4SLinus Torvalds 	int	      total_commands;
4311da177e4SLinus Torvalds 	int	      disconnections;
4321da177e4SLinus Torvalds 	int	      busfree_without_any_action;
4331da177e4SLinus Torvalds 	int	      busfree_without_old_command;
4341da177e4SLinus Torvalds 	int	      busfree_without_new_command;
4351da177e4SLinus Torvalds 	int	      busfree_without_done_command;
4361da177e4SLinus Torvalds 	int	      busfree_with_check_condition;
4371da177e4SLinus Torvalds 	int	      count[maxstate];
4381da177e4SLinus Torvalds 	int	      count_trans[maxstate];
4391da177e4SLinus Torvalds 	unsigned long time[maxstate];
4401da177e4SLinus Torvalds #endif
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 	int commands;		/* current number of commands */
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	int reconnect;		/* disconnection allowed */
4451da177e4SLinus Torvalds 	int parity;		/* parity checking enabled */
4461da177e4SLinus Torvalds 	int synchronous;	/* synchronous transferes enabled */
4471da177e4SLinus Torvalds 	int delay;		/* reset out delay */
4481da177e4SLinus Torvalds 	int ext_trans;		/* extended translation enabled */
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	int swint;		/* software-interrupt was fired during detect() */
4511da177e4SLinus Torvalds 	int service;		/* bh needs to be run */
4521da177e4SLinus Torvalds 	int in_intr;		/* bh is running */
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	/* current state,
4551da177e4SLinus Torvalds 	   previous state,
4561da177e4SLinus Torvalds 	   last state different from current state */
4571da177e4SLinus Torvalds 	enum aha152x_state state, prevstate, laststate;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	int target;
4601da177e4SLinus Torvalds 		/* reconnecting target */
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	unsigned char syncrate[8];
4631da177e4SLinus Torvalds 		/* current synchronous transfer agreements */
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	unsigned char syncneg[8];
4661da177e4SLinus Torvalds 		/* 0: no negotiation;
4671da177e4SLinus Torvalds 		 * 1: negotiation in progress;
4681da177e4SLinus Torvalds 		 * 2: negotiation completed
4691da177e4SLinus Torvalds 		 */
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	int cmd_i;
4721da177e4SLinus Torvalds 		/* number of sent bytes of current command */
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	int msgi_len;
4751da177e4SLinus Torvalds 		/* number of received message bytes */
4761da177e4SLinus Torvalds 	unsigned char msgi[256];
4771da177e4SLinus Torvalds 		/* received message bytes */
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 	int msgo_i, msgo_len;
4801da177e4SLinus Torvalds 		/* number of sent bytes and length of current messages */
4811da177e4SLinus Torvalds 	unsigned char msgo[256];
4821da177e4SLinus Torvalds 		/* pending messages */
4831da177e4SLinus Torvalds 
4841da177e4SLinus Torvalds 	int data_len;
4851da177e4SLinus Torvalds 		/* number of sent/received bytes in dataphase */
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	unsigned long io_port0;
4881da177e4SLinus Torvalds 	unsigned long io_port1;
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds #ifdef __ISAPNP__
4911da177e4SLinus Torvalds 	struct pnp_dev *pnpdev;
4921da177e4SLinus Torvalds #endif
4935fcda422SJames Bottomley 	struct list_head host_list;
4941da177e4SLinus Torvalds };
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds /*
4981da177e4SLinus Torvalds  * host specific command extension
4991da177e4SLinus Torvalds  *
5001da177e4SLinus Torvalds  */
5011da177e4SLinus Torvalds struct aha152x_scdata {
50291ebc1faSJohannes Thumshirn 	struct scsi_cmnd *next;	/* next sc in queue */
5030f06bb34SChristoph Hellwig 	struct completion *done;/* semaphore to block on */
50473d2cb16SBoaz Harrosh 	struct scsi_eh_save ses;
5051da177e4SLinus Torvalds };
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds /* access macros for hostdata */
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds #define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds #define HOSTNO			((shpnt)->host_no)
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds #define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)
5141da177e4SLinus Torvalds #define DONE_SC			(HOSTDATA(shpnt)->done_SC)
5151da177e4SLinus Torvalds #define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)
5161da177e4SLinus Torvalds #define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)
5171da177e4SLinus Torvalds #define QLOCK			(HOSTDATA(shpnt)->lock)
5181da177e4SLinus Torvalds #define QLOCKER			(HOSTDATA(shpnt)->locker)
5191da177e4SLinus Torvalds #define QLOCKERL		(HOSTDATA(shpnt)->lockerl)
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds #define STATE			(HOSTDATA(shpnt)->state)
5221da177e4SLinus Torvalds #define PREVSTATE		(HOSTDATA(shpnt)->prevstate)
5231da177e4SLinus Torvalds #define LASTSTATE		(HOSTDATA(shpnt)->laststate)
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds #define RECONN_TARGET		(HOSTDATA(shpnt)->target)
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds #define CMD_I			(HOSTDATA(shpnt)->cmd_i)
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds #define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])
5301da177e4SLinus Torvalds #define MSGO_I			(HOSTDATA(shpnt)->msgo_i)
5311da177e4SLinus Torvalds #define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)
5321da177e4SLinus Torvalds #define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds #define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])
5351da177e4SLinus Torvalds #define MSGILEN			(HOSTDATA(shpnt)->msgi_len)
5361da177e4SLinus Torvalds #define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds #define DATA_LEN		(HOSTDATA(shpnt)->data_len)
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds #define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
5411da177e4SLinus Torvalds #define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds #define DELAY			(HOSTDATA(shpnt)->delay)
5441da177e4SLinus Torvalds #define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)
5451da177e4SLinus Torvalds #define TC1550			(HOSTDATA(shpnt)->tc1550)
5461da177e4SLinus Torvalds #define RECONNECT		(HOSTDATA(shpnt)->reconnect)
5471da177e4SLinus Torvalds #define PARITY			(HOSTDATA(shpnt)->parity)
5481da177e4SLinus Torvalds #define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds #define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)
5511da177e4SLinus Torvalds #define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds #define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)
5541da177e4SLinus Torvalds #define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
5550f06bb34SChristoph Hellwig #define SCSEM(SCpnt)		SCDATA(SCpnt)->done
5561da177e4SLinus Torvalds 
55745711f1aSJens Axboe #define SG_ADDRESS(buffer)	((char *) sg_virt((buffer)))
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds /* state handling */
5601da177e4SLinus Torvalds static void seldi_run(struct Scsi_Host *shpnt);
5611da177e4SLinus Torvalds static void seldo_run(struct Scsi_Host *shpnt);
5621da177e4SLinus Torvalds static void selto_run(struct Scsi_Host *shpnt);
5631da177e4SLinus Torvalds static void busfree_run(struct Scsi_Host *shpnt);
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds static void msgo_init(struct Scsi_Host *shpnt);
5661da177e4SLinus Torvalds static void msgo_run(struct Scsi_Host *shpnt);
5671da177e4SLinus Torvalds static void msgo_end(struct Scsi_Host *shpnt);
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds static void cmd_init(struct Scsi_Host *shpnt);
5701da177e4SLinus Torvalds static void cmd_run(struct Scsi_Host *shpnt);
5711da177e4SLinus Torvalds static void cmd_end(struct Scsi_Host *shpnt);
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds static void datai_init(struct Scsi_Host *shpnt);
5741da177e4SLinus Torvalds static void datai_run(struct Scsi_Host *shpnt);
5751da177e4SLinus Torvalds static void datai_end(struct Scsi_Host *shpnt);
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds static void datao_init(struct Scsi_Host *shpnt);
5781da177e4SLinus Torvalds static void datao_run(struct Scsi_Host *shpnt);
5791da177e4SLinus Torvalds static void datao_end(struct Scsi_Host *shpnt);
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds static void status_run(struct Scsi_Host *shpnt);
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds static void msgi_run(struct Scsi_Host *shpnt);
5841da177e4SLinus Torvalds static void msgi_end(struct Scsi_Host *shpnt);
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds static void parerr_run(struct Scsi_Host *shpnt);
5871da177e4SLinus Torvalds static void rsti_run(struct Scsi_Host *shpnt);
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds static void is_complete(struct Scsi_Host *shpnt);
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds /*
5921da177e4SLinus Torvalds  * driver states
5931da177e4SLinus Torvalds  *
5941da177e4SLinus Torvalds  */
5951da177e4SLinus Torvalds static struct {
5961da177e4SLinus Torvalds 	char		*name;
5971da177e4SLinus Torvalds 	void		(*init)(struct Scsi_Host *);
5981da177e4SLinus Torvalds 	void		(*run)(struct Scsi_Host *);
5991da177e4SLinus Torvalds 	void		(*end)(struct Scsi_Host *);
6001da177e4SLinus Torvalds 	int		spio;
6011da177e4SLinus Torvalds } states[] = {
6021da177e4SLinus Torvalds 	{ "idle",	NULL,		NULL,		NULL,		0},
6031da177e4SLinus Torvalds 	{ "unknown",	NULL,		NULL,		NULL,		0},
6041da177e4SLinus Torvalds 	{ "seldo",	NULL,		seldo_run,	NULL,		0},
6051da177e4SLinus Torvalds 	{ "seldi",	NULL,		seldi_run,	NULL,		0},
6061da177e4SLinus Torvalds 	{ "selto",	NULL,		selto_run,	NULL,		0},
6071da177e4SLinus Torvalds 	{ "busfree",	NULL,		busfree_run,	NULL,		0},
6081da177e4SLinus Torvalds 	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
6091da177e4SLinus Torvalds 	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
6101da177e4SLinus Torvalds 	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},
6111da177e4SLinus Torvalds 	{ "status",	NULL,		status_run,	NULL,		1},
6121da177e4SLinus Torvalds 	{ "datai",	datai_init,	datai_run,	datai_end,	0},
6131da177e4SLinus Torvalds 	{ "datao",	datao_init,	datao_run,	datao_end,	0},
6141da177e4SLinus Torvalds 	{ "parerr",	NULL,		parerr_run,	NULL,		0},
6151da177e4SLinus Torvalds 	{ "rsti",	NULL,		rsti_run,	NULL,		0},
6161da177e4SLinus Torvalds };
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds /* setup & interrupt */
6197d12e780SDavid Howells static irqreturn_t intr(int irq, void *dev_id);
6201da177e4SLinus Torvalds static void reset_ports(struct Scsi_Host *shpnt);
6211da177e4SLinus Torvalds static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
6221da177e4SLinus Torvalds static void done(struct Scsi_Host *shpnt, int error);
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds /* diagnostics */
62591ebc1faSJohannes Thumshirn static void show_command(struct scsi_cmnd * ptr);
6261da177e4SLinus Torvalds static void show_queues(struct Scsi_Host *shpnt);
6271da177e4SLinus Torvalds static void disp_enintr(struct Scsi_Host *shpnt);
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds /*
6311da177e4SLinus Torvalds  *  queue services:
6321da177e4SLinus Torvalds  *
6331da177e4SLinus Torvalds  */
63491ebc1faSJohannes Thumshirn static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
6351da177e4SLinus Torvalds {
63691ebc1faSJohannes Thumshirn 	struct scsi_cmnd *end;
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	SCNEXT(new_SC) = NULL;
6391da177e4SLinus Torvalds 	if (!*SC)
6401da177e4SLinus Torvalds 		*SC = new_SC;
6411da177e4SLinus Torvalds 	else {
6421da177e4SLinus Torvalds 		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
6431da177e4SLinus Torvalds 			;
6441da177e4SLinus Torvalds 		SCNEXT(end) = new_SC;
6451da177e4SLinus Torvalds 	}
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds 
64891ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC)
6491da177e4SLinus Torvalds {
65091ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr;
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 	ptr = *SC;
6531da177e4SLinus Torvalds 	if (ptr) {
6541da177e4SLinus Torvalds 		*SC = SCNEXT(*SC);
6551da177e4SLinus Torvalds 		SCNEXT(ptr)=NULL;
6561da177e4SLinus Torvalds 	}
6571da177e4SLinus Torvalds 	return ptr;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds 
66091ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC,
66191ebc1faSJohannes Thumshirn 					      int target, int lun)
6621da177e4SLinus Torvalds {
66391ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr, *prev;
6641da177e4SLinus Torvalds 
6651da177e4SLinus Torvalds 	for (ptr = *SC, prev = NULL;
6661da177e4SLinus Torvalds 	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
6671da177e4SLinus Torvalds 	     prev = ptr, ptr = SCNEXT(ptr))
6681da177e4SLinus Torvalds 	     ;
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	if (ptr) {
6711da177e4SLinus Torvalds 		if (prev)
6721da177e4SLinus Torvalds 			SCNEXT(prev) = SCNEXT(ptr);
6731da177e4SLinus Torvalds 		else
6741da177e4SLinus Torvalds 			*SC = SCNEXT(ptr);
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 		SCNEXT(ptr)=NULL;
6771da177e4SLinus Torvalds 	}
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 	return ptr;
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds 
68291ebc1faSJohannes Thumshirn static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC,
68391ebc1faSJohannes Thumshirn 					  struct scsi_cmnd *SCp)
6841da177e4SLinus Torvalds {
68591ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr, *prev;
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	for (ptr = *SC, prev = NULL;
6881da177e4SLinus Torvalds 	     ptr && SCp!=ptr;
6891da177e4SLinus Torvalds 	     prev = ptr, ptr = SCNEXT(ptr))
6901da177e4SLinus Torvalds 	     ;
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	if (ptr) {
6931da177e4SLinus Torvalds 		if (prev)
6941da177e4SLinus Torvalds 			SCNEXT(prev) = SCNEXT(ptr);
6951da177e4SLinus Torvalds 		else
6961da177e4SLinus Torvalds 			*SC = SCNEXT(ptr);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 		SCNEXT(ptr)=NULL;
6991da177e4SLinus Torvalds 	}
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	return ptr;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds 
7047d12e780SDavid Howells static irqreturn_t swintr(int irqno, void *dev_id)
7051da177e4SLinus Torvalds {
706c7bec5abSJeff Garzik 	struct Scsi_Host *shpnt = dev_id;
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 	HOSTDATA(shpnt)->swint++;
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, INTEN);
7111da177e4SLinus Torvalds 	return IRQ_HANDLED;
7121da177e4SLinus Torvalds }
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
7151da177e4SLinus Torvalds {
7161da177e4SLinus Torvalds 	struct Scsi_Host *shpnt;
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
7191da177e4SLinus Torvalds 	if (!shpnt) {
7201da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
7211da177e4SLinus Torvalds 		return NULL;
7221da177e4SLinus Torvalds 	}
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
7255fcda422SJames Bottomley 	INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
7265fcda422SJames Bottomley 
7275fcda422SJames Bottomley 	/* need to have host registered before triggering any interrupt */
7285fcda422SJames Bottomley 	list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds 	shpnt->io_port   = setup->io_port;
7311da177e4SLinus Torvalds 	shpnt->n_io_port = IO_RANGE;
7321da177e4SLinus Torvalds 	shpnt->irq       = setup->irq;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	if (!setup->tc1550) {
7351da177e4SLinus Torvalds 		HOSTIOPORT0 = setup->io_port;
7361da177e4SLinus Torvalds 		HOSTIOPORT1 = setup->io_port;
7371da177e4SLinus Torvalds 	} else {
7381da177e4SLinus Torvalds 		HOSTIOPORT0 = setup->io_port+0x10;
7391da177e4SLinus Torvalds 		HOSTIOPORT1 = setup->io_port-0x10;
7401da177e4SLinus Torvalds 	}
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds 	spin_lock_init(&QLOCK);
7431da177e4SLinus Torvalds 	RECONNECT   = setup->reconnect;
7441da177e4SLinus Torvalds 	SYNCHRONOUS = setup->synchronous;
7451da177e4SLinus Torvalds 	PARITY      = setup->parity;
7461da177e4SLinus Torvalds 	DELAY       = setup->delay;
7471da177e4SLinus Torvalds 	EXT_TRANS   = setup->ext_trans;
7481da177e4SLinus Torvalds 
7491da177e4SLinus Torvalds 	SETPORT(SCSIID, setup->scsiid << 4);
7501da177e4SLinus Torvalds 	shpnt->this_id = setup->scsiid;
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 	if (setup->reconnect)
7531da177e4SLinus Torvalds 		shpnt->can_queue = AHA152X_MAXQUEUE;
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	/* RESET OUT */
7561da177e4SLinus Torvalds 	printk("aha152x: resetting bus...\n");
7571da177e4SLinus Torvalds 	SETPORT(SCSISEQ, SCSIRSTO);
7581da177e4SLinus Torvalds 	mdelay(256);
7591da177e4SLinus Torvalds 	SETPORT(SCSISEQ, 0);
7601da177e4SLinus Torvalds 	mdelay(DELAY);
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds 	reset_ports(shpnt);
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	printk(KERN_INFO
7651da177e4SLinus Torvalds 	       "aha152x%d%s: "
7661da177e4SLinus Torvalds 	       "vital data: rev=%x, "
7671da177e4SLinus Torvalds 	       "io=0x%03lx (0x%03lx/0x%03lx), "
7681da177e4SLinus Torvalds 	       "irq=%d, "
7691da177e4SLinus Torvalds 	       "scsiid=%d, "
7701da177e4SLinus Torvalds 	       "reconnect=%s, "
7711da177e4SLinus Torvalds 	       "parity=%s, "
7721da177e4SLinus Torvalds 	       "synchronous=%s, "
7731da177e4SLinus Torvalds 	       "delay=%d, "
7741da177e4SLinus Torvalds 	       "extended translation=%s\n",
7751da177e4SLinus Torvalds 	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
7761da177e4SLinus Torvalds 	       GETPORT(REV) & 0x7,
7771da177e4SLinus Torvalds 	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
7781da177e4SLinus Torvalds 	       shpnt->irq,
7791da177e4SLinus Torvalds 	       shpnt->this_id,
7801da177e4SLinus Torvalds 	       RECONNECT ? "enabled" : "disabled",
7811da177e4SLinus Torvalds 	       PARITY ? "enabled" : "disabled",
7821da177e4SLinus Torvalds 	       SYNCHRONOUS ? "enabled" : "disabled",
7831da177e4SLinus Torvalds 	       DELAY,
7841da177e4SLinus Torvalds 	       EXT_TRANS ? "enabled" : "disabled");
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 	/* not expecting any interrupts */
7871da177e4SLinus Torvalds 	SETPORT(SIMODE0, 0);
7881da177e4SLinus Torvalds 	SETPORT(SIMODE1, 0);
7891da177e4SLinus Torvalds 
7904909cc2bSMichael Opdenacker 	if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
7911da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
7921da177e4SLinus Torvalds 		goto out_host_put;
7931da177e4SLinus Torvalds 	}
7941da177e4SLinus Torvalds 
7951da177e4SLinus Torvalds 	HOSTDATA(shpnt)->swint = 0;
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 	mb();
8001da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, SWINT|INTEN);
8011da177e4SLinus Torvalds 	mdelay(1000);
8021da177e4SLinus Torvalds 	free_irq(shpnt->irq, shpnt);
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	if (!HOSTDATA(shpnt)->swint) {
8051da177e4SLinus Torvalds 		if (TESTHI(DMASTAT, INTSTAT)) {
8061da177e4SLinus Torvalds 			printk("lost.\n");
8071da177e4SLinus Torvalds 		} else {
8081da177e4SLinus Torvalds 			printk("failed.\n");
8091da177e4SLinus Torvalds 		}
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 		SETPORT(DMACNTRL0, INTEN);
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "
8141da177e4SLinus Torvalds 				"Please verify.\n", shpnt->host_no, shpnt->irq);
8151da177e4SLinus Torvalds 		goto out_host_put;
8161da177e4SLinus Torvalds 	}
8171da177e4SLinus Torvalds 	printk("ok.\n");
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 
8201da177e4SLinus Torvalds 	/* clear interrupts */
8211da177e4SLinus Torvalds 	SETPORT(SSTAT0, 0x7f);
8221da177e4SLinus Torvalds 	SETPORT(SSTAT1, 0xef);
8231da177e4SLinus Torvalds 
8244909cc2bSMichael Opdenacker 	if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
8251da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
8261da177e4SLinus Torvalds 		goto out_host_put;
8271da177e4SLinus Torvalds 	}
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds 	if( scsi_add_host(shpnt, NULL) ) {
8301da177e4SLinus Torvalds 		free_irq(shpnt->irq, shpnt);
8311da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
8321da177e4SLinus Torvalds 		goto out_host_put;
8331da177e4SLinus Torvalds 	}
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 	scsi_scan_host(shpnt);
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	return shpnt;
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds out_host_put:
8405fcda422SJames Bottomley 	list_del(&HOSTDATA(shpnt)->host_list);
8411da177e4SLinus Torvalds 	scsi_host_put(shpnt);
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 	return NULL;
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds void aha152x_release(struct Scsi_Host *shpnt)
8471da177e4SLinus Torvalds {
8481da177e4SLinus Torvalds 	if (!shpnt)
8491da177e4SLinus Torvalds 		return;
8501da177e4SLinus Torvalds 
8511bd40573SMatthew Wilcox 	scsi_remove_host(shpnt);
8521da177e4SLinus Torvalds 	if (shpnt->irq)
8531da177e4SLinus Torvalds 		free_irq(shpnt->irq, shpnt);
8541da177e4SLinus Torvalds 
8553eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA)
8561da177e4SLinus Torvalds 	if (shpnt->io_port)
8571da177e4SLinus Torvalds 		release_region(shpnt->io_port, IO_RANGE);
8581da177e4SLinus Torvalds #endif
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds #ifdef __ISAPNP__
8611da177e4SLinus Torvalds 	if (HOSTDATA(shpnt)->pnpdev)
8621da177e4SLinus Torvalds 		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
8631da177e4SLinus Torvalds #endif
8641da177e4SLinus Torvalds 
8655fcda422SJames Bottomley 	list_del(&HOSTDATA(shpnt)->host_list);
8661da177e4SLinus Torvalds 	scsi_host_put(shpnt);
8671da177e4SLinus Torvalds }
8681da177e4SLinus Torvalds 
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds /*
8711da177e4SLinus Torvalds  * setup controller to generate interrupts depending
8721da177e4SLinus Torvalds  * on current state (lock has to be acquired)
8731da177e4SLinus Torvalds  *
8741da177e4SLinus Torvalds  */
8751da177e4SLinus Torvalds static int setup_expected_interrupts(struct Scsi_Host *shpnt)
8761da177e4SLinus Torvalds {
8771da177e4SLinus Torvalds 	if(CURRENT_SC) {
8781da177e4SLinus Torvalds 		CURRENT_SC->SCp.phase |= 1 << 16;
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 		if(CURRENT_SC->SCp.phase & selecting) {
8811da177e4SLinus Torvalds 			SETPORT(SSTAT1, SELTO);
8821da177e4SLinus Torvalds 			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
8831da177e4SLinus Torvalds 			SETPORT(SIMODE1, ENSELTIMO);
8841da177e4SLinus Torvalds 		} else {
8851da177e4SLinus Torvalds 			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
8861da177e4SLinus Torvalds 			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
8871da177e4SLinus Torvalds 		}
8881da177e4SLinus Torvalds 	} else if(STATE==seldi) {
8891da177e4SLinus Torvalds 		SETPORT(SIMODE0, 0);
8901da177e4SLinus Torvalds 		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
8911da177e4SLinus Torvalds 	} else {
8921da177e4SLinus Torvalds 		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
8931da177e4SLinus Torvalds 		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
8941da177e4SLinus Torvalds 	}
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	if(!HOSTDATA(shpnt)->in_intr)
8971da177e4SLinus Torvalds 		SETBITS(DMACNTRL0, INTEN);
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	return TESTHI(DMASTAT, INTSTAT);
9001da177e4SLinus Torvalds }
9011da177e4SLinus Torvalds 
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds /*
9041da177e4SLinus Torvalds  *  Queue a command and setup interrupts for a free bus.
9051da177e4SLinus Torvalds  */
90691ebc1faSJohannes Thumshirn static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
90791ebc1faSJohannes Thumshirn 				  struct completion *complete,
90891ebc1faSJohannes Thumshirn 				  int phase, void (*done)(struct scsi_cmnd *))
9091da177e4SLinus Torvalds {
9101da177e4SLinus Torvalds 	struct Scsi_Host *shpnt = SCpnt->device->host;
9111da177e4SLinus Torvalds 	unsigned long flags;
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	SCpnt->scsi_done	= done;
9141da177e4SLinus Torvalds 	SCpnt->SCp.phase	= not_issued | phase;
9150ceb4798SBoaz Harrosh 	SCpnt->SCp.Status	= 0x1; /* Ilegal status by SCSI standard */
9161da177e4SLinus Torvalds 	SCpnt->SCp.Message	= 0;
9171da177e4SLinus Torvalds 	SCpnt->SCp.have_data_in	= 0;
9181da177e4SLinus Torvalds 	SCpnt->SCp.sent_command	= 0;
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	if(SCpnt->SCp.phase & (resetting|check_condition)) {
921172c122dSHarvey Harrison 		if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
922f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n");
9231da177e4SLinus Torvalds 			return FAILED;
9241da177e4SLinus Torvalds 		}
9251da177e4SLinus Torvalds 	} else {
9261da177e4SLinus Torvalds 		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
927172c122dSHarvey Harrison 		if(!SCpnt->host_scribble) {
928f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, SCpnt, "allocation failed\n");
9291da177e4SLinus Torvalds 			return FAILED;
9301da177e4SLinus Torvalds 		}
9311da177e4SLinus Torvalds 	}
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 	SCNEXT(SCpnt)		= NULL;
9340f06bb34SChristoph Hellwig 	SCSEM(SCpnt)		= complete;
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	/* setup scratch area
9371da177e4SLinus Torvalds 	   SCp.ptr              : buffer pointer
9381da177e4SLinus Torvalds 	   SCp.this_residual    : buffer length
9391da177e4SLinus Torvalds 	   SCp.buffer           : next buffer
9401da177e4SLinus Torvalds 	   SCp.phase            : current state of the command */
94166acdb03SBoaz Harrosh 
94273d2cb16SBoaz Harrosh 	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
94366acdb03SBoaz Harrosh 		SCpnt->SCp.ptr           = NULL;
94466acdb03SBoaz Harrosh 		SCpnt->SCp.this_residual = 0;
9452338545aSBoaz Harrosh 		scsi_set_resid(SCpnt, 0);
94666acdb03SBoaz Harrosh 		SCpnt->SCp.buffer           = NULL;
94766acdb03SBoaz Harrosh 	} else {
9482338545aSBoaz Harrosh 		scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
9492338545aSBoaz Harrosh 		SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
9501da177e4SLinus Torvalds 		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
9511da177e4SLinus Torvalds 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
95266acdb03SBoaz Harrosh 	}
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds 	DO_LOCK(flags);
9551da177e4SLinus Torvalds 
9561da177e4SLinus Torvalds #if defined(AHA152X_STAT)
9571da177e4SLinus Torvalds 	HOSTDATA(shpnt)->total_commands++;
9581da177e4SLinus Torvalds #endif
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds 	/* Turn led on, when this is the first command. */
9611da177e4SLinus Torvalds 	HOSTDATA(shpnt)->commands++;
9621da177e4SLinus Torvalds 	if (HOSTDATA(shpnt)->commands==1)
9631da177e4SLinus Torvalds 		SETPORT(PORTA, 1);
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	append_SC(&ISSUE_SC, SCpnt);
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds 	if(!HOSTDATA(shpnt)->in_intr)
9681da177e4SLinus Torvalds 		setup_expected_interrupts(shpnt);
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds 	DO_UNLOCK(flags);
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	return 0;
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds /*
9761da177e4SLinus Torvalds  *  queue a command
9771da177e4SLinus Torvalds  *
9781da177e4SLinus Torvalds  */
97991ebc1faSJohannes Thumshirn static int aha152x_queue_lck(struct scsi_cmnd *SCpnt,
98091ebc1faSJohannes Thumshirn 			     void (*done)(struct scsi_cmnd *))
9811da177e4SLinus Torvalds {
9821da177e4SLinus Torvalds 	return aha152x_internal_queue(SCpnt, NULL, 0, done);
9831da177e4SLinus Torvalds }
9841da177e4SLinus Torvalds 
985f281233dSJeff Garzik static DEF_SCSI_QCMD(aha152x_queue)
986f281233dSJeff Garzik 
9871da177e4SLinus Torvalds 
9881da177e4SLinus Torvalds /*
9891da177e4SLinus Torvalds  *
9901da177e4SLinus Torvalds  */
99191ebc1faSJohannes Thumshirn static void reset_done(struct scsi_cmnd *SCpnt)
9921da177e4SLinus Torvalds {
9931da177e4SLinus Torvalds 	if(SCSEM(SCpnt)) {
9940f06bb34SChristoph Hellwig 		complete(SCSEM(SCpnt));
9951da177e4SLinus Torvalds 	} else {
9960f06bb34SChristoph Hellwig 		printk(KERN_ERR "aha152x: reset_done w/o completion\n");
9971da177e4SLinus Torvalds 	}
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds /*
10011da177e4SLinus Torvalds  *  Abort a command
10021da177e4SLinus Torvalds  *
10031da177e4SLinus Torvalds  */
100491ebc1faSJohannes Thumshirn static int aha152x_abort(struct scsi_cmnd *SCpnt)
10051da177e4SLinus Torvalds {
10061da177e4SLinus Torvalds 	struct Scsi_Host *shpnt = SCpnt->device->host;
100791ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr;
10081da177e4SLinus Torvalds 	unsigned long flags;
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 	DO_LOCK(flags);
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 	ptr=remove_SC(&ISSUE_SC, SCpnt);
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	if(ptr) {
10151da177e4SLinus Torvalds 		HOSTDATA(shpnt)->commands--;
10161da177e4SLinus Torvalds 		if (!HOSTDATA(shpnt)->commands)
10171da177e4SLinus Torvalds 			SETPORT(PORTA, 0);
10181da177e4SLinus Torvalds 		DO_UNLOCK(flags);
10191da177e4SLinus Torvalds 
10201da177e4SLinus Torvalds 		kfree(SCpnt->host_scribble);
10211da177e4SLinus Torvalds 		SCpnt->host_scribble=NULL;
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 		return SUCCESS;
10241da177e4SLinus Torvalds 	}
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 	DO_UNLOCK(flags);
10271da177e4SLinus Torvalds 
10281da177e4SLinus Torvalds 	/*
10291da177e4SLinus Torvalds 	 * FIXME:
10301da177e4SLinus Torvalds 	 * for current command: queue ABORT for message out and raise ATN
10311da177e4SLinus Torvalds 	 * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
10321da177e4SLinus Torvalds 	 *
10331da177e4SLinus Torvalds 	 */
10341da177e4SLinus Torvalds 
1035f75ae8edSHannes Reinecke 	scmd_printk(KERN_ERR, SCpnt,
1036f75ae8edSHannes Reinecke 		    "cannot abort running or disconnected command\n");
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds 	return FAILED;
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds /*
10421da177e4SLinus Torvalds  * Reset a device
10431da177e4SLinus Torvalds  *
10441da177e4SLinus Torvalds  */
104591ebc1faSJohannes Thumshirn static int aha152x_device_reset(struct scsi_cmnd * SCpnt)
10461da177e4SLinus Torvalds {
10471da177e4SLinus Torvalds 	struct Scsi_Host *shpnt = SCpnt->device->host;
10480f06bb34SChristoph Hellwig 	DECLARE_COMPLETION(done);
10491da177e4SLinus Torvalds 	int ret, issued, disconnected;
1050631c228cSChristoph Hellwig 	unsigned char old_cmd_len = SCpnt->cmd_len;
10511da177e4SLinus Torvalds 	unsigned long flags;
10520f06bb34SChristoph Hellwig 	unsigned long timeleft;
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	if(CURRENT_SC==SCpnt) {
1055f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n");
10561da177e4SLinus Torvalds 		return FAILED;
10571da177e4SLinus Torvalds 	}
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	DO_LOCK(flags);
1060172c122dSHarvey Harrison 	issued       = remove_SC(&ISSUE_SC, SCpnt) == NULL;
10611da177e4SLinus Torvalds 	disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
10621da177e4SLinus Torvalds 	DO_UNLOCK(flags);
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 	SCpnt->cmd_len         = 0;
10651da177e4SLinus Torvalds 
10660f06bb34SChristoph Hellwig 	aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
10671da177e4SLinus Torvalds 
10680f06bb34SChristoph Hellwig 	timeleft = wait_for_completion_timeout(&done, 100*HZ);
10690f06bb34SChristoph Hellwig 	if (!timeleft) {
10700f06bb34SChristoph Hellwig 		/* remove command from issue queue */
10710f06bb34SChristoph Hellwig 		DO_LOCK(flags);
10720f06bb34SChristoph Hellwig 		remove_SC(&ISSUE_SC, SCpnt);
10730f06bb34SChristoph Hellwig 		DO_UNLOCK(flags);
10740f06bb34SChristoph Hellwig 	}
10751da177e4SLinus Torvalds 
1076631c228cSChristoph Hellwig 	SCpnt->cmd_len         = old_cmd_len;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	DO_LOCK(flags);
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds 	if(SCpnt->SCp.phase & resetted) {
10811da177e4SLinus Torvalds 		HOSTDATA(shpnt)->commands--;
10821da177e4SLinus Torvalds 		if (!HOSTDATA(shpnt)->commands)
10831da177e4SLinus Torvalds 			SETPORT(PORTA, 0);
10841da177e4SLinus Torvalds 		kfree(SCpnt->host_scribble);
10851da177e4SLinus Torvalds 		SCpnt->host_scribble=NULL;
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 		ret = SUCCESS;
10881da177e4SLinus Torvalds 	} else {
10891da177e4SLinus Torvalds 		/* requeue */
10901da177e4SLinus Torvalds 		if(!issued) {
10911da177e4SLinus Torvalds 			append_SC(&ISSUE_SC, SCpnt);
10921da177e4SLinus Torvalds 		} else if(disconnected) {
10931da177e4SLinus Torvalds 			append_SC(&DISCONNECTED_SC, SCpnt);
10941da177e4SLinus Torvalds 		}
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 		ret = FAILED;
10971da177e4SLinus Torvalds 	}
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	DO_UNLOCK(flags);
11001da177e4SLinus Torvalds 	return ret;
11011da177e4SLinus Torvalds }
11021da177e4SLinus Torvalds 
110391ebc1faSJohannes Thumshirn static void free_hard_reset_SCs(struct Scsi_Host *shpnt,
110491ebc1faSJohannes Thumshirn 				struct scsi_cmnd **SCs)
11051da177e4SLinus Torvalds {
110691ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr;
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 	ptr=*SCs;
11091da177e4SLinus Torvalds 	while(ptr) {
111091ebc1faSJohannes Thumshirn 		struct scsi_cmnd *next;
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 		if(SCDATA(ptr)) {
11131da177e4SLinus Torvalds 			next = SCNEXT(ptr);
11141da177e4SLinus Torvalds 		} else {
1115f75ae8edSHannes Reinecke 			scmd_printk(KERN_DEBUG, ptr,
1116f75ae8edSHannes Reinecke 				    "queue corrupted at %p\n", ptr);
11171da177e4SLinus Torvalds 			next = NULL;
11181da177e4SLinus Torvalds 		}
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds 		if (!ptr->device->soft_reset) {
11211da177e4SLinus Torvalds 			remove_SC(SCs, ptr);
11221da177e4SLinus Torvalds 			HOSTDATA(shpnt)->commands--;
11231da177e4SLinus Torvalds 			kfree(ptr->host_scribble);
11241da177e4SLinus Torvalds 			ptr->host_scribble=NULL;
11251da177e4SLinus Torvalds 		}
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 		ptr = next;
11281da177e4SLinus Torvalds 	}
11291da177e4SLinus Torvalds }
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds /*
11321da177e4SLinus Torvalds  * Reset the bus
11331da177e4SLinus Torvalds  *
1134819f80c9SHannes Reinecke  * AIC-6260 has a hard reset (MRST signal), but apparently
1135819f80c9SHannes Reinecke  * one cannot trigger it via software. So live with
1136819f80c9SHannes Reinecke  * a soft reset; no-one seemed to have cared.
11371da177e4SLinus Torvalds  */
1138e2482fa1SJürgen E. Fischer static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
11391da177e4SLinus Torvalds {
11401da177e4SLinus Torvalds 	unsigned long flags;
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 	DO_LOCK(flags);
11431da177e4SLinus Torvalds 
11441da177e4SLinus Torvalds 	free_hard_reset_SCs(shpnt, &ISSUE_SC);
11451da177e4SLinus Torvalds 	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
11461da177e4SLinus Torvalds 
11471da177e4SLinus Torvalds 	SETPORT(SCSISEQ, SCSIRSTO);
11481da177e4SLinus Torvalds 	mdelay(256);
11491da177e4SLinus Torvalds 	SETPORT(SCSISEQ, 0);
11501da177e4SLinus Torvalds 	mdelay(DELAY);
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds 	setup_expected_interrupts(shpnt);
11531da177e4SLinus Torvalds 	if(HOSTDATA(shpnt)->commands==0)
11541da177e4SLinus Torvalds 		SETPORT(PORTA, 0);
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds 	DO_UNLOCK(flags);
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	return SUCCESS;
11591da177e4SLinus Torvalds }
11601da177e4SLinus Torvalds 
1161e2482fa1SJürgen E. Fischer /*
1162e2482fa1SJürgen E. Fischer  * Reset the bus
1163e2482fa1SJürgen E. Fischer  *
1164e2482fa1SJürgen E. Fischer  */
116591ebc1faSJohannes Thumshirn static int aha152x_bus_reset(struct scsi_cmnd *SCpnt)
1166e2482fa1SJürgen E. Fischer {
1167e2482fa1SJürgen E. Fischer 	return aha152x_bus_reset_host(SCpnt->device->host);
1168e2482fa1SJürgen E. Fischer }
11691da177e4SLinus Torvalds 
11701da177e4SLinus Torvalds /*
11711da177e4SLinus Torvalds  *  Restore default values to the AIC-6260 registers and reset the fifos
11721da177e4SLinus Torvalds  *
11731da177e4SLinus Torvalds  */
11741da177e4SLinus Torvalds static void reset_ports(struct Scsi_Host *shpnt)
11751da177e4SLinus Torvalds {
11761da177e4SLinus Torvalds 	unsigned long flags;
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 	/* disable interrupts */
11791da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, RSTFIFO);
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds 	SETPORT(SCSISEQ, 0);
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds 	SETPORT(SXFRCTL1, 0);
11841da177e4SLinus Torvalds 	SETPORT(SCSISIG, 0);
11851da177e4SLinus Torvalds 	SETRATE(0);
11861da177e4SLinus Torvalds 
11871da177e4SLinus Torvalds 	/* clear all interrupt conditions */
11881da177e4SLinus Torvalds 	SETPORT(SSTAT0, 0x7f);
11891da177e4SLinus Torvalds 	SETPORT(SSTAT1, 0xef);
11901da177e4SLinus Torvalds 
11911da177e4SLinus Torvalds 	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, 0);
11941da177e4SLinus Torvalds 	SETPORT(DMACNTRL1, 0);
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds 	SETPORT(BRSTCNTRL, 0xf1);
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	/* clear SCSI fifos and transfer count */
11991da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
12001da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1);
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds 	DO_LOCK(flags);
12031da177e4SLinus Torvalds 	setup_expected_interrupts(shpnt);
12041da177e4SLinus Torvalds 	DO_UNLOCK(flags);
12051da177e4SLinus Torvalds }
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds /*
12081da177e4SLinus Torvalds  * Reset the host (bus and controller)
12091da177e4SLinus Torvalds  *
12101da177e4SLinus Torvalds  */
1211e2482fa1SJürgen E. Fischer int aha152x_host_reset_host(struct Scsi_Host *shpnt)
12121da177e4SLinus Torvalds {
1213e2482fa1SJürgen E. Fischer 	aha152x_bus_reset_host(shpnt);
1214e2482fa1SJürgen E. Fischer 	reset_ports(shpnt);
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds 	return SUCCESS;
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds /*
12201da177e4SLinus Torvalds  * Return the "logical geometry"
12211da177e4SLinus Torvalds  *
12221da177e4SLinus Torvalds  */
12231da177e4SLinus Torvalds static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
12241da177e4SLinus Torvalds 		sector_t capacity, int *info_array)
12251da177e4SLinus Torvalds {
12261da177e4SLinus Torvalds 	struct Scsi_Host *shpnt = sdev->host;
12271da177e4SLinus Torvalds 
12281da177e4SLinus Torvalds 	/* try default translation */
12291da177e4SLinus Torvalds 	info_array[0] = 64;
12301da177e4SLinus Torvalds 	info_array[1] = 32;
12311da177e4SLinus Torvalds 	info_array[2] = (unsigned long)capacity / (64 * 32);
12321da177e4SLinus Torvalds 
12331da177e4SLinus Torvalds 	/* for disks >1GB do some guessing */
12341da177e4SLinus Torvalds 	if (info_array[2] >= 1024) {
12351da177e4SLinus Torvalds 		int info[3];
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 		/* try to figure out the geometry from the partition table */
12381da177e4SLinus Torvalds 		if (scsicam_bios_param(bdev, capacity, info) < 0 ||
12391da177e4SLinus Torvalds 		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
12401da177e4SLinus Torvalds 			if (EXT_TRANS) {
12411da177e4SLinus Torvalds 				printk(KERN_NOTICE
12421da177e4SLinus Torvalds 				       "aha152x: unable to verify geometry for disk with >1GB.\n"
12431da177e4SLinus Torvalds 				       "         using extended translation.\n");
12441da177e4SLinus Torvalds 				info_array[0] = 255;
12451da177e4SLinus Torvalds 				info_array[1] = 63;
12461da177e4SLinus Torvalds 				info_array[2] = (unsigned long)capacity / (255 * 63);
12471da177e4SLinus Torvalds 			} else {
12481da177e4SLinus Torvalds 				printk(KERN_NOTICE
12491da177e4SLinus Torvalds 				       "aha152x: unable to verify geometry for disk with >1GB.\n"
12501da177e4SLinus Torvalds 				       "         Using default translation. Please verify yourself.\n"
12511da177e4SLinus Torvalds 				       "         Perhaps you need to enable extended translation in the driver.\n"
125294b5530fSMauro Carvalho Chehab 				       "         See Documentation/scsi/aha152x.rst for details.\n");
12531da177e4SLinus Torvalds 			}
12541da177e4SLinus Torvalds 		} else {
12551da177e4SLinus Torvalds 			info_array[0] = info[0];
12561da177e4SLinus Torvalds 			info_array[1] = info[1];
12571da177e4SLinus Torvalds 			info_array[2] = info[2];
12581da177e4SLinus Torvalds 
12591da177e4SLinus Torvalds 			if (info[0] == 255 && !EXT_TRANS) {
12601da177e4SLinus Torvalds 				printk(KERN_NOTICE
12611da177e4SLinus Torvalds 				       "aha152x: current partition table is using extended translation.\n"
12621da177e4SLinus Torvalds 				       "         using it also, although it's not explicitly enabled.\n");
12631da177e4SLinus Torvalds 			}
12641da177e4SLinus Torvalds 		}
12651da177e4SLinus Torvalds 	}
12661da177e4SLinus Torvalds 
12671da177e4SLinus Torvalds 	return 0;
12681da177e4SLinus Torvalds }
12691da177e4SLinus Torvalds 
12701da177e4SLinus Torvalds /*
12711da177e4SLinus Torvalds  *  Internal done function
12721da177e4SLinus Torvalds  *
12731da177e4SLinus Torvalds  */
12741da177e4SLinus Torvalds static void done(struct Scsi_Host *shpnt, int error)
12751da177e4SLinus Torvalds {
12761da177e4SLinus Torvalds 	if (CURRENT_SC) {
12771da177e4SLinus Torvalds 		if(DONE_SC)
1278f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC,
1279f75ae8edSHannes Reinecke 				    "there's already a completed command %p "
1280f75ae8edSHannes Reinecke 				    "- will cause abort\n", DONE_SC);
12811da177e4SLinus Torvalds 
12821da177e4SLinus Torvalds 		DONE_SC = CURRENT_SC;
12831da177e4SLinus Torvalds 		CURRENT_SC = NULL;
12841da177e4SLinus Torvalds 		DONE_SC->result = error;
12851da177e4SLinus Torvalds 	} else
12861da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x: done() called outside of command\n");
12871da177e4SLinus Torvalds }
12881da177e4SLinus Torvalds 
12891da177e4SLinus Torvalds static struct work_struct aha152x_tq;
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds /*
12921da177e4SLinus Torvalds  * Run service completions on the card with interrupts enabled.
12931da177e4SLinus Torvalds  *
12941da177e4SLinus Torvalds  */
1295c4028958SDavid Howells static void run(struct work_struct *work)
12961da177e4SLinus Torvalds {
12975fcda422SJames Bottomley 	struct aha152x_hostdata *hd;
12985fcda422SJames Bottomley 
12995fcda422SJames Bottomley 	list_for_each_entry(hd, &aha152x_host_list, host_list) {
13005fcda422SJames Bottomley 		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
13015fcda422SJames Bottomley 
13025fcda422SJames Bottomley 		is_complete(shost);
13031da177e4SLinus Torvalds 	}
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds /*
1307e2482fa1SJürgen E. Fischer  * Interrupt handler
13081da177e4SLinus Torvalds  *
13091da177e4SLinus Torvalds  */
13107d12e780SDavid Howells static irqreturn_t intr(int irqno, void *dev_id)
13111da177e4SLinus Torvalds {
1312e19166d5SJeff Garzik 	struct Scsi_Host *shpnt = dev_id;
1313e2482fa1SJürgen E. Fischer 	unsigned long flags;
13141da177e4SLinus Torvalds 	unsigned char rev, dmacntrl0;
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 	/*
13171da177e4SLinus Torvalds 	 * Read a couple of registers that are known to not be all 1's. If
13181da177e4SLinus Torvalds 	 * we read all 1's (-1), that means that either:
13191da177e4SLinus Torvalds 	 *
13201da177e4SLinus Torvalds 	 * a. The host adapter chip has gone bad, and we cannot control it,
13211da177e4SLinus Torvalds 	 *	OR
13221da177e4SLinus Torvalds 	 * b. The host adapter is a PCMCIA card that has been ejected
13231da177e4SLinus Torvalds 	 *
13241da177e4SLinus Torvalds 	 * In either case, we cannot do anything with the host adapter at
13251da177e4SLinus Torvalds 	 * this point in time. So just ignore the interrupt and return.
13261da177e4SLinus Torvalds 	 * In the latter case, the interrupt might actually be meant for
13271da177e4SLinus Torvalds 	 * someone else sharing this IRQ, and that driver will handle it.
13281da177e4SLinus Torvalds 	 */
13291da177e4SLinus Torvalds 	rev = GETPORT(REV);
13301da177e4SLinus Torvalds 	dmacntrl0 = GETPORT(DMACNTRL0);
13311da177e4SLinus Torvalds 	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
13321da177e4SLinus Torvalds 		return IRQ_NONE;
13331da177e4SLinus Torvalds 
1334e2482fa1SJürgen E. Fischer 	if( TESTLO(DMASTAT, INTSTAT) )
1335e2482fa1SJürgen E. Fischer 		return IRQ_NONE;
1336e2482fa1SJürgen E. Fischer 
13371da177e4SLinus Torvalds 	/* no more interrupts from the controller, while we're busy.
13381da177e4SLinus Torvalds 	   INTEN is restored by the BH handler */
13391da177e4SLinus Torvalds 	CLRBITS(DMACNTRL0, INTEN);
13401da177e4SLinus Torvalds 
1341e2482fa1SJürgen E. Fischer 	DO_LOCK(flags);
1342e2482fa1SJürgen E. Fischer 	if( HOSTDATA(shpnt)->service==0 ) {
1343e2482fa1SJürgen E. Fischer 		HOSTDATA(shpnt)->service=1;
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 		/* Poke the BH handler */
1346c4028958SDavid Howells 		INIT_WORK(&aha152x_tq, run);
13471da177e4SLinus Torvalds 		schedule_work(&aha152x_tq);
1348e2482fa1SJürgen E. Fischer 	}
1349e2482fa1SJürgen E. Fischer 	DO_UNLOCK(flags);
1350e2482fa1SJürgen E. Fischer 
13511da177e4SLinus Torvalds 	return IRQ_HANDLED;
13521da177e4SLinus Torvalds }
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds /*
13551da177e4SLinus Torvalds  * busfree phase
13561da177e4SLinus Torvalds  * - handle completition/disconnection/error of current command
13571da177e4SLinus Torvalds  * - start selection for next command (if any)
13581da177e4SLinus Torvalds  */
13591da177e4SLinus Torvalds static void busfree_run(struct Scsi_Host *shpnt)
13601da177e4SLinus Torvalds {
13611da177e4SLinus Torvalds 	unsigned long flags;
13621da177e4SLinus Torvalds #if defined(AHA152X_STAT)
13631da177e4SLinus Torvalds 	int action=0;
13641da177e4SLinus Torvalds #endif
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
13671da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1);
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 	SETPORT(SSTAT1, CLRBUSFREE);
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds 	if(CURRENT_SC) {
13721da177e4SLinus Torvalds #if defined(AHA152X_STAT)
13731da177e4SLinus Torvalds 		action++;
13741da177e4SLinus Torvalds #endif
13751da177e4SLinus Torvalds 		CURRENT_SC->SCp.phase &= ~syncneg;
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 		if(CURRENT_SC->SCp.phase & completed) {
13781da177e4SLinus Torvalds 			/* target sent COMMAND COMPLETE */
13791da177e4SLinus Torvalds 			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds 		} else if(CURRENT_SC->SCp.phase & aborted) {
13821da177e4SLinus Torvalds 			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
13831da177e4SLinus Torvalds 
13841da177e4SLinus Torvalds 		} else if(CURRENT_SC->SCp.phase & resetted) {
13851da177e4SLinus Torvalds 			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 		} else if(CURRENT_SC->SCp.phase & disconnected) {
13881da177e4SLinus Torvalds 			/* target sent DISCONNECT */
13891da177e4SLinus Torvalds #if defined(AHA152X_STAT)
13901da177e4SLinus Torvalds 			HOSTDATA(shpnt)->disconnections++;
13911da177e4SLinus Torvalds #endif
13921da177e4SLinus Torvalds 			append_SC(&DISCONNECTED_SC, CURRENT_SC);
13931da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase |= 1 << 16;
13941da177e4SLinus Torvalds 			CURRENT_SC = NULL;
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 		} else {
13971da177e4SLinus Torvalds 			done(shpnt, DID_ERROR << 16);
13981da177e4SLinus Torvalds 		}
13991da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14001da177e4SLinus Torvalds 	} else {
14011da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_old_command++;
14021da177e4SLinus Torvalds #endif
14031da177e4SLinus Torvalds 	}
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 	DO_LOCK(flags);
14061da177e4SLinus Torvalds 
14071da177e4SLinus Torvalds 	if(DONE_SC) {
14081da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14091da177e4SLinus Torvalds 		action++;
14101da177e4SLinus Torvalds #endif
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 		if(DONE_SC->SCp.phase & check_condition) {
14135e13cdfaSChristoph Hellwig 			struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
14145e13cdfaSChristoph Hellwig 			struct aha152x_scdata *sc = SCDATA(cmd);
14155e13cdfaSChristoph Hellwig 
141673d2cb16SBoaz Harrosh 			scsi_eh_restore_cmnd(cmd, &sc->ses);
14171da177e4SLinus Torvalds 
14180ceb4798SBoaz Harrosh 			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 			HOSTDATA(shpnt)->commands--;
14211da177e4SLinus Torvalds 			if (!HOSTDATA(shpnt)->commands)
14221da177e4SLinus Torvalds 				SETPORT(PORTA, 0);	/* turn led off */
14230ceb4798SBoaz Harrosh 		} else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) {
14241da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14251da177e4SLinus Torvalds 			HOSTDATA(shpnt)->busfree_with_check_condition++;
14261da177e4SLinus Torvalds #endif
14271da177e4SLinus Torvalds 
14280ceb4798SBoaz Harrosh 			if(!(DONE_SC->SCp.phase & not_issued)) {
142945333ffaSBoaz Harrosh 				struct aha152x_scdata *sc;
143091ebc1faSJohannes Thumshirn 				struct scsi_cmnd *ptr = DONE_SC;
14311da177e4SLinus Torvalds 				DONE_SC=NULL;
14321da177e4SLinus Torvalds 
143345333ffaSBoaz Harrosh 				sc = SCDATA(ptr);
143445333ffaSBoaz Harrosh 				/* It was allocated in aha152x_internal_queue? */
143545333ffaSBoaz Harrosh 				BUG_ON(!sc);
143673d2cb16SBoaz Harrosh 				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds 				DO_UNLOCK(flags);
14391da177e4SLinus Torvalds 				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
14401da177e4SLinus Torvalds 				DO_LOCK(flags);
14411da177e4SLinus Torvalds 			}
14421da177e4SLinus Torvalds 		}
14431da177e4SLinus Torvalds 
14441da177e4SLinus Torvalds 		if(DONE_SC && DONE_SC->scsi_done) {
144591ebc1faSJohannes Thumshirn 			struct scsi_cmnd *ptr = DONE_SC;
14461da177e4SLinus Torvalds 			DONE_SC=NULL;
14471da177e4SLinus Torvalds 
14481da177e4SLinus Torvalds 			/* turn led off, when no commands are in the driver */
14491da177e4SLinus Torvalds 			HOSTDATA(shpnt)->commands--;
14501da177e4SLinus Torvalds 			if (!HOSTDATA(shpnt)->commands)
14511da177e4SLinus Torvalds 				SETPORT(PORTA, 0);	/* turn led off */
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 			if(ptr->scsi_done != reset_done) {
14541da177e4SLinus Torvalds 				kfree(ptr->host_scribble);
14551da177e4SLinus Torvalds 				ptr->host_scribble=NULL;
14561da177e4SLinus Torvalds 			}
14571da177e4SLinus Torvalds 
14581da177e4SLinus Torvalds 			DO_UNLOCK(flags);
14591da177e4SLinus Torvalds 			ptr->scsi_done(ptr);
14601da177e4SLinus Torvalds 			DO_LOCK(flags);
14611da177e4SLinus Torvalds 		}
14621da177e4SLinus Torvalds 
14631da177e4SLinus Torvalds 		DONE_SC=NULL;
14641da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14651da177e4SLinus Torvalds 	} else {
14661da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_done_command++;
14671da177e4SLinus Torvalds #endif
14681da177e4SLinus Torvalds 	}
14691da177e4SLinus Torvalds 
14701da177e4SLinus Torvalds 	if(ISSUE_SC)
14711da177e4SLinus Torvalds 		CURRENT_SC = remove_first_SC(&ISSUE_SC);
14721da177e4SLinus Torvalds 
14731da177e4SLinus Torvalds 	DO_UNLOCK(flags);
14741da177e4SLinus Torvalds 
14751da177e4SLinus Torvalds 	if(CURRENT_SC) {
14761da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14771da177e4SLinus Torvalds 		action++;
14781da177e4SLinus Torvalds #endif
14791da177e4SLinus Torvalds 		CURRENT_SC->SCp.phase |= selecting;
14801da177e4SLinus Torvalds 
14811da177e4SLinus Torvalds 		/* clear selection timeout */
14821da177e4SLinus Torvalds 		SETPORT(SSTAT1, SELTO);
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
14851da177e4SLinus Torvalds 		SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
14861da177e4SLinus Torvalds 		SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
14871da177e4SLinus Torvalds 	} else {
14881da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14891da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_new_command++;
14901da177e4SLinus Torvalds #endif
14911da177e4SLinus Torvalds 		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
14921da177e4SLinus Torvalds 	}
14931da177e4SLinus Torvalds 
14941da177e4SLinus Torvalds #if defined(AHA152X_STAT)
14951da177e4SLinus Torvalds 	if(!action)
14961da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_any_action++;
14971da177e4SLinus Torvalds #endif
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds 
15001da177e4SLinus Torvalds /*
15011da177e4SLinus Torvalds  * Selection done (OUT)
15021da177e4SLinus Torvalds  * - queue IDENTIFY message and SDTR to selected target for message out
15031da177e4SLinus Torvalds  *   (ATN asserted automagically via ENAUTOATNO in busfree())
15041da177e4SLinus Torvalds  */
15051da177e4SLinus Torvalds static void seldo_run(struct Scsi_Host *shpnt)
15061da177e4SLinus Torvalds {
15071da177e4SLinus Torvalds 	SETPORT(SCSISIG, 0);
15081da177e4SLinus Torvalds 	SETPORT(SSTAT1, CLRBUSFREE);
15091da177e4SLinus Torvalds 	SETPORT(SSTAT1, CLRPHASECHG);
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 	CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds 	SETPORT(SCSISEQ, 0);
15141da177e4SLinus Torvalds 
15151da177e4SLinus Torvalds 	if (TESTLO(SSTAT0, SELDO)) {
1516f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, CURRENT_SC,
1517f75ae8edSHannes Reinecke 			    "aha152x: passing bus free condition\n");
15181da177e4SLinus Torvalds 		done(shpnt, DID_NO_CONNECT << 16);
15191da177e4SLinus Torvalds 		return;
15201da177e4SLinus Torvalds 	}
15211da177e4SLinus Torvalds 
15221da177e4SLinus Torvalds 	SETPORT(SSTAT0, CLRSELDO);
15231da177e4SLinus Torvalds 
15241da177e4SLinus Torvalds 	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
15251da177e4SLinus Torvalds 
15261da177e4SLinus Torvalds 	if (CURRENT_SC->SCp.phase & aborting) {
15271da177e4SLinus Torvalds 		ADDMSGO(ABORT);
15281da177e4SLinus Torvalds 	} else if (CURRENT_SC->SCp.phase & resetting) {
15291da177e4SLinus Torvalds 		ADDMSGO(BUS_DEVICE_RESET);
15301da177e4SLinus Torvalds 	} else if (SYNCNEG==0 && SYNCHRONOUS) {
15311da177e4SLinus Torvalds 		CURRENT_SC->SCp.phase |= syncneg;
15326ea3c0b2SMatthew Wilcox 		MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
15331da177e4SLinus Torvalds 		SYNCNEG=1;		/* negotiation in progress */
15341da177e4SLinus Torvalds 	}
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 	SETRATE(SYNCRATE);
15371da177e4SLinus Torvalds }
15381da177e4SLinus Torvalds 
15391da177e4SLinus Torvalds /*
15401da177e4SLinus Torvalds  * Selection timeout
15411da177e4SLinus Torvalds  * - return command to mid-level with failure cause
15421da177e4SLinus Torvalds  *
15431da177e4SLinus Torvalds  */
15441da177e4SLinus Torvalds static void selto_run(struct Scsi_Host *shpnt)
15451da177e4SLinus Torvalds {
15461da177e4SLinus Torvalds 	SETPORT(SCSISEQ, 0);
15471da177e4SLinus Torvalds 	SETPORT(SSTAT1, CLRSELTIMO);
15481da177e4SLinus Torvalds 
1549f75ae8edSHannes Reinecke 	if (!CURRENT_SC)
15501da177e4SLinus Torvalds 		return;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 	CURRENT_SC->SCp.phase &= ~selecting;
15531da177e4SLinus Torvalds 
1554f75ae8edSHannes Reinecke 	if (CURRENT_SC->SCp.phase & aborted)
15551da177e4SLinus Torvalds 		done(shpnt, DID_ABORT << 16);
1556f75ae8edSHannes Reinecke 	else if (TESTLO(SSTAT0, SELINGO))
15571da177e4SLinus Torvalds 		done(shpnt, DID_BUS_BUSY << 16);
1558f75ae8edSHannes Reinecke 	else
15591da177e4SLinus Torvalds 		/* ARBITRATION won, but SELECTION failed */
15601da177e4SLinus Torvalds 		done(shpnt, DID_NO_CONNECT << 16);
15611da177e4SLinus Torvalds }
15621da177e4SLinus Torvalds 
15631da177e4SLinus Torvalds /*
15641da177e4SLinus Torvalds  * Selection in done
15651da177e4SLinus Torvalds  * - put current command back to issue queue
15661da177e4SLinus Torvalds  *   (reconnection of a disconnected nexus instead
15671da177e4SLinus Torvalds  *    of successful selection out)
15681da177e4SLinus Torvalds  *
15691da177e4SLinus Torvalds  */
15701da177e4SLinus Torvalds static void seldi_run(struct Scsi_Host *shpnt)
15711da177e4SLinus Torvalds {
15721da177e4SLinus Torvalds 	int selid;
15731da177e4SLinus Torvalds 	int target;
15741da177e4SLinus Torvalds 	unsigned long flags;
15751da177e4SLinus Torvalds 
15761da177e4SLinus Torvalds 	SETPORT(SCSISIG, 0);
15771da177e4SLinus Torvalds 	SETPORT(SSTAT0, CLRSELDI);
15781da177e4SLinus Torvalds 	SETPORT(SSTAT1, CLRBUSFREE);
15791da177e4SLinus Torvalds 	SETPORT(SSTAT1, CLRPHASECHG);
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	if(CURRENT_SC) {
15821da177e4SLinus Torvalds 		if(!(CURRENT_SC->SCp.phase & not_issued))
1583f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC,
1584f75ae8edSHannes Reinecke 				    "command should not have been issued yet\n");
15851da177e4SLinus Torvalds 
15861da177e4SLinus Torvalds 		DO_LOCK(flags);
15871da177e4SLinus Torvalds 		append_SC(&ISSUE_SC, CURRENT_SC);
15881da177e4SLinus Torvalds 		DO_UNLOCK(flags);
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 		CURRENT_SC = NULL;
15911da177e4SLinus Torvalds 	}
15921da177e4SLinus Torvalds 
1593f75ae8edSHannes Reinecke 	if (!DISCONNECTED_SC)
15941da177e4SLinus Torvalds 		return;
15951da177e4SLinus Torvalds 
15961da177e4SLinus Torvalds 	RECONN_TARGET=-1;
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds 	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
15991da177e4SLinus Torvalds 
16001da177e4SLinus Torvalds 	if (selid==0) {
1601f75ae8edSHannes Reinecke 		shost_printk(KERN_INFO, shpnt,
1602f75ae8edSHannes Reinecke 			     "target id unknown (%02x)\n", selid);
16031da177e4SLinus Torvalds 		return;
16041da177e4SLinus Torvalds 	}
16051da177e4SLinus Torvalds 
16061da177e4SLinus Torvalds 	for(target=7; !(selid & (1 << target)); target--)
16071da177e4SLinus Torvalds 		;
16081da177e4SLinus Torvalds 
16091da177e4SLinus Torvalds 	if(selid & ~(1 << target)) {
1610f75ae8edSHannes Reinecke 		shost_printk(KERN_INFO, shpnt,
1611f75ae8edSHannes Reinecke 			     "multiple targets reconnected (%02x)\n", selid);
16121da177e4SLinus Torvalds 	}
16131da177e4SLinus Torvalds 
16141da177e4SLinus Torvalds 
16151da177e4SLinus Torvalds 	SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
16161da177e4SLinus Torvalds 	SETPORT(SCSISEQ, 0);
16171da177e4SLinus Torvalds 
16181da177e4SLinus Torvalds 	SETRATE(HOSTDATA(shpnt)->syncrate[target]);
16191da177e4SLinus Torvalds 
16201da177e4SLinus Torvalds 	RECONN_TARGET=target;
16211da177e4SLinus Torvalds }
16221da177e4SLinus Torvalds 
16231da177e4SLinus Torvalds /*
16241da177e4SLinus Torvalds  * message in phase
16251da177e4SLinus Torvalds  * - handle initial message after reconnection to identify
16261da177e4SLinus Torvalds  *   reconnecting nexus
16271da177e4SLinus Torvalds  * - queue command on DISCONNECTED_SC on DISCONNECT message
16281da177e4SLinus Torvalds  * - set completed flag on COMMAND COMPLETE
16291da177e4SLinus Torvalds  *   (other completition code moved to busfree_run)
16301da177e4SLinus Torvalds  * - handle response to SDTR
16311da177e4SLinus Torvalds  * - clear synchronous transfer agreements on BUS RESET
16321da177e4SLinus Torvalds  *
16331da177e4SLinus Torvalds  * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
16341da177e4SLinus Torvalds  *
16351da177e4SLinus Torvalds  */
16361da177e4SLinus Torvalds static void msgi_run(struct Scsi_Host *shpnt)
16371da177e4SLinus Torvalds {
16381da177e4SLinus Torvalds 	for(;;) {
16391da177e4SLinus Torvalds 		int sstat1 = GETPORT(SSTAT1);
16401da177e4SLinus Torvalds 
16411da177e4SLinus Torvalds 		if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
16421da177e4SLinus Torvalds 			return;
16431da177e4SLinus Torvalds 
1644f75ae8edSHannes Reinecke 		if (TESTLO(SSTAT0, SPIORDY))
16451da177e4SLinus Torvalds 			return;
16461da177e4SLinus Torvalds 
16471da177e4SLinus Torvalds 		ADDMSGI(GETPORT(SCSIDAT));
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds 		if(!CURRENT_SC) {
16501da177e4SLinus Torvalds 			if(LASTSTATE!=seldi) {
1651f75ae8edSHannes Reinecke 				shost_printk(KERN_ERR, shpnt,
1652f75ae8edSHannes Reinecke 					     "message in w/o current command"
1653f75ae8edSHannes Reinecke 					     " not after reselection\n");
16541da177e4SLinus Torvalds 			}
16551da177e4SLinus Torvalds 
16561da177e4SLinus Torvalds 			/*
16571da177e4SLinus Torvalds 			 * Handle reselection
16581da177e4SLinus Torvalds 			 */
16591da177e4SLinus Torvalds 			if(!(MSGI(0) & IDENTIFY_BASE)) {
1660f75ae8edSHannes Reinecke 				shost_printk(KERN_ERR, shpnt,
1661f75ae8edSHannes Reinecke 					     "target didn't identify after reselection\n");
16621da177e4SLinus Torvalds 				continue;
16631da177e4SLinus Torvalds 			}
16641da177e4SLinus Torvalds 
16651da177e4SLinus Torvalds 			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
16661da177e4SLinus Torvalds 
16671da177e4SLinus Torvalds 			if (!CURRENT_SC) {
16681da177e4SLinus Torvalds 				show_queues(shpnt);
1669f75ae8edSHannes Reinecke 				shost_printk(KERN_ERR, shpnt,
1670f75ae8edSHannes Reinecke 					     "no disconnected command"
1671f75ae8edSHannes Reinecke 					     " for target %d/%d\n",
1672f75ae8edSHannes Reinecke 					     RECONN_TARGET, MSGI(0) & 0x3f);
16731da177e4SLinus Torvalds 				continue;
16741da177e4SLinus Torvalds 			}
16751da177e4SLinus Torvalds 
16761da177e4SLinus Torvalds 			CURRENT_SC->SCp.Message = MSGI(0);
16771da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase &= ~disconnected;
16781da177e4SLinus Torvalds 
16791da177e4SLinus Torvalds 			MSGILEN=0;
16801da177e4SLinus Torvalds 
16811da177e4SLinus Torvalds 			/* next message if any */
16821da177e4SLinus Torvalds 			continue;
16831da177e4SLinus Torvalds 		}
16841da177e4SLinus Torvalds 
16851da177e4SLinus Torvalds 		CURRENT_SC->SCp.Message = MSGI(0);
16861da177e4SLinus Torvalds 
16871da177e4SLinus Torvalds 		switch (MSGI(0)) {
16881da177e4SLinus Torvalds 		case DISCONNECT:
16891da177e4SLinus Torvalds 			if (!RECONNECT)
1690f75ae8edSHannes Reinecke 				scmd_printk(KERN_WARNING, CURRENT_SC,
1691f75ae8edSHannes Reinecke 					    "target was not allowed to disconnect\n");
16921da177e4SLinus Torvalds 
16931da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase |= disconnected;
16941da177e4SLinus Torvalds 			break;
16951da177e4SLinus Torvalds 
16961da177e4SLinus Torvalds 		case COMMAND_COMPLETE:
16971da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase |= completed;
16981da177e4SLinus Torvalds 			break;
16991da177e4SLinus Torvalds 
17001da177e4SLinus Torvalds 		case MESSAGE_REJECT:
17011da177e4SLinus Torvalds 			if (SYNCNEG==1) {
1702f75ae8edSHannes Reinecke 				scmd_printk(KERN_INFO, CURRENT_SC,
1703f75ae8edSHannes Reinecke 					    "Synchronous Data Transfer Request"
1704f75ae8edSHannes Reinecke 					    " was rejected\n");
17051da177e4SLinus Torvalds 				SYNCNEG=2;	/* negotiation completed */
17061da177e4SLinus Torvalds 			} else
1707f75ae8edSHannes Reinecke 				scmd_printk(KERN_INFO, CURRENT_SC,
1708f75ae8edSHannes Reinecke 					    "inbound message (MESSAGE REJECT)\n");
17091da177e4SLinus Torvalds 			break;
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 		case SAVE_POINTERS:
17121da177e4SLinus Torvalds 			break;
17131da177e4SLinus Torvalds 
17141da177e4SLinus Torvalds 		case RESTORE_POINTERS:
17151da177e4SLinus Torvalds 			break;
17161da177e4SLinus Torvalds 
17171da177e4SLinus Torvalds 		case EXTENDED_MESSAGE:
17181da177e4SLinus Torvalds 			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
17191da177e4SLinus Torvalds 				/* not yet completed */
17201da177e4SLinus Torvalds 				continue;
17211da177e4SLinus Torvalds 			}
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 			switch (MSGI(2)) {
17241da177e4SLinus Torvalds 			case EXTENDED_SDTR:
17251da177e4SLinus Torvalds 				{
17261da177e4SLinus Torvalds 					long ticks;
17271da177e4SLinus Torvalds 
17281da177e4SLinus Torvalds 					if (MSGI(1) != 3) {
1729f75ae8edSHannes Reinecke 						scmd_printk(KERN_ERR, CURRENT_SC,
1730f75ae8edSHannes Reinecke 							    "SDTR message length!=3\n");
17311da177e4SLinus Torvalds 						break;
17321da177e4SLinus Torvalds 					}
17331da177e4SLinus Torvalds 
17341da177e4SLinus Torvalds 					if (!HOSTDATA(shpnt)->synchronous)
17351da177e4SLinus Torvalds 						break;
17361da177e4SLinus Torvalds 
17371da177e4SLinus Torvalds 					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
17381abfd370SMatthew Wilcox 					spi_print_msg(&MSGI(0));
17391da177e4SLinus Torvalds 					printk("\n");
17401da177e4SLinus Torvalds 
17411da177e4SLinus Torvalds 					ticks = (MSGI(3) * 4 + 49) / 50;
17421da177e4SLinus Torvalds 
17431da177e4SLinus Torvalds 					if (syncneg) {
17441da177e4SLinus Torvalds 						/* negotiation in progress */
17451da177e4SLinus Torvalds 						if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
17461da177e4SLinus Torvalds 							ADDMSGO(MESSAGE_REJECT);
1747f75ae8edSHannes Reinecke 							scmd_printk(KERN_INFO,
1748f75ae8edSHannes Reinecke 								    CURRENT_SC,
1749f75ae8edSHannes Reinecke 								    "received Synchronous Data Transfer Request invalid - rejected\n");
17501da177e4SLinus Torvalds 							break;
17511da177e4SLinus Torvalds 						}
17521da177e4SLinus Torvalds 
17531da177e4SLinus Torvalds 						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
17541da177e4SLinus Torvalds 					} else if (ticks <= 9 && MSGI(4) >= 1) {
17551da177e4SLinus Torvalds 						ADDMSGO(EXTENDED_MESSAGE);
17561da177e4SLinus Torvalds 						ADDMSGO(3);
17571da177e4SLinus Torvalds 						ADDMSGO(EXTENDED_SDTR);
17581da177e4SLinus Torvalds 						if (ticks < 4) {
17591da177e4SLinus Torvalds 							ticks = 4;
17601da177e4SLinus Torvalds 							ADDMSGO(50);
17611da177e4SLinus Torvalds 						} else
17621da177e4SLinus Torvalds 							ADDMSGO(MSGI(3));
17631da177e4SLinus Torvalds 
17641da177e4SLinus Torvalds 						if (MSGI(4) > 8)
17651da177e4SLinus Torvalds 							MSGI(4) = 8;
17661da177e4SLinus Torvalds 
17671da177e4SLinus Torvalds 						ADDMSGO(MSGI(4));
17681da177e4SLinus Torvalds 
17691da177e4SLinus Torvalds 						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
17701da177e4SLinus Torvalds 					} else {
17711da177e4SLinus Torvalds 						/* requested SDTR is too slow, do it asynchronously */
1772f75ae8edSHannes Reinecke 						scmd_printk(KERN_INFO,
1773f75ae8edSHannes Reinecke 							    CURRENT_SC,
1774f75ae8edSHannes Reinecke 							    "Synchronous Data Transfer Request too slow - Rejecting\n");
17751da177e4SLinus Torvalds 						ADDMSGO(MESSAGE_REJECT);
17761da177e4SLinus Torvalds 					}
17771da177e4SLinus Torvalds 
1778f75ae8edSHannes Reinecke 					/* negotiation completed */
1779f75ae8edSHannes Reinecke 					SYNCNEG=2;
17801da177e4SLinus Torvalds 					SETRATE(SYNCRATE);
17811da177e4SLinus Torvalds 				}
17821da177e4SLinus Torvalds 				break;
17831da177e4SLinus Torvalds 
17841da177e4SLinus Torvalds 			case BUS_DEVICE_RESET:
17851da177e4SLinus Torvalds 				{
17861da177e4SLinus Torvalds 					int i;
17871da177e4SLinus Torvalds 
17881da177e4SLinus Torvalds 					for(i=0; i<8; i++) {
17891da177e4SLinus Torvalds 						HOSTDATA(shpnt)->syncrate[i]=0;
17901da177e4SLinus Torvalds 						HOSTDATA(shpnt)->syncneg[i]=0;
17911da177e4SLinus Torvalds 					}
17921da177e4SLinus Torvalds 
17931da177e4SLinus Torvalds 				}
17941da177e4SLinus Torvalds 				break;
17951da177e4SLinus Torvalds 
17961da177e4SLinus Torvalds 			case EXTENDED_MODIFY_DATA_POINTER:
17971da177e4SLinus Torvalds 			case EXTENDED_EXTENDED_IDENTIFY:
17981da177e4SLinus Torvalds 			case EXTENDED_WDTR:
17991da177e4SLinus Torvalds 			default:
18001da177e4SLinus Torvalds 				ADDMSGO(MESSAGE_REJECT);
18011da177e4SLinus Torvalds 				break;
18021da177e4SLinus Torvalds 			}
18031da177e4SLinus Torvalds 			break;
18041da177e4SLinus Torvalds 		}
18051da177e4SLinus Torvalds 
18061da177e4SLinus Torvalds 		MSGILEN=0;
18071da177e4SLinus Torvalds 	}
18081da177e4SLinus Torvalds }
18091da177e4SLinus Torvalds 
18101da177e4SLinus Torvalds static void msgi_end(struct Scsi_Host *shpnt)
18111da177e4SLinus Torvalds {
18121da177e4SLinus Torvalds 	if(MSGILEN>0)
1813f75ae8edSHannes Reinecke 		scmd_printk(KERN_WARNING, CURRENT_SC,
1814f75ae8edSHannes Reinecke 			    "target left before message completed (%d)\n",
1815f75ae8edSHannes Reinecke 			    MSGILEN);
18161da177e4SLinus Torvalds 
1817f75ae8edSHannes Reinecke 	if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE))
18181da177e4SLinus Torvalds 		SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
18191da177e4SLinus Torvalds }
18201da177e4SLinus Torvalds 
18211da177e4SLinus Torvalds /*
18221da177e4SLinus Torvalds  * message out phase
18231da177e4SLinus Torvalds  *
18241da177e4SLinus Torvalds  */
18251da177e4SLinus Torvalds static void msgo_init(struct Scsi_Host *shpnt)
18261da177e4SLinus Torvalds {
18271da177e4SLinus Torvalds 	if(MSGOLEN==0) {
18281da177e4SLinus Torvalds 		if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
18291da177e4SLinus Torvalds 			ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
18301da177e4SLinus Torvalds 		} else {
1831f75ae8edSHannes Reinecke 			scmd_printk(KERN_INFO, CURRENT_SC,
1832f75ae8edSHannes Reinecke 				    "unexpected MESSAGE OUT phase; rejecting\n");
18331da177e4SLinus Torvalds 			ADDMSGO(MESSAGE_REJECT);
18341da177e4SLinus Torvalds 		}
18351da177e4SLinus Torvalds 	}
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds }
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds /*
18401da177e4SLinus Torvalds  * message out phase
18411da177e4SLinus Torvalds  *
18421da177e4SLinus Torvalds  */
18431da177e4SLinus Torvalds static void msgo_run(struct Scsi_Host *shpnt)
18441da177e4SLinus Torvalds {
18451da177e4SLinus Torvalds 	while(MSGO_I<MSGOLEN) {
1846f75ae8edSHannes Reinecke 		if (TESTLO(SSTAT0, SPIORDY))
18471da177e4SLinus Torvalds 			return;
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds 		if (MSGO_I==MSGOLEN-1) {
18501da177e4SLinus Torvalds 			/* Leave MESSAGE OUT after transfer */
18511da177e4SLinus Torvalds 			SETPORT(SSTAT1, CLRATNO);
18521da177e4SLinus Torvalds 		}
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds 
18551da177e4SLinus Torvalds 		if (MSGO(MSGO_I) & IDENTIFY_BASE)
18561da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase |= identified;
18571da177e4SLinus Torvalds 
18581da177e4SLinus Torvalds 		if (MSGO(MSGO_I)==ABORT)
18591da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase |= aborted;
18601da177e4SLinus Torvalds 
18611da177e4SLinus Torvalds 		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
18621da177e4SLinus Torvalds 			CURRENT_SC->SCp.phase |= resetted;
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds 		SETPORT(SCSIDAT, MSGO(MSGO_I++));
18651da177e4SLinus Torvalds 	}
18661da177e4SLinus Torvalds }
18671da177e4SLinus Torvalds 
18681da177e4SLinus Torvalds static void msgo_end(struct Scsi_Host *shpnt)
18691da177e4SLinus Torvalds {
18701da177e4SLinus Torvalds 	if(MSGO_I<MSGOLEN) {
1871f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, CURRENT_SC,
1872f75ae8edSHannes Reinecke 			    "message sent incompletely (%d/%d)\n",
1873f75ae8edSHannes Reinecke 			    MSGO_I, MSGOLEN);
18741da177e4SLinus Torvalds 		if(SYNCNEG==1) {
1875f75ae8edSHannes Reinecke 			scmd_printk(KERN_INFO, CURRENT_SC,
1876f75ae8edSHannes Reinecke 				    "Synchronous Data Transfer Request was rejected\n");
18771da177e4SLinus Torvalds 			SYNCNEG=2;
18781da177e4SLinus Torvalds 		}
18791da177e4SLinus Torvalds 	}
18801da177e4SLinus Torvalds 
18811da177e4SLinus Torvalds 	MSGO_I  = 0;
18821da177e4SLinus Torvalds 	MSGOLEN = 0;
18831da177e4SLinus Torvalds }
18841da177e4SLinus Torvalds 
18851da177e4SLinus Torvalds /*
18861da177e4SLinus Torvalds  * command phase
18871da177e4SLinus Torvalds  *
18881da177e4SLinus Torvalds  */
18891da177e4SLinus Torvalds static void cmd_init(struct Scsi_Host *shpnt)
18901da177e4SLinus Torvalds {
18911da177e4SLinus Torvalds 	if (CURRENT_SC->SCp.sent_command) {
1892f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, CURRENT_SC,
1893f75ae8edSHannes Reinecke 			    "command already sent\n");
18941da177e4SLinus Torvalds 		done(shpnt, DID_ERROR << 16);
18951da177e4SLinus Torvalds 		return;
18961da177e4SLinus Torvalds 	}
18971da177e4SLinus Torvalds 
18981da177e4SLinus Torvalds 	CMD_I=0;
18991da177e4SLinus Torvalds }
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds /*
19021da177e4SLinus Torvalds  * command phase
19031da177e4SLinus Torvalds  *
19041da177e4SLinus Torvalds  */
19051da177e4SLinus Torvalds static void cmd_run(struct Scsi_Host *shpnt)
19061da177e4SLinus Torvalds {
19071da177e4SLinus Torvalds 	while(CMD_I<CURRENT_SC->cmd_len) {
1908f75ae8edSHannes Reinecke 		if (TESTLO(SSTAT0, SPIORDY))
19091da177e4SLinus Torvalds 			return;
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds 		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
19121da177e4SLinus Torvalds 	}
19131da177e4SLinus Torvalds }
19141da177e4SLinus Torvalds 
19151da177e4SLinus Torvalds static void cmd_end(struct Scsi_Host *shpnt)
19161da177e4SLinus Torvalds {
19171da177e4SLinus Torvalds 	if(CMD_I<CURRENT_SC->cmd_len)
1918f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, CURRENT_SC,
1919f75ae8edSHannes Reinecke 			    "command sent incompletely (%d/%d)\n",
1920f75ae8edSHannes Reinecke 			    CMD_I, CURRENT_SC->cmd_len);
19211da177e4SLinus Torvalds 	else
19221da177e4SLinus Torvalds 		CURRENT_SC->SCp.sent_command++;
19231da177e4SLinus Torvalds }
19241da177e4SLinus Torvalds 
19251da177e4SLinus Torvalds /*
19261da177e4SLinus Torvalds  * status phase
19271da177e4SLinus Torvalds  *
19281da177e4SLinus Torvalds  */
19291da177e4SLinus Torvalds static void status_run(struct Scsi_Host *shpnt)
19301da177e4SLinus Torvalds {
1931f75ae8edSHannes Reinecke 	if (TESTLO(SSTAT0, SPIORDY))
19321da177e4SLinus Torvalds 		return;
19331da177e4SLinus Torvalds 
19341da177e4SLinus Torvalds 	CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
19351da177e4SLinus Torvalds 
19361da177e4SLinus Torvalds }
19371da177e4SLinus Torvalds 
19381da177e4SLinus Torvalds /*
19391da177e4SLinus Torvalds  * data in phase
19401da177e4SLinus Torvalds  *
19411da177e4SLinus Torvalds  */
19421da177e4SLinus Torvalds static void datai_init(struct Scsi_Host *shpnt)
19431da177e4SLinus Torvalds {
19441da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, RSTFIFO);
19451da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
19461da177e4SLinus Torvalds 
19471da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
19481da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds 	SETPORT(SIMODE0, 0);
19511da177e4SLinus Torvalds 	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds 	DATA_LEN=0;
19541da177e4SLinus Torvalds }
19551da177e4SLinus Torvalds 
19561da177e4SLinus Torvalds static void datai_run(struct Scsi_Host *shpnt)
19571da177e4SLinus Torvalds {
19581da177e4SLinus Torvalds 	unsigned long the_time;
19591da177e4SLinus Torvalds 	int fifodata, data_count;
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	/*
19621da177e4SLinus Torvalds 	 * loop while the phase persists or the fifos are not empty
19631da177e4SLinus Torvalds 	 *
19641da177e4SLinus Torvalds 	 */
19651da177e4SLinus Torvalds 	while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
19661da177e4SLinus Torvalds 		/* FIXME: maybe this should be done by setting up
19671da177e4SLinus Torvalds 		 * STCNT to trigger ENSWRAP interrupt, instead of
19681da177e4SLinus Torvalds 		 * polling for DFIFOFULL
19691da177e4SLinus Torvalds 		 */
19701da177e4SLinus Torvalds 		the_time=jiffies + 100*HZ;
19711da177e4SLinus Torvalds 		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
19721da177e4SLinus Torvalds 			barrier();
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds 		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
1975f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n");
19761da177e4SLinus Torvalds 			break;
19771da177e4SLinus Torvalds 		}
19781da177e4SLinus Torvalds 
19791da177e4SLinus Torvalds 		if(TESTHI(DMASTAT, DFIFOFULL)) {
19801da177e4SLinus Torvalds 			fifodata = 128;
19811da177e4SLinus Torvalds 		} else {
19821da177e4SLinus Torvalds 			the_time=jiffies + 100*HZ;
19831da177e4SLinus Torvalds 			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
19841da177e4SLinus Torvalds 				barrier();
19851da177e4SLinus Torvalds 
19861da177e4SLinus Torvalds 			if(TESTLO(SSTAT2, SEMPTY)) {
1987f75ae8edSHannes Reinecke 				scmd_printk(KERN_ERR, CURRENT_SC,
1988f75ae8edSHannes Reinecke 					    "datai sempty timeout");
19891da177e4SLinus Torvalds 				break;
19901da177e4SLinus Torvalds 			}
19911da177e4SLinus Torvalds 
19921da177e4SLinus Torvalds 			fifodata = GETPORT(FIFOSTAT);
19931da177e4SLinus Torvalds 		}
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds 		if(CURRENT_SC->SCp.this_residual>0) {
19961da177e4SLinus Torvalds 			while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
19971da177e4SLinus Torvalds 				data_count = fifodata > CURRENT_SC->SCp.this_residual ?
19981da177e4SLinus Torvalds 						CURRENT_SC->SCp.this_residual :
19991da177e4SLinus Torvalds 						fifodata;
20001da177e4SLinus Torvalds 				fifodata -= data_count;
20011da177e4SLinus Torvalds 
20021da177e4SLinus Torvalds 				if (data_count & 1) {
20031da177e4SLinus Torvalds 					SETPORT(DMACNTRL0, ENDMA|_8BIT);
20041da177e4SLinus Torvalds 					*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
20051da177e4SLinus Torvalds 					CURRENT_SC->SCp.this_residual--;
20061da177e4SLinus Torvalds 					DATA_LEN++;
20071da177e4SLinus Torvalds 					SETPORT(DMACNTRL0, ENDMA);
20081da177e4SLinus Torvalds 				}
20091da177e4SLinus Torvalds 
20101da177e4SLinus Torvalds 				if (data_count > 1) {
20111da177e4SLinus Torvalds 					data_count >>= 1;
20121da177e4SLinus Torvalds 					insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
20131da177e4SLinus Torvalds 					CURRENT_SC->SCp.ptr += 2 * data_count;
20141da177e4SLinus Torvalds 					CURRENT_SC->SCp.this_residual -= 2 * data_count;
20151da177e4SLinus Torvalds 					DATA_LEN += 2 * data_count;
20161da177e4SLinus Torvalds 				}
20171da177e4SLinus Torvalds 
2018f75ae8edSHannes Reinecke 				if (CURRENT_SC->SCp.this_residual == 0 &&
2019a7a253baSFinn Thain 				    !sg_is_last(CURRENT_SC->SCp.buffer)) {
20201da177e4SLinus Torvalds 					/* advance to next buffer */
2021a7a253baSFinn Thain 					CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
20221da177e4SLinus Torvalds 					CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
20231da177e4SLinus Torvalds 					CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
20241da177e4SLinus Torvalds 				}
20251da177e4SLinus Torvalds 			}
20261da177e4SLinus Torvalds 		} else if (fifodata > 0) {
2027f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC,
2028f75ae8edSHannes Reinecke 				    "no buffers left for %d(%d) bytes"
2029f75ae8edSHannes Reinecke 				    " (data overrun!?)\n",
2030f75ae8edSHannes Reinecke 				    fifodata, GETPORT(FIFOSTAT));
20311da177e4SLinus Torvalds 			SETPORT(DMACNTRL0, ENDMA|_8BIT);
20321da177e4SLinus Torvalds 			while(fifodata>0) {
2033*3c011793SLee Jones 				GETPORT(DATAPORT);
20341da177e4SLinus Torvalds 				fifodata--;
20351da177e4SLinus Torvalds 				DATA_LEN++;
20361da177e4SLinus Torvalds 			}
20371da177e4SLinus Torvalds 			SETPORT(DMACNTRL0, ENDMA|_8BIT);
20381da177e4SLinus Torvalds 		}
20391da177e4SLinus Torvalds 	}
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 	if(TESTLO(DMASTAT, INTSTAT) ||
20421da177e4SLinus Torvalds 	   TESTLO(DMASTAT, DFIFOEMP) ||
20431da177e4SLinus Torvalds 	   TESTLO(SSTAT2, SEMPTY) ||
20441da177e4SLinus Torvalds 	   GETPORT(FIFOSTAT)>0) {
20451da177e4SLinus Torvalds 		/*
20461da177e4SLinus Torvalds 		 * something went wrong, if there's something left in the fifos
20471da177e4SLinus Torvalds 		 * or the phase didn't change
20481da177e4SLinus Torvalds 		 */
2049f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, CURRENT_SC,
2050f75ae8edSHannes Reinecke 			    "fifos should be empty and phase should have changed\n");
20511da177e4SLinus Torvalds 	}
20521da177e4SLinus Torvalds 
20531da177e4SLinus Torvalds 	if(DATA_LEN!=GETSTCNT()) {
2054f75ae8edSHannes Reinecke 		scmd_printk(KERN_ERR, CURRENT_SC,
2055f75ae8edSHannes Reinecke 			    "manual transfer count differs from automatic "
2056f75ae8edSHannes Reinecke 			    "(count=%d;stcnt=%d;diff=%d;fifostat=%d)",
2057f75ae8edSHannes Reinecke 			    DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN,
2058f75ae8edSHannes Reinecke 			    GETPORT(FIFOSTAT));
20591da177e4SLinus Torvalds 		mdelay(10000);
20601da177e4SLinus Torvalds 	}
20611da177e4SLinus Torvalds }
20621da177e4SLinus Torvalds 
20631da177e4SLinus Torvalds static void datai_end(struct Scsi_Host *shpnt)
20641da177e4SLinus Torvalds {
20652338545aSBoaz Harrosh 	CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
20681da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, 0);
20691da177e4SLinus Torvalds }
20701da177e4SLinus Torvalds 
20711da177e4SLinus Torvalds /*
20721da177e4SLinus Torvalds  * data out phase
20731da177e4SLinus Torvalds  *
20741da177e4SLinus Torvalds  */
20751da177e4SLinus Torvalds static void datao_init(struct Scsi_Host *shpnt)
20761da177e4SLinus Torvalds {
20771da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
20781da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
20791da177e4SLinus Torvalds 
20801da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
20811da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
20821da177e4SLinus Torvalds 
20831da177e4SLinus Torvalds 	SETPORT(SIMODE0, 0);
20841da177e4SLinus Torvalds 	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
20851da177e4SLinus Torvalds 
20862338545aSBoaz Harrosh 	DATA_LEN = scsi_get_resid(CURRENT_SC);
20871da177e4SLinus Torvalds }
20881da177e4SLinus Torvalds 
20891da177e4SLinus Torvalds static void datao_run(struct Scsi_Host *shpnt)
20901da177e4SLinus Torvalds {
20911da177e4SLinus Torvalds 	unsigned long the_time;
20921da177e4SLinus Torvalds 	int data_count;
20931da177e4SLinus Torvalds 
20941da177e4SLinus Torvalds 	/* until phase changes or all data sent */
20951da177e4SLinus Torvalds 	while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
20961da177e4SLinus Torvalds 		data_count = 128;
20971da177e4SLinus Torvalds 		if(data_count > CURRENT_SC->SCp.this_residual)
20981da177e4SLinus Torvalds 			data_count=CURRENT_SC->SCp.this_residual;
20991da177e4SLinus Torvalds 
21001da177e4SLinus Torvalds 		if(TESTLO(DMASTAT, DFIFOEMP)) {
2101f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC,
2102f75ae8edSHannes Reinecke 				    "datao fifo not empty (%d)",
2103f75ae8edSHannes Reinecke 				    GETPORT(FIFOSTAT));
21041da177e4SLinus Torvalds 			break;
21051da177e4SLinus Torvalds 		}
21061da177e4SLinus Torvalds 
21071da177e4SLinus Torvalds 		if(data_count & 1) {
21081da177e4SLinus Torvalds 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
21091da177e4SLinus Torvalds 			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
21101da177e4SLinus Torvalds 			CURRENT_SC->SCp.this_residual--;
21112338545aSBoaz Harrosh 			CMD_INC_RESID(CURRENT_SC, -1);
21121da177e4SLinus Torvalds 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
21131da177e4SLinus Torvalds 		}
21141da177e4SLinus Torvalds 
21151da177e4SLinus Torvalds 		if(data_count > 1) {
21161da177e4SLinus Torvalds 			data_count >>= 1;
21171da177e4SLinus Torvalds 			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
21181da177e4SLinus Torvalds 			CURRENT_SC->SCp.ptr           += 2 * data_count;
21191da177e4SLinus Torvalds 			CURRENT_SC->SCp.this_residual -= 2 * data_count;
21202338545aSBoaz Harrosh 			CMD_INC_RESID(CURRENT_SC, -2 * data_count);
21211da177e4SLinus Torvalds 		}
21221da177e4SLinus Torvalds 
2123a7a253baSFinn Thain 		if (CURRENT_SC->SCp.this_residual == 0 &&
2124a7a253baSFinn Thain 		    !sg_is_last(CURRENT_SC->SCp.buffer)) {
21251da177e4SLinus Torvalds 			/* advance to next buffer */
2126a7a253baSFinn Thain 			CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
21271da177e4SLinus Torvalds 			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
21281da177e4SLinus Torvalds 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
21291da177e4SLinus Torvalds 		}
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds 		the_time=jiffies + 100*HZ;
21321da177e4SLinus Torvalds 		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
21331da177e4SLinus Torvalds 			barrier();
21341da177e4SLinus Torvalds 
21351da177e4SLinus Torvalds 		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
2136f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n");
21371da177e4SLinus Torvalds 			break;
21381da177e4SLinus Torvalds 		}
21391da177e4SLinus Torvalds 	}
21401da177e4SLinus Torvalds }
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds static void datao_end(struct Scsi_Host *shpnt)
21431da177e4SLinus Torvalds {
21441da177e4SLinus Torvalds 	if(TESTLO(DMASTAT, DFIFOEMP)) {
2145a7a253baSFinn Thain 		u32 datao_cnt = GETSTCNT();
2146a7a253baSFinn Thain 		int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
2147a7a253baSFinn Thain 		int done;
2148a7a253baSFinn Thain 		struct scatterlist *sg = scsi_sglist(CURRENT_SC);
21491da177e4SLinus Torvalds 
2150a7a253baSFinn Thain 		CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
21511da177e4SLinus Torvalds 
2152a7a253baSFinn Thain 		done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
2153a7a253baSFinn Thain 		/* Locate the first SG entry not yet sent */
2154a7a253baSFinn Thain 		while (done > 0 && !sg_is_last(sg)) {
2155a7a253baSFinn Thain 			if (done < sg->length)
2156a7a253baSFinn Thain 				break;
2157a7a253baSFinn Thain 			done -= sg->length;
2158a7a253baSFinn Thain 			sg = sg_next(sg);
21591da177e4SLinus Torvalds 		}
2160a7a253baSFinn Thain 
2161a7a253baSFinn Thain 		CURRENT_SC->SCp.buffer = sg;
2162a7a253baSFinn Thain 		CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done;
2163a7a253baSFinn Thain 		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length -
2164a7a253baSFinn Thain 			done;
21651da177e4SLinus Torvalds 	}
21661da177e4SLinus Torvalds 
21671da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
21681da177e4SLinus Torvalds 	SETPORT(SXFRCTL0, CH1);
21691da177e4SLinus Torvalds 
21701da177e4SLinus Torvalds 	SETPORT(DMACNTRL0, 0);
21711da177e4SLinus Torvalds }
21721da177e4SLinus Torvalds 
21731da177e4SLinus Torvalds /*
21741da177e4SLinus Torvalds  * figure out what state we're in
21751da177e4SLinus Torvalds  *
21761da177e4SLinus Torvalds  */
21771da177e4SLinus Torvalds static int update_state(struct Scsi_Host *shpnt)
21781da177e4SLinus Torvalds {
21791da177e4SLinus Torvalds 	int dataphase=0;
21801da177e4SLinus Torvalds 	unsigned int stat0 = GETPORT(SSTAT0);
21811da177e4SLinus Torvalds 	unsigned int stat1 = GETPORT(SSTAT1);
21821da177e4SLinus Torvalds 
21831da177e4SLinus Torvalds 	PREVSTATE = STATE;
21841da177e4SLinus Torvalds 	STATE=unknown;
21851da177e4SLinus Torvalds 
21861da177e4SLinus Torvalds 	if(stat1 & SCSIRSTI) {
21871da177e4SLinus Torvalds 		STATE=rsti;
21881da177e4SLinus Torvalds 		SETPORT(SCSISEQ,0);
21891da177e4SLinus Torvalds 		SETPORT(SSTAT1,SCSIRSTI);
21901da177e4SLinus Torvalds 	} else if (stat0 & SELDI && PREVSTATE == busfree) {
21911da177e4SLinus Torvalds 		STATE=seldi;
21921da177e4SLinus Torvalds 	} else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
21931da177e4SLinus Torvalds 		STATE=seldo;
21941da177e4SLinus Torvalds 	} else if(stat1 & SELTO) {
21951da177e4SLinus Torvalds 		STATE=selto;
21961da177e4SLinus Torvalds 	} else if(stat1 & BUSFREE) {
21971da177e4SLinus Torvalds 		STATE=busfree;
21981da177e4SLinus Torvalds 		SETPORT(SSTAT1,BUSFREE);
21991da177e4SLinus Torvalds 	} else if(stat1 & SCSIPERR) {
22001da177e4SLinus Torvalds 		STATE=parerr;
22011da177e4SLinus Torvalds 		SETPORT(SSTAT1,SCSIPERR);
22021da177e4SLinus Torvalds 	} else if(stat1 & REQINIT) {
22031da177e4SLinus Torvalds 		switch(GETPORT(SCSISIG) & P_MASK) {
22041da177e4SLinus Torvalds 		case P_MSGI:	STATE=msgi;	break;
22051da177e4SLinus Torvalds 		case P_MSGO:	STATE=msgo;	break;
22061da177e4SLinus Torvalds 		case P_DATAO:	STATE=datao;	break;
22071da177e4SLinus Torvalds 		case P_DATAI:	STATE=datai;	break;
22081da177e4SLinus Torvalds 		case P_STATUS:	STATE=status;	break;
22091da177e4SLinus Torvalds 		case P_CMD:	STATE=cmd;	break;
22101da177e4SLinus Torvalds 		}
22111da177e4SLinus Torvalds 		dataphase=1;
22121da177e4SLinus Torvalds 	}
22131da177e4SLinus Torvalds 
22141da177e4SLinus Torvalds 	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
2215f75ae8edSHannes Reinecke 		scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?");
22161da177e4SLinus Torvalds 	}
22171da177e4SLinus Torvalds 
22181da177e4SLinus Torvalds 	if(STATE!=PREVSTATE) {
22191da177e4SLinus Torvalds 		LASTSTATE=PREVSTATE;
22201da177e4SLinus Torvalds 	}
22211da177e4SLinus Torvalds 
22221da177e4SLinus Torvalds 	return dataphase;
22231da177e4SLinus Torvalds }
22241da177e4SLinus Torvalds 
22251da177e4SLinus Torvalds /*
22261da177e4SLinus Torvalds  * handle parity error
22271da177e4SLinus Torvalds  *
22281da177e4SLinus Torvalds  * FIXME: in which phase?
22291da177e4SLinus Torvalds  *
22301da177e4SLinus Torvalds  */
22311da177e4SLinus Torvalds static void parerr_run(struct Scsi_Host *shpnt)
22321da177e4SLinus Torvalds {
2233f75ae8edSHannes Reinecke 	scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
22341da177e4SLinus Torvalds 	done(shpnt, DID_PARITY << 16);
22351da177e4SLinus Torvalds }
22361da177e4SLinus Torvalds 
22371da177e4SLinus Torvalds /*
22381da177e4SLinus Torvalds  * handle reset in
22391da177e4SLinus Torvalds  *
22401da177e4SLinus Torvalds  */
22411da177e4SLinus Torvalds static void rsti_run(struct Scsi_Host *shpnt)
22421da177e4SLinus Torvalds {
224391ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr;
22441da177e4SLinus Torvalds 
2245f75ae8edSHannes Reinecke 	shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n");
22461da177e4SLinus Torvalds 
22471da177e4SLinus Torvalds 	ptr=DISCONNECTED_SC;
22481da177e4SLinus Torvalds 	while(ptr) {
224991ebc1faSJohannes Thumshirn 		struct scsi_cmnd *next = SCNEXT(ptr);
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds 		if (!ptr->device->soft_reset) {
22521da177e4SLinus Torvalds 			remove_SC(&DISCONNECTED_SC, ptr);
22531da177e4SLinus Torvalds 
22541da177e4SLinus Torvalds 			kfree(ptr->host_scribble);
22551da177e4SLinus Torvalds 			ptr->host_scribble=NULL;
22561da177e4SLinus Torvalds 
22571da177e4SLinus Torvalds 			ptr->result =  DID_RESET << 16;
22581da177e4SLinus Torvalds 			ptr->scsi_done(ptr);
22591da177e4SLinus Torvalds 		}
22601da177e4SLinus Torvalds 
22611da177e4SLinus Torvalds 		ptr = next;
22621da177e4SLinus Torvalds 	}
22631da177e4SLinus Torvalds 
22641da177e4SLinus Torvalds 	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
22651da177e4SLinus Torvalds 		done(shpnt, DID_RESET << 16 );
22661da177e4SLinus Torvalds }
22671da177e4SLinus Torvalds 
22681da177e4SLinus Torvalds 
22691da177e4SLinus Torvalds /*
22701da177e4SLinus Torvalds  * bottom-half handler
22711da177e4SLinus Torvalds  *
22721da177e4SLinus Torvalds  */
22731da177e4SLinus Torvalds static void is_complete(struct Scsi_Host *shpnt)
22741da177e4SLinus Torvalds {
22751da177e4SLinus Torvalds 	int dataphase;
22761da177e4SLinus Torvalds 	unsigned long flags;
22771da177e4SLinus Torvalds 	int pending;
22781da177e4SLinus Torvalds 
2279e2482fa1SJürgen E. Fischer 	if(!shpnt)
2280e2482fa1SJürgen E. Fischer 		return;
2281e2482fa1SJürgen E. Fischer 
22821da177e4SLinus Torvalds 	DO_LOCK(flags);
2283e2482fa1SJürgen E. Fischer 
2284e2482fa1SJürgen E. Fischer 	if( HOSTDATA(shpnt)->service==0 )  {
2285e2482fa1SJürgen E. Fischer 		DO_UNLOCK(flags);
2286e2482fa1SJürgen E. Fischer 		return;
2287e2482fa1SJürgen E. Fischer 	}
2288e2482fa1SJürgen E. Fischer 
2289e2482fa1SJürgen E. Fischer 	HOSTDATA(shpnt)->service = 0;
2290e2482fa1SJürgen E. Fischer 
22911da177e4SLinus Torvalds 	if(HOSTDATA(shpnt)->in_intr) {
22921da177e4SLinus Torvalds 		DO_UNLOCK(flags);
22931da177e4SLinus Torvalds 		/* aha152x_error never returns.. */
22941da177e4SLinus Torvalds 		aha152x_error(shpnt, "bottom-half already running!?");
22951da177e4SLinus Torvalds 	}
22961da177e4SLinus Torvalds 	HOSTDATA(shpnt)->in_intr++;
22971da177e4SLinus Torvalds 
22981da177e4SLinus Torvalds 	/*
22991da177e4SLinus Torvalds 	 * loop while there are interrupt conditions pending
23001da177e4SLinus Torvalds 	 *
23011da177e4SLinus Torvalds 	 */
23021da177e4SLinus Torvalds 	do {
23031da177e4SLinus Torvalds 		unsigned long start = jiffies;
23041da177e4SLinus Torvalds 		DO_UNLOCK(flags);
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 		dataphase=update_state(shpnt);
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds 		/*
23091da177e4SLinus Torvalds 		 * end previous state
23101da177e4SLinus Torvalds 		 *
23111da177e4SLinus Torvalds 		 */
23121da177e4SLinus Torvalds 		if(PREVSTATE!=STATE && states[PREVSTATE].end)
23131da177e4SLinus Torvalds 			states[PREVSTATE].end(shpnt);
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds 		/*
23161da177e4SLinus Torvalds 		 * disable SPIO mode if previous phase used it
23171da177e4SLinus Torvalds 		 * and this one doesn't
23181da177e4SLinus Torvalds 		 *
23191da177e4SLinus Torvalds 		 */
23201da177e4SLinus Torvalds 		if(states[PREVSTATE].spio && !states[STATE].spio) {
23211da177e4SLinus Torvalds 			SETPORT(SXFRCTL0, CH1);
23221da177e4SLinus Torvalds 			SETPORT(DMACNTRL0, 0);
23231da177e4SLinus Torvalds 			if(CURRENT_SC)
23241da177e4SLinus Torvalds 				CURRENT_SC->SCp.phase &= ~spiordy;
23251da177e4SLinus Torvalds 		}
23261da177e4SLinus Torvalds 
23271da177e4SLinus Torvalds 		/*
23281da177e4SLinus Torvalds 		 * accept current dataphase phase
23291da177e4SLinus Torvalds 		 *
23301da177e4SLinus Torvalds 		 */
23311da177e4SLinus Torvalds 		if(dataphase) {
23321da177e4SLinus Torvalds 			SETPORT(SSTAT0, REQINIT);
23331da177e4SLinus Torvalds 			SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
23341da177e4SLinus Torvalds 			SETPORT(SSTAT1, PHASECHG);
23351da177e4SLinus Torvalds 		}
23361da177e4SLinus Torvalds 
23371da177e4SLinus Torvalds 		/*
23381da177e4SLinus Torvalds 		 * enable SPIO mode if previous didn't use it
23391da177e4SLinus Torvalds 		 * and this one does
23401da177e4SLinus Torvalds 		 *
23411da177e4SLinus Torvalds 		 */
23421da177e4SLinus Torvalds 		if(!states[PREVSTATE].spio && states[STATE].spio) {
23431da177e4SLinus Torvalds 			SETPORT(DMACNTRL0, 0);
23441da177e4SLinus Torvalds 			SETPORT(SXFRCTL0, CH1|SPIOEN);
23451da177e4SLinus Torvalds 			if(CURRENT_SC)
23461da177e4SLinus Torvalds 				CURRENT_SC->SCp.phase |= spiordy;
23471da177e4SLinus Torvalds 		}
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds 		/*
23501da177e4SLinus Torvalds 		 * initialize for new state
23511da177e4SLinus Torvalds 		 *
23521da177e4SLinus Torvalds 		 */
23531da177e4SLinus Torvalds 		if(PREVSTATE!=STATE && states[STATE].init)
23541da177e4SLinus Torvalds 			states[STATE].init(shpnt);
23551da177e4SLinus Torvalds 
23561da177e4SLinus Torvalds 		/*
23571da177e4SLinus Torvalds 		 * handle current state
23581da177e4SLinus Torvalds 		 *
23591da177e4SLinus Torvalds 		 */
23601da177e4SLinus Torvalds 		if(states[STATE].run)
23611da177e4SLinus Torvalds 			states[STATE].run(shpnt);
23621da177e4SLinus Torvalds 		else
2363f75ae8edSHannes Reinecke 			scmd_printk(KERN_ERR, CURRENT_SC,
2364f75ae8edSHannes Reinecke 				    "unexpected state (%x)\n", STATE);
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 		/*
23671da177e4SLinus Torvalds 		 * setup controller to interrupt on
23681da177e4SLinus Torvalds 		 * the next expected condition and
23691da177e4SLinus Torvalds 		 * loop if it's already there
23701da177e4SLinus Torvalds 		 *
23711da177e4SLinus Torvalds 		 */
23721da177e4SLinus Torvalds 		DO_LOCK(flags);
23731da177e4SLinus Torvalds 		pending=setup_expected_interrupts(shpnt);
23741da177e4SLinus Torvalds #if defined(AHA152X_STAT)
23751da177e4SLinus Torvalds 		HOSTDATA(shpnt)->count[STATE]++;
23761da177e4SLinus Torvalds 		if(PREVSTATE!=STATE)
23771da177e4SLinus Torvalds 			HOSTDATA(shpnt)->count_trans[STATE]++;
23781da177e4SLinus Torvalds 		HOSTDATA(shpnt)->time[STATE] += jiffies-start;
23791da177e4SLinus Torvalds #endif
23801da177e4SLinus Torvalds 
23811da177e4SLinus Torvalds 	} while(pending);
23821da177e4SLinus Torvalds 
23831da177e4SLinus Torvalds 	/*
23841da177e4SLinus Torvalds 	 * enable interrupts and leave bottom-half
23851da177e4SLinus Torvalds 	 *
23861da177e4SLinus Torvalds 	 */
23871da177e4SLinus Torvalds 	HOSTDATA(shpnt)->in_intr--;
23881da177e4SLinus Torvalds 	SETBITS(DMACNTRL0, INTEN);
23891da177e4SLinus Torvalds 	DO_UNLOCK(flags);
23901da177e4SLinus Torvalds }
23911da177e4SLinus Torvalds 
23921da177e4SLinus Torvalds 
23931da177e4SLinus Torvalds /*
23941da177e4SLinus Torvalds  * Dump the current driver status and panic
23951da177e4SLinus Torvalds  */
23961da177e4SLinus Torvalds static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
23971da177e4SLinus Torvalds {
2398f75ae8edSHannes Reinecke 	shost_printk(KERN_EMERG, shpnt, "%s\n", msg);
23991da177e4SLinus Torvalds 	show_queues(shpnt);
24001da177e4SLinus Torvalds 	panic("aha152x panic\n");
24011da177e4SLinus Torvalds }
24021da177e4SLinus Torvalds 
24031da177e4SLinus Torvalds /*
24041da177e4SLinus Torvalds  * display enabled interrupts
24051da177e4SLinus Torvalds  */
24061da177e4SLinus Torvalds static void disp_enintr(struct Scsi_Host *shpnt)
24071da177e4SLinus Torvalds {
2408f75ae8edSHannes Reinecke 	int s0, s1;
24091da177e4SLinus Torvalds 
2410f75ae8edSHannes Reinecke 	s0 = GETPORT(SIMODE0);
2411f75ae8edSHannes Reinecke 	s1 = GETPORT(SIMODE1);
24121da177e4SLinus Torvalds 
2413f75ae8edSHannes Reinecke 	shost_printk(KERN_DEBUG, shpnt,
2414f75ae8edSHannes Reinecke 		     "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
2415f75ae8edSHannes Reinecke 		     (s0 & ENSELDO) ? "ENSELDO " : "",
2416f75ae8edSHannes Reinecke 		     (s0 & ENSELDI) ? "ENSELDI " : "",
2417f75ae8edSHannes Reinecke 		     (s0 & ENSELINGO) ? "ENSELINGO " : "",
2418f75ae8edSHannes Reinecke 		     (s0 & ENSWRAP) ? "ENSWRAP " : "",
2419f75ae8edSHannes Reinecke 		     (s0 & ENSDONE) ? "ENSDONE " : "",
2420f75ae8edSHannes Reinecke 		     (s0 & ENSPIORDY) ? "ENSPIORDY " : "",
2421f75ae8edSHannes Reinecke 		     (s0 & ENDMADONE) ? "ENDMADONE " : "",
2422f75ae8edSHannes Reinecke 		     (s1 & ENSELTIMO) ? "ENSELTIMO " : "",
2423f75ae8edSHannes Reinecke 		     (s1 & ENATNTARG) ? "ENATNTARG " : "",
2424f75ae8edSHannes Reinecke 		     (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "",
2425f75ae8edSHannes Reinecke 		     (s1 & ENBUSFREE) ? "ENBUSFREE " : "",
2426f75ae8edSHannes Reinecke 		     (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "",
2427f75ae8edSHannes Reinecke 		     (s1 & ENPHASECHG) ? "ENPHASECHG " : "",
2428f75ae8edSHannes Reinecke 		     (s1 & ENREQINIT) ? "ENREQINIT " : "");
24291da177e4SLinus Torvalds }
24301da177e4SLinus Torvalds 
24311da177e4SLinus Torvalds /*
24321da177e4SLinus Torvalds  * Show the command data of a command
24331da177e4SLinus Torvalds  */
243491ebc1faSJohannes Thumshirn static void show_command(struct scsi_cmnd *ptr)
24351da177e4SLinus Torvalds {
2436f75ae8edSHannes Reinecke 	scsi_print_command(ptr);
2437f75ae8edSHannes Reinecke 	scmd_printk(KERN_DEBUG, ptr,
2438f75ae8edSHannes Reinecke 		    "request_bufflen=%d; resid=%d; "
2439f75ae8edSHannes Reinecke 		    "phase |%s%s%s%s%s%s%s%s%s; next=0x%p",
2440f75ae8edSHannes Reinecke 		    scsi_bufflen(ptr), scsi_get_resid(ptr),
2441f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & not_issued) ? "not issued|" : "",
2442f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & selecting) ? "selecting|" : "",
2443f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & identified) ? "identified|" : "",
2444f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & disconnected) ? "disconnected|" : "",
2445f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & completed) ? "completed|" : "",
2446f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & spiordy) ? "spiordy|" : "",
2447f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & syncneg) ? "syncneg|" : "",
2448f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & aborted) ? "aborted|" : "",
2449f75ae8edSHannes Reinecke 		    (ptr->SCp.phase & resetted) ? "resetted|" : "",
2450f75ae8edSHannes Reinecke 		    (SCDATA(ptr)) ? SCNEXT(ptr) : NULL);
24511da177e4SLinus Torvalds }
24521da177e4SLinus Torvalds 
24531da177e4SLinus Torvalds /*
24541da177e4SLinus Torvalds  * Dump the queued data
24551da177e4SLinus Torvalds  */
24561da177e4SLinus Torvalds static void show_queues(struct Scsi_Host *shpnt)
24571da177e4SLinus Torvalds {
245891ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr;
24591da177e4SLinus Torvalds 	unsigned long flags;
24601da177e4SLinus Torvalds 
24611da177e4SLinus Torvalds 	DO_LOCK(flags);
24621da177e4SLinus Torvalds 	printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
24631da177e4SLinus Torvalds 	for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
24641da177e4SLinus Torvalds 		show_command(ptr);
24651da177e4SLinus Torvalds 	DO_UNLOCK(flags);
24661da177e4SLinus Torvalds 
24671da177e4SLinus Torvalds 	printk(KERN_DEBUG "current_SC:\n");
24681da177e4SLinus Torvalds 	if (CURRENT_SC)
24691da177e4SLinus Torvalds 		show_command(CURRENT_SC);
24701da177e4SLinus Torvalds 	else
24711da177e4SLinus Torvalds 		printk(KERN_DEBUG "none\n");
24721da177e4SLinus Torvalds 
24731da177e4SLinus Torvalds 	printk(KERN_DEBUG "disconnected_SC:\n");
24741da177e4SLinus Torvalds 	for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
24751da177e4SLinus Torvalds 		show_command(ptr);
24761da177e4SLinus Torvalds 
24771da177e4SLinus Torvalds 	disp_enintr(shpnt);
24781da177e4SLinus Torvalds }
24791da177e4SLinus Torvalds 
248091ebc1faSJohannes Thumshirn static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
24811da177e4SLinus Torvalds {
24821da177e4SLinus Torvalds 	int i;
24831da177e4SLinus Torvalds 
24840c3de38fSRasmus Villemoes 	seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
24859cb78c16SHannes Reinecke 		ptr, ptr->device->id, (u8)ptr->device->lun);
24861da177e4SLinus Torvalds 
24871da177e4SLinus Torvalds 	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
24880c3de38fSRasmus Villemoes 		seq_printf(m, "0x%02x ", ptr->cmnd[i]);
24891da177e4SLinus Torvalds 
24900c3de38fSRasmus Villemoes 	seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
24912338545aSBoaz Harrosh 		scsi_get_resid(ptr), ptr->SCp.this_residual,
2492a7a253baSFinn Thain 		sg_nents(ptr->SCp.buffer) - 1);
24931da177e4SLinus Torvalds 
24941da177e4SLinus Torvalds 	if (ptr->SCp.phase & not_issued)
2495ee7c7277SRasmus Villemoes 		seq_puts(m, "not issued|");
24961da177e4SLinus Torvalds 	if (ptr->SCp.phase & selecting)
2497ee7c7277SRasmus Villemoes 		seq_puts(m, "selecting|");
24981da177e4SLinus Torvalds 	if (ptr->SCp.phase & disconnected)
2499ee7c7277SRasmus Villemoes 		seq_puts(m, "disconnected|");
25001da177e4SLinus Torvalds 	if (ptr->SCp.phase & aborted)
2501ee7c7277SRasmus Villemoes 		seq_puts(m, "aborted|");
25021da177e4SLinus Torvalds 	if (ptr->SCp.phase & identified)
2503ee7c7277SRasmus Villemoes 		seq_puts(m, "identified|");
25041da177e4SLinus Torvalds 	if (ptr->SCp.phase & completed)
2505ee7c7277SRasmus Villemoes 		seq_puts(m, "completed|");
25061da177e4SLinus Torvalds 	if (ptr->SCp.phase & spiordy)
2507ee7c7277SRasmus Villemoes 		seq_puts(m, "spiordy|");
25081da177e4SLinus Torvalds 	if (ptr->SCp.phase & syncneg)
2509ee7c7277SRasmus Villemoes 		seq_puts(m, "syncneg|");
25100c3de38fSRasmus Villemoes 	seq_printf(m, "; next=0x%p\n", SCNEXT(ptr));
25111da177e4SLinus Torvalds }
25121da177e4SLinus Torvalds 
2513275084cbSAl Viro static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
25141da177e4SLinus Torvalds {
25151da177e4SLinus Torvalds 	int s;
25161da177e4SLinus Torvalds 
25170c3de38fSRasmus Villemoes 	seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
25181da177e4SLinus Torvalds 
25191da177e4SLinus Torvalds 	s = GETPORT(SCSISEQ);
2520ee7c7277SRasmus Villemoes 	seq_puts(m, "SCSISEQ( ");
25211da177e4SLinus Torvalds 	if (s & TEMODEO)
2522ee7c7277SRasmus Villemoes 		seq_puts(m, "TARGET MODE ");
25231da177e4SLinus Torvalds 	if (s & ENSELO)
2524ee7c7277SRasmus Villemoes 		seq_puts(m, "SELO ");
25251da177e4SLinus Torvalds 	if (s & ENSELI)
2526ee7c7277SRasmus Villemoes 		seq_puts(m, "SELI ");
25271da177e4SLinus Torvalds 	if (s & ENRESELI)
2528ee7c7277SRasmus Villemoes 		seq_puts(m, "RESELI ");
25291da177e4SLinus Torvalds 	if (s & ENAUTOATNO)
2530ee7c7277SRasmus Villemoes 		seq_puts(m, "AUTOATNO ");
25311da177e4SLinus Torvalds 	if (s & ENAUTOATNI)
2532ee7c7277SRasmus Villemoes 		seq_puts(m, "AUTOATNI ");
25331da177e4SLinus Torvalds 	if (s & ENAUTOATNP)
2534ee7c7277SRasmus Villemoes 		seq_puts(m, "AUTOATNP ");
25351da177e4SLinus Torvalds 	if (s & SCSIRSTO)
2536ee7c7277SRasmus Villemoes 		seq_puts(m, "SCSIRSTO ");
2537ee7c7277SRasmus Villemoes 	seq_puts(m, ");");
25381da177e4SLinus Torvalds 
2539ee7c7277SRasmus Villemoes 	seq_puts(m, " SCSISIG(");
25401da177e4SLinus Torvalds 	s = GETPORT(SCSISIG);
25411da177e4SLinus Torvalds 	switch (s & P_MASK) {
25421da177e4SLinus Torvalds 	case P_DATAO:
2543ee7c7277SRasmus Villemoes 		seq_puts(m, "DATA OUT");
25441da177e4SLinus Torvalds 		break;
25451da177e4SLinus Torvalds 	case P_DATAI:
2546ee7c7277SRasmus Villemoes 		seq_puts(m, "DATA IN");
25471da177e4SLinus Torvalds 		break;
25481da177e4SLinus Torvalds 	case P_CMD:
2549ee7c7277SRasmus Villemoes 		seq_puts(m, "COMMAND");
25501da177e4SLinus Torvalds 		break;
25511da177e4SLinus Torvalds 	case P_STATUS:
2552ee7c7277SRasmus Villemoes 		seq_puts(m, "STATUS");
25531da177e4SLinus Torvalds 		break;
25541da177e4SLinus Torvalds 	case P_MSGO:
2555ee7c7277SRasmus Villemoes 		seq_puts(m, "MESSAGE OUT");
25561da177e4SLinus Torvalds 		break;
25571da177e4SLinus Torvalds 	case P_MSGI:
2558ee7c7277SRasmus Villemoes 		seq_puts(m, "MESSAGE IN");
25591da177e4SLinus Torvalds 		break;
25601da177e4SLinus Torvalds 	default:
2561ee7c7277SRasmus Villemoes 		seq_puts(m, "*invalid*");
25621da177e4SLinus Torvalds 		break;
25631da177e4SLinus Torvalds 	}
25641da177e4SLinus Torvalds 
2565ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
25661da177e4SLinus Torvalds 
25670c3de38fSRasmus Villemoes 	seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
25681da177e4SLinus Torvalds 
2569ee7c7277SRasmus Villemoes 	seq_puts(m, "SSTAT( ");
25701da177e4SLinus Torvalds 	s = GETPORT(SSTAT0);
25711da177e4SLinus Torvalds 	if (s & TARGET)
2572ee7c7277SRasmus Villemoes 		seq_puts(m, "TARGET ");
25731da177e4SLinus Torvalds 	if (s & SELDO)
2574ee7c7277SRasmus Villemoes 		seq_puts(m, "SELDO ");
25751da177e4SLinus Torvalds 	if (s & SELDI)
2576ee7c7277SRasmus Villemoes 		seq_puts(m, "SELDI ");
25771da177e4SLinus Torvalds 	if (s & SELINGO)
2578ee7c7277SRasmus Villemoes 		seq_puts(m, "SELINGO ");
25791da177e4SLinus Torvalds 	if (s & SWRAP)
2580ee7c7277SRasmus Villemoes 		seq_puts(m, "SWRAP ");
25811da177e4SLinus Torvalds 	if (s & SDONE)
2582ee7c7277SRasmus Villemoes 		seq_puts(m, "SDONE ");
25831da177e4SLinus Torvalds 	if (s & SPIORDY)
2584ee7c7277SRasmus Villemoes 		seq_puts(m, "SPIORDY ");
25851da177e4SLinus Torvalds 	if (s & DMADONE)
2586ee7c7277SRasmus Villemoes 		seq_puts(m, "DMADONE ");
25871da177e4SLinus Torvalds 
25881da177e4SLinus Torvalds 	s = GETPORT(SSTAT1);
25891da177e4SLinus Torvalds 	if (s & SELTO)
2590ee7c7277SRasmus Villemoes 		seq_puts(m, "SELTO ");
25911da177e4SLinus Torvalds 	if (s & ATNTARG)
2592ee7c7277SRasmus Villemoes 		seq_puts(m, "ATNTARG ");
25931da177e4SLinus Torvalds 	if (s & SCSIRSTI)
2594ee7c7277SRasmus Villemoes 		seq_puts(m, "SCSIRSTI ");
25951da177e4SLinus Torvalds 	if (s & PHASEMIS)
2596ee7c7277SRasmus Villemoes 		seq_puts(m, "PHASEMIS ");
25971da177e4SLinus Torvalds 	if (s & BUSFREE)
2598ee7c7277SRasmus Villemoes 		seq_puts(m, "BUSFREE ");
25991da177e4SLinus Torvalds 	if (s & SCSIPERR)
2600ee7c7277SRasmus Villemoes 		seq_puts(m, "SCSIPERR ");
26011da177e4SLinus Torvalds 	if (s & PHASECHG)
2602ee7c7277SRasmus Villemoes 		seq_puts(m, "PHASECHG ");
26031da177e4SLinus Torvalds 	if (s & REQINIT)
2604ee7c7277SRasmus Villemoes 		seq_puts(m, "REQINIT ");
2605ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
26061da177e4SLinus Torvalds 
26071da177e4SLinus Torvalds 
2608ee7c7277SRasmus Villemoes 	seq_puts(m, "SSTAT( ");
26091da177e4SLinus Torvalds 
26101da177e4SLinus Torvalds 	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
26111da177e4SLinus Torvalds 
26121da177e4SLinus Torvalds 	if (s & TARGET)
2613ee7c7277SRasmus Villemoes 		seq_puts(m, "TARGET ");
26141da177e4SLinus Torvalds 	if (s & SELDO)
2615ee7c7277SRasmus Villemoes 		seq_puts(m, "SELDO ");
26161da177e4SLinus Torvalds 	if (s & SELDI)
2617ee7c7277SRasmus Villemoes 		seq_puts(m, "SELDI ");
26181da177e4SLinus Torvalds 	if (s & SELINGO)
2619ee7c7277SRasmus Villemoes 		seq_puts(m, "SELINGO ");
26201da177e4SLinus Torvalds 	if (s & SWRAP)
2621ee7c7277SRasmus Villemoes 		seq_puts(m, "SWRAP ");
26221da177e4SLinus Torvalds 	if (s & SDONE)
2623ee7c7277SRasmus Villemoes 		seq_puts(m, "SDONE ");
26241da177e4SLinus Torvalds 	if (s & SPIORDY)
2625ee7c7277SRasmus Villemoes 		seq_puts(m, "SPIORDY ");
26261da177e4SLinus Torvalds 	if (s & DMADONE)
2627ee7c7277SRasmus Villemoes 		seq_puts(m, "DMADONE ");
26281da177e4SLinus Torvalds 
26291da177e4SLinus Torvalds 	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
26301da177e4SLinus Torvalds 
26311da177e4SLinus Torvalds 	if (s & SELTO)
2632ee7c7277SRasmus Villemoes 		seq_puts(m, "SELTO ");
26331da177e4SLinus Torvalds 	if (s & ATNTARG)
2634ee7c7277SRasmus Villemoes 		seq_puts(m, "ATNTARG ");
26351da177e4SLinus Torvalds 	if (s & SCSIRSTI)
2636ee7c7277SRasmus Villemoes 		seq_puts(m, "SCSIRSTI ");
26371da177e4SLinus Torvalds 	if (s & PHASEMIS)
2638ee7c7277SRasmus Villemoes 		seq_puts(m, "PHASEMIS ");
26391da177e4SLinus Torvalds 	if (s & BUSFREE)
2640ee7c7277SRasmus Villemoes 		seq_puts(m, "BUSFREE ");
26411da177e4SLinus Torvalds 	if (s & SCSIPERR)
2642ee7c7277SRasmus Villemoes 		seq_puts(m, "SCSIPERR ");
26431da177e4SLinus Torvalds 	if (s & PHASECHG)
2644ee7c7277SRasmus Villemoes 		seq_puts(m, "PHASECHG ");
26451da177e4SLinus Torvalds 	if (s & REQINIT)
2646ee7c7277SRasmus Villemoes 		seq_puts(m, "REQINIT ");
2647ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
26481da177e4SLinus Torvalds 
2649ee7c7277SRasmus Villemoes 	seq_puts(m, "SXFRCTL0( ");
26501da177e4SLinus Torvalds 
26511da177e4SLinus Torvalds 	s = GETPORT(SXFRCTL0);
26521da177e4SLinus Torvalds 	if (s & SCSIEN)
2653ee7c7277SRasmus Villemoes 		seq_puts(m, "SCSIEN ");
26541da177e4SLinus Torvalds 	if (s & DMAEN)
2655ee7c7277SRasmus Villemoes 		seq_puts(m, "DMAEN ");
26561da177e4SLinus Torvalds 	if (s & CH1)
2657ee7c7277SRasmus Villemoes 		seq_puts(m, "CH1 ");
26581da177e4SLinus Torvalds 	if (s & CLRSTCNT)
2659ee7c7277SRasmus Villemoes 		seq_puts(m, "CLRSTCNT ");
26601da177e4SLinus Torvalds 	if (s & SPIOEN)
2661ee7c7277SRasmus Villemoes 		seq_puts(m, "SPIOEN ");
26621da177e4SLinus Torvalds 	if (s & CLRCH1)
2663ee7c7277SRasmus Villemoes 		seq_puts(m, "CLRCH1 ");
2664ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
26651da177e4SLinus Torvalds 
2666ee7c7277SRasmus Villemoes 	seq_puts(m, "SIGNAL( ");
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 	s = GETPORT(SCSISIG);
26691da177e4SLinus Torvalds 	if (s & SIG_ATNI)
2670ee7c7277SRasmus Villemoes 		seq_puts(m, "ATNI ");
26711da177e4SLinus Torvalds 	if (s & SIG_SELI)
2672ee7c7277SRasmus Villemoes 		seq_puts(m, "SELI ");
26731da177e4SLinus Torvalds 	if (s & SIG_BSYI)
2674ee7c7277SRasmus Villemoes 		seq_puts(m, "BSYI ");
26751da177e4SLinus Torvalds 	if (s & SIG_REQI)
2676ee7c7277SRasmus Villemoes 		seq_puts(m, "REQI ");
26771da177e4SLinus Torvalds 	if (s & SIG_ACKI)
2678ee7c7277SRasmus Villemoes 		seq_puts(m, "ACKI ");
2679ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
26801da177e4SLinus Torvalds 
26810c3de38fSRasmus Villemoes 	seq_printf(m, "SELID(%02x), ", GETPORT(SELID));
26821da177e4SLinus Torvalds 
26830c3de38fSRasmus Villemoes 	seq_printf(m, "STCNT(%d), ", GETSTCNT());
26841da177e4SLinus Torvalds 
2685ee7c7277SRasmus Villemoes 	seq_puts(m, "SSTAT2( ");
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds 	s = GETPORT(SSTAT2);
26881da177e4SLinus Torvalds 	if (s & SOFFSET)
2689ee7c7277SRasmus Villemoes 		seq_puts(m, "SOFFSET ");
26901da177e4SLinus Torvalds 	if (s & SEMPTY)
2691ee7c7277SRasmus Villemoes 		seq_puts(m, "SEMPTY ");
26921da177e4SLinus Torvalds 	if (s & SFULL)
2693ee7c7277SRasmus Villemoes 		seq_puts(m, "SFULL ");
26940c3de38fSRasmus Villemoes 	seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT));
26951da177e4SLinus Torvalds 
26961da177e4SLinus Torvalds 	s = GETPORT(SSTAT3);
26970c3de38fSRasmus Villemoes 	seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
26981da177e4SLinus Torvalds 
2699ee7c7277SRasmus Villemoes 	seq_puts(m, "SSTAT4( ");
27001da177e4SLinus Torvalds 	s = GETPORT(SSTAT4);
27011da177e4SLinus Torvalds 	if (s & SYNCERR)
2702ee7c7277SRasmus Villemoes 		seq_puts(m, "SYNCERR ");
27031da177e4SLinus Torvalds 	if (s & FWERR)
2704ee7c7277SRasmus Villemoes 		seq_puts(m, "FWERR ");
27051da177e4SLinus Torvalds 	if (s & FRERR)
2706ee7c7277SRasmus Villemoes 		seq_puts(m, "FRERR ");
2707ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
27081da177e4SLinus Torvalds 
2709ee7c7277SRasmus Villemoes 	seq_puts(m, "DMACNTRL0( ");
27101da177e4SLinus Torvalds 	s = GETPORT(DMACNTRL0);
27110c3de38fSRasmus Villemoes 	seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT");
27120c3de38fSRasmus Villemoes 	seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO");
27130c3de38fSRasmus Villemoes 	seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ");
27141da177e4SLinus Torvalds 	if (s & ENDMA)
2715ee7c7277SRasmus Villemoes 		seq_puts(m, "ENDMA ");
27161da177e4SLinus Torvalds 	if (s & INTEN)
2717ee7c7277SRasmus Villemoes 		seq_puts(m, "INTEN ");
27181da177e4SLinus Torvalds 	if (s & RSTFIFO)
2719ee7c7277SRasmus Villemoes 		seq_puts(m, "RSTFIFO ");
27201da177e4SLinus Torvalds 	if (s & SWINT)
2721ee7c7277SRasmus Villemoes 		seq_puts(m, "SWINT ");
2722ee7c7277SRasmus Villemoes 	seq_puts(m, "); ");
27231da177e4SLinus Torvalds 
2724ee7c7277SRasmus Villemoes 	seq_puts(m, "DMASTAT( ");
27251da177e4SLinus Torvalds 	s = GETPORT(DMASTAT);
27261da177e4SLinus Torvalds 	if (s & ATDONE)
2727ee7c7277SRasmus Villemoes 		seq_puts(m, "ATDONE ");
27281da177e4SLinus Torvalds 	if (s & WORDRDY)
2729ee7c7277SRasmus Villemoes 		seq_puts(m, "WORDRDY ");
27301da177e4SLinus Torvalds 	if (s & DFIFOFULL)
2731ee7c7277SRasmus Villemoes 		seq_puts(m, "DFIFOFULL ");
27321da177e4SLinus Torvalds 	if (s & DFIFOEMP)
2733ee7c7277SRasmus Villemoes 		seq_puts(m, "DFIFOEMP ");
2734ee7c7277SRasmus Villemoes 	seq_puts(m, ")\n");
27351da177e4SLinus Torvalds 
2736ee7c7277SRasmus Villemoes 	seq_puts(m, "enabled interrupts( ");
27371da177e4SLinus Torvalds 
27381da177e4SLinus Torvalds 	s = GETPORT(SIMODE0);
27391da177e4SLinus Torvalds 	if (s & ENSELDO)
2740ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSELDO ");
27411da177e4SLinus Torvalds 	if (s & ENSELDI)
2742ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSELDI ");
27431da177e4SLinus Torvalds 	if (s & ENSELINGO)
2744ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSELINGO ");
27451da177e4SLinus Torvalds 	if (s & ENSWRAP)
2746ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSWRAP ");
27471da177e4SLinus Torvalds 	if (s & ENSDONE)
2748ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSDONE ");
27491da177e4SLinus Torvalds 	if (s & ENSPIORDY)
2750ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSPIORDY ");
27511da177e4SLinus Torvalds 	if (s & ENDMADONE)
2752ee7c7277SRasmus Villemoes 		seq_puts(m, "ENDMADONE ");
27531da177e4SLinus Torvalds 
27541da177e4SLinus Torvalds 	s = GETPORT(SIMODE1);
27551da177e4SLinus Torvalds 	if (s & ENSELTIMO)
2756ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSELTIMO ");
27571da177e4SLinus Torvalds 	if (s & ENATNTARG)
2758ee7c7277SRasmus Villemoes 		seq_puts(m, "ENATNTARG ");
27591da177e4SLinus Torvalds 	if (s & ENPHASEMIS)
2760ee7c7277SRasmus Villemoes 		seq_puts(m, "ENPHASEMIS ");
27611da177e4SLinus Torvalds 	if (s & ENBUSFREE)
2762ee7c7277SRasmus Villemoes 		seq_puts(m, "ENBUSFREE ");
27631da177e4SLinus Torvalds 	if (s & ENSCSIPERR)
2764ee7c7277SRasmus Villemoes 		seq_puts(m, "ENSCSIPERR ");
27651da177e4SLinus Torvalds 	if (s & ENPHASECHG)
2766ee7c7277SRasmus Villemoes 		seq_puts(m, "ENPHASECHG ");
27671da177e4SLinus Torvalds 	if (s & ENREQINIT)
2768ee7c7277SRasmus Villemoes 		seq_puts(m, "ENREQINIT ");
2769ee7c7277SRasmus Villemoes 	seq_puts(m, ")\n");
27701da177e4SLinus Torvalds }
27711da177e4SLinus Torvalds 
2772275084cbSAl Viro static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
27731da177e4SLinus Torvalds {
27741da177e4SLinus Torvalds 	if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
27751da177e4SLinus Torvalds 		return -EINVAL;
27761da177e4SLinus Torvalds 
27771da177e4SLinus Torvalds #if defined(AHA152X_STAT)
27781da177e4SLinus Torvalds 	if(length>13 && strncmp("reset", buffer+8, 5)==0) {
27791da177e4SLinus Torvalds 		int i;
27801da177e4SLinus Torvalds 
27811da177e4SLinus Torvalds 		HOSTDATA(shpnt)->total_commands=0;
27821da177e4SLinus Torvalds 		HOSTDATA(shpnt)->disconnections=0;
27831da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_any_action=0;
27841da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_old_command=0;
27851da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_new_command=0;
27861da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_done_command=0;
27871da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_with_check_condition=0;
27881da177e4SLinus Torvalds 		for (i = idle; i<maxstate; i++) {
27891da177e4SLinus Torvalds 			HOSTDATA(shpnt)->count[i]=0;
27901da177e4SLinus Torvalds 			HOSTDATA(shpnt)->count_trans[i]=0;
27911da177e4SLinus Torvalds 			HOSTDATA(shpnt)->time[i]=0;
27921da177e4SLinus Torvalds 		}
27931da177e4SLinus Torvalds 
2794f75ae8edSHannes Reinecke 		shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n");
27951da177e4SLinus Torvalds 
27961da177e4SLinus Torvalds 	} else
27971da177e4SLinus Torvalds #endif
27981da177e4SLinus Torvalds 	{
27991da177e4SLinus Torvalds 		return -EINVAL;
28001da177e4SLinus Torvalds 	}
28011da177e4SLinus Torvalds 
28021da177e4SLinus Torvalds 
28031da177e4SLinus Torvalds 	return length;
28041da177e4SLinus Torvalds }
28051da177e4SLinus Torvalds 
2806275084cbSAl Viro static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
28071da177e4SLinus Torvalds {
28081da177e4SLinus Torvalds 	int i;
280991ebc1faSJohannes Thumshirn 	struct scsi_cmnd *ptr;
28101da177e4SLinus Torvalds 	unsigned long flags;
28111da177e4SLinus Torvalds 
2812ee7c7277SRasmus Villemoes 	seq_puts(m, AHA152X_REVID "\n");
28131da177e4SLinus Torvalds 
28140c3de38fSRasmus Villemoes 	seq_printf(m, "ioports 0x%04lx to 0x%04lx\n",
28151da177e4SLinus Torvalds 		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
28160c3de38fSRasmus Villemoes 	seq_printf(m, "interrupt 0x%02x\n", shpnt->irq);
28170c3de38fSRasmus Villemoes 	seq_printf(m, "disconnection/reconnection %s\n",
28181da177e4SLinus Torvalds 		RECONNECT ? "enabled" : "disabled");
28190c3de38fSRasmus Villemoes 	seq_printf(m, "parity checking %s\n",
28201da177e4SLinus Torvalds 		PARITY ? "enabled" : "disabled");
28210c3de38fSRasmus Villemoes 	seq_printf(m, "synchronous transfers %s\n",
28221da177e4SLinus Torvalds 		SYNCHRONOUS ? "enabled" : "disabled");
28230c3de38fSRasmus Villemoes 	seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands);
28241da177e4SLinus Torvalds 
28251da177e4SLinus Torvalds 	if(SYNCHRONOUS) {
2826ee7c7277SRasmus Villemoes 		seq_puts(m, "synchronously operating targets (tick=50 ns):\n");
28271da177e4SLinus Torvalds 		for (i = 0; i < 8; i++)
28281da177e4SLinus Torvalds 			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
28290c3de38fSRasmus Villemoes 				seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n",
28301da177e4SLinus Torvalds 					i,
28311da177e4SLinus Torvalds 					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
28321da177e4SLinus Torvalds 					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
28331da177e4SLinus Torvalds 				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
28341da177e4SLinus Torvalds 	}
2835ee7c7277SRasmus Villemoes 	seq_puts(m, "\nqueue status:\n");
28361da177e4SLinus Torvalds 	DO_LOCK(flags);
28371da177e4SLinus Torvalds 	if (ISSUE_SC) {
2838ee7c7277SRasmus Villemoes 		seq_puts(m, "not yet issued commands:\n");
28391da177e4SLinus Torvalds 		for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
2840275084cbSAl Viro 			get_command(m, ptr);
28411da177e4SLinus Torvalds 	} else
2842ee7c7277SRasmus Villemoes 		seq_puts(m, "no not yet issued commands\n");
28431da177e4SLinus Torvalds 	DO_UNLOCK(flags);
28441da177e4SLinus Torvalds 
28451da177e4SLinus Torvalds 	if (CURRENT_SC) {
2846ee7c7277SRasmus Villemoes 		seq_puts(m, "current command:\n");
2847275084cbSAl Viro 		get_command(m, CURRENT_SC);
28481da177e4SLinus Torvalds 	} else
2849ee7c7277SRasmus Villemoes 		seq_puts(m, "no current command\n");
28501da177e4SLinus Torvalds 
28511da177e4SLinus Torvalds 	if (DISCONNECTED_SC) {
2852ee7c7277SRasmus Villemoes 		seq_puts(m, "disconnected commands:\n");
28531da177e4SLinus Torvalds 		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
2854275084cbSAl Viro 			get_command(m, ptr);
28551da177e4SLinus Torvalds 	} else
2856ee7c7277SRasmus Villemoes 		seq_puts(m, "no disconnected commands\n");
28571da177e4SLinus Torvalds 
2858275084cbSAl Viro 	get_ports(m, shpnt);
28591da177e4SLinus Torvalds 
28601da177e4SLinus Torvalds #if defined(AHA152X_STAT)
28610c3de38fSRasmus Villemoes 	seq_printf(m, "statistics:\n"
28621da177e4SLinus Torvalds 		"total commands:               %d\n"
28631da177e4SLinus Torvalds 		"disconnections:               %d\n"
28641da177e4SLinus Torvalds 		"busfree with check condition: %d\n"
28651da177e4SLinus Torvalds 		"busfree without old command:  %d\n"
28661da177e4SLinus Torvalds 		"busfree without new command:  %d\n"
28671da177e4SLinus Torvalds 		"busfree without done command: %d\n"
28681da177e4SLinus Torvalds 		"busfree without any action:   %d\n"
28691da177e4SLinus Torvalds 		"state      "
28701da177e4SLinus Torvalds 		"transitions  "
28711da177e4SLinus Torvalds 		"count        "
28721da177e4SLinus Torvalds 		"time\n",
28731da177e4SLinus Torvalds 		HOSTDATA(shpnt)->total_commands,
28741da177e4SLinus Torvalds 		HOSTDATA(shpnt)->disconnections,
28751da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_with_check_condition,
28761da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_old_command,
28771da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_new_command,
28781da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_done_command,
28791da177e4SLinus Torvalds 		HOSTDATA(shpnt)->busfree_without_any_action);
28801da177e4SLinus Torvalds 	for(i=0; i<maxstate; i++) {
28810c3de38fSRasmus Villemoes 		seq_printf(m, "%-10s %-12d %-12d %-12ld\n",
28821da177e4SLinus Torvalds 			states[i].name,
28831da177e4SLinus Torvalds 			HOSTDATA(shpnt)->count_trans[i],
28841da177e4SLinus Torvalds 			HOSTDATA(shpnt)->count[i],
28851da177e4SLinus Torvalds 			HOSTDATA(shpnt)->time[i]);
28861da177e4SLinus Torvalds 	}
28871da177e4SLinus Torvalds #endif
28881da177e4SLinus Torvalds 	return 0;
28891da177e4SLinus Torvalds }
28901da177e4SLinus Torvalds 
2891b1ee0795SBoaz Harrosh static int aha152x_adjust_queue(struct scsi_device *device)
2892b1ee0795SBoaz Harrosh {
2893b1ee0795SBoaz Harrosh 	blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
2894b1ee0795SBoaz Harrosh 	return 0;
2895b1ee0795SBoaz Harrosh }
2896b1ee0795SBoaz Harrosh 
2897d0be4a7dSChristoph Hellwig static struct scsi_host_template aha152x_driver_template = {
28981da177e4SLinus Torvalds 	.module				= THIS_MODULE,
28991da177e4SLinus Torvalds 	.name				= AHA152X_REVID,
29001da177e4SLinus Torvalds 	.proc_name			= "aha152x",
2901275084cbSAl Viro 	.show_info			= aha152x_show_info,
2902275084cbSAl Viro 	.write_info			= aha152x_set_info,
29031da177e4SLinus Torvalds 	.queuecommand			= aha152x_queue,
29041da177e4SLinus Torvalds 	.eh_abort_handler		= aha152x_abort,
29051da177e4SLinus Torvalds 	.eh_device_reset_handler	= aha152x_device_reset,
29061da177e4SLinus Torvalds 	.eh_bus_reset_handler		= aha152x_bus_reset,
29071da177e4SLinus Torvalds 	.bios_param			= aha152x_biosparam,
29081da177e4SLinus Torvalds 	.can_queue			= 1,
29091da177e4SLinus Torvalds 	.this_id			= 7,
29101da177e4SLinus Torvalds 	.sg_tablesize			= SG_ALL,
29114af14d11SChristoph Hellwig 	.dma_boundary			= PAGE_SIZE - 1,
2912b1ee0795SBoaz Harrosh 	.slave_alloc			= aha152x_adjust_queue,
29131da177e4SLinus Torvalds };
29141da177e4SLinus Torvalds 
29153eb2ebcbSChristoph Hellwig #if !defined(AHA152X_PCMCIA)
29161da177e4SLinus Torvalds static int setup_count;
29171da177e4SLinus Torvalds static struct aha152x_setup setup[2];
29181da177e4SLinus Torvalds 
29191da177e4SLinus Torvalds /* possible i/o addresses for the AIC-6260; default first */
29201da177e4SLinus Torvalds static unsigned short ports[] = { 0x340, 0x140 };
29211da177e4SLinus Torvalds 
29221da177e4SLinus Torvalds #if !defined(SKIP_BIOSTEST)
29231da177e4SLinus Torvalds /* possible locations for the Adaptec BIOS; defaults first */
29241da177e4SLinus Torvalds static unsigned int addresses[] =
29251da177e4SLinus Torvalds {
29261da177e4SLinus Torvalds 	0xdc000,		/* default first */
29271da177e4SLinus Torvalds 	0xc8000,
29281da177e4SLinus Torvalds 	0xcc000,
29291da177e4SLinus Torvalds 	0xd0000,
29301da177e4SLinus Torvalds 	0xd4000,
29311da177e4SLinus Torvalds 	0xd8000,
29321da177e4SLinus Torvalds 	0xe0000,
29331da177e4SLinus Torvalds 	0xeb800,		/* VTech Platinum SMP */
29341da177e4SLinus Torvalds 	0xf0000,
29351da177e4SLinus Torvalds };
29361da177e4SLinus Torvalds 
29371da177e4SLinus Torvalds /* signatures for various AIC-6[23]60 based controllers.
29381da177e4SLinus Torvalds    The point in detecting signatures is to avoid useless and maybe
29391da177e4SLinus Torvalds    harmful probes on ports. I'm not sure that all listed boards pass
29401da177e4SLinus Torvalds    auto-configuration. For those which fail the BIOS signature is
29411da177e4SLinus Torvalds    obsolete, because user intervention to supply the configuration is
29421da177e4SLinus Torvalds    needed anyway.  May be an information whether or not the BIOS supports
29431da177e4SLinus Torvalds    extended translation could be also useful here. */
29441da177e4SLinus Torvalds static struct signature {
29451da177e4SLinus Torvalds 	unsigned char *signature;
29461da177e4SLinus Torvalds 	int sig_offset;
29471da177e4SLinus Torvalds 	int sig_length;
29481da177e4SLinus Torvalds } signatures[] =
29491da177e4SLinus Torvalds {
29501da177e4SLinus Torvalds 	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
29511da177e4SLinus Torvalds 		/* Adaptec 152x */
29521da177e4SLinus Torvalds 	{ "Adaptec AHA-1520B",		0x000b, 17 },
29531da177e4SLinus Torvalds 		/* Adaptec 152x rev B */
29541da177e4SLinus Torvalds 	{ "Adaptec AHA-1520B",		0x0026, 17 },
29551da177e4SLinus Torvalds 		/* Iomega Jaz Jet ISA (AIC6370Q) */
29561da177e4SLinus Torvalds 	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
29571da177e4SLinus Torvalds 		/* on-board controller */
29581da177e4SLinus Torvalds 	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
29591da177e4SLinus Torvalds 		/* on-board controller */
29601da177e4SLinus Torvalds 	{ "Adaptec ASW-B626 S2",	0x2e6c, 19 },
29611da177e4SLinus Torvalds 		/* on-board controller */
29621da177e4SLinus Torvalds 	{ "Adaptec BIOS:AIC-6360",	0x000c, 21 },
29631da177e4SLinus Torvalds 		/* on-board controller */
29641da177e4SLinus Torvalds 	{ "ScsiPro SP-360 BIOS",	0x2873, 19 },
29651da177e4SLinus Torvalds 		/* ScsiPro-Controller  */
29661da177e4SLinus Torvalds 	{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
29671da177e4SLinus Torvalds 		/* Gigabyte Local-Bus-SCSI */
29681da177e4SLinus Torvalds 	{ "Adaptec BIOS:AVA-282X",	0x000c, 21 },
29691da177e4SLinus Torvalds 		/* Adaptec 282x */
29701da177e4SLinus Torvalds 	{ "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
29711da177e4SLinus Torvalds 		/* IBM Thinkpad Dock II */
29721da177e4SLinus Torvalds 	{ "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
29731da177e4SLinus Torvalds 		/* IBM Thinkpad Dock II SCSI */
29741da177e4SLinus Torvalds 	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
29751da177e4SLinus Torvalds 		/* DTC 3520A ISA SCSI */
29761da177e4SLinus Torvalds };
29771da177e4SLinus Torvalds #endif /* !SKIP_BIOSTEST */
29781da177e4SLinus Torvalds 
29791da177e4SLinus Torvalds /*
29801da177e4SLinus Torvalds  * Test, if port_base is valid.
29811da177e4SLinus Torvalds  *
29821da177e4SLinus Torvalds  */
29831da177e4SLinus Torvalds static int aha152x_porttest(int io_port)
29841da177e4SLinus Torvalds {
29851da177e4SLinus Torvalds 	int i;
29861da177e4SLinus Torvalds 
29871da177e4SLinus Torvalds 	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
29881da177e4SLinus Torvalds 	for (i = 0; i < 16; i++)
29891da177e4SLinus Torvalds 		SETPORT(io_port + O_STACK, i);
29901da177e4SLinus Torvalds 
29911da177e4SLinus Torvalds 	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
29921da177e4SLinus Torvalds 	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
29931da177e4SLinus Torvalds 		;
29941da177e4SLinus Torvalds 
29951da177e4SLinus Torvalds 	return (i == 16);
29961da177e4SLinus Torvalds }
29971da177e4SLinus Torvalds 
29981da177e4SLinus Torvalds static int tc1550_porttest(int io_port)
29991da177e4SLinus Torvalds {
30001da177e4SLinus Torvalds 	int i;
30011da177e4SLinus Torvalds 
30021da177e4SLinus Torvalds 	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
30031da177e4SLinus Torvalds 	for (i = 0; i < 16; i++)
30041da177e4SLinus Torvalds 		SETPORT(io_port + O_STACK, i);
30051da177e4SLinus Torvalds 
30061da177e4SLinus Torvalds 	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
30071da177e4SLinus Torvalds 	for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
30081da177e4SLinus Torvalds 		;
30091da177e4SLinus Torvalds 
30101da177e4SLinus Torvalds 	return (i == 16);
30111da177e4SLinus Torvalds }
30121da177e4SLinus Torvalds 
30131da177e4SLinus Torvalds 
30141da177e4SLinus Torvalds static int checksetup(struct aha152x_setup *setup)
30151da177e4SLinus Torvalds {
30161da177e4SLinus Torvalds 	int i;
30171da177e4SLinus Torvalds 	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
30181da177e4SLinus Torvalds 		;
30191da177e4SLinus Torvalds 
30201da177e4SLinus Torvalds 	if (i == ARRAY_SIZE(ports))
30211da177e4SLinus Torvalds 		return 0;
30221da177e4SLinus Torvalds 
30239bcf0910SHarvey Harrison 	if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
30241da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
30251da177e4SLinus Torvalds 		return 0;
30261da177e4SLinus Torvalds 	}
30271da177e4SLinus Torvalds 
30281da177e4SLinus Torvalds 	if( aha152x_porttest(setup->io_port) ) {
30291da177e4SLinus Torvalds 		setup->tc1550=0;
30301da177e4SLinus Torvalds 	} else if( tc1550_porttest(setup->io_port) ) {
30311da177e4SLinus Torvalds 		setup->tc1550=1;
30321da177e4SLinus Torvalds 	} else {
30331da177e4SLinus Torvalds 		release_region(setup->io_port, IO_RANGE);
30341da177e4SLinus Torvalds 		return 0;
30351da177e4SLinus Torvalds 	}
30361da177e4SLinus Torvalds 
30371da177e4SLinus Torvalds 	release_region(setup->io_port, IO_RANGE);
30381da177e4SLinus Torvalds 
30391da177e4SLinus Torvalds 	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
30401da177e4SLinus Torvalds 		return 0;
30411da177e4SLinus Torvalds 
30421da177e4SLinus Torvalds 	if ((setup->scsiid < 0) || (setup->scsiid > 7))
30431da177e4SLinus Torvalds 		return 0;
30441da177e4SLinus Torvalds 
30451da177e4SLinus Torvalds 	if ((setup->reconnect < 0) || (setup->reconnect > 1))
30461da177e4SLinus Torvalds 		return 0;
30471da177e4SLinus Torvalds 
30481da177e4SLinus Torvalds 	if ((setup->parity < 0) || (setup->parity > 1))
30491da177e4SLinus Torvalds 		return 0;
30501da177e4SLinus Torvalds 
30511da177e4SLinus Torvalds 	if ((setup->synchronous < 0) || (setup->synchronous > 1))
30521da177e4SLinus Torvalds 		return 0;
30531da177e4SLinus Torvalds 
30541da177e4SLinus Torvalds 	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
30551da177e4SLinus Torvalds 		return 0;
30561da177e4SLinus Torvalds 
30571da177e4SLinus Torvalds 
30581da177e4SLinus Torvalds 	return 1;
30591da177e4SLinus Torvalds }
30601da177e4SLinus Torvalds 
30611da177e4SLinus Torvalds 
30621da177e4SLinus Torvalds static int __init aha152x_init(void)
30631da177e4SLinus Torvalds {
30641da177e4SLinus Torvalds 	int i, j, ok;
30651da177e4SLinus Torvalds #if defined(AUTOCONF)
30661da177e4SLinus Torvalds 	aha152x_config conf;
30671da177e4SLinus Torvalds #endif
30681da177e4SLinus Torvalds #ifdef __ISAPNP__
30691da177e4SLinus Torvalds 	struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
30701da177e4SLinus Torvalds #endif
30711da177e4SLinus Torvalds 
30721da177e4SLinus Torvalds 	if ( setup_count ) {
30731da177e4SLinus Torvalds 		printk(KERN_INFO "aha152x: processing commandline: ");
30741da177e4SLinus Torvalds 
30751da177e4SLinus Torvalds 		for (i = 0; i<setup_count; i++) {
30761da177e4SLinus Torvalds 			if (!checksetup(&setup[i])) {
30771da177e4SLinus Torvalds 				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
30781da177e4SLinus Torvalds 				printk(KERN_ERR "aha152x: invalid line\n");
30791da177e4SLinus Torvalds 			}
30801da177e4SLinus Torvalds 		}
30811da177e4SLinus Torvalds 		printk("ok\n");
30821da177e4SLinus Torvalds 	}
30831da177e4SLinus Torvalds 
30841da177e4SLinus Torvalds #if defined(SETUP0)
30851da177e4SLinus Torvalds 	if (setup_count < ARRAY_SIZE(setup)) {
30861da177e4SLinus Torvalds 		struct aha152x_setup override = SETUP0;
30871da177e4SLinus Torvalds 
30881da177e4SLinus Torvalds 		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
30891da177e4SLinus Torvalds 			if (!checksetup(&override)) {
30901da177e4SLinus Torvalds 				printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
30911da177e4SLinus Torvalds 				       override.io_port,
30921da177e4SLinus Torvalds 				       override.irq,
30931da177e4SLinus Torvalds 				       override.scsiid,
30941da177e4SLinus Torvalds 				       override.reconnect,
30951da177e4SLinus Torvalds 				       override.parity,
30961da177e4SLinus Torvalds 				       override.synchronous,
30971da177e4SLinus Torvalds 				       override.delay,
30981da177e4SLinus Torvalds 				       override.ext_trans);
30991da177e4SLinus Torvalds 			} else
31001da177e4SLinus Torvalds 				setup[setup_count++] = override;
31011da177e4SLinus Torvalds 		}
31021da177e4SLinus Torvalds 	}
31031da177e4SLinus Torvalds #endif
31041da177e4SLinus Torvalds 
31051da177e4SLinus Torvalds #if defined(SETUP1)
31061da177e4SLinus Torvalds 	if (setup_count < ARRAY_SIZE(setup)) {
31071da177e4SLinus Torvalds 		struct aha152x_setup override = SETUP1;
31081da177e4SLinus Torvalds 
31091da177e4SLinus Torvalds 		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
31101da177e4SLinus Torvalds 			if (!checksetup(&override)) {
31111da177e4SLinus Torvalds 				printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
31121da177e4SLinus Torvalds 				       override.io_port,
31131da177e4SLinus Torvalds 				       override.irq,
31141da177e4SLinus Torvalds 				       override.scsiid,
31151da177e4SLinus Torvalds 				       override.reconnect,
31161da177e4SLinus Torvalds 				       override.parity,
31171da177e4SLinus Torvalds 				       override.synchronous,
31181da177e4SLinus Torvalds 				       override.delay,
31191da177e4SLinus Torvalds 				       override.ext_trans);
31201da177e4SLinus Torvalds 			} else
31211da177e4SLinus Torvalds 				setup[setup_count++] = override;
31221da177e4SLinus Torvalds 		}
31231da177e4SLinus Torvalds 	}
31241da177e4SLinus Torvalds #endif
31251da177e4SLinus Torvalds 
31261da177e4SLinus Torvalds #if defined(MODULE)
31271da177e4SLinus Torvalds 	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
31281da177e4SLinus Torvalds 		if(aha152x[0]!=0) {
31291da177e4SLinus Torvalds 			setup[setup_count].conf        = "";
31301da177e4SLinus Torvalds 			setup[setup_count].io_port     = aha152x[0];
31311da177e4SLinus Torvalds 			setup[setup_count].irq         = aha152x[1];
31321da177e4SLinus Torvalds 			setup[setup_count].scsiid      = aha152x[2];
31331da177e4SLinus Torvalds 			setup[setup_count].reconnect   = aha152x[3];
31341da177e4SLinus Torvalds 			setup[setup_count].parity      = aha152x[4];
31351da177e4SLinus Torvalds 			setup[setup_count].synchronous = aha152x[5];
31361da177e4SLinus Torvalds 			setup[setup_count].delay       = aha152x[6];
31371da177e4SLinus Torvalds 			setup[setup_count].ext_trans   = aha152x[7];
31381da177e4SLinus Torvalds 		} else if (io[0] != 0 || irq[0] != 0) {
31391da177e4SLinus Torvalds 			if(io[0]!=0)  setup[setup_count].io_port = io[0];
31401da177e4SLinus Torvalds 			if(irq[0]!=0) setup[setup_count].irq     = irq[0];
31411da177e4SLinus Torvalds 
31421da177e4SLinus Torvalds 			setup[setup_count].scsiid      = scsiid[0];
31431da177e4SLinus Torvalds 			setup[setup_count].reconnect   = reconnect[0];
31441da177e4SLinus Torvalds 			setup[setup_count].parity      = parity[0];
31451da177e4SLinus Torvalds 			setup[setup_count].synchronous = sync[0];
31461da177e4SLinus Torvalds 			setup[setup_count].delay       = delay[0];
31471da177e4SLinus Torvalds 			setup[setup_count].ext_trans   = exttrans[0];
31481da177e4SLinus Torvalds 		}
31491da177e4SLinus Torvalds 
31501da177e4SLinus Torvalds 		if (checksetup(&setup[setup_count]))
31511da177e4SLinus Torvalds 			setup_count++;
31521da177e4SLinus Torvalds 		else
31531da177e4SLinus Torvalds 			printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
31541da177e4SLinus Torvalds 			       setup[setup_count].io_port,
31551da177e4SLinus Torvalds 			       setup[setup_count].irq,
31561da177e4SLinus Torvalds 			       setup[setup_count].scsiid,
31571da177e4SLinus Torvalds 			       setup[setup_count].reconnect,
31581da177e4SLinus Torvalds 			       setup[setup_count].parity,
31591da177e4SLinus Torvalds 			       setup[setup_count].synchronous,
31601da177e4SLinus Torvalds 			       setup[setup_count].delay,
31611da177e4SLinus Torvalds 			       setup[setup_count].ext_trans);
31621da177e4SLinus Torvalds 	}
31631da177e4SLinus Torvalds 
31641da177e4SLinus Torvalds 	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
31651da177e4SLinus Torvalds 		if(aha152x1[0]!=0) {
31661da177e4SLinus Torvalds 			setup[setup_count].conf        = "";
31671da177e4SLinus Torvalds 			setup[setup_count].io_port     = aha152x1[0];
31681da177e4SLinus Torvalds 			setup[setup_count].irq         = aha152x1[1];
31691da177e4SLinus Torvalds 			setup[setup_count].scsiid      = aha152x1[2];
31701da177e4SLinus Torvalds 			setup[setup_count].reconnect   = aha152x1[3];
31711da177e4SLinus Torvalds 			setup[setup_count].parity      = aha152x1[4];
31721da177e4SLinus Torvalds 			setup[setup_count].synchronous = aha152x1[5];
31731da177e4SLinus Torvalds 			setup[setup_count].delay       = aha152x1[6];
31741da177e4SLinus Torvalds 			setup[setup_count].ext_trans   = aha152x1[7];
31751da177e4SLinus Torvalds 		} else if (io[1] != 0 || irq[1] != 0) {
31761da177e4SLinus Torvalds 			if(io[1]!=0)  setup[setup_count].io_port = io[1];
31771da177e4SLinus Torvalds 			if(irq[1]!=0) setup[setup_count].irq     = irq[1];
31781da177e4SLinus Torvalds 
31791da177e4SLinus Torvalds 			setup[setup_count].scsiid      = scsiid[1];
31801da177e4SLinus Torvalds 			setup[setup_count].reconnect   = reconnect[1];
31811da177e4SLinus Torvalds 			setup[setup_count].parity      = parity[1];
31821da177e4SLinus Torvalds 			setup[setup_count].synchronous = sync[1];
31831da177e4SLinus Torvalds 			setup[setup_count].delay       = delay[1];
31841da177e4SLinus Torvalds 			setup[setup_count].ext_trans   = exttrans[1];
31851da177e4SLinus Torvalds 		}
31861da177e4SLinus Torvalds 		if (checksetup(&setup[setup_count]))
31871da177e4SLinus Torvalds 			setup_count++;
31881da177e4SLinus Torvalds 		else
31891da177e4SLinus Torvalds 			printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
31901da177e4SLinus Torvalds 			       setup[setup_count].io_port,
31911da177e4SLinus Torvalds 			       setup[setup_count].irq,
31921da177e4SLinus Torvalds 			       setup[setup_count].scsiid,
31931da177e4SLinus Torvalds 			       setup[setup_count].reconnect,
31941da177e4SLinus Torvalds 			       setup[setup_count].parity,
31951da177e4SLinus Torvalds 			       setup[setup_count].synchronous,
31961da177e4SLinus Torvalds 			       setup[setup_count].delay,
31971da177e4SLinus Torvalds 			       setup[setup_count].ext_trans);
31981da177e4SLinus Torvalds 	}
31991da177e4SLinus Torvalds #endif
32001da177e4SLinus Torvalds 
32011da177e4SLinus Torvalds #ifdef __ISAPNP__
32021da177e4SLinus Torvalds 	for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
32031da177e4SLinus Torvalds 		while ( setup_count<ARRAY_SIZE(setup) &&
32041da177e4SLinus Torvalds 			(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
32051da177e4SLinus Torvalds 			if (pnp_device_attach(dev) < 0)
32061da177e4SLinus Torvalds 				continue;
32071da177e4SLinus Torvalds 
32081da177e4SLinus Torvalds 			if (pnp_activate_dev(dev) < 0) {
32091da177e4SLinus Torvalds 				pnp_device_detach(dev);
32101da177e4SLinus Torvalds 				continue;
32111da177e4SLinus Torvalds 			}
32121da177e4SLinus Torvalds 
32131da177e4SLinus Torvalds 			if (!pnp_port_valid(dev, 0)) {
32141da177e4SLinus Torvalds 				pnp_device_detach(dev);
32151da177e4SLinus Torvalds 				continue;
32161da177e4SLinus Torvalds 			}
32171da177e4SLinus Torvalds 
32181da177e4SLinus Torvalds 			if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
32191da177e4SLinus Torvalds 				pnp_device_detach(dev);
32201da177e4SLinus Torvalds 				continue;
32211da177e4SLinus Torvalds 			}
32221da177e4SLinus Torvalds 
32231da177e4SLinus Torvalds 			setup[setup_count].io_port     = pnp_port_start(dev, 0);
32241da177e4SLinus Torvalds 			setup[setup_count].irq         = pnp_irq(dev, 0);
32251da177e4SLinus Torvalds 			setup[setup_count].scsiid      = 7;
32261da177e4SLinus Torvalds 			setup[setup_count].reconnect   = 1;
32271da177e4SLinus Torvalds 			setup[setup_count].parity      = 1;
32281da177e4SLinus Torvalds 			setup[setup_count].synchronous = 1;
32291da177e4SLinus Torvalds 			setup[setup_count].delay       = DELAY_DEFAULT;
32301da177e4SLinus Torvalds 			setup[setup_count].ext_trans   = 0;
32311da177e4SLinus Torvalds #if defined(__ISAPNP__)
32321da177e4SLinus Torvalds 			pnpdev[setup_count]            = dev;
32331da177e4SLinus Torvalds #endif
32341da177e4SLinus Torvalds 			printk (KERN_INFO
32351da177e4SLinus Torvalds 				"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
32361da177e4SLinus Torvalds 				setup[setup_count].io_port, setup[setup_count].irq);
32371da177e4SLinus Torvalds 			setup_count++;
32381da177e4SLinus Torvalds 		}
32391da177e4SLinus Torvalds 	}
32401da177e4SLinus Torvalds #endif
32411da177e4SLinus Torvalds 
32421da177e4SLinus Torvalds #if defined(AUTOCONF)
32431da177e4SLinus Torvalds 	if (setup_count<ARRAY_SIZE(setup)) {
32441da177e4SLinus Torvalds #if !defined(SKIP_BIOSTEST)
32451da177e4SLinus Torvalds 		ok = 0;
32461da177e4SLinus Torvalds 		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
32471da177e4SLinus Torvalds 			void __iomem *p = ioremap(addresses[i], 0x4000);
32481da177e4SLinus Torvalds 			if (!p)
32491da177e4SLinus Torvalds 				continue;
32501da177e4SLinus Torvalds 			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
32511da177e4SLinus Torvalds 				ok = check_signature(p + signatures[j].sig_offset,
32521da177e4SLinus Torvalds 								signatures[j].signature, signatures[j].sig_length);
32531da177e4SLinus Torvalds 			iounmap(p);
32541da177e4SLinus Torvalds 		}
32551da177e4SLinus Torvalds 		if (!ok && setup_count == 0)
3256ad2fa42dSJames Bottomley 			return -ENODEV;
32571da177e4SLinus Torvalds 
32581da177e4SLinus Torvalds 		printk(KERN_INFO "aha152x: BIOS test: passed, ");
32591da177e4SLinus Torvalds #else
32601da177e4SLinus Torvalds 		printk(KERN_INFO "aha152x: ");
32611da177e4SLinus Torvalds #endif				/* !SKIP_BIOSTEST */
32621da177e4SLinus Torvalds 
32631da177e4SLinus Torvalds 		ok = 0;
32641da177e4SLinus Torvalds 		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
32651da177e4SLinus Torvalds 			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
32661da177e4SLinus Torvalds 				continue;
32671da177e4SLinus Torvalds 
32689bcf0910SHarvey Harrison 			if (!request_region(ports[i], IO_RANGE, "aha152x")) {
32691da177e4SLinus Torvalds 				printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
32701da177e4SLinus Torvalds 				continue;
32711da177e4SLinus Torvalds 			}
32721da177e4SLinus Torvalds 
32731da177e4SLinus Torvalds 			if (aha152x_porttest(ports[i])) {
32741da177e4SLinus Torvalds 				setup[setup_count].tc1550  = 0;
32751da177e4SLinus Torvalds 
32761da177e4SLinus Torvalds 				conf.cf_port =
32771da177e4SLinus Torvalds 				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
32781da177e4SLinus Torvalds 			} else if (tc1550_porttest(ports[i])) {
32791da177e4SLinus Torvalds 				setup[setup_count].tc1550  = 1;
32801da177e4SLinus Torvalds 
32811da177e4SLinus Torvalds 				conf.cf_port =
32821da177e4SLinus Torvalds 				    (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
32831da177e4SLinus Torvalds 			} else {
32841da177e4SLinus Torvalds 				release_region(ports[i], IO_RANGE);
32851da177e4SLinus Torvalds 				continue;
32861da177e4SLinus Torvalds 			}
32871da177e4SLinus Torvalds 
32881da177e4SLinus Torvalds 			release_region(ports[i], IO_RANGE);
32891da177e4SLinus Torvalds 
32901da177e4SLinus Torvalds 			ok++;
32911da177e4SLinus Torvalds 			setup[setup_count].io_port = ports[i];
32921da177e4SLinus Torvalds 			setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
32931da177e4SLinus Torvalds 			setup[setup_count].scsiid = conf.cf_id;
32941da177e4SLinus Torvalds 			setup[setup_count].reconnect = conf.cf_tardisc;
32951da177e4SLinus Torvalds 			setup[setup_count].parity = !conf.cf_parity;
32961da177e4SLinus Torvalds 			setup[setup_count].synchronous = conf.cf_syncneg;
32971da177e4SLinus Torvalds 			setup[setup_count].delay = DELAY_DEFAULT;
32981da177e4SLinus Torvalds 			setup[setup_count].ext_trans = 0;
32991da177e4SLinus Torvalds 			setup_count++;
33001da177e4SLinus Torvalds 
33011da177e4SLinus Torvalds 		}
33021da177e4SLinus Torvalds 
33031da177e4SLinus Torvalds 		if (ok)
33041da177e4SLinus Torvalds 			printk("auto configuration: ok, ");
33051da177e4SLinus Torvalds 	}
33061da177e4SLinus Torvalds #endif
33071da177e4SLinus Torvalds 
33081da177e4SLinus Torvalds 	printk("%d controller(s) configured\n", setup_count);
33091da177e4SLinus Torvalds 
33101da177e4SLinus Torvalds 	for (i=0; i<setup_count; i++) {
33111da177e4SLinus Torvalds 		if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
33121da177e4SLinus Torvalds 			struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
33131da177e4SLinus Torvalds 
33141da177e4SLinus Torvalds 			if( !shpnt ) {
33151da177e4SLinus Torvalds 				release_region(setup[i].io_port, IO_RANGE);
33161da177e4SLinus Torvalds #if defined(__ISAPNP__)
33171da177e4SLinus Torvalds 			} else if( pnpdev[i] ) {
33181da177e4SLinus Torvalds 				HOSTDATA(shpnt)->pnpdev=pnpdev[i];
33191da177e4SLinus Torvalds 				pnpdev[i]=NULL;
33201da177e4SLinus Torvalds #endif
33211da177e4SLinus Torvalds 			}
33221da177e4SLinus Torvalds 		} else {
33231da177e4SLinus Torvalds 			printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
33241da177e4SLinus Torvalds 		}
33251da177e4SLinus Torvalds 
33261da177e4SLinus Torvalds #if defined(__ISAPNP__)
33271da177e4SLinus Torvalds 		if( pnpdev[i] )
33281da177e4SLinus Torvalds 			pnp_device_detach(pnpdev[i]);
33291da177e4SLinus Torvalds #endif
33301da177e4SLinus Torvalds 	}
33311da177e4SLinus Torvalds 
3332ad2fa42dSJames Bottomley 	return 0;
33331da177e4SLinus Torvalds }
33341da177e4SLinus Torvalds 
33351da177e4SLinus Torvalds static void __exit aha152x_exit(void)
33361da177e4SLinus Torvalds {
333764976a03SJames Bottomley 	struct aha152x_hostdata *hd, *tmp;
33381da177e4SLinus Torvalds 
333964976a03SJames Bottomley 	list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
33405fcda422SJames Bottomley 		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
33415fcda422SJames Bottomley 
33425fcda422SJames Bottomley 		aha152x_release(shost);
33431da177e4SLinus Torvalds 	}
33441da177e4SLinus Torvalds }
33451da177e4SLinus Torvalds 
33461da177e4SLinus Torvalds module_init(aha152x_init);
33471da177e4SLinus Torvalds module_exit(aha152x_exit);
33481da177e4SLinus Torvalds 
33491da177e4SLinus Torvalds #if !defined(MODULE)
33501da177e4SLinus Torvalds static int __init aha152x_setup(char *str)
33511da177e4SLinus Torvalds {
33521da177e4SLinus Torvalds 	int ints[10];
3353f75ae8edSHannes Reinecke 
33541da177e4SLinus Torvalds 	get_options(str, ARRAY_SIZE(ints), ints);
33551da177e4SLinus Torvalds 
33561da177e4SLinus Torvalds 	if(setup_count>=ARRAY_SIZE(setup)) {
33571da177e4SLinus Torvalds 		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
33581da177e4SLinus Torvalds 		return 1;
33591da177e4SLinus Torvalds 	}
33601da177e4SLinus Torvalds 
33611da177e4SLinus Torvalds 	setup[setup_count].conf        = str;
33621da177e4SLinus Torvalds 	setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
33631da177e4SLinus Torvalds 	setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
33641da177e4SLinus Torvalds 	setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
33651da177e4SLinus Torvalds 	setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
33661da177e4SLinus Torvalds 	setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
33671da177e4SLinus Torvalds 	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
33681da177e4SLinus Torvalds 	setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
33691da177e4SLinus Torvalds 	setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
33701da177e4SLinus Torvalds 	if (ints[0] > 8) {                                                /*}*/
33711da177e4SLinus Torvalds 		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
33721da177e4SLinus Torvalds 		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
33731da177e4SLinus Torvalds 	} else {
33741da177e4SLinus Torvalds 		setup_count++;
33751da177e4SLinus Torvalds 		return 0;
33761da177e4SLinus Torvalds 	}
33771da177e4SLinus Torvalds 
33781da177e4SLinus Torvalds 	return 1;
33791da177e4SLinus Torvalds }
33801da177e4SLinus Torvalds __setup("aha152x=", aha152x_setup);
33811da177e4SLinus Torvalds #endif
33821da177e4SLinus Torvalds 
33833eb2ebcbSChristoph Hellwig #endif /* !AHA152X_PCMCIA */
3384