Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
new file mode 100644
index 0000000..d7b8efe
--- /dev/null
+++ b/drivers/scsi/aha152x.c
@@ -0,0 +1,3982 @@
+/* aha152x.c -- Adaptec AHA-152x driver
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-2004 Jürgen E. Fischer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *
+ * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
+ *
+ * $Log: aha152x.c,v $
+ * Revision 2.7  2004/01/24 11:42:59  fischer
+ * - gather code that is not used by PCMCIA at the end
+ * - move request_region for !PCMCIA case to detection
+ * - migration to new scsi host api (remove legacy code)
+ * - free host scribble before scsi_done
+ * - fix error handling
+ * - one isapnp device added to id_table
+ *
+ * Revision 2.6  2003/10/30 20:52:47  fischer
+ * - interfaces changes for kernel 2.6
+ * - aha152x_probe_one introduced for pcmcia stub
+ * - fixed pnpdev handling
+ * - instead of allocation a new one, reuse command for request sense after check condition and reset
+ * - fixes race in is_complete
+ *
+ * Revision 2.5  2002/04/14 11:24:53  fischer
+ * - isapnp support
+ * - abort fixed
+ * - 2.5 support
+ *
+ * Revision 2.4  2000/12/16 12:53:56  fischer
+ * - allow REQUEST SENSE to be queued
+ * - handle shared PCI interrupts
+ *
+ * Revision 2.3  2000/11/04 16:40:26  fischer
+ * - handle data overruns
+ * - extend timeout for data phases
+ *
+ * Revision 2.2  2000/08/08 19:54:53  fischer
+ * - minor changes
+ *
+ * Revision 2.1  2000/05/17 16:23:17  fischer
+ * - signature update
+ * - fix for data out w/o scatter gather
+ *
+ * Revision 2.0  1999/12/25 15:07:32  fischer
+ * - interrupt routine completly reworked
+ * - basic support for new eh code
+ *
+ * Revision 1.21  1999/11/10 23:46:36  fischer
+ * - default to synchronous operation
+ * - synchronous negotiation fixed
+ * - added timeout to loops
+ * - debugging output can be controlled through procfs
+ *
+ * Revision 1.20  1999/11/07 18:37:31  fischer
+ * - synchronous operation works
+ * - resid support for sg driver
+ *
+ * Revision 1.19  1999/11/02 22:39:59  fischer
+ * - moved leading comments to README.aha152x
+ * - new additional module parameters
+ * - updates for 2.3
+ * - support for the Tripace TC1550 controller
+ * - interrupt handling changed
+ *
+ * Revision 1.18  1996/09/07 20:10:40  fischer
+ * - fixed can_queue handling (multiple outstanding commands working again)
+ *
+ * Revision 1.17  1996/08/17 16:05:14  fischer
+ * - biosparam improved
+ * - interrupt verification
+ * - updated documentation
+ * - cleanups
+ *
+ * Revision 1.16  1996/06/09 00:04:56  root
+ * - added configuration symbols for insmod (aha152x/aha152x1)
+ *
+ * Revision 1.15  1996/04/30 14:52:06  fischer
+ * - proc info fixed
+ * - support for extended translation for >1GB disks
+ *
+ * Revision 1.14  1996/01/17  15:11:20  fischer
+ * - fixed lockup in MESSAGE IN phase after reconnection
+ *
+ * Revision 1.13  1996/01/09  02:15:53  fischer
+ * - some cleanups
+ * - moved request_irq behind controller initialization
+ *   (to avoid spurious interrupts)
+ *
+ * Revision 1.12  1995/12/16  12:26:07  fischer
+ * - barrier()s added
+ * - configurable RESET delay added
+ *
+ * Revision 1.11  1995/12/06  21:18:35  fischer
+ * - some minor updates
+ *
+ * Revision 1.10  1995/07/22  19:18:45  fischer
+ * - support for 2 controllers
+ * - started synchronous data transfers (not working yet)
+ *
+ * Revision 1.9  1995/03/18  09:20:24  root
+ * - patches for PCMCIA and modules
+ *
+ * Revision 1.8  1995/01/21  22:07:19  root
+ * - snarf_region => request_region
+ * - aha152x_intr interface change
+ *
+ * Revision 1.7  1995/01/02  23:19:36  root
+ * - updated COMMAND_SIZE to cmd_len
+ * - changed sti() to restore_flags()
+ * - fixed some #ifdef which generated warnings
+ *
+ * Revision 1.6  1994/11/24  20:35:27  root
+ * - problem with odd number of bytes in fifo fixed
+ *
+ * Revision 1.5  1994/10/30  14:39:56  root
+ * - abort code fixed
+ * - debugging improved
+ *
+ * Revision 1.4  1994/09/12  11:33:01  root
+ * - irqaction to request_irq
+ * - abortion updated
+ *
+ * Revision 1.3  1994/08/04  13:53:05  root
+ * - updates for mid-level-driver changes
+ * - accept unexpected BUSFREE phase as error condition
+ * - parity check now configurable
+ *
+ * Revision 1.2  1994/07/03  12:56:36  root
+ * - cleaned up debugging code
+ * - more tweaking on reset delays
+ * - updated abort/reset code (pretty untested...)
+ *
+ * Revision 1.1  1994/05/28  21:18:49  root
+ * - update for mid-level interface change (abort-reset)
+ * - delays after resets adjusted for some slow devices
+ *
+ * Revision 1.0  1994/03/25  12:52:00  root
+ * - Fixed "more data than expected" problem
+ * - added new BIOS signatures
+ *
+ * Revision 0.102  1994/01/31  20:44:12  root
+ * - minor changes in insw/outsw handling
+ *
+ * Revision 0.101  1993/12/13  01:16:27  root
+ * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
+ *   fixes problems with CD-ROM sector size detection & media change)
+ *
+ * Revision 0.100  1993/12/10  16:58:47  root
+ * - fix for unsuccessful selections in case of non-continuous id assignments
+ *   on the scsi bus.
+ *
+ * Revision 0.99  1993/10/24  16:19:59  root
+ * - fixed DATA IN (rare read errors gone)
+ *
+ * Revision 0.98  1993/10/17  12:54:44  root
+ * - fixed some recent fixes (shame on me)
+ * - moved initialization of scratch area to aha152x_queue
+ *
+ * Revision 0.97  1993/10/09  18:53:53  root
+ * - DATA IN fixed. Rarely left data in the fifo.
+ *
+ * Revision 0.96  1993/10/03  00:53:59  root
+ * - minor changes on DATA IN
+ *
+ * Revision 0.95  1993/09/24  10:36:01  root
+ * - change handling of MSGI after reselection
+ * - fixed sti/cli
+ * - minor changes
+ *
+ * Revision 0.94  1993/09/18  14:08:22  root
+ * - fixed bug in multiple outstanding command code
+ * - changed detection
+ * - support for kernel command line configuration
+ * - reset corrected
+ * - changed message handling
+ *
+ * Revision 0.93  1993/09/15  20:41:19  root
+ * - fixed bugs with multiple outstanding commands
+ *
+ * Revision 0.92  1993/09/13  02:46:33  root
+ * - multiple outstanding commands work (no problems with IBM drive)
+ *
+ * Revision 0.91  1993/09/12  20:51:46  root
+ * added multiple outstanding commands
+ * (some problem with this $%&? IBM device remain)
+ *
+ * Revision 0.9  1993/09/12  11:11:22  root
+ * - corrected auto-configuration
+ * - changed the auto-configuration (added some '#define's)
+ * - added support for dis-/reconnection
+ *
+ * Revision 0.8  1993/09/06  23:09:39  root
+ * - added support for the drive activity light
+ * - minor changes
+ *
+ * Revision 0.7  1993/09/05  14:30:15  root
+ * - improved phase detection
+ * - now using the new snarf_region code of 0.99pl13
+ *
+ * Revision 0.6  1993/09/02  11:01:38  root
+ * first public release; added some signatures and biosparam()
+ *
+ * Revision 0.5  1993/08/30  10:23:30  root
+ * fixed timing problems with my IBM drive
+ *
+ * Revision 0.4  1993/08/29  14:06:52  root
+ * fixed some problems with timeouts due incomplete commands
+ *
+ * Revision 0.3  1993/08/28  15:55:03  root
+ * writing data works too.  mounted and worked on a dos partition
+ *
+ * Revision 0.2  1993/08/27  22:42:07  root
+ * reading data works.  Mounted a msdos partition.
+ *
+ * Revision 0.1  1993/08/25  13:38:30  root
+ * first "damn thing doesn't work" version
+ *
+ * Revision 0.0  1993/08/14  19:54:25  root
+ * empty function bodies; detect() works.
+ *
+ *
+ **************************************************************************
+ 
+ see Documentation/scsi/aha152x.txt for configuration details
+
+ **************************************************************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/blkdev.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/isapnp.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <asm/semaphore.h>
+#include <scsi/scsicam.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aha152x.h"
+
+
+/* DEFINES */
+
+/* For PCMCIA cards, always use AUTOCONF */
+#if defined(PCMCIA) || defined(MODULE)
+#if !defined(AUTOCONF)
+#define AUTOCONF
+#endif
+#endif
+
+#if !defined(AUTOCONF) && !defined(SETUP0)
+#error define AUTOCONF or SETUP0
+#endif
+
+#if defined(AHA152X_DEBUG)
+#define DEBUG_DEFAULT debug_eh
+
+#define DPRINTK(when,msgs...) \
+	do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
+
+#define DO_LOCK(flags)	\
+	do { \
+		if(spin_is_locked(&QLOCK)) { \
+			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		} \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		spin_lock_irqsave(&QLOCK,flags); \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		QLOCKER=__FUNCTION__; \
+		QLOCKERL=__LINE__; \
+	} while(0)
+
+#define DO_UNLOCK(flags)	\
+	do { \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		spin_unlock_irqrestore(&QLOCK,flags); \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		QLOCKER="(not locked)"; \
+		QLOCKERL=0; \
+	} while(0)
+
+#else
+#define DPRINTK(when,msgs...)
+#define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
+#define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
+#endif
+
+#define LEAD		"(scsi%d:%d:%d) "
+#define WARN_LEAD	KERN_WARNING	LEAD
+#define INFO_LEAD	KERN_INFO	LEAD
+#define NOTE_LEAD	KERN_NOTICE	LEAD
+#define ERR_LEAD	KERN_ERR	LEAD
+#define DEBUG_LEAD	KERN_DEBUG	LEAD
+#define CMDINFO(cmd) \
+			(cmd) ? ((cmd)->device->host->host_no) : -1, \
+                        (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
+			(cmd) ? ((cmd)->device->lun & 0x07) : -1
+
+#define DELAY_DEFAULT 1000
+
+#if defined(PCMCIA)
+#define IRQ_MIN 0
+#define IRQ_MAX 16
+#else
+#define IRQ_MIN 9
+#if defined(__PPC)
+#define IRQ_MAX (NR_IRQS-1)
+#else
+#define IRQ_MAX 12
+#endif
+#endif
+
+enum {
+	not_issued	= 0x0001,	/* command not yet issued */
+	selecting	= 0x0002, 	/* target is beeing selected */
+	identified	= 0x0004,	/* IDENTIFY was sent */
+	disconnected	= 0x0008,	/* target disconnected */
+	completed	= 0x0010,	/* target sent COMMAND COMPLETE */ 
+	aborted		= 0x0020,	/* ABORT was sent */
+	resetted	= 0x0040,	/* BUS DEVICE RESET was sent */
+	spiordy		= 0x0080,	/* waiting for SPIORDY to raise */
+	syncneg		= 0x0100,	/* synchronous negotiation in progress */
+	aborting	= 0x0200,	/* ABORT is pending */
+	resetting	= 0x0400,	/* BUS DEVICE RESET is pending */
+	check_condition = 0x0800,	/* requesting sense after CHECK CONDITION */
+};
+
+MODULE_AUTHOR("Jürgen Fischer");
+MODULE_DESCRIPTION(AHA152X_REVID);
+MODULE_LICENSE("GPL");
+
+#if !defined(PCMCIA)
+#if defined(MODULE)
+static int io[] = {0, 0};
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io,"base io address of controller");
+
+static int irq[] = {0, 0};
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq,"interrupt for controller");
+
+static int scsiid[] = {7, 7};
+module_param_array(scsiid, int, NULL, 0);
+MODULE_PARM_DESC(scsiid,"scsi id of controller");
+
+static int reconnect[] = {1, 1};
+module_param_array(reconnect, int, NULL, 0);
+MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
+
+static int parity[] = {1, 1};
+module_param_array(parity, int, NULL, 0);
+MODULE_PARM_DESC(parity,"use scsi parity");
+
+static int sync[] = {1, 1};
+module_param_array(sync, int, NULL, 0);
+MODULE_PARM_DESC(sync,"use synchronous transfers");
+
+static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
+module_param_array(delay, int, NULL, 0);
+MODULE_PARM_DESC(delay,"scsi reset delay");
+
+static int exttrans[] = {0, 0};
+module_param_array(exttrans, int, NULL, 0);
+MODULE_PARM_DESC(exttrans,"use extended translation");
+
+#if !defined(AHA152X_DEBUG)
+static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+module_param_array(aha152x, int, NULL, 0);
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+
+static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+module_param_array(aha152x1, int, NULL, 0);
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+#else
+static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
+module_param_array(debug, int, NULL, 0);
+MODULE_PARM_DESC(debug, "flags for driver debugging");
+
+static int aha152x[]   = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+module_param_array(aha152x, int, NULL, 0);
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+
+static int aha152x1[]  = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+module_param_array(aha152x1, int, NULL, 0);
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+#endif /* !defined(AHA152X_DEBUG) */
+#endif /* MODULE */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1530), 0 },
+	{ ISAPNP_DEVICE_SINGLE_END, }
+};
+MODULE_DEVICE_TABLE(isapnp, id_table);
+#endif /* ISAPNP */
+
+#endif /* !PCMCIA */
+
+static int registered_count=0;
+static struct Scsi_Host *aha152x_host[2];
+static Scsi_Host_Template aha152x_driver_template;
+
+/*
+ * internal states of the host
+ *
+ */ 
+enum aha152x_state {
+	idle=0,
+	unknown,
+	seldo,
+	seldi,
+	selto,
+	busfree,
+	msgo,
+	cmd,
+	msgi,
+	status,
+	datai,
+	datao,
+	parerr,
+	rsti,
+	maxstate
+};
+
+/*
+ * current state information of the host
+ *
+ */
+struct aha152x_hostdata {
+	Scsi_Cmnd *issue_SC;
+		/* pending commands to issue */
+
+	Scsi_Cmnd *current_SC;
+		/* current command on the bus */
+
+	Scsi_Cmnd *disconnected_SC;
+		/* commands that disconnected */
+
+	Scsi_Cmnd *done_SC;
+		/* command that was completed */
+
+	spinlock_t lock;
+		/* host lock */
+
+#if defined(AHA152X_DEBUG)
+	const char *locker;
+		/* which function has the lock */
+	int lockerl;	/* where did it get it */
+
+	int debug;	/* current debugging setting */
+#endif
+
+#if defined(AHA152X_STAT)
+	int           total_commands;
+	int	      disconnections;
+	int	      busfree_without_any_action;
+	int	      busfree_without_old_command;
+	int	      busfree_without_new_command;
+	int	      busfree_without_done_command;
+	int	      busfree_with_check_condition;
+	int           count[maxstate];
+	int           count_trans[maxstate];
+	unsigned long time[maxstate];
+#endif
+
+	int commands;		/* current number of commands */
+
+	int reconnect;		/* disconnection allowed */
+	int parity;		/* parity checking enabled */
+	int synchronous;	/* synchronous transferes enabled */
+	int delay;		/* reset out delay */
+	int ext_trans;		/* extended translation enabled */
+
+	int swint; 		/* software-interrupt was fired during detect() */
+	int service;		/* bh needs to be run */
+	int in_intr;		/* bh is running */
+
+	/* current state,
+	   previous state,
+	   last state different from current state */
+	enum aha152x_state state, prevstate, laststate;
+
+	int target;
+		/* reconnecting target */
+
+	unsigned char syncrate[8];
+		/* current synchronous transfer agreements */
+
+	unsigned char syncneg[8];
+		/* 0: no negotiation;
+		 * 1: negotiation in progress;
+		 * 2: negotiation completed
+		 */
+
+	int cmd_i;
+		/* number of sent bytes of current command */
+
+	int msgi_len;
+		/* number of received message bytes */
+	unsigned char msgi[256];
+		/* received message bytes */
+
+	int msgo_i, msgo_len;	
+		/* number of sent bytes and length of current messages */
+	unsigned char msgo[256];
+		/* pending messages */
+
+	int data_len;
+		/* number of sent/received bytes in dataphase */
+
+	unsigned long io_port0;
+	unsigned long io_port1;
+
+#ifdef __ISAPNP__
+	struct pnp_dev *pnpdev;
+#endif
+};
+
+
+/*
+ * host specific command extension
+ *
+ */
+struct aha152x_scdata {
+	Scsi_Cmnd *next;	/* next sc in queue */
+	struct semaphore *sem;	/* semaphore to block on */
+};
+
+
+/* access macros for hostdata */
+
+#define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
+
+#define HOSTNO			((shpnt)->host_no)
+
+#define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)
+#define DONE_SC			(HOSTDATA(shpnt)->done_SC)
+#define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)
+#define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)
+#define QLOCK			(HOSTDATA(shpnt)->lock)
+#define QLOCKER			(HOSTDATA(shpnt)->locker)
+#define QLOCKERL		(HOSTDATA(shpnt)->lockerl)
+
+#define STATE			(HOSTDATA(shpnt)->state)
+#define PREVSTATE		(HOSTDATA(shpnt)->prevstate)
+#define LASTSTATE		(HOSTDATA(shpnt)->laststate)
+
+#define RECONN_TARGET		(HOSTDATA(shpnt)->target)
+
+#define CMD_I			(HOSTDATA(shpnt)->cmd_i)
+
+#define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])
+#define MSGO_I			(HOSTDATA(shpnt)->msgo_i)
+#define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)
+#define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
+
+#define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])
+#define MSGILEN			(HOSTDATA(shpnt)->msgi_len)
+#define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
+
+#define DATA_LEN		(HOSTDATA(shpnt)->data_len)
+
+#define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
+#define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
+
+#define DELAY			(HOSTDATA(shpnt)->delay)
+#define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)
+#define TC1550			(HOSTDATA(shpnt)->tc1550)
+#define RECONNECT		(HOSTDATA(shpnt)->reconnect)
+#define PARITY			(HOSTDATA(shpnt)->parity)
+#define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)
+
+#define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)
+#define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)
+
+#define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)
+#define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
+#define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
+
+#define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
+
+/* state handling */
+static void seldi_run(struct Scsi_Host *shpnt);
+static void seldo_run(struct Scsi_Host *shpnt);
+static void selto_run(struct Scsi_Host *shpnt);
+static void busfree_run(struct Scsi_Host *shpnt);
+
+static void msgo_init(struct Scsi_Host *shpnt);
+static void msgo_run(struct Scsi_Host *shpnt);
+static void msgo_end(struct Scsi_Host *shpnt);
+
+static void cmd_init(struct Scsi_Host *shpnt);
+static void cmd_run(struct Scsi_Host *shpnt);
+static void cmd_end(struct Scsi_Host *shpnt);
+
+static void datai_init(struct Scsi_Host *shpnt);
+static void datai_run(struct Scsi_Host *shpnt);
+static void datai_end(struct Scsi_Host *shpnt);
+
+static void datao_init(struct Scsi_Host *shpnt);
+static void datao_run(struct Scsi_Host *shpnt);
+static void datao_end(struct Scsi_Host *shpnt);
+
+static void status_run(struct Scsi_Host *shpnt);
+
+static void msgi_run(struct Scsi_Host *shpnt);
+static void msgi_end(struct Scsi_Host *shpnt);
+
+static void parerr_run(struct Scsi_Host *shpnt);
+static void rsti_run(struct Scsi_Host *shpnt);
+
+static void is_complete(struct Scsi_Host *shpnt);
+
+/*
+ * driver states
+ *
+ */
+static struct {
+	char		*name;
+	void		(*init)(struct Scsi_Host *);
+	void		(*run)(struct Scsi_Host *);
+	void		(*end)(struct Scsi_Host *);
+	int		spio;
+} states[] = {
+	{ "idle",	NULL,		NULL,		NULL,		0},
+	{ "unknown",	NULL,		NULL,		NULL,		0},
+	{ "seldo",	NULL,		seldo_run,	NULL,		0},
+	{ "seldi",	NULL,		seldi_run,	NULL,		0},
+	{ "selto",	NULL,		selto_run,	NULL,		0},
+	{ "busfree",	NULL,		busfree_run,	NULL,		0},
+	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
+	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
+	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},
+	{ "status",	NULL,		status_run,	NULL,		1},
+	{ "datai",	datai_init,	datai_run,	datai_end,	0},
+	{ "datao",	datao_init,	datao_run,	datao_end,	0},
+	{ "parerr",	NULL,		parerr_run,	NULL,		0},
+	{ "rsti",	NULL,		rsti_run,	NULL,		0},
+};
+
+/* setup & interrupt */
+static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);
+static void reset_ports(struct Scsi_Host *shpnt);
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
+static void done(struct Scsi_Host *shpnt, int error);
+
+/* diagnostics */
+static void disp_ports(struct Scsi_Host *shpnt);
+static void show_command(Scsi_Cmnd * ptr);
+static void show_queues(struct Scsi_Host *shpnt);
+static void disp_enintr(struct Scsi_Host *shpnt);
+
+
+/*
+ *  queue services:
+ *
+ */
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+	Scsi_Cmnd *end;
+
+	SCNEXT(new_SC) = NULL;
+	if (!*SC)
+		*SC = new_SC;
+	else {
+		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
+			;
+		SCNEXT(end) = new_SC;
+	}
+}
+
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC)
+{
+	Scsi_Cmnd *ptr;
+
+	ptr = *SC;
+	if (ptr) {
+		*SC = SCNEXT(*SC);
+		SCNEXT(ptr)=NULL;
+	}
+	return ptr;
+}
+
+static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun)
+{
+	Scsi_Cmnd *ptr, *prev;
+
+	for (ptr = *SC, prev = NULL;
+	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
+	     prev = ptr, ptr = SCNEXT(ptr))
+	     ;
+
+	if (ptr) {
+		if (prev)
+			SCNEXT(prev) = SCNEXT(ptr);
+		else
+			*SC = SCNEXT(ptr);
+
+		SCNEXT(ptr)=NULL;
+	}
+
+	return ptr;
+}
+
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
+{
+	Scsi_Cmnd *ptr, *prev;
+
+	for (ptr = *SC, prev = NULL;
+	     ptr && SCp!=ptr;
+	     prev = ptr, ptr = SCNEXT(ptr))
+	     ;
+
+	if (ptr) {
+		if (prev)
+			SCNEXT(prev) = SCNEXT(ptr);
+		else
+			*SC = SCNEXT(ptr);
+
+		SCNEXT(ptr)=NULL;
+	}
+
+	return ptr;
+}
+
+static inline struct Scsi_Host *lookup_irq(int irqno)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
+		if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
+			return aha152x_host[i];
+
+	return NULL;
+}
+
+static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *shpnt = lookup_irq(irqno);
+
+	if (!shpnt) {
+        	printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
+		return IRQ_NONE;
+	}
+
+	HOSTDATA(shpnt)->swint++;
+
+	SETPORT(DMACNTRL0, INTEN);
+	return IRQ_HANDLED;
+}
+
+struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
+{
+	struct Scsi_Host *shpnt;
+
+	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
+	if (!shpnt) {
+		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
+		return NULL;
+	}
+
+	/* need to have host registered before triggering any interrupt */
+	aha152x_host[registered_count] = shpnt;
+
+	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
+
+	shpnt->io_port   = setup->io_port;
+	shpnt->n_io_port = IO_RANGE;
+	shpnt->irq       = setup->irq;
+
+	if (!setup->tc1550) {
+		HOSTIOPORT0 = setup->io_port;
+		HOSTIOPORT1 = setup->io_port;
+	} else {
+		HOSTIOPORT0 = setup->io_port+0x10;
+		HOSTIOPORT1 = setup->io_port-0x10;
+	}
+
+	spin_lock_init(&QLOCK);
+	RECONNECT   = setup->reconnect;
+	SYNCHRONOUS = setup->synchronous;
+	PARITY      = setup->parity;
+	DELAY       = setup->delay;
+	EXT_TRANS   = setup->ext_trans;
+
+#if defined(AHA152X_DEBUG)
+	HOSTDATA(shpnt)->debug = setup->debug;
+#endif
+
+	SETPORT(SCSIID, setup->scsiid << 4);
+	shpnt->this_id = setup->scsiid;
+
+	if (setup->reconnect)
+		shpnt->can_queue = AHA152X_MAXQUEUE;
+
+	/* RESET OUT */
+	printk("aha152x: resetting bus...\n");
+	SETPORT(SCSISEQ, SCSIRSTO);
+	mdelay(256);
+	SETPORT(SCSISEQ, 0);
+	mdelay(DELAY);
+
+	reset_ports(shpnt);
+
+	printk(KERN_INFO
+	       "aha152x%d%s: "
+	       "vital data: rev=%x, "
+	       "io=0x%03lx (0x%03lx/0x%03lx), "
+	       "irq=%d, "
+	       "scsiid=%d, "
+	       "reconnect=%s, "
+	       "parity=%s, "
+	       "synchronous=%s, "
+	       "delay=%d, "
+	       "extended translation=%s\n",
+	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
+	       GETPORT(REV) & 0x7,
+	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
+	       shpnt->irq,
+	       shpnt->this_id,
+	       RECONNECT ? "enabled" : "disabled",
+	       PARITY ? "enabled" : "disabled",
+	       SYNCHRONOUS ? "enabled" : "disabled",
+	       DELAY,
+	       EXT_TRANS ? "enabled" : "disabled");
+
+	/* not expecting any interrupts */
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, 0);
+
+	if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
+		goto out_host_put;
+	}
+
+	HOSTDATA(shpnt)->swint = 0;
+
+	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
+
+	mb();
+	SETPORT(DMACNTRL0, SWINT|INTEN);
+	mdelay(1000);
+	free_irq(shpnt->irq, shpnt);
+
+	if (!HOSTDATA(shpnt)->swint) {
+		if (TESTHI(DMASTAT, INTSTAT)) {
+			printk("lost.\n");
+		} else {
+			printk("failed.\n");
+		}
+
+		SETPORT(DMACNTRL0, INTEN);
+
+		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "
+				"Please verify.\n", shpnt->host_no, shpnt->irq);
+		goto out_host_put;
+	}
+	printk("ok.\n");
+
+
+	/* clear interrupts */
+	SETPORT(SSTAT0, 0x7f);
+	SETPORT(SSTAT1, 0xef);
+
+	if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
+		goto out_host_put;
+	}
+
+	if( scsi_add_host(shpnt, NULL) ) {
+		free_irq(shpnt->irq, shpnt);
+		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
+		goto out_host_put;
+	}
+
+	scsi_scan_host(shpnt);
+
+	registered_count++;
+
+	return shpnt;
+
+out_host_put:
+	aha152x_host[registered_count]=NULL;
+	scsi_host_put(shpnt);
+
+	return NULL;
+}
+
+void aha152x_release(struct Scsi_Host *shpnt)
+{
+	if(!shpnt)
+		return;
+
+	if (shpnt->irq)
+		free_irq(shpnt->irq, shpnt);
+
+#if !defined(PCMCIA)
+	if (shpnt->io_port)
+		release_region(shpnt->io_port, IO_RANGE);
+#endif
+
+#ifdef __ISAPNP__
+	if (HOSTDATA(shpnt)->pnpdev)
+		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
+#endif
+
+	scsi_remove_host(shpnt);
+	scsi_host_put(shpnt);
+}
+
+
+/*
+ * setup controller to generate interrupts depending
+ * on current state (lock has to be acquired)
+ *
+ */ 
+static int setup_expected_interrupts(struct Scsi_Host *shpnt)
+{
+	if(CURRENT_SC) {
+		CURRENT_SC->SCp.phase |= 1 << 16;
+	
+		if(CURRENT_SC->SCp.phase & selecting) {
+			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
+			SETPORT(SSTAT1, SELTO);
+			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+			SETPORT(SIMODE1, ENSELTIMO);
+		} else {
+			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
+			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
+		}
+	} else if(STATE==seldi) {
+		DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
+		SETPORT(SIMODE0, 0);
+		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
+	} else {
+		DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
+			CMDINFO(CURRENT_SC),
+			DISCONNECTED_SC ? "(reselection)" : "",
+			ISSUE_SC ? "(busfree)" : "");
+		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
+	}
+
+	if(!HOSTDATA(shpnt)->in_intr)
+		SETBITS(DMACNTRL0, INTEN);
+
+	return TESTHI(DMASTAT, INTSTAT);
+}
+
+
+/* 
+ *  Queue a command and setup interrupts for a free bus.
+ */
+static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *))
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_queue) {
+		printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
+		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+		print_command(SCpnt->cmnd);
+	}
+#endif
+
+	SCpnt->scsi_done	= done;
+	SCpnt->resid 		= SCpnt->request_bufflen;
+	SCpnt->SCp.phase	= not_issued | phase;
+	SCpnt->SCp.Status	= CHECK_CONDITION;
+	SCpnt->SCp.Message	= 0;
+	SCpnt->SCp.have_data_in	= 0;
+	SCpnt->SCp.sent_command	= 0;
+
+	if(SCpnt->SCp.phase & (resetting|check_condition)) {
+		if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
+			printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt));
+			return FAILED;
+		}
+	} else {
+		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
+		if(SCpnt->host_scribble==0) {
+			printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
+			return FAILED;
+		}
+	}
+
+	SCNEXT(SCpnt)		= NULL;
+	SCSEM(SCpnt)		= sem;
+
+	/* setup scratch area
+	   SCp.ptr              : buffer pointer
+	   SCp.this_residual    : buffer length
+	   SCp.buffer           : next buffer
+	   SCp.buffers_residual : left buffers in list
+	   SCp.phase            : current state of the command */
+	if (SCpnt->use_sg) {
+		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
+		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+	} else {
+		SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
+		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer           = NULL;
+		SCpnt->SCp.buffers_residual = 0;
+	}
+
+	DO_LOCK(flags);
+
+#if defined(AHA152X_STAT)
+	HOSTDATA(shpnt)->total_commands++;
+#endif
+
+	/* Turn led on, when this is the first command. */
+	HOSTDATA(shpnt)->commands++;
+	if (HOSTDATA(shpnt)->commands==1)
+		SETPORT(PORTA, 1);
+
+	append_SC(&ISSUE_SC, SCpnt);
+
+	if(!HOSTDATA(shpnt)->in_intr)
+		setup_expected_interrupts(shpnt);
+
+	DO_UNLOCK(flags);
+
+	return 0;
+}
+
+/*
+ *  queue a command
+ *
+ */
+static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+#if 0
+	if(*SCpnt->cmnd == REQUEST_SENSE) {
+		SCpnt->result = 0;
+		done(SCpnt);
+
+		return 0;
+	}
+#endif
+
+	return aha152x_internal_queue(SCpnt, NULL, 0, done);
+}
+
+
+/*
+ *  
+ *
+ */
+static void reset_done(Scsi_Cmnd *SCpnt)
+{
+#if 0
+	struct Scsi_Host *shpnt = SCpnt->host;
+	DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt));
+#endif
+	if(SCSEM(SCpnt)) {
+		up(SCSEM(SCpnt));
+	} else {
+		printk(KERN_ERR "aha152x: reset_done w/o semaphore\n");
+	}
+}
+
+/*
+ *  Abort a command
+ *
+ */
+static int aha152x_abort(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	DO_LOCK(flags);
+
+	ptr=remove_SC(&ISSUE_SC, SCpnt);
+
+	if(ptr) {
+		DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt));
+
+		HOSTDATA(shpnt)->commands--;
+		if (!HOSTDATA(shpnt)->commands)
+			SETPORT(PORTA, 0);
+		DO_UNLOCK(flags);
+
+		kfree(SCpnt->host_scribble);
+		SCpnt->host_scribble=NULL;
+
+		return SUCCESS;
+	} 
+
+	DO_UNLOCK(flags);
+
+	/*
+	 * FIXME:
+	 * for current command: queue ABORT for message out and raise ATN
+	 * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
+	 *
+	 */
+
+	printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
+
+	return FAILED;
+}
+
+static void timer_expired(unsigned long p)
+{
+	Scsi_Cmnd	 *SCp   = (Scsi_Cmnd *)p;
+	struct semaphore *sem   = SCSEM(SCp);
+	struct Scsi_Host *shpnt = SCp->device->host;
+	unsigned long flags;
+
+	/* remove command from issue queue */
+	DO_LOCK(flags);
+	remove_SC(&ISSUE_SC, SCp);
+	DO_UNLOCK(flags);
+
+	up(sem);
+}
+
+/*
+ * Reset a device
+ *
+ */
+static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	DECLARE_MUTEX_LOCKED(sem);
+	struct timer_list timer;
+	int ret, issued, disconnected;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	if(CURRENT_SC==SCpnt) {
+		printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt));
+		return FAILED;
+	}
+
+	DO_LOCK(flags);
+	issued       = remove_SC(&ISSUE_SC, SCpnt)==0;
+	disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
+	DO_UNLOCK(flags);
+
+	SCpnt->cmd_len         = 0;
+	SCpnt->use_sg          = 0;
+	SCpnt->request_buffer  = NULL;
+	SCpnt->request_bufflen = 0;
+
+	init_timer(&timer);
+	timer.data     = (unsigned long) SCpnt;
+	timer.expires  = jiffies + 100*HZ;   /* 10s */
+	timer.function = (void (*)(unsigned long)) timer_expired;
+
+	aha152x_internal_queue(SCpnt, &sem, resetting, reset_done);
+	add_timer(&timer);
+	down(&sem);
+	del_timer(&timer);
+	
+	SCpnt->cmd_len         = SCpnt->old_cmd_len;
+	SCpnt->use_sg          = SCpnt->old_use_sg;
+  	SCpnt->request_buffer  = SCpnt->buffer;
+       	SCpnt->request_bufflen = SCpnt->bufflen;
+
+	DO_LOCK(flags);
+
+	if(SCpnt->SCp.phase & resetted) {
+		HOSTDATA(shpnt)->commands--;
+		if (!HOSTDATA(shpnt)->commands)
+			SETPORT(PORTA, 0);
+		kfree(SCpnt->host_scribble);
+		SCpnt->host_scribble=NULL;
+
+		ret = SUCCESS;
+	} else {
+		/* requeue */
+		if(!issued) {
+			append_SC(&ISSUE_SC, SCpnt);
+		} else if(disconnected) {
+			append_SC(&DISCONNECTED_SC, SCpnt);
+		}
+	
+		ret = FAILED;
+	}
+
+	DO_UNLOCK(flags);
+
+	spin_lock_irq(shpnt->host_lock);
+	return ret;
+}
+
+static void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
+{
+	Scsi_Cmnd *ptr;
+
+	ptr=*SCs;
+	while(ptr) {
+		Scsi_Cmnd *next;
+
+		if(SCDATA(ptr)) {
+			next = SCNEXT(ptr);
+		} else {
+			printk(DEBUG_LEAD "queue corrupted at %p\n", CMDINFO(ptr), ptr);
+			next = NULL;
+		}
+
+		if (!ptr->device->soft_reset) {
+			DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr);
+			remove_SC(SCs, ptr);
+			HOSTDATA(shpnt)->commands--;
+			kfree(ptr->host_scribble);
+			ptr->host_scribble=NULL;
+		}
+
+		ptr = next;
+	}
+}
+
+/*
+ * Reset the bus
+ *
+ */
+static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	unsigned long flags;
+
+	DO_LOCK(flags);
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	free_hard_reset_SCs(shpnt, &ISSUE_SC);
+	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
+
+	DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt));
+
+	SETPORT(SCSISEQ, SCSIRSTO);
+	mdelay(256);
+	SETPORT(SCSISEQ, 0);
+	mdelay(DELAY);
+
+	DPRINTK(debug_eh, DEBUG_LEAD "bus resetted\n", CMDINFO(SCpnt));
+
+	setup_expected_interrupts(shpnt);
+	if(HOSTDATA(shpnt)->commands==0)
+		SETPORT(PORTA, 0);
+
+	DO_UNLOCK(flags);
+
+	return SUCCESS;
+}
+
+
+/*
+ *  Restore default values to the AIC-6260 registers and reset the fifos
+ *
+ */
+static void reset_ports(struct Scsi_Host *shpnt)
+{
+	unsigned long flags;
+
+	/* disable interrupts */
+	SETPORT(DMACNTRL0, RSTFIFO);
+
+	SETPORT(SCSISEQ, 0);
+
+	SETPORT(SXFRCTL1, 0);
+	SETPORT(SCSISIG, 0);
+	SETRATE(0);
+
+	/* clear all interrupt conditions */
+	SETPORT(SSTAT0, 0x7f);
+	SETPORT(SSTAT1, 0xef);
+
+	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
+
+	SETPORT(DMACNTRL0, 0);
+	SETPORT(DMACNTRL1, 0);
+
+	SETPORT(BRSTCNTRL, 0xf1);
+
+	/* clear SCSI fifos and transfer count */
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
+
+	DO_LOCK(flags);
+	setup_expected_interrupts(shpnt);
+	DO_UNLOCK(flags);
+}
+
+/*
+ * Reset the host (bus and controller)
+ *
+ */
+int aha152x_host_reset(Scsi_Cmnd * SCpnt)
+{
+#if defined(AHA152X_DEBUG)
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+#endif
+
+	DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
+
+	aha152x_bus_reset(SCpnt);
+
+	DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
+	reset_ports(SCpnt->device->host);
+
+	return SUCCESS;
+}
+
+/*
+ * Return the "logical geometry"
+ *
+ */
+static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int *info_array)
+{
+	struct Scsi_Host *shpnt = sdev->host;
+
+	/* try default translation */
+	info_array[0] = 64;
+	info_array[1] = 32;
+	info_array[2] = (unsigned long)capacity / (64 * 32);
+
+	/* for disks >1GB do some guessing */
+	if (info_array[2] >= 1024) {
+		int info[3];
+
+		/* try to figure out the geometry from the partition table */
+		if (scsicam_bios_param(bdev, capacity, info) < 0 ||
+		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
+			if (EXT_TRANS) {
+				printk(KERN_NOTICE
+				       "aha152x: unable to verify geometry for disk with >1GB.\n"
+				       "         using extended translation.\n");
+				info_array[0] = 255;
+				info_array[1] = 63;
+				info_array[2] = (unsigned long)capacity / (255 * 63);
+			} else {
+				printk(KERN_NOTICE
+				       "aha152x: unable to verify geometry for disk with >1GB.\n"
+				       "         Using default translation. Please verify yourself.\n"
+				       "         Perhaps you need to enable extended translation in the driver.\n"
+				       "         See Documentation/scsi/aha152x.txt for details.\n");
+			}
+		} else {
+			info_array[0] = info[0];
+			info_array[1] = info[1];
+			info_array[2] = info[2];
+
+			if (info[0] == 255 && !EXT_TRANS) {
+				printk(KERN_NOTICE
+				       "aha152x: current partition table is using extended translation.\n"
+				       "         using it also, although it's not explicitly enabled.\n");
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ *  Internal done function
+ *
+ */
+static void done(struct Scsi_Host *shpnt, int error)
+{
+	if (CURRENT_SC) {
+		if(DONE_SC)
+			printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC);
+
+		DONE_SC = CURRENT_SC;
+		CURRENT_SC = NULL;
+		DONE_SC->result = error;
+	} else
+		printk(KERN_ERR "aha152x: done() called outside of command\n");
+}
+
+static struct work_struct aha152x_tq;
+
+/*
+ * Run service completions on the card with interrupts enabled.
+ *
+ */
+static void run(void)
+{
+	int i;
+	for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
+		struct Scsi_Host *shpnt = aha152x_host[i];
+		if (shpnt && HOSTDATA(shpnt)->service) {
+			HOSTDATA(shpnt)->service=0;
+			is_complete(shpnt);
+		}
+	}
+}
+
+/*
+ *    Interrupts handler
+ *
+ */
+
+static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *shpnt = lookup_irq(irqno);
+	unsigned char rev, dmacntrl0;
+
+	if (!shpnt) {
+		printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno);
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Read a couple of registers that are known to not be all 1's. If
+	 * we read all 1's (-1), that means that either:
+	 *
+	 * a. The host adapter chip has gone bad, and we cannot control it,
+	 *	OR
+	 * b. The host adapter is a PCMCIA card that has been ejected
+	 *
+	 * In either case, we cannot do anything with the host adapter at
+	 * this point in time. So just ignore the interrupt and return.
+	 * In the latter case, the interrupt might actually be meant for
+	 * someone else sharing this IRQ, and that driver will handle it.
+	 */
+	rev = GETPORT(REV);
+	dmacntrl0 = GETPORT(DMACNTRL0);
+	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
+		return IRQ_NONE;
+
+	/* no more interrupts from the controller, while we're busy.
+	   INTEN is restored by the BH handler */
+	CLRBITS(DMACNTRL0, INTEN);
+
+#if 0
+	/* check if there is already something to be
+           serviced; should not happen */
+	if(HOSTDATA(shpnt)->service) {
+		printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service);
+	        show_queues(shpnt);
+	}
+#endif
+	
+	/* Poke the BH handler */
+	HOSTDATA(shpnt)->service++;
+	INIT_WORK(&aha152x_tq, (void *) run, NULL);
+	schedule_work(&aha152x_tq);
+	return IRQ_HANDLED;
+}
+
+/*
+ * busfree phase
+ * - handle completition/disconnection/error of current command
+ * - start selection for next command (if any)
+ */
+static void busfree_run(struct Scsi_Host *shpnt)
+{
+	unsigned long flags;
+#if defined(AHA152X_STAT)
+	int action=0;
+#endif
+
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
+
+	SETPORT(SSTAT1, CLRBUSFREE);
+	
+	if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+		CURRENT_SC->SCp.phase &= ~syncneg;
+
+		if(CURRENT_SC->SCp.phase & completed) {
+			/* target sent COMMAND COMPLETE */
+			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
+
+		} else if(CURRENT_SC->SCp.phase & aborted) {
+			DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC));
+			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
+
+		} else if(CURRENT_SC->SCp.phase & resetted) {
+			DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC));
+			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
+
+		} else if(CURRENT_SC->SCp.phase & disconnected) {
+			/* target sent DISCONNECT */
+			DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
+				CMDINFO(CURRENT_SC),
+				CURRENT_SC->resid,
+				CURRENT_SC->request_bufflen);
+#if defined(AHA152X_STAT)
+			HOSTDATA(shpnt)->disconnections++;
+#endif
+			append_SC(&DISCONNECTED_SC, CURRENT_SC);
+			CURRENT_SC->SCp.phase |= 1 << 16;
+			CURRENT_SC = NULL;
+
+		} else {
+			done(shpnt, DID_ERROR << 16);
+		}
+#if defined(AHA152X_STAT)
+	} else {
+		HOSTDATA(shpnt)->busfree_without_old_command++;
+#endif
+	}
+
+	DO_LOCK(flags);
+
+	if(DONE_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+
+		if(DONE_SC->SCp.phase & check_condition) {
+#if 0
+			if(HOSTDATA(shpnt)->debug & debug_eh) {
+				printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
+				print_sense("bh", DONE_SC);
+			}
+#endif
+
+			/* restore old command */
+			memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd));
+			DONE_SC->request_buffer  = DONE_SC->buffer;
+			DONE_SC->request_bufflen = DONE_SC->bufflen;
+			DONE_SC->use_sg          = DONE_SC->old_use_sg;
+			DONE_SC->cmd_len         = DONE_SC->old_cmd_len;
+
+			DONE_SC->SCp.Status = 0x02;
+
+			HOSTDATA(shpnt)->commands--;
+			if (!HOSTDATA(shpnt)->commands)
+				SETPORT(PORTA, 0);	/* turn led off */
+		} else if(DONE_SC->SCp.Status==0x02) {
+#if defined(AHA152X_STAT)
+			HOSTDATA(shpnt)->busfree_with_check_condition++;
+#endif
+#if 0
+			DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
+#endif
+
+			if(!(DONE_SC->SCp.Status & not_issued)) {
+				Scsi_Cmnd *ptr = DONE_SC;
+				DONE_SC=NULL;
+#if 0
+				DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+#endif
+
+				ptr->cmnd[0]         = REQUEST_SENSE;
+				ptr->cmnd[1]         = 0;
+				ptr->cmnd[2]         = 0;
+				ptr->cmnd[3]         = 0;
+				ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
+				ptr->cmnd[5]         = 0;
+				ptr->cmd_len         = 6;
+				ptr->use_sg          = 0; 
+				ptr->request_buffer  = ptr->sense_buffer;
+				ptr->request_bufflen = sizeof(ptr->sense_buffer);
+			
+				DO_UNLOCK(flags);
+				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
+				DO_LOCK(flags);
+#if 0
+			} else {
+				DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));
+#endif
+			}
+		}
+
+		if(DONE_SC && DONE_SC->scsi_done) {
+#if defined(AHA152X_DEBUG)
+			int hostno=DONE_SC->device->host->host_no;
+			int id=DONE_SC->device->id & 0xf;
+			int lun=DONE_SC->device->lun & 0x7;
+#endif
+			Scsi_Cmnd *ptr = DONE_SC;
+			DONE_SC=NULL;
+
+			/* turn led off, when no commands are in the driver */
+			HOSTDATA(shpnt)->commands--;
+			if (!HOSTDATA(shpnt)->commands)
+				SETPORT(PORTA, 0);	/* turn led off */
+
+			if(ptr->scsi_done != reset_done) {
+				kfree(ptr->host_scribble);
+				ptr->host_scribble=NULL;
+			}
+
+			DO_UNLOCK(flags);
+			DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", hostno, id, lun, ptr);
+                	ptr->scsi_done(ptr);
+			DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", hostno, id, lun, ptr);
+			DO_LOCK(flags);
+		}
+
+		DONE_SC=NULL;
+#if defined(AHA152X_STAT)
+	} else {
+		HOSTDATA(shpnt)->busfree_without_done_command++;
+#endif
+	}
+
+	if(ISSUE_SC)
+		CURRENT_SC = remove_first_SC(&ISSUE_SC);
+
+	DO_UNLOCK(flags);
+
+	if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+	    	CURRENT_SC->SCp.phase |= selecting;
+
+		DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
+
+		/* clear selection timeout */
+		SETPORT(SSTAT1, SELTO);
+
+		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
+		SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
+		SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
+	} else {
+#if defined(AHA152X_STAT)
+		HOSTDATA(shpnt)->busfree_without_new_command++;
+#endif
+		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+	}
+
+#if defined(AHA152X_STAT)
+	if(!action)
+		HOSTDATA(shpnt)->busfree_without_any_action++;
+#endif
+}
+
+/*
+ * Selection done (OUT)
+ * - queue IDENTIFY message and SDTR to selected target for message out
+ *   (ATN asserted automagically via ENAUTOATNO in busfree())
+ */
+static void seldo_run(struct Scsi_Host *shpnt)
+{
+	SETPORT(SCSISIG, 0);
+	SETPORT(SSTAT1, CLRBUSFREE);
+	SETPORT(SSTAT1, CLRPHASECHG);
+
+    	CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
+
+	SETPORT(SCSISEQ, 0);
+
+	if (TESTLO(SSTAT0, SELDO)) {
+		printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_NO_CONNECT << 16);
+		return;
+	}
+
+	SETPORT(SSTAT0, CLRSELDO);
+	
+	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
+
+	if (CURRENT_SC->SCp.phase & aborting) {
+		ADDMSGO(ABORT);
+	} else if (CURRENT_SC->SCp.phase & resetting) {
+		ADDMSGO(BUS_DEVICE_RESET);
+	} else if (SYNCNEG==0 && SYNCHRONOUS) {
+    		CURRENT_SC->SCp.phase |= syncneg;
+		ADDMSGO(EXTENDED_MESSAGE);
+		ADDMSGO(3);
+		ADDMSGO(EXTENDED_SDTR);
+		ADDMSGO(50);		/* 200ns */
+		ADDMSGO(8);		/* 8 byte req/ack offset */
+
+		SYNCNEG=1;		/* negotiation in progress */
+	}
+
+	SETRATE(SYNCRATE);
+}
+
+/*
+ * Selection timeout
+ * - return command to mid-level with failure cause
+ *
+ */
+static void selto_run(struct Scsi_Host *shpnt)
+{
+	SETPORT(SCSISEQ, 0);		
+	SETPORT(SSTAT1, CLRSELTIMO);
+
+	DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC));
+
+	if(!CURRENT_SC) {
+		DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC));
+		return;
+	}
+
+    	CURRENT_SC->SCp.phase &= ~selecting;
+
+	if (CURRENT_SC->SCp.phase & aborted) {
+		DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_ABORT << 16);
+	} else if (TESTLO(SSTAT0, SELINGO)) {
+		DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_BUS_BUSY << 16);
+	} else {
+		/* ARBITRATION won, but SELECTION failed */
+		DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_NO_CONNECT << 16);
+	}
+}
+
+/*
+ * Selection in done
+ * - put current command back to issue queue
+ *   (reconnection of a disconnected nexus instead
+ *    of successful selection out)
+ *
+ */
+static void seldi_run(struct Scsi_Host *shpnt)
+{
+	int selid;
+	int target;
+	unsigned long flags;
+
+	SETPORT(SCSISIG, 0);
+	SETPORT(SSTAT0, CLRSELDI);
+	SETPORT(SSTAT1, CLRBUSFREE);
+	SETPORT(SSTAT1, CLRPHASECHG);
+
+	if(CURRENT_SC) {
+		if(!(CURRENT_SC->SCp.phase & not_issued))
+			printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
+
+		DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
+
+		DO_LOCK(flags);
+		append_SC(&ISSUE_SC, CURRENT_SC);
+		DO_UNLOCK(flags);
+
+		CURRENT_SC = NULL;
+	}
+
+	if(!DISCONNECTED_SC) {
+		DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+		return;
+	}
+
+	RECONN_TARGET=-1;
+
+	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
+
+	if (selid==0) {
+		printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+		return;
+	}
+
+	for(target=7; !(selid & (1 << target)); target--)
+		;
+
+	if(selid & ~(1 << target)) {
+		printk("aha152x%d: multiple targets reconnected (%02x)\n",
+		       HOSTNO, selid);
+	}
+
+
+	SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+	SETPORT(SCSISEQ, 0);
+
+	SETRATE(HOSTDATA(shpnt)->syncrate[target]);
+
+	RECONN_TARGET=target;
+	DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid);
+}
+
+/*
+ * message in phase
+ * - handle initial message after reconnection to identify
+ *   reconnecting nexus
+ * - queue command on DISCONNECTED_SC on DISCONNECT message
+ * - set completed flag on COMMAND COMPLETE
+ *   (other completition code moved to busfree_run)
+ * - handle response to SDTR
+ * - clear synchronous transfer agreements on BUS RESET
+ *
+ * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
+ *
+ */
+static void msgi_run(struct Scsi_Host *shpnt)
+{
+	for(;;) {
+		int sstat1 = GETPORT(SSTAT1);
+
+		if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
+			return;
+
+		if(TESTLO(SSTAT0,SPIORDY)) {
+			DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}	
+
+		ADDMSGI(GETPORT(SCSIDAT));
+
+#if defined(AHA152X_DEBUG)
+		if (HOSTDATA(shpnt)->debug & debug_msgi) {
+			printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
+			print_msg(&MSGI(0));
+			printk("\n");
+		}
+#endif
+
+		if(!CURRENT_SC) {
+			if(LASTSTATE!=seldi) {
+				printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO);
+			}
+
+			/*
+	 	 	 * Handle reselection
+	 		 */
+			if(!(MSGI(0) & IDENTIFY_BASE)) {
+				printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+				continue;
+			}
+
+			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
+
+			if (!CURRENT_SC) {
+				show_queues(shpnt);
+				printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f);
+				continue;
+			}
+
+			DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
+
+			CURRENT_SC->SCp.Message = MSGI(0);
+			CURRENT_SC->SCp.phase &= ~disconnected;
+
+			MSGILEN=0;
+
+			/* next message if any */
+			continue;
+		} 
+
+		CURRENT_SC->SCp.Message = MSGI(0);
+
+		switch (MSGI(0)) {
+		case DISCONNECT:
+			if (!RECONNECT)
+				printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
+
+			CURRENT_SC->SCp.phase |= disconnected;
+			break;
+
+		case COMMAND_COMPLETE:
+			if(CURRENT_SC->SCp.phase & completed)
+				DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC));
+
+			CURRENT_SC->SCp.phase |= completed;
+			break;
+
+		case MESSAGE_REJECT:
+			if (SYNCNEG==1) {
+				printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+				SYNCNEG=2;	/* negotiation completed */
+			} else
+				printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC));
+			break;
+
+		case SAVE_POINTERS:
+			break;
+
+		case RESTORE_POINTERS:
+			break;
+
+		case EXTENDED_MESSAGE:
+			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
+				/* not yet completed */
+				continue;
+			}
+
+			switch (MSGI(2)) {
+			case EXTENDED_SDTR:
+				{
+					long ticks;
+
+					if (MSGI(1) != 3) {
+						printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+						break;
+					}
+
+					if (!HOSTDATA(shpnt)->synchronous)
+						break;
+
+					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
+					print_msg(&MSGI(0));
+					printk("\n");
+
+					ticks = (MSGI(3) * 4 + 49) / 50;
+
+					if (syncneg) {
+						/* negotiation in progress */
+						if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
+							ADDMSGO(MESSAGE_REJECT);
+							printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC));
+							break;
+						}
+						
+						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+					} else if (ticks <= 9 && MSGI(4) >= 1) {
+						ADDMSGO(EXTENDED_MESSAGE);
+						ADDMSGO(3);
+						ADDMSGO(EXTENDED_SDTR);
+						if (ticks < 4) {
+							ticks = 4;
+							ADDMSGO(50);
+						} else
+							ADDMSGO(MSGI(3));
+
+						if (MSGI(4) > 8)
+							MSGI(4) = 8;
+
+						ADDMSGO(MSGI(4));
+
+						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+					} else {
+						/* requested SDTR is too slow, do it asynchronously */
+						printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC));
+						ADDMSGO(MESSAGE_REJECT);
+					}
+
+					SYNCNEG=2;		/* negotiation completed */
+					SETRATE(SYNCRATE);
+				}
+				break;
+
+			case BUS_DEVICE_RESET:
+				{
+					int i;
+
+					for(i=0; i<8; i++) {
+						HOSTDATA(shpnt)->syncrate[i]=0;
+						HOSTDATA(shpnt)->syncneg[i]=0;
+					}
+
+				}
+				break;
+
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			case EXTENDED_WDTR:
+			default:
+				ADDMSGO(MESSAGE_REJECT);
+				break;
+			}
+			break;
+		}
+
+		MSGILEN=0;
+	}
+}
+
+static void msgi_end(struct Scsi_Host *shpnt)
+{
+	if(MSGILEN>0)
+		printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN);
+
+	if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) {
+		DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC));
+		SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
+	} 
+}
+
+/*
+ * message out phase
+ *
+ */
+static void msgo_init(struct Scsi_Host *shpnt)
+{
+	if(MSGOLEN==0) {
+		if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
+			ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
+		} else {
+			printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC));
+			ADDMSGO(MESSAGE_REJECT);
+		}
+	}
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_msgo) {
+		int i;
+
+		printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
+		for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+			;
+		printk(")\n");
+	}
+#endif
+}
+
+/*
+ * message out phase
+ *
+ */
+static void msgo_run(struct Scsi_Host *shpnt)
+{
+	if(MSGO_I==MSGOLEN)
+		DPRINTK(debug_msgo, DEBUG_LEAD "messages all sent (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+
+	while(MSGO_I<MSGOLEN) {
+		DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
+
+		if(TESTLO(SSTAT0, SPIORDY)) {
+			DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}
+
+		if (MSGO_I==MSGOLEN-1) {
+			/* Leave MESSAGE OUT after transfer */
+			SETPORT(SSTAT1, CLRATNO);
+		}
+
+
+		if (MSGO(MSGO_I) & IDENTIFY_BASE)
+			CURRENT_SC->SCp.phase |= identified;
+
+		if (MSGO(MSGO_I)==ABORT)
+			CURRENT_SC->SCp.phase |= aborted;
+
+		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
+			CURRENT_SC->SCp.phase |= resetted;
+
+		SETPORT(SCSIDAT, MSGO(MSGO_I++));
+	}
+}
+
+static void msgo_end(struct Scsi_Host *shpnt)
+{
+	if(MSGO_I<MSGOLEN) {
+		printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+		if(SYNCNEG==1) {
+			printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+			SYNCNEG=2;
+		}
+	}
+		
+	MSGO_I  = 0;
+	MSGOLEN = 0;
+}
+
+/* 
+ * command phase
+ *
+ */
+static void cmd_init(struct Scsi_Host *shpnt)
+{
+	if (CURRENT_SC->SCp.sent_command) {
+		printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_ERROR << 16);
+		return;
+	}
+
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_cmd) {
+		printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
+		print_command(CURRENT_SC->cmnd);
+	}
+#endif
+
+	CMD_I=0;
+}
+
+/*
+ * command phase
+ *
+ */
+static void cmd_run(struct Scsi_Host *shpnt)
+{
+	if(CMD_I==CURRENT_SC->cmd_len) {
+		DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+		disp_ports(shpnt);
+	}
+
+	while(CMD_I<CURRENT_SC->cmd_len) {
+		DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len);
+
+		if(TESTLO(SSTAT0, SPIORDY)) {
+			DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}
+
+		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
+	}
+}
+
+static void cmd_end(struct Scsi_Host *shpnt)
+{
+	if(CMD_I<CURRENT_SC->cmd_len)
+		printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+	else
+		CURRENT_SC->SCp.sent_command++;
+}
+
+/*
+ * status phase
+ *
+ */
+static void status_run(struct Scsi_Host *shpnt)
+{
+	if(TESTLO(SSTAT0,SPIORDY)) {
+		DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+		return;
+	}
+
+	CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
+
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_status) {
+		printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
+		print_status(CURRENT_SC->SCp.Status);
+		printk("\n");
+	}
+#endif
+}
+
+/*
+ * data in phase
+ *
+ */
+static void datai_init(struct Scsi_Host *shpnt)
+{
+	SETPORT(DMACNTRL0, RSTFIFO);
+	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
+
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
+
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
+
+	DATA_LEN=0;
+	DPRINTK(debug_datai,
+		DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
+
+static void datai_run(struct Scsi_Host *shpnt)
+{
+	unsigned long the_time;
+	int fifodata, data_count;
+
+	/*
+	 * loop while the phase persists or the fifos are not empty
+	 *
+	 */
+	while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
+		/* FIXME: maybe this should be done by setting up
+		 * STCNT to trigger ENSWRAP interrupt, instead of
+		 * polling for DFIFOFULL
+		 */
+		the_time=jiffies + 100*HZ;
+		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
+			barrier();
+
+		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
+			printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
+			disp_ports(shpnt);
+			break;
+		}
+
+		if(TESTHI(DMASTAT, DFIFOFULL)) {
+			fifodata = 128;
+		} else {
+			the_time=jiffies + 100*HZ;
+			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
+				barrier();
+
+			if(TESTLO(SSTAT2, SEMPTY)) {
+				printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
+				disp_ports(shpnt);
+				break;
+			}
+
+			fifodata = GETPORT(FIFOSTAT);
+		}
+
+		if(CURRENT_SC->SCp.this_residual>0) {
+			while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
+                        	data_count = fifodata>CURRENT_SC->SCp.this_residual ?
+						CURRENT_SC->SCp.this_residual :
+						fifodata;
+				fifodata -= data_count;
+
+                        	if(data_count & 1) {
+					DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
+                                	SETPORT(DMACNTRL0, ENDMA|_8BIT);
+                                	*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+                                	CURRENT_SC->SCp.this_residual--;
+                                	DATA_LEN++;
+                                	SETPORT(DMACNTRL0, ENDMA);
+                        	}
+	
+                        	if(data_count > 1) {
+					DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
+                                	data_count >>= 1;
+                                	insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+                                	CURRENT_SC->SCp.ptr           += 2 * data_count;
+                                	CURRENT_SC->SCp.this_residual -= 2 * data_count;
+                                	DATA_LEN                      += 2 * data_count;
+                        	}
+	
+                        	if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+                               		/* advance to next buffer */
+                               		CURRENT_SC->SCp.buffers_residual--;
+                               		CURRENT_SC->SCp.buffer++;
+                               		CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+                               		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+				} 
+                	}
+		} else if(fifodata>0) { 
+			printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
+                        SETPORT(DMACNTRL0, ENDMA|_8BIT);
+			while(fifodata>0) {
+				int data;
+				data=GETPORT(DATAPORT);
+				DPRINTK(debug_datai, DEBUG_LEAD "data=%02x\n", CMDINFO(CURRENT_SC), data);
+				fifodata--;
+				DATA_LEN++;
+			}
+                        SETPORT(DMACNTRL0, ENDMA|_8BIT);
+		}
+	}
+
+	if(TESTLO(DMASTAT, INTSTAT) ||
+	   TESTLO(DMASTAT, DFIFOEMP) ||
+	   TESTLO(SSTAT2, SEMPTY) ||
+	   GETPORT(FIFOSTAT)>0) {
+	   	/*
+		 * something went wrong, if there's something left in the fifos
+		 * or the phase didn't change
+		 */
+		printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC));
+		disp_ports(shpnt);
+	}
+
+	if(DATA_LEN!=GETSTCNT()) {
+		printk(ERR_LEAD
+		       "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)",
+		       CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT));
+		disp_ports(shpnt);
+		mdelay(10000);
+	}
+}
+
+static void datai_end(struct Scsi_Host *shpnt)
+{
+	CURRENT_SC->resid -= GETSTCNT();
+
+	DPRINTK(debug_datai,
+		DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
+
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(DMACNTRL0, 0);
+}
+
+/*
+ * data out phase
+ *
+ */
+static void datao_init(struct Scsi_Host *shpnt)
+{
+	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
+
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
+
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
+
+	DATA_LEN = CURRENT_SC->resid;
+
+	DPRINTK(debug_datao,
+		DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
+
+static void datao_run(struct Scsi_Host *shpnt)
+{
+	unsigned long the_time;
+	int data_count;
+
+	/* until phase changes or all data sent */
+	while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
+		data_count = 128;
+		if(data_count > CURRENT_SC->SCp.this_residual)
+			data_count=CURRENT_SC->SCp.this_residual;
+
+		if(TESTLO(DMASTAT, DFIFOEMP)) {
+			printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
+			disp_ports(shpnt);
+			break;
+		}
+
+		if(data_count & 1) {
+			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
+			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+			CURRENT_SC->SCp.this_residual--;
+			CURRENT_SC->resid--;
+			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
+		}
+
+		if(data_count > 1) {
+			data_count >>= 1;
+			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+			CURRENT_SC->SCp.ptr           += 2 * data_count;
+			CURRENT_SC->SCp.this_residual -= 2 * data_count;
+			CURRENT_SC->resid             -= 2 * data_count;
+	  	}
+
+		if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+			/* advance to next buffer */
+			CURRENT_SC->SCp.buffers_residual--;
+			CURRENT_SC->SCp.buffer++;
+			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+		}
+
+		the_time=jiffies + 100*HZ;
+		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
+			barrier();
+
+		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
+			printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
+			disp_ports(shpnt);
+			break;
+		}
+	}
+}
+
+static void datao_end(struct Scsi_Host *shpnt)
+{
+	if(TESTLO(DMASTAT, DFIFOEMP)) {
+		int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+
+		DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
+			CMDINFO(CURRENT_SC),
+			data_count,
+			DATA_LEN-CURRENT_SC->resid,
+			GETSTCNT());
+
+		CURRENT_SC->resid += data_count;
+
+		if(CURRENT_SC->use_sg) {
+			data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
+			while(data_count>0) {
+				CURRENT_SC->SCp.buffer--;
+				CURRENT_SC->SCp.buffers_residual++;
+				data_count -= CURRENT_SC->SCp.buffer->length;
+			}
+			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
+			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
+		} else {
+			CURRENT_SC->SCp.ptr           -= data_count;
+			CURRENT_SC->SCp.this_residual += data_count;
+		}
+	}
+
+	DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
+		CMDINFO(CURRENT_SC),
+		CURRENT_SC->request_bufflen,
+		CURRENT_SC->resid,
+		GETSTCNT());
+
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
+
+	SETPORT(DMACNTRL0, 0);
+}
+
+/*
+ * figure out what state we're in
+ *
+ */
+static int update_state(struct Scsi_Host *shpnt)
+{
+	int dataphase=0;
+	unsigned int stat0 = GETPORT(SSTAT0);
+	unsigned int stat1 = GETPORT(SSTAT1);
+
+	PREVSTATE = STATE;
+	STATE=unknown;
+
+	if(stat1 & SCSIRSTI) {
+		STATE=rsti;
+		SETPORT(SCSISEQ,0);
+		SETPORT(SSTAT1,SCSIRSTI);
+  	} else if(stat0 & SELDI && PREVSTATE==busfree) {
+		STATE=seldi;
+	} else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
+		STATE=seldo;
+	} else if(stat1 & SELTO) {
+		STATE=selto;
+	} else if(stat1 & BUSFREE) {
+		STATE=busfree;
+		SETPORT(SSTAT1,BUSFREE);
+	} else if(stat1 & SCSIPERR) {
+		STATE=parerr;
+		SETPORT(SSTAT1,SCSIPERR);
+	} else if(stat1 & REQINIT) {
+		switch(GETPORT(SCSISIG) & P_MASK) {
+		case P_MSGI:	STATE=msgi;	break;
+		case P_MSGO:	STATE=msgo;	break;
+		case P_DATAO:	STATE=datao;	break;
+		case P_DATAI:	STATE=datai;	break;
+		case P_STATUS:	STATE=status;	break;
+		case P_CMD:	STATE=cmd;	break;
+		}
+		dataphase=1;
+	}
+
+	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
+		printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
+		disp_ports(shpnt);
+	}
+
+	if(STATE!=PREVSTATE) {
+		LASTSTATE=PREVSTATE;
+	}
+
+	return dataphase;
+}
+
+/*
+ * handle parity error
+ *
+ * FIXME: in which phase?
+ *
+ */
+static void parerr_run(struct Scsi_Host *shpnt)
+{
+	printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC));
+	done(shpnt, DID_PARITY << 16);
+}
+
+/*
+ * handle reset in
+ *
+ */
+static void rsti_run(struct Scsi_Host *shpnt)
+{
+	Scsi_Cmnd *ptr;
+
+	printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
+	
+	ptr=DISCONNECTED_SC;
+	while(ptr) {
+		Scsi_Cmnd *next = SCNEXT(ptr);
+
+		if (!ptr->device->soft_reset) {
+			remove_SC(&DISCONNECTED_SC, ptr);
+
+			kfree(ptr->host_scribble);
+			ptr->host_scribble=NULL;
+
+			ptr->result =  DID_RESET << 16;
+			ptr->scsi_done(ptr);
+		}
+
+		ptr = next;
+	}
+
+	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
+		done(shpnt, DID_RESET << 16 );
+}
+
+
+/*
+ * bottom-half handler
+ *
+ */
+static void is_complete(struct Scsi_Host *shpnt)
+{
+	int dataphase;
+	unsigned long flags;
+	int pending;
+
+	DO_LOCK(flags);
+	if(HOSTDATA(shpnt)->in_intr) {
+		DO_UNLOCK(flags);
+		/* aha152x_error never returns.. */
+		aha152x_error(shpnt, "bottom-half already running!?");
+	}
+	HOSTDATA(shpnt)->in_intr++;
+
+	/*
+	 * loop while there are interrupt conditions pending
+	 *
+	 */
+	do {
+		unsigned long start = jiffies;
+		DO_UNLOCK(flags);
+
+		dataphase=update_state(shpnt);
+
+		DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+
+		/*
+		 * end previous state
+		 *
+		 */
+		if(PREVSTATE!=STATE && states[PREVSTATE].end)
+			states[PREVSTATE].end(shpnt);
+
+		/*
+		 * disable SPIO mode if previous phase used it
+		 * and this one doesn't
+		 *
+		 */
+		if(states[PREVSTATE].spio && !states[STATE].spio) {
+			SETPORT(SXFRCTL0, CH1);
+			SETPORT(DMACNTRL0, 0);
+			if(CURRENT_SC)
+				CURRENT_SC->SCp.phase &= ~spiordy;
+		}
+
+		/*
+		 * accept current dataphase phase
+		 *
+		 */
+		if(dataphase) {
+			SETPORT(SSTAT0, REQINIT);
+			SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
+			SETPORT(SSTAT1, PHASECHG);  
+		}
+		
+		/*
+		 * enable SPIO mode if previous didn't use it
+		 * and this one does
+		 *
+		 */
+		if(!states[PREVSTATE].spio && states[STATE].spio) {
+			SETPORT(DMACNTRL0, 0);
+			SETPORT(SXFRCTL0, CH1|SPIOEN);
+			if(CURRENT_SC)
+				CURRENT_SC->SCp.phase |= spiordy;
+		}
+		
+		/*
+		 * initialize for new state
+		 *
+		 */
+		if(PREVSTATE!=STATE && states[STATE].init)
+			states[STATE].init(shpnt);
+		
+		/*
+		 * handle current state
+		 *
+		 */
+		if(states[STATE].run)
+			states[STATE].run(shpnt);
+		else
+			printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE);
+		
+		/*
+		 * setup controller to interrupt on
+		 * the next expected condition and
+		 * loop if it's already there
+		 *
+		 */
+		DO_LOCK(flags);
+		pending=setup_expected_interrupts(shpnt);
+#if defined(AHA152X_STAT)
+		HOSTDATA(shpnt)->count[STATE]++;
+		if(PREVSTATE!=STATE)
+			HOSTDATA(shpnt)->count_trans[STATE]++;
+		HOSTDATA(shpnt)->time[STATE] += jiffies-start;
+#endif
+
+		DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+	} while(pending);
+
+	/*
+	 * enable interrupts and leave bottom-half
+	 *
+	 */
+	HOSTDATA(shpnt)->in_intr--;
+	SETBITS(DMACNTRL0, INTEN);
+	DO_UNLOCK(flags);
+}
+
+
+/* 
+ * Dump the current driver status and panic
+ */
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
+{
+	printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg);
+	show_queues(shpnt);
+	panic("aha152x panic\n");
+}
+
+/*
+ * Display registers of AIC-6260
+ */
+static void disp_ports(struct Scsi_Host *shpnt)
+{
+#if defined(AHA152X_DEBUG)
+	int s;
+
+	printk("\n%s: %s(%s) ",
+		CURRENT_SC ? "busy" : "waiting",
+		states[STATE].name,
+		states[PREVSTATE].name);
+
+	s = GETPORT(SCSISEQ);
+	printk("SCSISEQ( ");
+	if (s & TEMODEO)
+		printk("TARGET MODE ");
+	if (s & ENSELO)
+		printk("SELO ");
+	if (s & ENSELI)
+		printk("SELI ");
+	if (s & ENRESELI)
+		printk("RESELI ");
+	if (s & ENAUTOATNO)
+		printk("AUTOATNO ");
+	if (s & ENAUTOATNI)
+		printk("AUTOATNI ");
+	if (s & ENAUTOATNP)
+		printk("AUTOATNP ");
+	if (s & SCSIRSTO)
+		printk("SCSIRSTO ");
+	printk(");");
+
+	printk(" SCSISIG(");
+	s = GETPORT(SCSISIG);
+	switch (s & P_MASK) {
+	case P_DATAO:
+		printk("DATA OUT");
+		break;
+	case P_DATAI:
+		printk("DATA IN");
+		break;
+	case P_CMD:
+		printk("COMMAND");
+		break;
+	case P_STATUS:
+		printk("STATUS");
+		break;
+	case P_MSGO:
+		printk("MESSAGE OUT");
+		break;
+	case P_MSGI:
+		printk("MESSAGE IN");
+		break;
+	default:
+		printk("*invalid*");
+		break;
+	}
+
+	printk("); ");
+
+	printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+
+	printk("SSTAT( ");
+	s = GETPORT(SSTAT0);
+	if (s & TARGET)
+		printk("TARGET ");
+	if (s & SELDO)
+		printk("SELDO ");
+	if (s & SELDI)
+		printk("SELDI ");
+	if (s & SELINGO)
+		printk("SELINGO ");
+	if (s & SWRAP)
+		printk("SWRAP ");
+	if (s & SDONE)
+		printk("SDONE ");
+	if (s & SPIORDY)
+		printk("SPIORDY ");
+	if (s & DMADONE)
+		printk("DMADONE ");
+
+	s = GETPORT(SSTAT1);
+	if (s & SELTO)
+		printk("SELTO ");
+	if (s & ATNTARG)
+		printk("ATNTARG ");
+	if (s & SCSIRSTI)
+		printk("SCSIRSTI ");
+	if (s & PHASEMIS)
+		printk("PHASEMIS ");
+	if (s & BUSFREE)
+		printk("BUSFREE ");
+	if (s & SCSIPERR)
+		printk("SCSIPERR ");
+	if (s & PHASECHG)
+		printk("PHASECHG ");
+	if (s & REQINIT)
+		printk("REQINIT ");
+	printk("); ");
+
+
+	printk("SSTAT( ");
+
+	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+	if (s & TARGET)
+		printk("TARGET ");
+	if (s & SELDO)
+		printk("SELDO ");
+	if (s & SELDI)
+		printk("SELDI ");
+	if (s & SELINGO)
+		printk("SELINGO ");
+	if (s & SWRAP)
+		printk("SWRAP ");
+	if (s & SDONE)
+		printk("SDONE ");
+	if (s & SPIORDY)
+		printk("SPIORDY ");
+	if (s & DMADONE)
+		printk("DMADONE ");
+
+	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+	if (s & SELTO)
+		printk("SELTO ");
+	if (s & ATNTARG)
+		printk("ATNTARG ");
+	if (s & SCSIRSTI)
+		printk("SCSIRSTI ");
+	if (s & PHASEMIS)
+		printk("PHASEMIS ");
+	if (s & BUSFREE)
+		printk("BUSFREE ");
+	if (s & SCSIPERR)
+		printk("SCSIPERR ");
+	if (s & PHASECHG)
+		printk("PHASECHG ");
+	if (s & REQINIT)
+		printk("REQINIT ");
+	printk("); ");
+
+	printk("SXFRCTL0( ");
+
+	s = GETPORT(SXFRCTL0);
+	if (s & SCSIEN)
+		printk("SCSIEN ");
+	if (s & DMAEN)
+		printk("DMAEN ");
+	if (s & CH1)
+		printk("CH1 ");
+	if (s & CLRSTCNT)
+		printk("CLRSTCNT ");
+	if (s & SPIOEN)
+		printk("SPIOEN ");
+	if (s & CLRCH1)
+		printk("CLRCH1 ");
+	printk("); ");
+
+	printk("SIGNAL( ");
+
+	s = GETPORT(SCSISIG);
+	if (s & SIG_ATNI)
+		printk("ATNI ");
+	if (s & SIG_SELI)
+		printk("SELI ");
+	if (s & SIG_BSYI)
+		printk("BSYI ");
+	if (s & SIG_REQI)
+		printk("REQI ");
+	if (s & SIG_ACKI)
+		printk("ACKI ");
+	printk("); ");
+
+	printk("SELID (%02x), ", GETPORT(SELID));
+
+	printk("STCNT (%d), ", GETSTCNT());
+	
+	printk("SSTAT2( ");
+
+	s = GETPORT(SSTAT2);
+	if (s & SOFFSET)
+		printk("SOFFSET ");
+	if (s & SEMPTY)
+		printk("SEMPTY ");
+	if (s & SFULL)
+		printk("SFULL ");
+	printk("); SFCNT (%d); ", s & (SFULL | SFCNT));
+
+	s = GETPORT(SSTAT3);
+	printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+
+	printk("SSTAT4( ");
+	s = GETPORT(SSTAT4);
+	if (s & SYNCERR)
+		printk("SYNCERR ");
+	if (s & FWERR)
+		printk("FWERR ");
+	if (s & FRERR)
+		printk("FRERR ");
+	printk("); ");
+
+	printk("DMACNTRL0( ");
+	s = GETPORT(DMACNTRL0);
+	printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
+	printk("%s ", s & DMA ? "DMA" : "PIO");
+	printk("%s ", s & WRITE_READ ? "WRITE" : "READ");
+	if (s & ENDMA)
+		printk("ENDMA ");
+	if (s & INTEN)
+		printk("INTEN ");
+	if (s & RSTFIFO)
+		printk("RSTFIFO ");
+	if (s & SWINT)
+		printk("SWINT ");
+	printk("); ");
+
+	printk("DMASTAT( ");
+	s = GETPORT(DMASTAT);
+	if (s & ATDONE)
+		printk("ATDONE ");
+	if (s & WORDRDY)
+		printk("WORDRDY ");
+	if (s & DFIFOFULL)
+		printk("DFIFOFULL ");
+	if (s & DFIFOEMP)
+		printk("DFIFOEMP ");
+	printk(")\n");
+#endif
+}
+
+/*
+ * display enabled interrupts
+ */
+static void disp_enintr(struct Scsi_Host *shpnt)
+{
+	int s;
+
+	printk(KERN_DEBUG "enabled interrupts ( ");
+
+	s = GETPORT(SIMODE0);
+	if (s & ENSELDO)
+		printk("ENSELDO ");
+	if (s & ENSELDI)
+		printk("ENSELDI ");
+	if (s & ENSELINGO)
+		printk("ENSELINGO ");
+	if (s & ENSWRAP)
+		printk("ENSWRAP ");
+	if (s & ENSDONE)
+		printk("ENSDONE ");
+	if (s & ENSPIORDY)
+		printk("ENSPIORDY ");
+	if (s & ENDMADONE)
+		printk("ENDMADONE ");
+
+	s = GETPORT(SIMODE1);
+	if (s & ENSELTIMO)
+		printk("ENSELTIMO ");
+	if (s & ENATNTARG)
+		printk("ENATNTARG ");
+	if (s & ENPHASEMIS)
+		printk("ENPHASEMIS ");
+	if (s & ENBUSFREE)
+		printk("ENBUSFREE ");
+	if (s & ENSCSIPERR)
+		printk("ENSCSIPERR ");
+	if (s & ENPHASECHG)
+		printk("ENPHASECHG ");
+	if (s & ENREQINIT)
+		printk("ENREQINIT ");
+	printk(")\n");
+}
+
+/*
+ * Show the command data of a command
+ */
+static void show_command(Scsi_Cmnd *ptr)
+{
+	printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
+	       (unsigned int) ptr, ptr->device->id, ptr->device->lun);
+
+	print_command(ptr->cmnd);
+
+	printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
+	       ptr->request_bufflen, ptr->resid);
+
+	if (ptr->SCp.phase & not_issued)
+		printk("not issued|");
+	if (ptr->SCp.phase & selecting)
+		printk("selecting|");
+	if (ptr->SCp.phase & identified)
+		printk("identified|");
+	if (ptr->SCp.phase & disconnected)
+		printk("disconnected|");
+	if (ptr->SCp.phase & completed)
+		printk("completed|");
+	if (ptr->SCp.phase & spiordy)
+		printk("spiordy|");
+	if (ptr->SCp.phase & syncneg)
+		printk("syncneg|");
+	if (ptr->SCp.phase & aborted)
+		printk("aborted|");
+	if (ptr->SCp.phase & resetted)
+		printk("resetted|");
+	if( SCDATA(ptr) ) {
+		printk("; next=0x%p\n", SCNEXT(ptr));
+	} else {
+		printk("; next=(host scribble NULL)\n");
+	}
+}
+
+/*
+ * Dump the queued data
+ */
+static void show_queues(struct Scsi_Host *shpnt)
+{
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+
+	DO_LOCK(flags);
+	printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
+	for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
+		show_command(ptr);
+	DO_UNLOCK(flags);
+
+	printk(KERN_DEBUG "current_SC:\n");
+	if (CURRENT_SC)
+		show_command(CURRENT_SC);
+	else
+		printk(KERN_DEBUG "none\n");
+
+	printk(KERN_DEBUG "disconnected_SC:\n");
+	for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
+		show_command(ptr);
+
+	disp_ports(shpnt);
+	disp_enintr(shpnt);
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+static int get_command(char *pos, Scsi_Cmnd * ptr)
+{
+	char *start = pos;
+	int i;
+
+	SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ",
+		(unsigned int) ptr, ptr->device->id, ptr->device->lun);
+
+	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
+		SPRINTF("0x%02x ", ptr->cmnd[i]);
+
+	SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
+		ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+
+	if (ptr->SCp.phase & not_issued)
+		SPRINTF("not issued|");
+	if (ptr->SCp.phase & selecting)
+		SPRINTF("selecting|");
+	if (ptr->SCp.phase & disconnected)
+		SPRINTF("disconnected|");
+	if (ptr->SCp.phase & aborted)
+		SPRINTF("aborted|");
+	if (ptr->SCp.phase & identified)
+		SPRINTF("identified|");
+	if (ptr->SCp.phase & completed)
+		SPRINTF("completed|");
+	if (ptr->SCp.phase & spiordy)
+		SPRINTF("spiordy|");
+	if (ptr->SCp.phase & syncneg)
+		SPRINTF("syncneg|");
+	SPRINTF("; next=0x%p\n", SCNEXT(ptr));
+
+	return (pos - start);
+}
+
+static int get_ports(struct Scsi_Host *shpnt, char *pos)
+{
+	char *start = pos;
+	int s;
+
+	SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
+
+	s = GETPORT(SCSISEQ);
+	SPRINTF("SCSISEQ( ");
+	if (s & TEMODEO)
+		SPRINTF("TARGET MODE ");
+	if (s & ENSELO)
+		SPRINTF("SELO ");
+	if (s & ENSELI)
+		SPRINTF("SELI ");
+	if (s & ENRESELI)
+		SPRINTF("RESELI ");
+	if (s & ENAUTOATNO)
+		SPRINTF("AUTOATNO ");
+	if (s & ENAUTOATNI)
+		SPRINTF("AUTOATNI ");
+	if (s & ENAUTOATNP)
+		SPRINTF("AUTOATNP ");
+	if (s & SCSIRSTO)
+		SPRINTF("SCSIRSTO ");
+	SPRINTF(");");
+
+	SPRINTF(" SCSISIG(");
+	s = GETPORT(SCSISIG);
+	switch (s & P_MASK) {
+	case P_DATAO:
+		SPRINTF("DATA OUT");
+		break;
+	case P_DATAI:
+		SPRINTF("DATA IN");
+		break;
+	case P_CMD:
+		SPRINTF("COMMAND");
+		break;
+	case P_STATUS:
+		SPRINTF("STATUS");
+		break;
+	case P_MSGO:
+		SPRINTF("MESSAGE OUT");
+		break;
+	case P_MSGI:
+		SPRINTF("MESSAGE IN");
+		break;
+	default:
+		SPRINTF("*invalid*");
+		break;
+	}
+
+	SPRINTF("); ");
+
+	SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+
+	SPRINTF("SSTAT( ");
+	s = GETPORT(SSTAT0);
+	if (s & TARGET)
+		SPRINTF("TARGET ");
+	if (s & SELDO)
+		SPRINTF("SELDO ");
+	if (s & SELDI)
+		SPRINTF("SELDI ");
+	if (s & SELINGO)
+		SPRINTF("SELINGO ");
+	if (s & SWRAP)
+		SPRINTF("SWRAP ");
+	if (s & SDONE)
+		SPRINTF("SDONE ");
+	if (s & SPIORDY)
+		SPRINTF("SPIORDY ");
+	if (s & DMADONE)
+		SPRINTF("DMADONE ");
+
+	s = GETPORT(SSTAT1);
+	if (s & SELTO)
+		SPRINTF("SELTO ");
+	if (s & ATNTARG)
+		SPRINTF("ATNTARG ");
+	if (s & SCSIRSTI)
+		SPRINTF("SCSIRSTI ");
+	if (s & PHASEMIS)
+		SPRINTF("PHASEMIS ");
+	if (s & BUSFREE)
+		SPRINTF("BUSFREE ");
+	if (s & SCSIPERR)
+		SPRINTF("SCSIPERR ");
+	if (s & PHASECHG)
+		SPRINTF("PHASECHG ");
+	if (s & REQINIT)
+		SPRINTF("REQINIT ");
+	SPRINTF("); ");
+
+
+	SPRINTF("SSTAT( ");
+
+	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+	if (s & TARGET)
+		SPRINTF("TARGET ");
+	if (s & SELDO)
+		SPRINTF("SELDO ");
+	if (s & SELDI)
+		SPRINTF("SELDI ");
+	if (s & SELINGO)
+		SPRINTF("SELINGO ");
+	if (s & SWRAP)
+		SPRINTF("SWRAP ");
+	if (s & SDONE)
+		SPRINTF("SDONE ");
+	if (s & SPIORDY)
+		SPRINTF("SPIORDY ");
+	if (s & DMADONE)
+		SPRINTF("DMADONE ");
+
+	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+	if (s & SELTO)
+		SPRINTF("SELTO ");
+	if (s & ATNTARG)
+		SPRINTF("ATNTARG ");
+	if (s & SCSIRSTI)
+		SPRINTF("SCSIRSTI ");
+	if (s & PHASEMIS)
+		SPRINTF("PHASEMIS ");
+	if (s & BUSFREE)
+		SPRINTF("BUSFREE ");
+	if (s & SCSIPERR)
+		SPRINTF("SCSIPERR ");
+	if (s & PHASECHG)
+		SPRINTF("PHASECHG ");
+	if (s & REQINIT)
+		SPRINTF("REQINIT ");
+	SPRINTF("); ");
+
+	SPRINTF("SXFRCTL0( ");
+
+	s = GETPORT(SXFRCTL0);
+	if (s & SCSIEN)
+		SPRINTF("SCSIEN ");
+	if (s & DMAEN)
+		SPRINTF("DMAEN ");
+	if (s & CH1)
+		SPRINTF("CH1 ");
+	if (s & CLRSTCNT)
+		SPRINTF("CLRSTCNT ");
+	if (s & SPIOEN)
+		SPRINTF("SPIOEN ");
+	if (s & CLRCH1)
+		SPRINTF("CLRCH1 ");
+	SPRINTF("); ");
+
+	SPRINTF("SIGNAL( ");
+
+	s = GETPORT(SCSISIG);
+	if (s & SIG_ATNI)
+		SPRINTF("ATNI ");
+	if (s & SIG_SELI)
+		SPRINTF("SELI ");
+	if (s & SIG_BSYI)
+		SPRINTF("BSYI ");
+	if (s & SIG_REQI)
+		SPRINTF("REQI ");
+	if (s & SIG_ACKI)
+		SPRINTF("ACKI ");
+	SPRINTF("); ");
+
+	SPRINTF("SELID(%02x), ", GETPORT(SELID));
+
+	SPRINTF("STCNT(%d), ", GETSTCNT());
+
+	SPRINTF("SSTAT2( ");
+
+	s = GETPORT(SSTAT2);
+	if (s & SOFFSET)
+		SPRINTF("SOFFSET ");
+	if (s & SEMPTY)
+		SPRINTF("SEMPTY ");
+	if (s & SFULL)
+		SPRINTF("SFULL ");
+	SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT));
+
+	s = GETPORT(SSTAT3);
+	SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+
+	SPRINTF("SSTAT4( ");
+	s = GETPORT(SSTAT4);
+	if (s & SYNCERR)
+		SPRINTF("SYNCERR ");
+	if (s & FWERR)
+		SPRINTF("FWERR ");
+	if (s & FRERR)
+		SPRINTF("FRERR ");
+	SPRINTF("); ");
+
+	SPRINTF("DMACNTRL0( ");
+	s = GETPORT(DMACNTRL0);
+	SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
+	SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
+	SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ");
+	if (s & ENDMA)
+		SPRINTF("ENDMA ");
+	if (s & INTEN)
+		SPRINTF("INTEN ");
+	if (s & RSTFIFO)
+		SPRINTF("RSTFIFO ");
+	if (s & SWINT)
+		SPRINTF("SWINT ");
+	SPRINTF("); ");
+
+	SPRINTF("DMASTAT( ");
+	s = GETPORT(DMASTAT);
+	if (s & ATDONE)
+		SPRINTF("ATDONE ");
+	if (s & WORDRDY)
+		SPRINTF("WORDRDY ");
+	if (s & DFIFOFULL)
+		SPRINTF("DFIFOFULL ");
+	if (s & DFIFOEMP)
+		SPRINTF("DFIFOEMP ");
+	SPRINTF(")\n");
+
+	SPRINTF("enabled interrupts( ");
+
+	s = GETPORT(SIMODE0);
+	if (s & ENSELDO)
+		SPRINTF("ENSELDO ");
+	if (s & ENSELDI)
+		SPRINTF("ENSELDI ");
+	if (s & ENSELINGO)
+		SPRINTF("ENSELINGO ");
+	if (s & ENSWRAP)
+		SPRINTF("ENSWRAP ");
+	if (s & ENSDONE)
+		SPRINTF("ENSDONE ");
+	if (s & ENSPIORDY)
+		SPRINTF("ENSPIORDY ");
+	if (s & ENDMADONE)
+		SPRINTF("ENDMADONE ");
+
+	s = GETPORT(SIMODE1);
+	if (s & ENSELTIMO)
+		SPRINTF("ENSELTIMO ");
+	if (s & ENATNTARG)
+		SPRINTF("ENATNTARG ");
+	if (s & ENPHASEMIS)
+		SPRINTF("ENPHASEMIS ");
+	if (s & ENBUSFREE)
+		SPRINTF("ENBUSFREE ");
+	if (s & ENSCSIPERR)
+		SPRINTF("ENSCSIPERR ");
+	if (s & ENPHASECHG)
+		SPRINTF("ENPHASECHG ");
+	if (s & ENREQINIT)
+		SPRINTF("ENREQINIT ");
+	SPRINTF(")\n");
+
+	return (pos - start);
+}
+
+static int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+	if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
+		return -EINVAL;
+
+#if defined(AHA152X_DEBUG)
+	if(length>14 && strncmp("debug ", buffer+8, 6)==0) {
+		int debug = HOSTDATA(shpnt)->debug;
+
+		HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0);
+
+		printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug);
+	} else
+#endif
+#if defined(AHA152X_STAT)
+	if(length>13 && strncmp("reset", buffer+8, 5)==0) {
+		int i;
+
+		HOSTDATA(shpnt)->total_commands=0;
+		HOSTDATA(shpnt)->disconnections=0;
+		HOSTDATA(shpnt)->busfree_without_any_action=0;
+		HOSTDATA(shpnt)->busfree_without_old_command=0;
+		HOSTDATA(shpnt)->busfree_without_new_command=0;
+		HOSTDATA(shpnt)->busfree_without_done_command=0;
+		HOSTDATA(shpnt)->busfree_with_check_condition=0;
+		for (i = idle; i<maxstate; i++) {
+			HOSTDATA(shpnt)->count[i]=0;
+			HOSTDATA(shpnt)->count_trans[i]=0;
+			HOSTDATA(shpnt)->time[i]=0;
+		}
+
+		printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO);
+
+	} else
+#endif
+	{
+		return -EINVAL;
+	}
+
+
+	return length;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+	do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+
+static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start,
+		      off_t offset, int length, int inout)
+{
+	int i;
+	char *pos = buffer;
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+	int thislength;
+
+	DPRINTK(debug_procinfo, 
+	       KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
+	       buffer, offset, length, shpnt->host_no, inout);
+
+
+	if (inout)
+		return aha152x_set_info(buffer, length, shpnt);
+
+	SPRINTF(AHA152X_REVID "\n");
+
+	SPRINTF("ioports 0x%04lx to 0x%04lx\n",
+		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
+	SPRINTF("interrupt 0x%02x\n", shpnt->irq);
+	SPRINTF("disconnection/reconnection %s\n",
+		RECONNECT ? "enabled" : "disabled");
+	SPRINTF("parity checking %s\n",
+		PARITY ? "enabled" : "disabled");
+	SPRINTF("synchronous transfers %s\n",
+		SYNCHRONOUS ? "enabled" : "disabled");
+	SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
+
+	if(SYNCHRONOUS) {
+		SPRINTF("synchronously operating targets (tick=50 ns):\n");
+		for (i = 0; i < 8; i++)
+			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
+				SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n",
+					i,
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
+				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
+	}
+#if defined(AHA152X_DEBUG)
+#define PDEBUG(flags,txt) \
+	if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
+
+	SPRINTF("enabled debugging options: ");
+
+	PDEBUG(debug_procinfo, "procinfo");
+	PDEBUG(debug_queue, "queue");
+	PDEBUG(debug_intr, "interrupt");
+	PDEBUG(debug_selection, "selection");
+	PDEBUG(debug_msgo, "message out");
+	PDEBUG(debug_msgi, "message in");
+	PDEBUG(debug_status, "status");
+	PDEBUG(debug_cmd, "command");
+	PDEBUG(debug_datai, "data in");
+	PDEBUG(debug_datao, "data out");
+	PDEBUG(debug_eh, "eh");
+	PDEBUG(debug_locks, "locks");
+	PDEBUG(debug_phases, "phases");
+
+	SPRINTF("\n");
+#endif
+
+	SPRINTF("\nqueue status:\n");
+	DO_LOCK(flags);
+	if (ISSUE_SC) {
+		SPRINTF("not yet issued commands:\n");
+		for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
+			pos += get_command(pos, ptr);
+	} else
+		SPRINTF("no not yet issued commands\n");
+	DO_UNLOCK(flags);
+
+	if (CURRENT_SC) {
+		SPRINTF("current command:\n");
+		pos += get_command(pos, CURRENT_SC);
+	} else
+		SPRINTF("no current command\n");
+
+	if (DISCONNECTED_SC) {
+		SPRINTF("disconnected commands:\n");
+		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
+			pos += get_command(pos, ptr);
+	} else
+		SPRINTF("no disconnected commands\n");
+
+	pos += get_ports(shpnt, pos);
+
+#if defined(AHA152X_STAT)
+	SPRINTF("statistics:\n"
+	        "total commands:               %d\n"
+	        "disconnections:               %d\n"
+		"busfree with check condition: %d\n"
+		"busfree without old command:  %d\n"
+		"busfree without new command:  %d\n"
+		"busfree without done command: %d\n"
+		"busfree without any action:   %d\n"
+		"state      "
+		"transitions  "
+		"count        "
+		"time\n",
+		HOSTDATA(shpnt)->total_commands,
+		HOSTDATA(shpnt)->disconnections,
+		HOSTDATA(shpnt)->busfree_with_check_condition,
+		HOSTDATA(shpnt)->busfree_without_old_command,
+		HOSTDATA(shpnt)->busfree_without_new_command,
+		HOSTDATA(shpnt)->busfree_without_done_command,
+		HOSTDATA(shpnt)->busfree_without_any_action);
+	for(i=0; i<maxstate; i++) {
+		SPRINTF("%-10s %-12d %-12d %-12ld\n",
+		        states[i].name,
+			HOSTDATA(shpnt)->count_trans[i],
+			HOSTDATA(shpnt)->count[i],
+			HOSTDATA(shpnt)->time[i]);
+	}
+#endif
+
+	DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos);
+
+	thislength = pos - (buffer + offset);
+	DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength);
+
+	if(thislength<0) {
+		DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n");
+		*start = NULL;
+		return 0;
+	}
+
+	thislength = thislength<length ? thislength : length;
+
+	DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: return %d\n", thislength);
+
+	*start = buffer + offset;
+	return thislength < length ? thislength : length;
+}
+
+static Scsi_Host_Template aha152x_driver_template = {
+	.module				= THIS_MODULE,
+	.name				= AHA152X_REVID,
+	.proc_name			= "aha152x",
+	.proc_info			= aha152x_proc_info,
+	.queuecommand			= aha152x_queue,
+	.eh_abort_handler		= aha152x_abort,
+	.eh_device_reset_handler	= aha152x_device_reset,
+	.eh_bus_reset_handler		= aha152x_bus_reset,
+	.eh_host_reset_handler		= aha152x_host_reset,
+	.bios_param			= aha152x_biosparam,
+	.can_queue			= 1,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+};
+
+#if !defined(PCMCIA)
+static int setup_count;
+static struct aha152x_setup setup[2];
+
+/* possible i/o addresses for the AIC-6260; default first */
+static unsigned short ports[] = { 0x340, 0x140 };
+
+#if !defined(SKIP_BIOSTEST)
+/* possible locations for the Adaptec BIOS; defaults first */
+static unsigned int addresses[] =
+{
+	0xdc000,		/* default first */
+	0xc8000,
+	0xcc000,
+	0xd0000,
+	0xd4000,
+	0xd8000,
+	0xe0000,
+	0xeb800,		/* VTech Platinum SMP */
+	0xf0000,
+};
+
+/* signatures for various AIC-6[23]60 based controllers.
+   The point in detecting signatures is to avoid useless and maybe
+   harmful probes on ports. I'm not sure that all listed boards pass
+   auto-configuration. For those which fail the BIOS signature is
+   obsolete, because user intervention to supply the configuration is
+   needed anyway.  May be an information whether or not the BIOS supports
+   extended translation could be also useful here. */
+static struct signature {
+	unsigned char *signature;
+	int sig_offset;
+	int sig_length;
+} signatures[] =
+{
+	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
+		/* Adaptec 152x */
+	{ "Adaptec AHA-1520B",		0x000b, 17 },
+		/* Adaptec 152x rev B */
+	{ "Adaptec AHA-1520B",		0x0026, 17 },
+		/* Iomega Jaz Jet ISA (AIC6370Q) */
+	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
+		/* on-board controller */
+	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
+		/* on-board controller */
+	{ "Adaptec ASW-B626 S2",	0x2e6c, 19 },
+		/* on-board controller */
+	{ "Adaptec BIOS:AIC-6360",	0x000c, 21 },
+		/* on-board controller */
+	{ "ScsiPro SP-360 BIOS",	0x2873, 19 },
+		/* ScsiPro-Controller  */
+	{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
+		/* Gigabyte Local-Bus-SCSI */
+	{ "Adaptec BIOS:AVA-282X",	0x000c, 21 },
+		/* Adaptec 282x */
+	{ "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
+		/* IBM Thinkpad Dock II */
+	{ "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
+		/* IBM Thinkpad Dock II SCSI */
+	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
+		/* DTC 3520A ISA SCSI */
+};
+#endif /* !SKIP_BIOSTEST */
+
+/*
+ * Test, if port_base is valid.
+ *
+ */
+static int aha152x_porttest(int io_port)
+{
+	int i;
+
+	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16; i++)
+		SETPORT(io_port + O_STACK, i);
+
+	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
+		;
+
+	return (i == 16);
+}
+
+static int tc1550_porttest(int io_port)
+{
+	int i;
+
+	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16; i++)
+		SETPORT(io_port + O_STACK, i);
+
+	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
+		;
+
+	return (i == 16);
+}
+
+
+static int checksetup(struct aha152x_setup *setup)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
+		;
+
+	if (i == ARRAY_SIZE(ports))
+		return 0;
+
+	if ( request_region(setup->io_port, IO_RANGE, "aha152x")==0 ) {
+		printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
+		return 0;
+	}
+
+	if( aha152x_porttest(setup->io_port) ) {
+		setup->tc1550=0;
+	} else if( tc1550_porttest(setup->io_port) ) {
+		setup->tc1550=1;
+	} else {
+		release_region(setup->io_port, IO_RANGE);
+		return 0;
+	}
+
+	release_region(setup->io_port, IO_RANGE);
+
+	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
+		return 0;
+
+	if ((setup->scsiid < 0) || (setup->scsiid > 7))
+		return 0;
+
+	if ((setup->reconnect < 0) || (setup->reconnect > 1))
+		return 0;
+
+	if ((setup->parity < 0) || (setup->parity > 1))
+		return 0;
+
+	if ((setup->synchronous < 0) || (setup->synchronous > 1))
+		return 0;
+
+	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
+		return 0;
+
+
+	return 1;
+}
+
+
+static int __init aha152x_init(void)
+{
+	int i, j, ok;
+#if defined(AUTOCONF)
+	aha152x_config conf;
+#endif
+#ifdef __ISAPNP__
+	struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
+#endif
+
+	if ( setup_count ) {
+		printk(KERN_INFO "aha152x: processing commandline: ");
+
+		for (i = 0; i<setup_count; i++) {
+			if (!checksetup(&setup[i])) {
+				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
+				printk(KERN_ERR "aha152x: invalid line\n");
+			}
+		}
+		printk("ok\n");
+	}
+
+#if defined(SETUP0)
+	if (setup_count < ARRAY_SIZE(setup)) {
+		struct aha152x_setup override = SETUP0;
+
+		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
+			if (!checksetup(&override)) {
+				printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+				       override.io_port,
+				       override.irq,
+				       override.scsiid,
+				       override.reconnect,
+				       override.parity,
+				       override.synchronous,
+				       override.delay,
+				       override.ext_trans);
+			} else
+				setup[setup_count++] = override;
+		}
+	}
+#endif
+
+#if defined(SETUP1)
+	if (setup_count < ARRAY_SIZE(setup)) {
+		struct aha152x_setup override = SETUP1;
+
+		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
+			if (!checksetup(&override)) {
+				printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+				       override.io_port,
+				       override.irq,
+				       override.scsiid,
+				       override.reconnect,
+				       override.parity,
+				       override.synchronous,
+				       override.delay,
+				       override.ext_trans);
+			} else
+				setup[setup_count++] = override;
+		}
+	}
+#endif
+
+#if defined(MODULE)
+	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
+		if(aha152x[0]!=0) {
+			setup[setup_count].conf        = "";
+			setup[setup_count].io_port     = aha152x[0];
+			setup[setup_count].irq         = aha152x[1];
+			setup[setup_count].scsiid      = aha152x[2];
+			setup[setup_count].reconnect   = aha152x[3];
+			setup[setup_count].parity      = aha152x[4];
+			setup[setup_count].synchronous = aha152x[5];
+			setup[setup_count].delay       = aha152x[6];
+			setup[setup_count].ext_trans   = aha152x[7];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = aha152x[8];
+#endif
+	  	} else if(io[0]!=0 || irq[0]!=0) {
+			if(io[0]!=0)  setup[setup_count].io_port = io[0];
+			if(irq[0]!=0) setup[setup_count].irq     = irq[0];
+
+	    		setup[setup_count].scsiid      = scsiid[0];
+	    		setup[setup_count].reconnect   = reconnect[0];
+	    		setup[setup_count].parity      = parity[0];
+	    		setup[setup_count].synchronous = sync[0];
+	    		setup[setup_count].delay       = delay[0];
+	    		setup[setup_count].ext_trans   = exttrans[0];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = debug[0];
+#endif
+		}
+
+          	if (checksetup(&setup[setup_count]))
+			setup_count++;
+		else
+			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",
+			       setup[setup_count].io_port,
+			       setup[setup_count].irq,
+			       setup[setup_count].scsiid,
+			       setup[setup_count].reconnect,
+			       setup[setup_count].parity,
+			       setup[setup_count].synchronous,
+			       setup[setup_count].delay,
+			       setup[setup_count].ext_trans);
+	}
+
+	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
+		if(aha152x1[0]!=0) {
+			setup[setup_count].conf        = "";
+			setup[setup_count].io_port     = aha152x1[0];
+			setup[setup_count].irq         = aha152x1[1];
+			setup[setup_count].scsiid      = aha152x1[2];
+			setup[setup_count].reconnect   = aha152x1[3];
+			setup[setup_count].parity      = aha152x1[4];
+			setup[setup_count].synchronous = aha152x1[5];
+			setup[setup_count].delay       = aha152x1[6];
+			setup[setup_count].ext_trans   = aha152x1[7];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = aha152x1[8];
+#endif
+	  	} else if(io[1]!=0 || irq[1]!=0) {
+			if(io[1]!=0)  setup[setup_count].io_port = io[1];
+			if(irq[1]!=0) setup[setup_count].irq     = irq[1];
+
+	    		setup[setup_count].scsiid      = scsiid[1];
+	    		setup[setup_count].reconnect   = reconnect[1];
+	    		setup[setup_count].parity      = parity[1];
+	    		setup[setup_count].synchronous = sync[1];
+	    		setup[setup_count].delay       = delay[1];
+	    		setup[setup_count].ext_trans   = exttrans[1];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = debug[1];
+#endif
+		}
+		if (checksetup(&setup[setup_count]))
+			setup_count++;
+		else
+			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",
+			       setup[setup_count].io_port,
+			       setup[setup_count].irq,
+			       setup[setup_count].scsiid,
+			       setup[setup_count].reconnect,
+			       setup[setup_count].parity,
+			       setup[setup_count].synchronous,
+			       setup[setup_count].delay,
+			       setup[setup_count].ext_trans);
+	}
+#endif
+
+#ifdef __ISAPNP__
+	for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
+		while ( setup_count<ARRAY_SIZE(setup) &&
+			(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
+			if (pnp_device_attach(dev) < 0)
+				continue;
+
+			if (pnp_activate_dev(dev) < 0) {
+				pnp_device_detach(dev);
+				continue;
+			}
+
+			if (!pnp_port_valid(dev, 0)) {
+				pnp_device_detach(dev);
+				continue;
+			}
+
+			if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
+				pnp_device_detach(dev);
+				continue;
+			}
+
+			setup[setup_count].io_port     = pnp_port_start(dev, 0);
+			setup[setup_count].irq         = pnp_irq(dev, 0);
+			setup[setup_count].scsiid      = 7;
+			setup[setup_count].reconnect   = 1;
+			setup[setup_count].parity      = 1;
+			setup[setup_count].synchronous = 1;
+			setup[setup_count].delay       = DELAY_DEFAULT;
+			setup[setup_count].ext_trans   = 0;
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = DEBUG_DEFAULT;
+#endif
+#if defined(__ISAPNP__)
+			pnpdev[setup_count]            = dev;
+#endif
+			printk (KERN_INFO
+				"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
+				setup[setup_count].io_port, setup[setup_count].irq);
+			setup_count++;
+		}
+	}
+#endif
+
+#if defined(AUTOCONF)
+	if (setup_count<ARRAY_SIZE(setup)) {
+#if !defined(SKIP_BIOSTEST)
+		ok = 0;
+		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
+			void __iomem *p = ioremap(addresses[i], 0x4000);
+			if (!p)
+				continue;
+			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
+				ok = check_signature(p + signatures[j].sig_offset,
+								signatures[j].signature, signatures[j].sig_length);
+			iounmap(p);
+		}
+		if (!ok && setup_count == 0)
+			return 0;
+
+		printk(KERN_INFO "aha152x: BIOS test: passed, ");
+#else
+		printk(KERN_INFO "aha152x: ");
+#endif				/* !SKIP_BIOSTEST */
+
+		ok = 0;
+		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
+			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
+				continue;
+
+			if ( request_region(ports[i], IO_RANGE, "aha152x")==0 ) {
+				printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
+				continue;
+			}
+
+			if (aha152x_porttest(ports[i])) {
+				setup[setup_count].tc1550  = 0;
+
+				conf.cf_port =
+				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
+			} else if (tc1550_porttest(ports[i])) {
+				setup[setup_count].tc1550  = 1;
+
+				conf.cf_port =
+				    (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
+			} else {
+				release_region(ports[i], IO_RANGE);
+				continue;
+			}
+
+			release_region(ports[i], IO_RANGE);
+
+			ok++;
+			setup[setup_count].io_port = ports[i];
+			setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
+			setup[setup_count].scsiid = conf.cf_id;
+			setup[setup_count].reconnect = conf.cf_tardisc;
+			setup[setup_count].parity = !conf.cf_parity;
+			setup[setup_count].synchronous = conf.cf_syncneg;
+			setup[setup_count].delay = DELAY_DEFAULT;
+			setup[setup_count].ext_trans = 0;
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug = DEBUG_DEFAULT;
+#endif
+			setup_count++;
+
+		}
+
+		if (ok)
+			printk("auto configuration: ok, ");
+	}
+#endif
+
+	printk("%d controller(s) configured\n", setup_count);
+
+	for (i=0; i<setup_count; i++) {
+		if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
+			struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
+
+			if( !shpnt ) {
+				release_region(setup[i].io_port, IO_RANGE);
+#if defined(__ISAPNP__)
+			} else if( pnpdev[i] ) {
+				HOSTDATA(shpnt)->pnpdev=pnpdev[i];
+				pnpdev[i]=NULL;
+#endif
+			}
+		} else {
+			printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
+		}
+
+#if defined(__ISAPNP__)
+		if( pnpdev[i] )
+			pnp_device_detach(pnpdev[i]);
+#endif
+	}
+
+	return registered_count>0;
+}
+
+static void __exit aha152x_exit(void)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(setup); i++) {
+		aha152x_release(aha152x_host[i]);
+		aha152x_host[i]=NULL;
+	}
+}
+
+module_init(aha152x_init);
+module_exit(aha152x_exit);
+
+#if !defined(MODULE)
+static int __init aha152x_setup(char *str)
+{
+#if defined(AHA152X_DEBUG)
+	int ints[11];
+#else
+	int ints[10];
+#endif
+	get_options(str, ARRAY_SIZE(ints), ints);
+
+	if(setup_count>=ARRAY_SIZE(setup)) {
+		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
+		return 1;
+	}
+
+	setup[setup_count].conf        = str;
+	setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
+	setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
+	setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
+	setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
+	setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
+	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
+	setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
+	setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
+#if defined(AHA152X_DEBUG)
+	setup[setup_count].debug       = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
+	if (ints[0] > 9) {
+		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
+#else
+	if (ints[0] > 8) {                                                /*}*/
+		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
+#endif
+	} else {
+		setup_count++;
+		return 0;
+	}
+
+	return 1;
+}
+__setup("aha152x=", aha152x_setup);
+#endif
+
+#endif /* !PCMCIA */