patch-2.3.36 linux/drivers/scsi/aha152x.c

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

diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
@@ -1,13 +1,6 @@
 /* aha152x.c -- Adaptec AHA-152x driver
- * Author: Jürgen E. Fischer, fischer@et-inf.fho-emden.de
- * Copyright 1993, 1994, 1995, 1996 Jürgen E. Fischer
- *
- *
- * This driver is based on
- *   fdomain.c -- Future Domain TMC-16x0 driver
- * which is
- *   Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
- *
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-1999 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
@@ -20,9 +13,30 @@
  * General Public License for more details.
  *
  *
- * $Id: aha152x.c,v 1.18 1996/09/07 20:10:40 fischer Exp $
+ * $Id: aha152x.c,v 2.0 1999/12/25 15:07:32 fischer Exp fischer $
  *
  * $Log: aha152x.c,v $
+ * 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)
  *
@@ -181,152 +195,18 @@
  *
  *
  **************************************************************************
-
-
-
- DESCRIPTION:
-
- This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI
- host adapters.
-
-
- CONFIGURATION ARGUMENTS:
-
- IOPORT        base io address                           (0x340/0x140)
- IRQ           interrupt level                           (9-12; default 11)
- SCSI_ID       scsi id of controller                     (0-7; default 7)
- RECONNECT     allow targets to disconnect from the bus  (0/1; default 1 [on])
- PARITY        enable parity checking                    (0/1; default 1 [on])
- SYNCHRONOUS   enable synchronous transfers              (0/1; default 0 [off])
- (NOT WORKING YET)
- DELAY:        bus reset delay                           (default 100)
- EXT_TRANS:    enable extended translation               (0/1: default 0 [off])
- (see NOTES below)
-
- COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile):
-
- -DAUTOCONF
- use configuration the controller reports (AHA-152x only)
-
- -DSKIP_BIOSTEST
- Don't test for BIOS signature (AHA-1510 or disabled BIOS)
-
- -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
- override for the first controller 
-
- -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
- override for the second controller
-
-
- LILO COMMAND LINE OPTIONS:
-
- aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY> [,<EXT_TRANS]]]]]]]
-
- The normal configuration can be overridden by specifying a command line.
- When you do this, the BIOS test is skipped. Entered values have to be
- valid (known).  Don't use values that aren't supported under normal
- operation.  If you think that you need other values: contact me.
- For two controllers use the aha152x statement twice.
-
-
- SYMBOLS FOR MODULE CONFIGURATION:
-
- aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
- configuration override of first controller
-
-
- aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
- configuration override of second controller
-
-
- NOTES ON EXT_TRANS: 
-
- SCSI uses block numbers to address blocks/sectors on a device.
- The BIOS uses a cylinder/head/sector addressing scheme (C/H/S)
- scheme instead.  DOS expects a BIOS or driver that understands this
- C/H/S addressing.
-
- The number of cylinders/heads/sectors is called geometry and is required
- as base for requests in C/H/S addressing.  SCSI only knows about the
- total capacity of disks in blocks (sectors).
-
- Therefore the SCSI BIOS/DOS driver has to calculate a logical/virtual
- geometry just to be able to support that addressing scheme.  The geometry
- returned by the SCSI BIOS is a pure calculation and has nothing to
- do with the real/physical geometry of the disk (which is usually
- irrelevant anyway).
-
- Basically this has no impact at all on Linux, because it also uses block
- instead of C/H/S addressing.  Unfortunately C/H/S addressing is also used
- in the partition table and therefore every operating system has to know
- the right geometry to be able to interpret it.
-
- Moreover there are certain limitations to the C/H/S addressing scheme,
- namely the address space is limited to upto 255 heads, upto 63 sectors
- and a maximum of 1023 cylinders.
-
- The AHA-1522 BIOS calculates the geometry by fixing the number of heads
- to 64, the number of sectors to 32 and by calculating the number of
- cylinders by dividing the capacity reported by the disk by 64*32 (1 MB).
- This is considered to be the default translation.
-
- With respect to the limit of 1023 cylinders using C/H/S you can only
- address the first GB of your disk in the partition table.  Therefore
- BIOSes of some newer controllers based on the AIC-6260/6360 support
- extended translation.  This means that the BIOS uses 255 for heads,
- 63 for sectors and then divides the capacity of the disk by 255*63
- (about 8 MB), as soon it sees a disk greater than 1 GB.  That results
- in a maximum of about 8 GB addressable diskspace in the partition table
- (but there are already bigger disks out there today).
-
- To make it even more complicated the translation mode might/might
- not be configurable in certain BIOS setups.
-
- This driver does some more or less failsafe guessing to get the
- geometry right in most cases:
-
- - for disks<1GB: use default translation (C/32/64)
- - for disks>1GB:
- - take current geometry from the partition table
- (using scsicam_bios_param and accept only `valid' geometries,
- ie. either (C/32/64) or (C/63/255)).  This can be extended
- translation even if it's not enabled in the driver.
- - if that fails, take extended translation if enabled by override,
- kernel or module parameter, otherwise take default translation and
- ask the user for verification.  This might on not yet partitioned
- disks or
-
-
- REFERENCES USED:
-
- "AIC-6260 SCSI Chip Specification", Adaptec Corporation.
-
- "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
-
- "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
-
- "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
-
- "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
-
- Michael K. Johnson (johnsonm@sunsite.unc.edu)
-
- Drew Eckhardt (drew@cs.colorado.edu)
-
- Eric Youngdale (ericy@cais.com) 
-
- special thanks to Eric Youngdale for the free(!) supplying the
- documentation on the chip.
+ 
+ see README.aha152x for configuration details
 
  **************************************************************************/
 
-#ifdef PCMCIA
+#if defined(PCMCIA)
 #define MODULE
 #endif
 
 #include <linux/module.h>
 
-#ifdef PCMCIA
+#if defined(PCMCIA)
 #undef MODULE
 #endif
 
@@ -342,10 +222,13 @@
 #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 <asm/semaphore.h>
+#include <linux/spinlock.h>
 
 #include "aha152x.h"
 #include <linux/stat.h>
@@ -365,53 +248,55 @@
 #error define AUTOCONF or SETUP0
 #endif
 
-#if defined(DEBUG_AHA152X)
-
-#undef  SKIP_PORTS		/* don't display ports */
-
-#undef  DEBUG_QUEUE		/* debug queue() */
-#undef  DEBUG_RESET		/* debug reset() */
-#undef  DEBUG_INTR		/* debug intr() */
-#undef  DEBUG_SELECTION		/* debug selection part in intr() */
-#undef  DEBUG_MSGO		/* debug message out phase in intr() */
-#undef  DEBUG_MSGI		/* debug message in phase in intr() */
-#undef  DEBUG_STATUS		/* debug status phase in intr() */
-#undef  DEBUG_CMD		/* debug command phase in intr() */
-#undef  DEBUG_DATAI		/* debug data in phase in intr() */
-#undef  DEBUG_DATAO		/* debug data out phase in intr() */
-#undef  DEBUG_ABORT		/* debug abort() */
-#undef  DEBUG_DONE		/* debug done() */
-#undef  DEBUG_BIOSPARAM		/* debug biosparam() */
-
-#undef  DEBUG_RACE		/* debug race conditions */
-#undef  DEBUG_PHASES		/* debug phases (useful to trace) */
-#undef  DEBUG_QUEUES		/* debug reselection */
-
-/* recently used for debugging */
-#if 0
-#endif
-
-#define DEBUG_SELECTION
-#define DEBUG_PHASES
-#define DEBUG_RESET
-#define DEBUG_ABORT
-
-#define DEBUG_DEFAULT (debug_reset|debug_abort)
+#if defined(AHA152X_DEBUG)
+#define DEBUG_DEFAULT debug_eh
 
-#endif
+#define DPRINTK(when,msgs...) \
+	do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
 
-/* END OF DEFINES */
+#define DO_LOCK(flags)	\
+	do { \
+		if(QLOCK.lock) { \
+			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)
 
-extern long loops_per_sec;
+#else
+#define DPRINTK(when,msgs...)
+#define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
+#define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
+#define DEBUG_DEFAULT	0
+#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)->host->host_no) : -1, \
+                        (cmd) ? ((cmd)->target & 0x0f) : -1, \
+			(cmd) ? ((cmd)->lun & 0x07) : -1
 
 #define DELAY_DEFAULT 100
 
-/* some additional "phases" for getphase() */
-#define P_BUSFREE  1
-#define P_PARITY   2
-
 /* possible irq range */
-#ifdef PCMCIA
+#if defined(PCMCIA)
 #define IRQ_MIN 0
 #define IRQ_MAX 16
 #else
@@ -421,33 +306,76 @@
 #define IRQS    IRQ_MAX-IRQ_MIN+1
 
 enum {
-	not_issued = 0x0001,
-	in_selection = 0x0002,
-	disconnected = 0x0004,
-	aborted = 0x0008,
-	sent_ident = 0x0010,
-	in_other = 0x0020,
-	in_sync = 0x0040,
-	sync_ok = 0x0080,
+	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 */
 };
 
 #if defined(MODULE)
-#if defined(DEBUG_AHA152X)
-int aha152x[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-int aha152x1[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-MODULE_PARM(aha152x, "1-9i");
-MODULE_PARM(aha152x1, "1-9i");
-#else
-int aha152x[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
-int aha152x1[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+MODULE_AUTHOR("Jürgen Fischer");
+MODULE_DESCRIPTION(AHA152X_REVID);
+MODULE_PARM(io, "1-2i");
+MODULE_PARM_DESC(io,"base io address of controller");
+static int io[] = {0, 0};
+
+MODULE_PARM(irq, "1-2i");
+MODULE_PARM_DESC(irq,"interrupt for controller");
+static int irq[] = {0, 0};
+
+MODULE_PARM(scsiid, "1-2i");
+MODULE_PARM_DESC(scsiid,"scsi id of controller");
+static int scsiid[] = {7, 7};
+
+MODULE_PARM(reconnect, "1-2i");
+MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
+static int reconnect[] = {1, 1};
+
+MODULE_PARM(parity, "1-2i");
+MODULE_PARM_DESC(parity,"use scsi parity");
+static int parity[] = {1, 1};
+
+MODULE_PARM(sync, "1-2i");
+MODULE_PARM_DESC(sync,"use synchronous transfers");
+static int sync[] = {1, 1};
+
+MODULE_PARM(delay, "1-2i");
+MODULE_PARM_DESC(delay,"scsi reset delay");
+static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
+
+MODULE_PARM(exttrans, "1-2i");
+MODULE_PARM_DESC(exttrans,"use extended translation");
+static int exttrans[] = {0, 0};
+
+#if !defined(AHA152X_DEBUG)
 MODULE_PARM(aha152x, "1-8i");
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+static int aha152x[]   = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+
 MODULE_PARM(aha152x1, "1-8i");
-#endif
-#endif
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+static int aha152x1[]  = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+#else
+MODULE_PARM(debug, "1-2i");
+MODULE_PARM_DESC(debug, "flags for driver debugging");
+static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
+
+MODULE_PARM(aha152x, "1-9i");
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+
+MODULE_PARM(aha152x1, "1-9i");
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+#endif /* !defined(AHA152X_DEBUG) */
+#endif /* MODULE */
 
 /* set by aha152x_setup according to the command line */
 static int setup_count = 0;
@@ -461,7 +389,8 @@
 	int synchronous;
 	int delay;
 	int ext_trans;
-#ifdef DEBUG_AHA152X
+	int tc1550;
+#if defined(AHA152X_DEBUG)
 	int debug;
 #endif
 	char *conf;
@@ -469,73 +398,259 @@
 
 static struct Scsi_Host *aha152x_host[IRQS];
 
-#define HOSTDATA(shpnt)   ((struct aha152x_hostdata *) &shpnt->hostdata)
-#define CURRENT_SC        (HOSTDATA(shpnt)->current_SC)
-#define ISSUE_SC          (HOSTDATA(shpnt)->issue_SC)
-#define DISCONNECTED_SC   (HOSTDATA(shpnt)->disconnected_SC)
-#define DELAY             (HOSTDATA(shpnt)->delay)
-#define EXT_TRANS         (HOSTDATA(shpnt)->ext_trans)
-#define SYNCRATE          (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
-#define MSG(i)            (HOSTDATA(shpnt)->message[i])
-#define MSGLEN            (HOSTDATA(shpnt)->message_len)
-#define ADDMSG(x)         (MSG(MSGLEN++)=x)
+/*
+ * 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;
-	int aborting;
-	int abortion_complete;
-	int abort_result;
-	int commands;
+		/* commands that disconnected */
 
-	int reconnect;
-	int parity;
-	int synchronous;
-	int delay;
-	int ext_trans;
+	Scsi_Cmnd *done_SC;
+		/* command that was completed */
+
+	spinlock_t lock;
+		/* host lock */
 
-	int swint;
-	int service;
+#if defined(AHA152X_DEBUG)
+	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 message[256];
-	int message_len;
+	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 */
 
-#ifdef DEBUG_AHA152X
-	int debug;
-#endif
+	int data_len;
+		/* number of sent/received bytes in dataphase */
+
+	unsigned long io_port0;
+	unsigned long io_port1;
+};
+
+
+/*
+ * host specific command extension
+ *
+ */
+struct aha152x_scdata {
+	Scsi_Cmnd *next;	/* next sc in queue */
+	Scsi_Cmnd *done;	/* done command */
+	struct semaphore *sem;	/* semaphore to block on */
 };
 
-static void aha152x_intr(int irq, void *dev_id, struct pt_regs *);
-void aha152x_done(struct Scsi_Host *shpnt, int error);
-void aha152x_setup(char *str, int *ints);
-int aha152x_checksetup(struct aha152x_setup *setup);
 
-static void aha152x_reset_ports(struct Scsi_Host *shpnt);
-static void aha152x_panic(struct Scsi_Host *shpnt, char *msg);
+/* 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 ? 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 ? MSGI(MSGILEN++)=x : aha152x_error(shpnt,"MSGI overflow"))
+
+#define DATA_LEN		(HOSTDATA(shpnt)->data_len)
+
+#define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
+#define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->target])
+
+#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 SCDONE(SCpnt)		SCDATA(SCpnt)->done
+#define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
+
+
+/* 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 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",	0,		0,		0,		0},
+	{ "unknown",	0,		0,		0,		0},
+	{ "seldo",	0,		seldo_run,	0,		0},
+	{ "seldi",	0,		seldi_run,	0,		0},
+	{ "selto",	0,		selto_run,	0,		0},
+	{ "busfree",	0,		busfree_run,	0,		0},
+	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
+	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
+	{ "msgi",	0,		msgi_run,	msgi_end,	1},
+	{ "status",	0,		status_run,	0,		1},
+	{ "datai",	datai_init,	datai_run,	datai_end,	0},
+	{ "datao",	datao_init,	datao_run,	datao_end,	0},
+	{ "parerr",	0,		parerr_run,	0,		0},
+	{ "rsti",	0,		rsti_run,	0,		0},
+};
+
+/* setup & interrupt */
+static void 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);
+static int checksetup(struct aha152x_setup *setup);
+
+/* 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);
 
-#if defined(DEBUG_RACE)
-static void enter_driver(const char *);
-static void leave_driver(const char *);
-#endif
-
-/* possible i/o addresses for the AIC-6260 */
-static unsigned short ports[] =
-{
-	0x340,			/* default first */
-	0x140
-};
+/* possible i/o addresses for the AIC-6260; default first */
+static unsigned short ports[] = { 0x340, 0x140 };
 #define PORT_COUNT (sizeof(ports) / sizeof(unsigned short))
 
 #if !defined(SKIP_BIOSTEST)
-/* possible locations for the Adaptec BIOS */
+/* possible locations for the Adaptec BIOS; defaults first */
 static unsigned int addresses[] =
 {
 	0xdc000,		/* default first */
@@ -562,71 +677,52 @@
 	int sig_offset;
 	int sig_length;
 } signatures[] =
-
 {
-	{
-		"Adaptec AHA-1520 BIOS", 0x102e, 21
-	},			/* Adaptec 152x */
-	{
-		"Adaptec AHA-1520B", 0x0b, 19
-	},			/* Adaptec 152x rev B */
-	{
-		"Adaptec ASW-B626 BIOS", 0x1029, 21
-	},			/* on-board controller */
-	{
-		"Adaptec BIOS: ASW-B626", 0x0f, 22
-	},			/* on-board controller */
-	{
-		"Adaptec ASW-B626 S2", 0x2e6c, 19
-	},			/* on-board controller */
-	{
-		"Adaptec BIOS:AIC-6360", 0xc, 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", 0xc, 21
-	},			/* Adaptec 282x */
-	{
-		"Adaptec IBM Dock II SCSI", 0x2edd, 24
-	},			/* IBM Thinkpad Dock II */
-	{
-		"Adaptec BIOS:AHA-1532P", 0x1c, 22
-	},			/* IBM Thinkpad Dock II SCSI */
-	{
-		"DTC3520A Host Adapter BIOS", 0x318a, 26
-	},			/* DTC 3520A ISA SCSI */
+	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
+		/* Adaptec 152x */
+	{ "Adaptec AHA-1520B",		0x000b, 19 },
+		/* Adaptec 152x rev B */
+	{ "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 */
 };
 
 #define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature))
 #endif
 
 
-static void do_pause(unsigned amount)
-{				/* Pause for amount*10 milliseconds */
-	unsigned long the_time = jiffies + amount;	/* 0.01 seconds per jiffy */
-
-	while (time_before(jiffies, the_time))
-		barrier();
-}
-
 /*
  *  queue services:
+ *
  */
-static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC)
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
 {
 	Scsi_Cmnd *end;
 
-	new_SC->host_scribble = (unsigned char *) NULL;
+	SCNEXT(new_SC) = NULL;
 	if (!*SC)
 		*SC = new_SC;
 	else {
-		for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble);
-		end->host_scribble = (unsigned char *) new_SC;
+		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
+			;
+		SCNEXT(end) = new_SC;
 	}
 }
 
@@ -635,135 +731,113 @@
 	Scsi_Cmnd *ptr;
 
 	ptr = *SC;
-	if (ptr)
-		*SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+	if (ptr) {
+		*SC = SCNEXT(*SC);
+		SCNEXT(ptr)=NULL;
+	}
 	return ptr;
 }
 
-static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun)
+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->target != target) || (ptr->lun != lun));
-	     prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+	     prev = ptr, ptr = SCNEXT(ptr))
+	     ;
 
 	if (ptr) {
 		if (prev)
-			prev->host_scribble = ptr->host_scribble;
+			SCNEXT(prev) = SCNEXT(ptr);
 		else
-			*SC = (Scsi_Cmnd *) ptr->host_scribble;
-	}
-	return ptr;
-}
+			*SC = SCNEXT(ptr);
 
-/*
- * read inbound byte and wait for ACK to get low
- */
-static void make_acklow(struct Scsi_Host *shpnt)
-{
-	SETPORT(SXFRCTL0, CH1 | SPIOEN);
-	GETPORT(SCSIDAT);
-	SETPORT(SXFRCTL0, CH1);
+		SCNEXT(ptr)=NULL;
+	}
 
-	while (TESTHI(SCSISIG, ACKI))
-		barrier();
+	return ptr;
 }
 
-/*
- * detect current phase more reliable:
- * phase is valid, when the target asserts REQ after we've deasserted ACK.
- *
- * return value is a valid phase or an error code.
- *
- * errorcodes:
- *   P_BUSFREE   BUS FREE phase detected
- *   P_PARITY    parity error in DATA phase
- */
-static int getphase(struct Scsi_Host *shpnt)
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
 {
-	int phase, sstat1;
-
-	while (1) {
-		do {
-			while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT)))
-				barrier();
-			if (sstat1 & BUSFREE)
-				return P_BUSFREE;
-			if (sstat1 & SCSIRSTI) {
-				printk("aha152x: RESET IN\n");
-				SETPORT(SSTAT1, SCSIRSTI);
-			}
-		} while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT));
-
-		SETPORT(SSTAT1, CLRSCSIPERR);
+	Scsi_Cmnd *ptr, *prev;
 
-		phase = GETPORT(SCSISIG) & P_MASK;
+	for (ptr = *SC, prev = NULL;
+	     ptr && SCp!=ptr;
+	     prev = ptr, ptr = SCNEXT(ptr))
+	     ;
 
-		if (TESTHI(SSTAT1, SCSIPERR)) {
-			if ((phase & (CDO | MSGO)) == 0)	/* DATA phase */
-				return P_PARITY;
+	if (ptr) {
+		if (prev)
+			SCNEXT(prev) = SCNEXT(ptr);
+		else
+			*SC = SCNEXT(ptr);
 
-			make_acklow(shpnt);
-		} else
-			return phase;
+		SCNEXT(ptr)=NULL;
 	}
+
+	return ptr;
 }
 
-#ifdef PCMCIA
+#if defined(PCMCIA) || !defined(MODULE)
 void aha152x_setup(char *str, int *ints)
 {
-	if (setup_count > 2)
-		panic("aha152x: you can only configure up to two controllers\n");
+	if(setup_count>2) {
+		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
+		return;
+	}
 
-	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] : 0 /* FIXME: 1 */ ;
-	setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
-	setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
-#ifdef DEBUG_AHA152X
-	setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
+	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("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
 		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
 #else
-	if (ints[0] > 8) {
-		printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+	if (ints[0] > 8) {                                                /*}*/
+		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
 		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
 #endif
-	} else
+		return;
+	} else {
 		setup_count++;
+		return;
+	}
 }
-#endif /* PCMCIA */
+#endif
 
-#ifndef MODULE
-static int __init do_aha152x_setup (char * str)
+#if !defined(MODULE)
+static int __init do_setup(char *str)
 {
-	if (setup_count > 2) {
-		printk(KERN_ERR"aha152x: you can only configure up to two
-controllers\n");
-	return 0;
-	}
 
-	setup[setup_count].conf = str;
-	get_option(&str,&setup[setup_count].io_port);
-	get_option(&str,&setup[setup_count].irq);
-	get_option(&str,&setup[setup_count].scsiid);
-	get_option(&str,&setup[setup_count].reconnect);
-	
-	setup_count++;
-	return 1;
+#if defined(AHA152X_DEBUG)
+	int ints[11];
+#else
+	int ints[10];
+#endif
+	int count=setup_count;
+
+	get_options(str, sizeof(ints)/sizeof(int), ints);
+	aha152x_setup(str,ints);
+
+	return count<setup_count;
 }
 
-__setup("aha152x=",do_aha152x_setup);
+__setup("aha152x=", do_setup);
 #endif
- 
+
 /*
  * Test, if port_base is valid.
+ *
  */
 static int aha152x_porttest(int io_port)
 {
@@ -777,24 +851,48 @@
 		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++);
+	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
+		;
+
+	return (i == 16);
+}
+
+static int tc1550_porttest(int io_port)
+{
+	int i;
+
+	if (check_region(io_port, IO_RANGE))
+		return 0;
+
+	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);
 }
 
-int aha152x_checksetup(struct aha152x_setup *setup)
+static int checksetup(struct aha152x_setup *setup)
 {
 	int i;
 
-#ifndef PCMCIA
-	for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++);
+#if !defined(PCMCIA)
+	for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++)
+		;
 
 	if (i == PORT_COUNT)
 		return 0;
 #endif
 
-	if (!aha152x_porttest(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
+          return 0;
 
 	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
 		return 0;
@@ -818,12 +916,12 @@
 	return 1;
 }
 
-void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs)
+static void swintr(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
 
 	if (!shpnt)
-		panic("aha152x: catched software interrupt for unknown controller.\n");
+        	printk(KERN_ERR "aha152x%d: catched software interrupt for unknown controller.\n", HOSTNO);
 
 	HOSTDATA(shpnt)->swint++;
 }
@@ -835,29 +933,28 @@
 #if defined(AUTOCONF)
 	aha152x_config conf;
 #endif
-
-	tpnt->proc_name = "aha152x";
+	tpnt->proc_name = "aha152x"; 
 
 	for (i = 0; i < IRQS; i++)
 		aha152x_host[i] = (struct Scsi_Host *) NULL;
 
 	if (setup_count) {
-		printk("aha152x: processing commandline: ");
+		printk(KERN_INFO "aha152x: processing commandline: ");
 
 		for (i = 0; i < setup_count; i++)
-			if (!aha152x_checksetup(&setup[i])) {
-				printk("\naha152x: %s\n", setup[i].conf);
-				printk("aha152x: invalid line (controller=%d)\n", i + 1);
+			if (!checksetup(&setup[i])) {
+				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
+				printk(KERN_ERR "aha152x: invalid line\n");
 			}
 		printk("ok\n");
 	}
-#ifdef SETUP0
+#if defined(SETUP0)
 	if (setup_count < 2) {
 		struct aha152x_setup override = SETUP0;
 
 		if (setup_count == 0 || (override.io_port != setup[0].io_port))
-			if (!aha152x_checksetup(&override)) {
-				printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+			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,
@@ -871,13 +968,13 @@
 	}
 #endif
 
-#ifdef SETUP1
+#if defined(SETUP1)
 	if (setup_count < 2) {
 		struct aha152x_setup override = SETUP1;
 
 		if (setup_count == 0 || (override.io_port != setup[0].io_port))
-			if (!aha152x_checksetup(&override)) {
-				printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+			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,
@@ -892,23 +989,39 @@
 #endif
 
 #if defined(MODULE)
-	if (setup_count < 2 && 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];
-#ifdef DEBUG_AHA152X
-		setup[setup_count].debug = aha152x[8];
+	if (setup_count<2 && (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 (aha152x_checksetup(&setup[setup_count]))
+		}
+
+          	if (checksetup(&setup[setup_count]))
 			setup_count++;
 		else
-			printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+			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,
@@ -918,23 +1031,39 @@
 			       setup[setup_count].delay,
 			       setup[setup_count].ext_trans);
 	}
-	if (setup_count < 2 && 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];
-#ifdef DEBUG_AHA152X
-		setup[setup_count].debug = aha152x1[8];
+
+	if (setup_count < 2 && (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 (aha152x_checksetup(&setup[setup_count]))
+		}
+		if (checksetup(&setup[setup_count]))
 			setup_count++;
 		else
-			printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+			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,
@@ -953,14 +1082,14 @@
 		for (i = 0; i < ADDRESS_COUNT && !ok; i++)
 			for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++)
 				ok = isa_check_signature(addresses[i] + signatures[j].sig_offset,
-						     signatures[j].signature, signatures[j].sig_length);
+								signatures[j].signature, signatures[j].sig_length);
 
 		if (!ok && setup_count == 0)
 			return 0;
 
-		printk("aha152x: BIOS test: passed, ");
+		printk(KERN_INFO "aha152x: BIOS test: passed, ");
 #else
-		printk("aha152x: ");
+		printk(KERN_INFO "aha152x: ");
 #endif				/* !SKIP_BIOSTEST */
 
 		ok = 0;
@@ -971,6 +1100,26 @@
 			if (aha152x_porttest(ports[i])) {
 				ok++;
 				setup[setup_count].io_port = ports[i];
+				setup[setup_count].tc1550  = 0;
+
+				conf.cf_port =
+				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
+
+				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++;
+			} else if (tc1550_porttest(ports[i])) {
+				ok++;
+				setup[setup_count].io_port = ports[i];
+				setup[setup_count].tc1550  = 1;
 
 				conf.cf_port =
 				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
@@ -979,10 +1128,10 @@
 				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 = 0 /* FIXME: conf.cf_syncneg */ ;
+				setup[setup_count].synchronous = conf.cf_syncneg;
 				setup[setup_count].delay = DELAY_DEFAULT;
 				setup[setup_count].ext_trans = 0;
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
 				setup[setup_count].debug = DEBUG_DEFAULT;
 #endif
 				setup_count++;
@@ -996,40 +1145,75 @@
 
 	printk("detected %d controller(s)\n", setup_count);
 
-	for (i = 0; i < setup_count; i++) {
+	for (i=0; i<setup_count; i++) {
 		struct Scsi_Host *shpnt;
-		unsigned long int the_time;
 
-		shpnt = aha152x_host[setup[i].irq - IRQ_MIN] =
+		aha152x_host[setup[i].irq - IRQ_MIN] = shpnt =
 		    scsi_register(tpnt, sizeof(struct aha152x_hostdata));
+
+		if(!shpnt) {
+			printk(KERN_ERR "aha152x: scsi_register failed\n");
+			continue;
+		}
+
 		registered_count++;
 
-		shpnt->io_port = setup[i].io_port;
+		shpnt->io_port   = setup[i].io_port;
 		shpnt->n_io_port = IO_RANGE;
-		shpnt->irq = setup[i].irq;
+		shpnt->irq       = setup[i].irq;
+
+		if(!setup[i].tc1550) {
+			HOSTIOPORT0 = setup[i].io_port;
+			HOSTIOPORT1 = setup[i].io_port;
+		} else {
+			HOSTIOPORT0 = setup[i].io_port+0x10;
+			HOSTIOPORT1 = setup[i].io_port-0x10;
+		}
 
-		ISSUE_SC = (Scsi_Cmnd *) NULL;
-		CURRENT_SC = (Scsi_Cmnd *) NULL;
-		DISCONNECTED_SC = (Scsi_Cmnd *) NULL;
-
-		HOSTDATA(shpnt)->reconnect = setup[i].reconnect;
-		HOSTDATA(shpnt)->parity = setup[i].parity;
-		HOSTDATA(shpnt)->synchronous = setup[i].synchronous;
-		HOSTDATA(shpnt)->delay = setup[i].delay;
-		HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans;
-#ifdef DEBUG_AHA152X
+		ISSUE_SC	= 0;
+		CURRENT_SC	= 0;
+		DONE_SC		= 0;
+		DISCONNECTED_SC	= 0;
+
+		QLOCK		= SPIN_LOCK_UNLOCKED;
+
+		STATE		= 0;
+		PREVSTATE	= 0;
+		LASTSTATE	= 0;
+
+		MSGILEN		= 0;
+		MSGOLEN		= 0;
+
+		RECONNECT	= setup[i].reconnect;
+		SYNCHRONOUS	= setup[i].synchronous;
+		PARITY		= setup[i].parity;
+		DELAY		= setup[i].delay;
+		EXT_TRANS	= setup[i].ext_trans;
+#if defined(AHA152X_DEBUG)
 		HOSTDATA(shpnt)->debug = setup[i].debug;
 #endif
-
-		HOSTDATA(shpnt)->aborting = 0;
-		HOSTDATA(shpnt)->abortion_complete = 0;
-		HOSTDATA(shpnt)->abort_result = 0;
+		HOSTDATA(shpnt)->in_intr = 0;
 		HOSTDATA(shpnt)->commands = 0;
 
-		HOSTDATA(shpnt)->message_len = 0;
+#if defined(AHA152X_STAT)
+		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 (j = idle; j<maxstate; j++) {
+			HOSTDATA(shpnt)->count[j]=0;
+			HOSTDATA(shpnt)->count_trans[j]=0;
+			HOSTDATA(shpnt)->time[j]=0;
+		}
+#endif
 
-		for (j = 0; j < 8; j++)
+		for (j = 0; j < 8; j++) {
 			HOSTDATA(shpnt)->syncrate[j] = 0;
+			HOSTDATA(shpnt)->syncneg[j] = 0;
+		}
 
 		SETPORT(SCSIID, setup[i].scsiid << 4);
 		shpnt->this_id = setup[i].scsiid;
@@ -1037,59 +1221,73 @@
 		if (setup[i].reconnect)
 			shpnt->can_queue = AHA152X_MAXQUEUE;
 
-		/* RESET OUT */
-		SETBITS(SCSISEQ, SCSIRSTO);
-		do_pause(30);
-		CLRBITS(SCSISEQ, SCSIRSTO);
-		do_pause(setup[i].delay);
-
-		aha152x_reset_ports(shpnt);
-
-		printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d,"
-		       " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n",
-		       i,
-		       shpnt->io_port,
+#if 0
+		if(!shpnt->hostt->use_new_eh_code) {
+#endif
+			/* RESET OUT */
+			printk("aha152x: resetting bus...\n");
+			SETPORT(SCSISEQ, SCSIRSTO);
+			mdelay(256);
+			SETPORT(SCSISEQ, 0);
+			mdelay(DELAY);
+#if 0
+		}
+#endif
+
+		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",
+		       HOSTNO, setup[i].tc1550 ? " (tc1550 mode)" : "",
+		       GETPORT(REV) & 0x7,
+		       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
 		       shpnt->irq,
 		       shpnt->this_id,
-		     HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled",
-		       HOSTDATA(shpnt)->parity ? "enabled" : "disabled",
-		   HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled",
-		       HOSTDATA(shpnt)->delay,
-		    HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled");
+		       RECONNECT ? "enabled" : "disabled",
+		       PARITY ? "enabled" : "disabled",
+		       SYNCHRONOUS ? "enabled" : "disabled",
+		       DELAY,
+		       EXT_TRANS ? "enabled" : "disabled");
 
-		request_region(shpnt->io_port, IO_RANGE, "aha152x");	/* Register */
+		request_region(shpnt->io_port, IO_RANGE, "aha152x");
 
 		/* not expecting any interrupts */
 		SETPORT(SIMODE0, 0);
 		SETPORT(SIMODE1, 0);
 
-		SETBITS(DMACNTRL0, INTEN);
-
-		ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt);
+		ok = request_irq(shpnt->irq, swintr, SA_INTERRUPT, "aha152x", shpnt);
 		if (ok < 0) {
-			if (ok == -EINVAL)
-				printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq);
-			else if (ok == -EBUSY)
-				printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq);
+			if (ok==-EINVAL)
+				printk(KERN_ERR "aha152x%d: bad IRQ %d.\n", HOSTNO, shpnt->irq);
+			else if(ok==-EBUSY)
+				printk(KERN_ERR "aha152x%d: IRQ %d already in use.\n", HOSTNO, shpnt->irq);
 			else
-				printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq);
-			printk("aha152x: driver needs an IRQ.\n");
+				printk(KERN_ERR "aha152x%d: Unexpected error code %d on requesting IRQ %d.\n", HOSTNO, ok, shpnt->irq);
+
+			printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", HOSTNO);
 
 			scsi_unregister(shpnt);
 			registered_count--;
 			release_region(shpnt->io_port, IO_RANGE);
-			shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			aha152x_host[shpnt->irq - IRQ_MIN] = shpnt = 0;
 			continue;
 		}
 		HOSTDATA(shpnt)->swint = 0;
 
-		printk("aha152x: trying software interrupt, ");
-		SETBITS(DMACNTRL0, SWINT);
-
-		the_time = jiffies + 100;
-		while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time))
-			barrier();
-
+		printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
+		SETPORT(DMACNTRL0, SWINT|INTEN);
+		spin_unlock_irq(&io_request_lock);
+		mdelay(1000);
+		spin_lock_irq(&io_request_lock);
 		free_irq(shpnt->irq, shpnt);
 
 		if (!HOSTDATA(shpnt)->swint) {
@@ -1099,7 +1297,7 @@
 				printk("failed.\n");
 			}
 
-			printk("aha152x: IRQ %d possibly wrong.  Please verify.\n", shpnt->irq);
+			printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong.  Please verify.\n", HOSTNO, shpnt->irq);
 
 			scsi_unregister(shpnt);
 			registered_count--;
@@ -1109,60 +1307,114 @@
 		}
 		printk("ok.\n");
 
-		CLRBITS(DMACNTRL0, SWINT);
+		SETPORT(DMACNTRL0, INTEN);
 
 		/* clear interrupts */
 		SETPORT(SSTAT0, 0x7f);
 		SETPORT(SSTAT1, 0xef);
 
-		if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
-			printk("aha152x: failed to reassign interrupt.\n");
-		}
-	}
-
-	return (registered_count > 0);
-}
-
+		if (request_irq(shpnt->irq, intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
+			printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO);
+
+			scsi_unregister(shpnt);
+			registered_count--;
+			release_region(shpnt->io_port, IO_RANGE);
+			shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+			continue;
+		}
+	}
+
+	return registered_count>0;
+}
+
 
 int aha152x_release(struct Scsi_Host *shpnt)
 {
 	if (shpnt->irq)
 		free_irq(shpnt->irq, shpnt);
+
 	if (shpnt->io_port)
 		release_region(shpnt->io_port, IO_RANGE);
 
+	scsi_unregister(shpnt);
+
 	return 0;
 }
 
+/*
+ * setup controller to generate interrupts depending
+ * on current state (lock has to be aquired)
+ *
+ */ 
+static int setup_expected_interrupts(struct Scsi_Host *shpnt)
+{
+	ASSERT_LOCK(&QLOCK,1);
+
+	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.
  */
-int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *))
 {
 	struct Scsi_Host *shpnt = SCpnt->host;
 	unsigned long flags;
 
-#if defined(DEBUG_RACE)
-	enter_driver("queue");
-#else
-#if defined(DEBUG_QUEUE)
-	if (HOSTDATA(shpnt)->debug & debug_queue)
-		printk("aha152x: queue(), ");
-#endif
-#endif
-
-#if defined(DEBUG_QUEUE)
+#if defined(AHA152X_DEBUG)
 	if (HOSTDATA(shpnt)->debug & debug_queue) {
-		printk("SCpnt (target = %d lun = %d cmnd = ",
-		       SCpnt->target, SCpnt->lun);
+		printk(INFO_LEAD "queue: cmd_len=%d pieces=%d size=%u cmnd=",
+		       CMDINFO(SCpnt), SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
 		print_command(SCpnt->cmnd);
-		printk(", cmd_len=%d, pieces = %d size = %u), ",
-		  SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
-		disp_ports(shpnt);
 	}
 #endif
 
-	SCpnt->scsi_done = done;
+	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;
+	SCpnt->host_scribble    = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
+	if(!SCpnt->host_scribble) {
+		printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
+		return FAILED;
+	}
+
+	SCNEXT(SCpnt)		= 0;
+	SCDONE(SCpnt)		= done_SC;
+	SCSEM(SCpnt)		= sem;
 
 	/* setup scratch area
 	   SCp.ptr              : buffer pointer
@@ -1170,193 +1422,265 @@
 	   SCp.buffer           : next buffer
 	   SCp.buffers_residual : left buffers in list
 	   SCp.phase            : current state of the command */
-	SCpnt->SCp.phase = not_issued;
 	if (SCpnt->use_sg) {
-		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
-		SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
-		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.ptr              = SCpnt->SCp.buffer->address;
+		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.ptr              = (char *) SCpnt->request_buffer;
+		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer           = NULL;
 		SCpnt->SCp.buffers_residual = 0;
 	}
 
-	SCpnt->SCp.Status = CHECK_CONDITION;
-	SCpnt->SCp.Message = 0;
-	SCpnt->SCp.have_data_in = 0;
-	SCpnt->SCp.sent_command = 0;
+	DO_LOCK(flags);
+
+#if defined(AHA152X_STAT)
+	HOSTDATA(shpnt)->total_commands++;
+#endif
 
 	/* Turn led on, when this is the first command. */
-	save_flags(flags);
-	cli();
 	HOSTDATA(shpnt)->commands++;
-	if (HOSTDATA(shpnt)->commands == 1)
+	if (HOSTDATA(shpnt)->commands==1)
 		SETPORT(PORTA, 1);
 
-#if defined(DEBUG_QUEUES)
-	if (HOSTDATA(shpnt)->debug & debug_queues)
-		printk("i+ (%d), ", HOSTDATA(shpnt)->commands);
-#endif
 	append_SC(&ISSUE_SC, SCpnt);
 
-	/* Enable bus free interrupt, when we aren't currently on the bus */
-	if (!CURRENT_SC) {
-		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-	}
-	restore_flags(flags);
+	if(!HOSTDATA(shpnt)->in_intr)
+		setup_expected_interrupts(shpnt);
 
-#if defined(DEBUG_RACE)
-	leave_driver("queue");
-#endif
+	DO_UNLOCK(flags);
 
 	return 0;
 }
 
+int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	if(*SCpnt->cmnd == REQUEST_SENSE) {
+		SCpnt->result = 0;
+		done(SCpnt);
+
+		return SUCCESS;
+	}
+
+	return aha152x_internal_queue(SCpnt, 0, 0, 0, done);
+}
+
+
 /*
- *  We only support commands in interrupt-driven fashion
+ *  run a command
+ *
  */
+void internal_done(Scsi_Cmnd *SCpnt)
+{
+#if 0
+	struct Scsi_Host *shpnt = SCpnt->host;
+
+	DPRINTK(debug_eh, INFO_LEAD "internal_done called\n", CMDINFO(SCpnt));
+#endif
+	if(SCSEM(SCpnt))
+		up(SCSEM(SCpnt));
+}
+
 int aha152x_command(Scsi_Cmnd * SCpnt)
 {
-	printk("aha152x: interrupt driven driver; use aha152x_queue()\n");
-	return -1;
+	DECLARE_MUTEX_LOCKED(sem);
+
+	aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done);
+	down(&sem);
+
+	return SUCCESS;
 }
 
 /*
- *  Abort a queued command
- *  (commands that are on the bus can't be aborted easily)
+ *  Abort a command
+ *
  */
-int aha152x_abort(Scsi_Cmnd * SCpnt)
+int aha152x_abort(Scsi_Cmnd *SCpnt)
 {
 	struct Scsi_Host *shpnt = SCpnt->host;
+	Scsi_Cmnd *ptr;
 	unsigned long flags;
-	Scsi_Cmnd *ptr, *prev;
 
-	save_flags(flags);
-	cli();
+	if(!shpnt) {
+		printk(ERR_LEAD "abort(%p): no host structure\n", CMDINFO(SCpnt), SCpnt);
+		return FAILED;
+	}
 
-#if defined(DEBUG_ABORT)
-	if (HOSTDATA(shpnt)->debug & debug_abort) {
-		printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt);
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
 		show_queues(shpnt);
+		mdelay(1000);
 	}
 #endif
 
-	/* look for command in issue queue */
-	for (ptr = ISSUE_SC, prev = NULL;
-	     ptr && ptr != SCpnt;
-	     prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+	DO_LOCK(flags);
 
-	if (ptr) {
-		/* dequeue */
-		if (prev)
-			prev->host_scribble = ptr->host_scribble;
-		else
-			ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble;
+	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);
 
-		restore_flags(flags);
+		kfree(SCpnt->host_scribble);
+		SCpnt->host_scribble=0;
 
-		ptr->host_scribble = NULL;
-		ptr->result = DID_ABORT << 16;
-		spin_lock_irqsave(&io_request_lock, flags);
-		ptr->scsi_done(ptr);
-		spin_unlock_irqrestore(&io_request_lock, flags);
+		return SUCCESS;
+	} 
 
-		return SCSI_ABORT_SUCCESS;
-	}
-	/* if the bus is busy or a command is currently processed,
-	   we can't do anything more */
-	if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) {
-		/* fail abortion, if bus is busy */
+	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?
+	 *
+	 */
 
-		if (!CURRENT_SC)
-			printk("bus busy w/o current command, ");
+	printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
 
-		restore_flags(flags);
+	return FAILED;
+}
 
-		return SCSI_ABORT_BUSY;
-	}
-	/* bus is free */
+static void timer_expired(unsigned long p)
+{
+	struct semaphore *sem = (void *)p;
 
-	if (CURRENT_SC) {
-		HOSTDATA(shpnt)->commands--;
+	printk(KERN_INFO "aha152x: timer expired\n");
+	up(sem);
+}
 
-		/* target entered bus free before COMMAND COMPLETE, nothing to abort */
-		restore_flags(flags);
-		spin_lock_irqsave(&io_request_lock, flags);
-		CURRENT_SC->result = DID_ERROR << 16;
-		CURRENT_SC->scsi_done(CURRENT_SC);
-		CURRENT_SC = (Scsi_Cmnd *) NULL;
-		spin_unlock_irqrestore(&io_request_lock, flags);
-
-		return SCSI_ABORT_SUCCESS;
-	}
-	/* look for command in disconnected queue */
-	for (ptr = DISCONNECTED_SC, prev = NULL;
-	     ptr && ptr != SCpnt;
-	     prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
-
-	if (!ptr) {
-		/* command wasn't found */
-		printk("command not found\n");
-		restore_flags(flags);
+/*
+ * Reset a device
+ *
+ * FIXME: never seen this live. might lockup...
+ *
+ */
+int aha152x_device_reset(Scsi_Cmnd * SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->host;
+	DECLARE_MUTEX_LOCKED(sem);
+	struct timer_list timer;
+	Scsi_Cmnd cmnd;
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+		mdelay(1000);
+	}
+#endif
 
-		return SCSI_ABORT_NOT_RUNNING;
+	if(CURRENT_SC==SCpnt) {
+		printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt));
+		return FAILED;
 	}
-	if (!HOSTDATA(shpnt)->aborting) {
-		/* dequeue */
-		if (prev)
-			prev->host_scribble = ptr->host_scribble;
-		else
-			DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
 
-		HOSTDATA(shpnt)->commands--;
+	cmnd.cmd_len         = 0;
+	cmnd.host            = SCpnt->host;
+	cmnd.target          = SCpnt->target;
+	cmnd.lun             = SCpnt->lun;
+	cmnd.use_sg          = 0;
+	cmnd.request_buffer  = 0;
+	cmnd.request_bufflen = 0;
 
-		/* set command current and initiate selection,
-		   let the interrupt routine take care of the abortion */
-		CURRENT_SC = ptr;
-		ptr->SCp.phase = in_selection | aborted;
-		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+	init_timer(&timer);
+	timer.data     = (unsigned long) &sem;
+	timer.expires  = jiffies + 10000;   /* 10s */
+	timer.function = (void (*)(unsigned long)) timer_expired;
+	add_timer(&timer);
 
-		ADDMSG(ABORT);
+	aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done);
 
-		/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-		SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
-		SETPORT(SIMODE1, ENSELTIMO);
+	down(&sem);
 
-		/* Enable SELECTION OUT sequence */
-		SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+	del_timer(&timer);
 
-		SETBITS(DMACNTRL0, INTEN);
-		HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
-		HOSTDATA(shpnt)->aborting++;
-		HOSTDATA(shpnt)->abortion_complete = 0;
+	if(cmnd.SCp.phase & resetted) {
+		return SUCCESS;
+	} else {
+		return FAILED;
+	}
+}
+
+void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
+{
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
 
-		restore_flags(flags);
+	DO_LOCK(flags);
 
-		/* sleep until the abortion is complete */
-		while (!HOSTDATA(shpnt)->abortion_complete)
-			barrier();
-		HOSTDATA(shpnt)->aborting = 0;
+	ptr=*SCs;
+	while(ptr) {
+		Scsi_Cmnd *next = SCNEXT(ptr);
 
-		return HOSTDATA(shpnt)->abort_result;
-	} else {
-		/* we're already aborting a command */
-		restore_flags(flags);
+		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=0;
+		}
 
-		return SCSI_ABORT_BUSY;
+		ptr = next;
 	}
+
+	DO_UNLOCK(flags);
 }
 
 /*
+ * Reset the bus
+ *
+ */
+int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->host;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+		mdelay(1000);
+	}
+#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 reset returns\n", CMDINFO(SCpnt));
+
+	DO_LOCK(flags);
+	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 aha152x_reset_ports(struct Scsi_Host *shpnt)
+static void reset_ports(struct Scsi_Host *shpnt)
 {
+	unsigned long flags;
+
 	/* disable interrupts */
 	SETPORT(DMACNTRL0, RSTFIFO);
 
@@ -1364,7 +1688,7 @@
 
 	SETPORT(SXFRCTL1, 0);
 	SETPORT(SCSISIG, 0);
-	SETPORT(SCSIRATE, 0);
+	SETRATE(0);
 
 	/* clear all interrupt conditions */
 	SETPORT(SSTAT0, 0x7f);
@@ -1377,106 +1701,41 @@
 
 	SETPORT(BRSTCNTRL, 0xf1);
 
-	/* clear SCSI fifo and transfer count */
-	SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT);
+	/* clear SCSI fifos and transfer count */
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
 	SETPORT(SXFRCTL0, CH1);
 
-	/* enable interrupts */
-	SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-	SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+	DO_LOCK(flags);
+	setup_expected_interrupts(shpnt);
+	DO_UNLOCK(flags);
 }
 
 /*
- *  Reset registers, reset a hanging bus and
- *  kill active and disconnected commands for target w/o soft reset
+ * Reset the host (bus and controller)
+ *
  */
-int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused)
+int aha152x_host_reset(Scsi_Cmnd * SCpnt)
 {
 	struct Scsi_Host *shpnt = SCpnt->host;
-	unsigned long flags;
-	Scsi_Cmnd *ptr, *prev, *next;
-
-	aha152x_reset_ports(shpnt);
-
-	/* Reset, if bus hangs */
-	if (TESTLO(SSTAT1, BUSFREE)) {
-		CLRBITS(DMACNTRL0, INTEN);
-
-#if defined(DEBUG_RESET)
-		if (HOSTDATA(shpnt)->debug & debug_reset) {
-			printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
-			show_queues(shpnt);
-		}
-#endif
-
-		ptr = CURRENT_SC;
-		if (ptr && !ptr->device->soft_reset) {
-			ptr->host_scribble = NULL;
-			ptr->result = DID_RESET << 16;
-			ptr->scsi_done(CURRENT_SC);
-			CURRENT_SC = NULL;
-		}
-		save_flags(flags);
-		cli();
-		prev = NULL;
-		ptr = DISCONNECTED_SC;
-		while (ptr) {
-			if (!ptr->device->soft_reset) {
-				if (prev)
-					prev->host_scribble = ptr->host_scribble;
-				else
-					DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
-				next = (Scsi_Cmnd *) ptr->host_scribble;
-
-				ptr->host_scribble = NULL;
-				ptr->result = DID_RESET << 16;
-				spin_lock_irqsave(&io_request_lock, flags);
-				ptr->scsi_done(ptr);
-				spin_unlock_irqrestore(&io_request_lock, flags);
-
-				ptr = next;
-			} else {
-				prev = ptr;
-				ptr = (Scsi_Cmnd *) ptr->host_scribble;
-			}
-		}
-		restore_flags(flags);
 
-#if defined(DEBUG_RESET)
-		if (HOSTDATA(shpnt)->debug & debug_reset) {
-			printk("commands on targets w/ soft-resets:\n");
-			show_queues(shpnt);
-		}
-#endif
+	DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
 
-		/* RESET OUT */
-		SETPORT(SCSISEQ, SCSIRSTO);
-		do_pause(30);
-		SETPORT(SCSISEQ, 0);
-		do_pause(DELAY);
+	aha152x_bus_reset(SCpnt);
 
-		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+	DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
+	reset_ports(SCpnt->host);
 
-		SETPORT(DMACNTRL0, INTEN);
-	}
-	return SCSI_RESET_SUCCESS;
+	return SUCCESS;
 }
 
 /*
  * Return the "logical geometry"
+ *
  */
 int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
 {
 	struct Scsi_Host *shpnt = disk->device->host;
 
-#if defined(DEBUG_BIOSPARAM)
-	if (HOSTDATA(shpnt)->debug & debug_biosparam)
-		printk("aha152x_biosparam: dev=%s, size=%d, ",
-		       kdevname(dev), disk->capacity);
-#endif
-
 	/* try default translation */
 	info_array[0] = 64;
 	info_array[1] = 32;
@@ -1490,16 +1749,18 @@
 		if (scsicam_bios_param(disk, dev, info) < 0 ||
 		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
 			if (EXT_TRANS) {
-				printk("aha152x: unable to verify geometry for disk with >1GB.\n"
-				"         using extended translation.\n");
+				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] = disk->capacity / (255 * 63);
 			} else {
-				printk("aha152x: unable to verify geometry for disk with >1GB.\n"
+				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 /usr/src/linux/drivers/scsi/aha152x.c for details.\n");
+				       "         See /usr/src/linux/drivers/scsi/README.aha152x for details.\n");
 			}
 		} else {
 			info_array[0] = info[0];
@@ -1507,1158 +1768,1211 @@
 			info_array[2] = info[2];
 
 			if (info[0] == 255 && !EXT_TRANS) {
-				printk("aha152x: current partition table is using extended translation.\n"
-				       "         using it also, although it's not explicty enabled.\n");
+				printk(KERN_NOTICE
+				       "aha152x: current partition table is using extended translation.\n"
+				       "         using it also, although it's not explictly enabled.\n");
 			}
 		}
 	}
-#if defined(DEBUG_BIOSPARAM)
-	if (HOSTDATA(shpnt)->debug & debug_biosparam) {
-		printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
-		       info_array[0], info_array[1], info_array[2]);
-		printk("WARNING: check, if the bios geometry is correct.\n");
-	}
-#endif
 
 	return 0;
 }
 
 /*
  *  Internal done function
+ *
  */
-void aha152x_done(struct Scsi_Host *shpnt, int error)
+static void done(struct Scsi_Host *shpnt, int error)
 {
-	unsigned long flags;
-	Scsi_Cmnd *done_SC;
-
-#if defined(DEBUG_DONE)
-	if (HOSTDATA(shpnt)->debug & debug_done) {
-		printk("\naha152x: done(), ");
-		disp_ports(shpnt);
-	}
-#endif
-
 	if (CURRENT_SC) {
-#if defined(DEBUG_DONE)
-		if (HOSTDATA(shpnt)->debug & debug_done)
-			printk("done(%x), ", error);
-#endif
-
-		save_flags(flags);
-		cli();
+		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;
-
-		/* turn led off, when no commands are in the driver */
-		HOSTDATA(shpnt)->commands--;
-		if (!HOSTDATA(shpnt)->commands)
-			SETPORT(PORTA, 0);	/* turn led off */
-
-#if defined(DEBUG_QUEUES)
-		if (HOSTDATA(shpnt)->debug & debug_queues)
-			printk("ok (%d), ", HOSTDATA(shpnt)->commands);
-#endif
-		restore_flags(flags);
-
-		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-
-#if 0
-/* Why poll for the BUS FREE phase, when we have setup the interrupt!? */
-#if defined(DEBUG_PHASES)
-		if (HOSTDATA(shpnt)->debug & debug_phases)
-			printk("BUS FREE loop, ");
-#endif
-		while (TESTLO(SSTAT1, BUSFREE))
-			barrier();
-#if defined(DEBUG_PHASES)
-		if (HOSTDATA(shpnt)->debug & debug_phases)
-			printk("BUS FREE\n");
-#endif
-#endif
-
-		done_SC->result = error;
-		if (done_SC->scsi_done) {
-#if defined(DEBUG_DONE)
-			if (HOSTDATA(shpnt)->debug & debug_done)
-				printk("calling scsi_done, ");
-#endif
-			spin_lock_irqsave(&io_request_lock, flags);
-			done_SC->scsi_done(done_SC);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-#if defined(DEBUG_DONE)
-			if (HOSTDATA(shpnt)->debug & debug_done)
-				printk("done returned, ");
-#endif
-		} else
-			panic("aha152x: current_SC->scsi_done() == NULL");
+		DONE_SC = CURRENT_SC;
+		CURRENT_SC = 0;
+		DONE_SC->result = error;
 	} else
-		aha152x_panic(shpnt, "done() called outside of command");
+		printk(KERN_ERR "aha152x: done() called outside of command\n");
 }
 
-
-static void aha152x_complete(struct Scsi_Host *);
-
 static struct tq_struct aha152x_tq;
 
 /*
- *    Run service completions on the card with interrupts enabled.
+ * Run service completions on the card with interrupts enabled.
+ *
  */
-
-static void aha152x_run(void)
+static void run(void)
 {
 	int i;
 	for (i = 0; i < IRQS; i++) {
 		struct Scsi_Host *shpnt = aha152x_host[i];
 		if (shpnt && HOSTDATA(shpnt)->service) {
-			HOSTDATA(shpnt)->service = 0;
-			aha152x_complete(shpnt);
+			HOSTDATA(shpnt)->service=0;
+			complete(shpnt);
 		}
 	}
 }
 
 /*
- *    Interrupts handler (main routine of the driver)
+ *    Interrupts handler
+ *
  */
 
-static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs)
+static void intr(int irqno, void *dev_id, struct pt_regs *regs)
 {
 	struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
 
-#if defined(DEBUG_RACE)
-	enter_driver("intr");
-#else
-#if defined(DEBUG_INTR)
-	if (HOSTDATA(shpnt)->debug & debug_intr)
-		printk("\naha152x: intr(), ");
-#endif
-#endif
-
-	if (!shpnt)
-		panic("aha152x: catched interrupt for unknown controller.\n");
+	if (!shpnt) {
+		printk(KERN_ERR "aha152x: catched interrupt for unknown controller.\n");
+		return;
+	}
 
 	/* 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 = 1;
-	aha152x_tq.routine = (void *) aha152x_run;
+	HOSTDATA(shpnt)->service++;
+	aha152x_tq.routine = (void *) run;
 	queue_task(&aha152x_tq, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 }
 
-static void aha152x_complete(struct Scsi_Host *shpnt)
+/*
+ * 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 int flags;
-	int done = 0, phase;
+	unsigned long flags;
+#if defined(AHA152X_STAT)
+	int action=0;
+#endif
 
-	/* disconnected target is trying to reconnect.
-	   Only possible, if we have disconnected nexuses and
-	   nothing is occupying the bus.
-	 */
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
 
-	if (TESTHI(SSTAT0, SELDI) &&
-	    DISCONNECTED_SC &&
-	    (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) {
-		int identify_msg, target, i;
+	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 = 0;
 
-		/* Avoid conflicts when a target reconnects
-		   while we are trying to connect to another. */
-		if (CURRENT_SC) {
-#if defined(DEBUG_QUEUES)
-			if (HOSTDATA(shpnt)->debug & debug_queues)
-				printk("i+, ");
-#endif
-			save_flags(flags);
-			cli();
-			append_SC(&ISSUE_SC, CURRENT_SC);
-			CURRENT_SC = NULL;
-			restore_flags(flags);
+		} else {
+			done(shpnt, DID_ERROR << 16);
 		}
-		/* disable sequences */
-		SETPORT(SCSISEQ, 0);
-		SETPORT(SSTAT0, CLRSELDI);
-		SETPORT(SSTAT1, CLRBUSFREE);
-
-#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
-		if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases))
-			printk("reselected, ");
+#if defined(AHA152X_STAT)
+	} else {
+		HOSTDATA(shpnt)->busfree_without_old_command++;
 #endif
+	}
 
-		i = GETPORT(SELID) & ~(1 << shpnt->this_id);
-		target = 0;
+	DO_LOCK(flags);
 
-		if (i == 0)
-			aha152x_panic(shpnt, "reconnecting target unknown");
+	if(DONE_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+		if(SCDONE(DONE_SC)) {
+			Scsi_Cmnd *ptr=DONE_SC;
+			DONE_SC=SCDONE(DONE_SC);
 
-		for (; (i & 1) == 0; target++, i >>= 1);
+#if 0
+			if(HOSTDATA(shpnt)->debug & debug_eh) {
+				printk(ERR_LEAD "received sense: ", CMDINFO(ptr));
+				print_sense("bh", DONE_SC);
+			}
+#endif
 
-#if defined(DEBUG_QUEUES)
-		if (HOSTDATA(shpnt)->debug & debug_queues)
-			printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
+			HOSTDATA(shpnt)->commands--;
+			if (!HOSTDATA(shpnt)->commands)
+				SETPORT(PORTA, 0);	/* turn led off */
+
+			kfree(ptr->host_scribble);
+			kfree(ptr);
+		} 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
-		SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
-		SETPORT(SCSISEQ, ENRESELI);
 
-		if (TESTLO(SSTAT0, SELDI))
-			aha152x_panic(shpnt, "RESELI failed");
+			if(!(DONE_SC->SCp.Status & not_issued)) {
+				Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
 
-		SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f);
+				if(cmnd) {
+					Scsi_Cmnd *ptr=DONE_SC;
+					DONE_SC=0;
 
-		SETPORT(SCSISIG, P_MSGI);
+#if 0
+					DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+#endif
 
-		/* Get identify message */
-		if ((i = getphase(shpnt)) != P_MSGI) {
-			printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
-			aha152x_panic(shpnt, "unknown lun");
+					cmnd->cmnd[0]         = REQUEST_SENSE;
+					cmnd->cmnd[1]         = 0;
+					cmnd->cmnd[2]         = 0;
+					cmnd->cmnd[3]         = 0;
+					cmnd->cmnd[4]         = sizeof(ptr->sense_buffer);
+					cmnd->cmnd[5]         = 0;
+					cmnd->cmd_len	      = 6;
+					cmnd->host            = ptr->host;
+					cmnd->target          = ptr->target;
+					cmnd->lun             = ptr->lun;
+					cmnd->use_sg          = 0; 
+					cmnd->request_buffer  = ptr->sense_buffer;
+					cmnd->request_bufflen = sizeof(ptr->sense_buffer);
+			
+					DO_UNLOCK(flags);
+					aha152x_internal_queue(cmnd, 0, 0, ptr, internal_done);
+					DO_LOCK(flags);
+				} else {
+					printk(ERR_LEAD "allocation failed\n", CMDINFO(CURRENT_SC));
+					if(cmnd)
+						kfree(cmnd);
+				}
+			} else {
+#if 0
+				DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));
+#endif				
+			}
 		}
-		SETPORT(SCSISEQ, 0);
-
-		SETPORT(SXFRCTL0, CH1);
 
-		identify_msg = GETPORT(SCSIBUS);
-
-		if (!(identify_msg & IDENTIFY_BASE)) {
-			printk("target=%d, inbound message (%02x) != IDENTIFY\n",
-			       target, identify_msg);
-			aha152x_panic(shpnt, "unknown lun");
+		if(DONE_SC && DONE_SC->scsi_done) {
+			/* turn led off, when no commands are in the driver */
+			HOSTDATA(shpnt)->commands--;
+			if (!HOSTDATA(shpnt)->commands)
+				SETPORT(PORTA, 0);	/* turn led off */
+
+			kfree(DONE_SC->host_scribble);
+			DONE_SC->host_scribble=0;
+
+			DO_UNLOCK(flags);
+			DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC);
+                	DONE_SC->scsi_done(DONE_SC);
+			DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC);
+			DO_LOCK(flags);
 		}
-#if defined(DEBUG_QUEUES)
-		if (HOSTDATA(shpnt)->debug & debug_queues)
-			printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
+
+		DONE_SC=0;
+#if defined(AHA152X_STAT)
+	} else {
+		HOSTDATA(shpnt)->busfree_without_done_command++;
 #endif
+	}
+
+	if(ISSUE_SC)
+		CURRENT_SC = remove_first_SC(&ISSUE_SC);
 
-		save_flags(flags);
-		cli();
+	DO_UNLOCK(flags);
 
-#if defined(DEBUG_QUEUES)
-		if (HOSTDATA(shpnt)->debug & debug_queues)
-			printk("d-, ");
+	if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+		action++;
 #endif
-		CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f);
+	    	CURRENT_SC->SCp.phase |= selecting;
 
-		if (!CURRENT_SC) {
-			printk("lun=%d, ", identify_msg & 0x3f);
-			aha152x_panic(shpnt, "no disconnected command for that lun");
-		}
-		CURRENT_SC->SCp.phase &= ~disconnected;
-		restore_flags(flags);
+		DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
 
-		make_acklow(shpnt);
-		if (getphase(shpnt) != P_MSGI) {
-			SETPORT(SIMODE0, 0);
-			SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_RACE)
-			leave_driver("(reselected) intr");
+		/* clear selection timeout */
+		SETPORT(SSTAT1, SELTO);
+
+		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+		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
-			SETBITS(DMACNTRL0, INTEN);
-			return;
-		}
+		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
 	}
-	/* Check, if we aren't busy with a command */
-	if (!CURRENT_SC) {
-		/* bus is free to issue a queued command */
-		if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) {
-			save_flags(flags);
-			cli();
-#if defined(DEBUG_QUEUES)
-			if (HOSTDATA(shpnt)->debug & debug_queues)
-				printk("i-, ");
-#endif
-			CURRENT_SC = remove_first_SC(&ISSUE_SC);
-			restore_flags(flags);
-
-#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
-				printk("issuing command, ");
-#endif
-			CURRENT_SC->SCp.phase = in_selection;
-
-#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
-				printk("selecting %d, ", CURRENT_SC->target);
+
+#if defined(AHA152X_STAT)
+	if(!action)
+		HOSTDATA(shpnt)->busfree_without_any_action++;
 #endif
-			SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+}
 
-			/* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
-			SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER);
+/*
+ * 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);
 
-			/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
-			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
-			SETPORT(SIMODE1, ENSELTIMO);
+    	CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
 
-			/* Enable SELECTION OUT sequence */
-			SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+	SETPORT(SCSISEQ, 0);
 
-		} else {
-			/* No command we are busy with and no new to issue */
-			printk("aha152x: ignoring spurious interrupt, nothing to do\n");
-			if (TESTHI(DMACNTRL0, SWINT)) {
-				printk("aha152x: SWINT is set!  Why?\n");
-				CLRBITS(DMACNTRL0, SWINT);
-			}
-			show_queues(shpnt);
-		}
+	if (TESTLO(SSTAT0, SELDO)) {
+		printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_NO_CONNECT << 16);
+		return;
+	}
 
-#if defined(DEBUG_RACE)
-		leave_driver("(selecting) intr");
-#endif
-		SETBITS(DMACNTRL0, INTEN);
+	SETPORT(SSTAT0, CLRSELDO);
+	
+	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->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;
 	}
-	/* the bus is busy with something */
 
-#if defined(DEBUG_INTR)
-	if (HOSTDATA(shpnt)->debug & debug_intr)
-		disp_ports(shpnt);
-#endif
+    	CURRENT_SC->SCp.phase &= ~selecting;
 
-	/* we are waiting for the result of a selection attempt */
-	if (CURRENT_SC->SCp.phase & in_selection) {
-		if (TESTLO(SSTAT1, SELTO)) {
-			/* no timeout */
-			if (TESTHI(SSTAT0, SELDO)) {
-				/* clear BUS FREE interrupt */
-				SETPORT(SSTAT1, CLRBUSFREE);
-
-				/* Disable SELECTION OUT sequence */
-				CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
-
-				/* Disable SELECTION OUT DONE interrupt */
-				CLRBITS(SIMODE0, ENSELDO);
-				CLRBITS(SIMODE1, ENSELTIMO);
-
-				if (TESTLO(SSTAT0, SELDO)) {
-					printk("aha152x: passing bus free condition\n");
-
-#if defined(DEBUG_RACE)
-					leave_driver("(passing bus free) intr");
-#endif
-					SETBITS(DMACNTRL0, INTEN);
-
-					if (CURRENT_SC->SCp.phase & aborted) {
-						HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
-						HOSTDATA(shpnt)->abortion_complete++;
-					}
-					aha152x_done(shpnt, DID_NO_CONNECT << 16);
+	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);
+	}
+}
 
-					return;
-				}
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-				if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
-					printk("SELDO (SELID=%x), ", GETPORT(SELID));
-#endif
+/*
+ * 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;
 
-				/* selection was done */
-				SETPORT(SSTAT0, CLRSELDO);
+	SETPORT(SCSISIG, 0);
+	SETPORT(SSTAT0, CLRSELDI);
+	SETPORT(SSTAT1, CLRBUSFREE);
+	SETPORT(SSTAT1, CLRPHASECHG);
 
-#if defined(DEBUG_ABORT)
-				if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted))
-					printk("(ABORT) target selected, ");
-#endif
+	if(CURRENT_SC) {
+		if(!(CURRENT_SC->SCp.phase & not_issued))
+			printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
 
-				CURRENT_SC->SCp.phase &= ~in_selection;
-				CURRENT_SC->SCp.phase |= in_other;
+		DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
 
-				ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun));
+		DO_LOCK(flags);
+		append_SC(&ISSUE_SC, CURRENT_SC);
+		DO_UNLOCK(flags);
 
-				if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) {
-					ADDMSG(EXTENDED_MESSAGE);
-					ADDMSG(3);
-					ADDMSG(EXTENDED_SDTR);
-					ADDMSG(50);
-					ADDMSG(8);
+		CURRENT_SC = 0;
+	}
 
-					printk("outbound SDTR: ");
-					print_msg(&MSG(MSGLEN - 5));
+	if(!DISCONNECTED_SC) {
+		DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+		return;
+	}
 
-					SYNCRATE = 0x80;
-					CURRENT_SC->SCp.phase |= in_sync;
-				}
-#if defined(DEBUG_RACE)
-				leave_driver("(SELDO) intr");
-#endif
-				SETPORT(SCSIRATE, SYNCRATE & 0x7f);
+	RECONN_TARGET=-1;
 
-				SETPORT(SCSISIG, P_MSGO);
+	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
 
-				SETPORT(SIMODE0, 0);
-				SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
-				SETBITS(DMACNTRL0, INTEN);
+	if (selid==0) {
+		printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+		return;
+	}
 
-				return;
-			} else
-				aha152x_panic(shpnt, "neither timeout nor selection\007");
-		} else {
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
-				printk("SELTO, ");
-#endif
-			/* end selection attempt */
-			CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
-
-			/* timeout */
-			SETPORT(SSTAT1, CLRSELTIMO);
-
-			SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-			SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-			SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
-			leave_driver("(SELTO) intr");
-#endif
-
-			if (CURRENT_SC->SCp.phase & aborted) {
-#if defined(DEBUG_ABORT)
-				if (HOSTDATA(shpnt)->debug & debug_abort)
-					printk("(ABORT) selection timeout, ");
-#endif
-				HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
-				HOSTDATA(shpnt)->abortion_complete++;
-			}
-			if (TESTLO(SSTAT0, SELINGO))
-				/* ARBITRATION not won */
-				aha152x_done(shpnt, DID_BUS_BUSY << 16);
-			else
-				/* ARBITRATION won, but SELECTION failed */
-				aha152x_done(shpnt, DID_NO_CONNECT << 16);
+	for(target=7; !(selid & (1 << target)); target--)
+		;
 
-			return;
-		}
+	if(selid & ~(1 << target)) {
+		printk("aha152x%d: multiple targets reconnected (%02x)\n",
+		       HOSTNO, selid);
 	}
-	/* enable interrupt, when target leaves current phase */
-	phase = getphase(shpnt);
-	if (!(phase & ~P_MASK))	/* "real" phase */
-		SETPORT(SCSISIG, phase);
-	SETPORT(SSTAT1, CLRPHASECHG);
-	CURRENT_SC->SCp.phase =
-	    (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16);
 
-	/* information transfer phase */
-	switch (phase) {
-	case P_MSGO:		/* MESSAGE OUT */
-		{
-			int i, identify = 0, abort = 0;
-
-#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases))
-				printk("MESSAGE OUT, ");
-#endif
-			if (MSGLEN == 0) {
-				ADDMSG(MESSAGE_REJECT);
-#if defined(DEBUG_MSGO)
-				if (HOSTDATA(shpnt)->debug & debug_msgo)
-					printk("unexpected MESSAGE OUT phase; rejecting, ");
+
+	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);
 			}
-			CLRBITS(SXFRCTL0, ENDMA);
 
-			SETPORT(SIMODE0, 0);
-			SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+			/*
+	 	 	 * Handle reselection
+	 		 */
+			if(!(MSGI(0) & IDENTIFY_BASE)) {
+				printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+				continue;
+			}
 
-			/* wait for data latch to become ready or a phase change */
-			while (TESTLO(DMASTAT, INTSTAT))
-				barrier();
+			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
 
-#if defined(DEBUG_MSGO)
-			if (HOSTDATA(shpnt)->debug & debug_msgo) {
-				int i;
-
-				printk("messages (");
-				for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" "));
-				printk("), ");
+			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;
 			}
-#endif
 
-			for (i = 0; i < MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) {
-#if defined(DEBUG_MSGO)
-				if (HOSTDATA(shpnt)->debug & debug_msgo)
-					printk("%x ", MSG(i));
-#endif
-				if (i == MSGLEN - 1) {
-					/* Leave MESSAGE OUT after transfer */
-					SETPORT(SSTAT1, CLRATNO);
-				}
-				SETPORT(SCSIDAT, MSG(i));
+			DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
 
-				make_acklow(shpnt);
-				getphase(shpnt);
+			CURRENT_SC->SCp.Message = MSGI(0);
+			CURRENT_SC->SCp.phase &= ~disconnected;
 
-				if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun))
-					identify++;
+			MSGILEN=0;
 
-				if (MSG(i) == ABORT)
-					abort++;
+			/* next message if any */
+			continue;
+		} 
 
-			}
+		CURRENT_SC->SCp.Message = MSGI(0);
 
-			MSGLEN = 0;
+		switch (MSGI(0)) {
+		case DISCONNECT:
+			if (!RECONNECT)
+				printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
 
-			if (identify)
-				CURRENT_SC->SCp.phase |= sent_ident;
+			CURRENT_SC->SCp.phase |= disconnected;
+			break;
 
-			if (abort) {
-				/* revive abort(); abort() enables interrupts */
-				HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
-				HOSTDATA(shpnt)->abortion_complete++;
+		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 &= ~(P_MASK << 16);
+			CURRENT_SC->SCp.phase |= completed;
+			break;
 
-				/* exit */
-				SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
-				leave_driver("(ABORT) intr");
-#endif
-				aha152x_done(shpnt, DID_ABORT << 16);
+		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;
 
-				return;
-			}
-		}
-		break;
+		case SAVE_POINTERS:
+			break;
 
-	case P_CMD:		/* COMMAND phase */
-#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
-		if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases))
-			printk("COMMAND, ");
-#endif
-		if (!(CURRENT_SC->SCp.sent_command)) {
-			int i;
+		case RESTORE_POINTERS:
+			break;
 
-			CLRBITS(SXFRCTL0, ENDMA);
+		case EXTENDED_MESSAGE:
+			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
+				/* not yet completed */
+				continue;
+			}
 
-			SETPORT(SIMODE0, 0);
-			SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+			switch (MSGI(2)) {
+			case EXTENDED_SDTR:
+				{
+					long ticks;
+
+					if (MSGI(1) != 3) {
+						printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+						break;
+					}
 
-			/* wait for data latch to become ready or a phase change */
-			while (TESTLO(DMASTAT, INTSTAT))
-				barrier();
+					if (!HOSTDATA(shpnt)->synchronous)
+						break;
 
-			for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) {
-				SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
+					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);
+					}
 
-				make_acklow(shpnt);
-				getphase(shpnt);
-			}
+					SYNCNEG=2;		/* negotiation completed */
+					SETRATE(SYNCRATE);
+				}
+				break;
 
-			if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
-				aha152x_panic(shpnt, "target left COMMAND");
+			case BUS_DEVICE_RESET:
+				{
+					int i;
+
+					for(i=0; i<8; i++) {
+						HOSTDATA(shpnt)->syncrate[i]=0;
+						HOSTDATA(shpnt)->syncneg[i]=0;
+					}
 
-			CURRENT_SC->SCp.sent_command++;
-		} else
-			aha152x_panic(shpnt, "Nothing to send while in COMMAND");
-		break;
+				}
+				break;
 
-	case P_MSGI:		/* MESSAGE IN phase */
-		{
-			int start_sync = 0;
-
-#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases))
-				printk("MESSAGE IN, ");
-#endif
-			SETPORT(SXFRCTL0, CH1);
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			case EXTENDED_WDTR:
+			default:
+				ADDMSGO(MESSAGE_REJECT);
+				break;
+			}
+			break;
+		}
 
-			SETPORT(SIMODE0, 0);
-			SETPORT(SIMODE1, ENBUSFREE);
+		MSGILEN=0;
+	}
+}
 
-			while (phase == P_MSGI) {
-				CURRENT_SC->SCp.Message = GETPORT(SCSIDAT);
-				switch (CURRENT_SC->SCp.Message) {
-				case DISCONNECT:
-#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-					if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
-						printk("target disconnected, ");
-#endif
-					CURRENT_SC->SCp.Message = 0;
-					CURRENT_SC->SCp.phase |= disconnected;
-					if (!HOSTDATA(shpnt)->reconnect)
-						aha152x_panic(shpnt, "target was not allowed to disconnect");
-
-					break;
-
-				case COMMAND_COMPLETE:
-#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
-					if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
-						printk("inbound message (COMMAND COMPLETE), ");
-#endif
-					done++;
-					break;
-
-				case MESSAGE_REJECT:
-					if (CURRENT_SC->SCp.phase & in_sync) {
-						CURRENT_SC->SCp.phase &= ~in_sync;
-						SYNCRATE = 0x80;
-						printk("synchronous rejected, ");
-					} else
-						printk("inbound message (MESSAGE REJECT), ");
-#if defined(DEBUG_MSGI)
-					if (HOSTDATA(shpnt)->debug & debug_msgi)
-						printk("inbound message (MESSAGE REJECT), ");
-#endif
-					break;
-
-				case SAVE_POINTERS:
-#if defined(DEBUG_MSGI)
-					if (HOSTDATA(shpnt)->debug & debug_msgi)
-						printk("inbound message (SAVE DATA POINTERS), ");
-#endif
-					break;
-
-				case RESTORE_POINTERS:
-#if defined(DEBUG_MSGI)
-					if (HOSTDATA(shpnt)->debug & debug_msgi)
-						printk("inbound message (RESTORE DATA POINTERS), ");
-#endif
-					break;
-
-				case EXTENDED_MESSAGE:
-					{
-						char buffer[16];
-						int i;
-
-#if defined(DEBUG_MSGI)
-						if (HOSTDATA(shpnt)->debug & debug_msgi)
-							printk("inbound message (EXTENDED MESSAGE), ");
-#endif
-						make_acklow(shpnt);
-						if (getphase(shpnt) != P_MSGI)
-							break;
+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);
+	} 
+}
 
-						buffer[0] = EXTENDED_MESSAGE;
-						buffer[1] = GETPORT(SCSIDAT);
+/*
+ * 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->lun));
+		} else {
+			printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC));
+			ADDMSGO(MESSAGE_REJECT);
+		}
+	}
 
-						for (i = 0; i < buffer[1] &&
-						     (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++)
-							buffer[2 + i] = GETPORT(SCSIDAT);
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_msgo) {
+		int i;
 
-#if defined(DEBUG_MSGI)
-						if (HOSTDATA(shpnt)->debug & debug_msgi)
-							print_msg(buffer);
+		printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
+		for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+			;
+		printk(")\n");
+	}
 #endif
+}
 
-						switch (buffer[2]) {
-						case EXTENDED_SDTR:
-							{
-								long ticks;
-
-								if (buffer[1] != 3)
-									aha152x_panic(shpnt, "SDTR message length != 3");
+/*
+ * 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);
 
-								if (!HOSTDATA(shpnt)->synchronous)
-									break;
+	while(MSGO_I<MSGOLEN) {
+		DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
 
-								printk("inbound SDTR: ");
-								print_msg(buffer);
+		if(TESTLO(SSTAT0, SPIORDY)) {
+			DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}
 
-								ticks = (buffer[3] * 4 + 49) / 50;
+		if (MSGO_I==MSGOLEN-1) {
+			/* Leave MESSAGE OUT after transfer */
+			SETPORT(SSTAT1, CLRATNO);
+		}
 
-								if (CURRENT_SC->SCp.phase & in_sync) {
-									/* we initiated SDTR */
-									if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8)
-										aha152x_panic(shpnt, "received SDTR invalid");
 
-									SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
-								} else if (ticks <= 9 && buffer[4] >= 1) {
-									if (buffer[4] > 8)
-										buffer[4] = 8;
+		if (MSGO(MSGO_I) & IDENTIFY_BASE)
+			CURRENT_SC->SCp.phase |= identified;
 
-									ADDMSG(EXTENDED_MESSAGE);
-									ADDMSG(3);
-									ADDMSG(EXTENDED_SDTR);
-									if (ticks < 4) {
-										ticks = 4;
-										ADDMSG(50);
-									} else
-										ADDMSG(buffer[3]);
+		if (MSGO(MSGO_I)==ABORT)
+			CURRENT_SC->SCp.phase |= aborted;
 
-									ADDMSG(buffer[4]);
+		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
+			CURRENT_SC->SCp.phase |= resetted;
 
-									printk("outbound SDTR: ");
-									print_msg(&MSG(MSGLEN - 5));
+		SETPORT(SCSIDAT, MSGO(MSGO_I++));
+	}
+}
 
-									CURRENT_SC->SCp.phase |= in_sync;
+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);
+		
+	MSGO_I  = 0;
+	MSGOLEN = 0;
+}
 
-									SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
+/* 
+ * 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;
+	}
 
-									start_sync++;
-								} else {
-									/* requested SDTR is too slow, do it asynchronously */
-									ADDMSG(MESSAGE_REJECT);
-									SYNCRATE = 0;
-								}
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_cmd) {
+		printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
+		print_command(CURRENT_SC->cmnd);
+	}
+#endif
 
-								SETPORT(SCSIRATE, SYNCRATE & 0x7f);
-							}
-							break;
+	CMD_I=0;
+}
 
-						case EXTENDED_MODIFY_DATA_POINTER:
-						case EXTENDED_EXTENDED_IDENTIFY:
-						case EXTENDED_WDTR:
-						default:
-							ADDMSG(MESSAGE_REJECT);
-							break;
-						}
-					}
-					break;
+/*
+ * 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);
+	}
 
-				default:
-					printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message);
-					break;
+	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;
+		}
 
-				make_acklow(shpnt);
-				phase = getphase(shpnt);
-			}
+		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
+	}
+}
 
-			if (start_sync)
-				CURRENT_SC->SCp.phase |= in_sync;
-			else
-				CURRENT_SC->SCp.phase &= ~in_sync;
+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++;
+}
 
-			if (MSGLEN > 0)
-				SETPORT(SCSISIG, P_MSGI | ATNO);
+/*
+ * 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;
+	}
 
-			/* clear SCSI fifo on BUSFREE */
-			if (phase == P_BUSFREE)
-				SETPORT(SXFRCTL0, CH1 | CLRCH1);
+	CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
 
-			if (CURRENT_SC->SCp.phase & disconnected) {
-				save_flags(flags);
-				cli();
-#if defined(DEBUG_QUEUES)
-				if (HOSTDATA(shpnt)->debug & debug_queues)
-					printk("d+, ");
+#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
-				append_SC(&DISCONNECTED_SC, CURRENT_SC);
-				CURRENT_SC->SCp.phase |= 1 << 16;
-				CURRENT_SC = NULL;
-				restore_flags(flags);
-
-				SETBITS(SCSISEQ, ENRESELI);
+}
 
-				SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-				SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+/*
+ * data in phase
+ *
+ */
+static void datai_init(struct Scsi_Host *shpnt)
+{
+	SETPORT(DMACNTRL0, RSTFIFO);
+	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
 
-				SETBITS(DMACNTRL0, INTEN);
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
 
-				return;
-			}
-		}
-		break;
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
 
-	case P_STATUS:		/* STATUS IN phase */
-#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-		if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases))
-			printk("STATUS, ");
-#endif
-		SETPORT(SXFRCTL0, CH1);
+	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);
+}
 
-		SETPORT(SIMODE0, 0);
-		SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
+static void datai_run(struct Scsi_Host *shpnt)
+{
+	unsigned int the_time;
+	int fifodata, data_count;
 
-		if (TESTHI(SSTAT1, PHASEMIS))
-			printk("aha152x: passing STATUS phase");
+	/*
+	 * 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;
+		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
+			barrier();
 
-		CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
-		make_acklow(shpnt);
-		getphase(shpnt);
-
-#if defined(DEBUG_STATUS)
-		if (HOSTDATA(shpnt)->debug & debug_status) {
-			printk("inbound status ");
-			print_status(CURRENT_SC->SCp.Status);
-			printk(", ");
+		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
+			printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
+			disp_ports(shpnt);
+			break;
 		}
-#endif
-		break;
 
-	case P_DATAI:		/* DATA IN phase */
-		{
-			int fifodata, data_count, done;
-
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases))
-				printk("DATA IN, ");
-#endif
+		if(TESTHI(DMASTAT, DFIFOFULL)) {
+			fifodata = 128;
+		} else {
+			the_time=jiffies + 100;
+			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
+				barrier();
 
-#if 0
-			if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT))
-				printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
-				       GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
-#endif
+			if(TESTLO(SSTAT2, SEMPTY)) {
+				printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
+				disp_ports(shpnt);
+				break;
+			}
 
-			/* reset host fifo */
-			SETPORT(DMACNTRL0, RSTFIFO);
-			SETPORT(DMACNTRL0, RSTFIFO | ENDMA);
+			fifodata = GETPORT(FIFOSTAT);
+		}
 
-			SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN);
+                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           = CURRENT_SC->SCp.buffer->address;
+                               	CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+			} 
+                }
 
-			SETPORT(SIMODE0, 0);
-			SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+		if(fifodata>0 && CURRENT_SC->SCp.this_residual==0) {
+			printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
+			break;
+		}
+	}
 
-			/* done is set when the FIFO is empty after the target left DATA IN */
-			done = 0;
+	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);
+	}
 
-			/* while the target stays in DATA to transfer data */
-			while (!done) {
-#if defined(DEBUG_DATAI)
-				if (HOSTDATA(shpnt)->debug & debug_datai)
-					printk("expecting data, ");
-#endif
-				/* wait for PHASEMIS or full FIFO */
-				while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT))
-					barrier();
+	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);
+	}
+}
 
-#if defined(DEBUG_DATAI)
-				if (HOSTDATA(shpnt)->debug & debug_datai)
-					printk("ok, ");
-#endif
+static void datai_end(struct Scsi_Host *shpnt)
+{
+	CURRENT_SC->resid -= GETSTCNT();
 
-				if (TESTHI(DMASTAT, DFIFOFULL))
-					fifodata = GETPORT(FIFOSTAT);
-				else {
-					/* wait for SCSI fifo to get empty */
-					while (TESTLO(SSTAT2, SEMPTY))
-						barrier();
+	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());
 
-					/* rest of data in FIFO */
-					fifodata = GETPORT(FIFOSTAT);
-#if defined(DEBUG_DATAI)
-					if (HOSTDATA(shpnt)->debug & debug_datai)
-						printk("last transfer, ");
-#endif
-					done = 1;
-				}
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(DMACNTRL0, 0);
+}
 
-#if defined(DEBUG_DATAI)
-				if (HOSTDATA(shpnt)->debug & debug_datai)
-					printk("fifodata=%d, ", fifodata);
-#endif
+/*
+ * data out phase
+ *
+ */
+static void datao_init(struct Scsi_Host *shpnt)
+{
+	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
 
-				while (fifodata && CURRENT_SC->SCp.this_residual) {
-					data_count = fifodata;
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
 
-					/* limit data transfer to size of first sg buffer */
-					if (data_count > CURRENT_SC->SCp.this_residual)
-						data_count = CURRENT_SC->SCp.this_residual;
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
 
-					fifodata -= data_count;
+	DATA_LEN = CURRENT_SC->resid;
 
-#if defined(DEBUG_DATAI)
-					if (HOSTDATA(shpnt)->debug & debug_datai)
-						printk("data_count=%d, ", data_count);
-#endif
+	DPRINTK(debug_datao,
+		DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
 
-					if (data_count & 1) {
-						/* get a single byte in byte mode */
-						SETBITS(DMACNTRL0, _8BIT);
-						*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
-						CURRENT_SC->SCp.this_residual--;
-					}
-					if (data_count > 1) {
-						CLRBITS(DMACNTRL0, _8BIT);
-						data_count >>= 1;	/* Number of words */
-						insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-#if defined(DEBUG_DATAI)
-						if (HOSTDATA(shpnt)->debug & debug_datai)
-							/* show what comes with the last transfer */
-							if (done) {
-#if 0
-								int i;
-								unsigned char *data;
-#endif
+static void datao_run(struct Scsi_Host *shpnt)
+{
+	unsigned int the_time;
+	int data_count;
 
-								printk("data on last transfer (%d bytes) ",
-								       2 * data_count);
-#if 0
-								printk("data on last transfer (%d bytes: ",
-								       2 * data_count);
-								data = (unsigned char *) CURRENT_SC->SCp.ptr;
-								for (i = 0; i < 2 * data_count; i++)
-									printk("%2x ", *data++);
-								printk("), ");
-#endif
-							}
-#endif
-						CURRENT_SC->SCp.ptr += 2 * data_count;
-						CURRENT_SC->SCp.this_residual -= 2 * data_count;
-					}
-					/* if this buffer is full and there are more buffers left */
-					if (!CURRENT_SC->SCp.this_residual &&
-					    CURRENT_SC->SCp.buffers_residual) {
-						/* advance to next buffer */
-						CURRENT_SC->SCp.buffers_residual--;
-						CURRENT_SC->SCp.buffer++;
-						CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
-						CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
-					}
-				}
+	/* 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;
 
-				/*
-				 * FIFO should be empty
-				 */
-				if (fifodata > 0) {
-					printk("aha152x: more data than expected (%d bytes)\n",
-					       GETPORT(FIFOSTAT));
-					SETBITS(DMACNTRL0, _8BIT);
-					printk("aha152x: data (");
-					while (fifodata--)
-						printk("%2x ", GETPORT(DATAPORT));
-					printk(")\n");
-				}
-#if defined(DEBUG_DATAI)
-				if (HOSTDATA(shpnt)->debug & debug_datai)
-					if (!fifodata)
-						printk("fifo empty, ");
-					else
-						printk("something left in fifo, ");
-#endif
-			}
+		if(TESTLO(DMASTAT, DFIFOEMP)) {
+			printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
+			disp_ports(shpnt);
+			break;
+		}
 
-#if defined(DEBUG_DATAI)
-			if ((HOSTDATA(shpnt)->debug & debug_datai) &&
-			    (CURRENT_SC->SCp.buffers_residual ||
-			     CURRENT_SC->SCp.this_residual))
-				printk("left buffers (buffers=%d, bytes=%d), ",
-				       CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual);
-#endif
-			/* transfer can be considered ended, when SCSIEN reads back zero */
-			CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
-			while (TESTHI(SXFRCTL0, SCSIEN))
-				barrier();
-			CLRBITS(DMACNTRL0, ENDMA);
+		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           = CURRENT_SC->SCp.buffer->address;
+			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+		}
 
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
-			if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr))
-				printk("got %d bytes, ", GETSTCNT());
-#endif
+		the_time=jiffies+100;
+		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
+			barrier();
 
-			CURRENT_SC->SCp.have_data_in++;
+		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
+			printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
+			disp_ports(shpnt);
+			break;
 		}
-		break;
-
-	case P_DATAO:		/* DATA OUT phase */
-		{
-			int data_count;
-
-#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
-			if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases))
-				printk("DATA OUT, ");
-#endif
-#if defined(DEBUG_DATAO)
-			if (HOSTDATA(shpnt)->debug & debug_datao)
-				printk("got data to send (bytes=%d, buffers=%d), ",
-				       CURRENT_SC->SCp.this_residual,
-				       CURRENT_SC->SCp.buffers_residual);
-#endif
-
-			if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) {
-				printk("%d(%d) left in FIFO, ",
-				       GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
-				aha152x_panic(shpnt, "FIFO should be empty");
-			}
-			SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1);
-			SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1);
+	}
+}
 
-			SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
-			SETPORT(DMACNTRL0, ENDMA | WRITE_READ);
+static void datao_end(struct Scsi_Host *shpnt)
+{
+	if(TESTLO(DMASTAT, DFIFOEMP)) {
+		int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
 
-			SETPORT(SIMODE0, 0);
-			SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+		DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transfered)\n",
+			CMDINFO(CURRENT_SC),
+			data_count,
+			DATA_LEN-CURRENT_SC->resid,
+			GETSTCNT());
 
-			/* while current buffer is not empty or
-			   there are more buffers to transfer */
-			while (TESTLO(SSTAT1, PHASEMIS) &&
-			       (CURRENT_SC->SCp.this_residual ||
-				CURRENT_SC->SCp.buffers_residual)) {
-#if defined(DEBUG_DATAO)
-				if (HOSTDATA(shpnt)->debug & debug_datao)
-					printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
-					   CURRENT_SC->SCp.this_residual,
-					CURRENT_SC->SCp.buffers_residual);
-#endif
-				/* transfer rest of buffer, but max. 128 byte */
-				data_count =
-				    CURRENT_SC->SCp.this_residual > 128 ?
-				    128 : CURRENT_SC->SCp.this_residual;
-
-#if defined(DEBUG_DATAO)
-				if (HOSTDATA(shpnt)->debug & debug_datao)
-					printk("data_count=%d, ", data_count);
-#endif
-
-				if (data_count & 1) {
-					/* put a single byte in byte mode */
-					SETBITS(DMACNTRL0, _8BIT);
-					SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
-					CURRENT_SC->SCp.this_residual--;
-				}
-				if (data_count > 1) {
-					CLRBITS(DMACNTRL0, _8BIT);
-					data_count >>= 1;	/* number of words */
-					outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-					CURRENT_SC->SCp.ptr += 2 * data_count;
-					CURRENT_SC->SCp.this_residual -= 2 * data_count;
-				}
-				/* wait for FIFO to get empty */
-				while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT))
-					barrier();
-
-#if defined(DEBUG_DATAO)
-				if (HOSTDATA(shpnt)->debug & debug_datao)
-					printk("fifo (%d bytes), transfered (%d bytes), ",
-					  GETPORT(FIFOSTAT), GETSTCNT());
-#endif
-
-				/* if this buffer is empty and there are more buffers left */
-				if (TESTLO(SSTAT1, PHASEMIS) &&
-				    !CURRENT_SC->SCp.this_residual &&
-				    CURRENT_SC->SCp.buffers_residual) {
-					/* advance to next buffer */
-					CURRENT_SC->SCp.buffers_residual--;
-					CURRENT_SC->SCp.buffer++;
-					CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
-					CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
-				}
-			}
+		CURRENT_SC->resid += data_count;
 
-			if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) {
-				/* target leaves DATA OUT for an other phase (perhaps disconnect) */
+		data_count -= CURRENT_SC->SCp.ptr - CURRENT_SC->SCp.buffer->address;
+		while(data_count>0) {
+			CURRENT_SC->SCp.buffer--;
+			CURRENT_SC->SCp.buffers_residual++;
+			data_count -= CURRENT_SC->SCp.buffer->length;
+		}
+		CURRENT_SC->SCp.ptr           = CURRENT_SC->SCp.buffer->address - data_count;
+		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
+	}
 
-				/* data in fifos has to be resend */
-				data_count = GETPORT(SSTAT2) & (SFULL | SFCNT);
+	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());
 
-				data_count += GETPORT(FIFOSTAT);
-				CURRENT_SC->SCp.ptr -= data_count;
-				CURRENT_SC->SCp.this_residual += data_count;
-#if defined(DEBUG_DATAO)
-				if (HOSTDATA(shpnt)->debug & debug_datao)
-					printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), "
-					       "transfer incomplete, resetting fifo, ",
-					   CURRENT_SC->SCp.this_residual,
-					CURRENT_SC->SCp.buffers_residual,
-					       data_count);
-#endif
-				SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
-				CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
-				CLRBITS(DMACNTRL0, ENDMA);
-			} else {
-#if defined(DEBUG_DATAO)
-				if (HOSTDATA(shpnt)->debug & debug_datao)
-					printk("waiting for SCSI fifo to get empty, ");
-#endif
-				/* wait for SCSI fifo to get empty */
-				while (TESTLO(SSTAT2, SEMPTY))
-					barrier();
-#if defined(DEBUG_DATAO)
-				if (HOSTDATA(shpnt)->debug & debug_datao)
-					printk("ok, left data (bytes=%d, buffers=%d) ",
-					   CURRENT_SC->SCp.this_residual,
-					CURRENT_SC->SCp.buffers_residual);
-#endif
-				CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
-
-				/* transfer can be considered ended, when SCSIEN reads back zero */
-				while (TESTHI(SXFRCTL0, SCSIEN))
-					barrier();
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
 
-				CLRBITS(DMACNTRL0, ENDMA);
-			}
+	SETPORT(DMACNTRL0, 0);
+}
 
-#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
-			if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr))
-				printk("sent %d data bytes, ", GETSTCNT());
-#endif
+/*
+ * 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;
 		}
-		break;
+		dataphase=1;
+	}
 
-	case P_BUSFREE:	/* BUSFREE */
-#if defined(DEBUG_RACE)
-		leave_driver("(BUSFREE) intr");
-#endif
-#if defined(DEBUG_PHASES)
-		if (HOSTDATA(shpnt)->debug & debug_phases)
-			printk("unexpected BUS FREE, ");
-#endif
-		CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
+	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
+		printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
+		disp_ports(shpnt);
+	}
 
-		aha152x_done(shpnt, DID_ERROR << 16);	/* Don't know any better */
-		return;
-		break;
+	if(STATE!=PREVSTATE) {
+		LASTSTATE=PREVSTATE;
+	}
 
-	case P_PARITY:		/* parity error in DATA phase */
-#if defined(DEBUG_RACE)
-		leave_driver("(DID_PARITY) intr");
-#endif
-		printk("PARITY error in DATA phase, ");
+	return dataphase;
+}
 
-		CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
+/*
+ * 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);
+}
 
-		SETBITS(DMACNTRL0, INTEN);
-		aha152x_done(shpnt, DID_PARITY << 16);
-		return;
-		break;
+/*
+ * handle reset in
+ *
+ */
+static void rsti_run(struct Scsi_Host *shpnt)
+{
+	Scsi_Cmnd *ptr;
 
-	default:
-		printk("aha152x: unexpected phase\n");
-		break;
-	}
+	printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
+	
+	ptr=DISCONNECTED_SC;
+	while(ptr) {
+		Scsi_Cmnd *next = SCNEXT(ptr);
 
-	if (done) {
-#if defined(DEBUG_INTR)
-		if (HOSTDATA(shpnt)->debug & debug_intr)
-			printk("command done.\n");
-#endif
-#if defined(DEBUG_RACE)
-		leave_driver("(done) intr");
-#endif
+		if (!ptr->device->soft_reset) {
+			remove_SC(&DISCONNECTED_SC, ptr);
 
-		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
-		SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+			kfree(ptr->host_scribble);
+			ptr->host_scribble=0;
 
-		SETBITS(DMACNTRL0, INTEN);
+			ptr->result =  DID_RESET << 16;
+			ptr->scsi_done(ptr);
+		}
 
-		aha152x_done(shpnt,
-			     (CURRENT_SC->SCp.Status & 0xff)
-			     | ((CURRENT_SC->SCp.Message & 0xff) << 8)
-			     | (DID_OK << 16));
-
-#if defined(DEBUG_RACE)
-		printk("done returned (DID_OK: Status=%x; Message=%x).\n",
-		       CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message);
-#endif
-		return;
+		ptr = next;
 	}
-	if (CURRENT_SC)
-		CURRENT_SC->SCp.phase |= 1 << 16;
 
-	SETPORT(SIMODE0, 0);
-	SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_INTR)
-	if (HOSTDATA(shpnt)->debug & debug_intr)
-		disp_enintr(shpnt);
-#endif
-#if defined(DEBUG_RACE)
-	leave_driver("(PHASEEND) intr");
-#endif
+	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
+		done(shpnt, DID_RESET << 16 );
+}
+
 
+/*
+ * bottom-half handler
+ *
+ */
+static void complete(struct Scsi_Host *shpnt)
+{
+	int dataphase;
+	unsigned long flags;
+	int pending;
+
+	DO_LOCK(flags);
+	if(HOSTDATA(shpnt)->in_intr!=0)
+		aha152x_error(shpnt, "bottom-half already running!?");
+	HOSTDATA(shpnt)->in_intr++;
+	DO_UNLOCK(flags);
+
+	/*
+	 * loop while there are interrupt conditions pending
+	 *
+	 */
+	do {
+		unsigned long start = jiffies;
+		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
+		DO_UNLOCK(flags);
+
+		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
+	 *
+	 */
+	DO_LOCK(flags);
+	HOSTDATA(shpnt)->in_intr--;
 	SETBITS(DMACNTRL0, INTEN);
-	return;
+	DO_UNLOCK(flags);
 }
 
+
 /* 
- * Dump the current driver status and panic...
+ * Dump the current driver status and panic
  */
-static void aha152x_panic(struct Scsi_Host *shpnt, char *msg)
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
 {
-	printk("\naha152x: %s\n", msg);
+	printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg);
 	show_queues(shpnt);
-	panic("aha152x panic");
+	panic("aha152x panic\n");
 }
 
 /*
@@ -2666,18 +2980,16 @@
  */
 static void disp_ports(struct Scsi_Host *shpnt)
 {
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
 	int s;
 
-#ifdef SKIP_PORTS
-	if (HOSTDATA(shpnt)->debug & debug_skipports)
-		return;
-#endif
-
-	printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+	printk("\n%s: %s(%s) ",
+		CURRENT_SC ? "busy" : "waiting",
+		states[STATE].name,
+		states[PREVSTATE].name);
 
 	s = GETPORT(SCSISEQ);
-	printk("SCSISEQ (");
+	printk("SCSISEQ( ");
 	if (s & TEMODEO)
 		printk("TARGET MODE ");
 	if (s & ENSELO)
@@ -2696,7 +3008,7 @@
 		printk("SCSIRSTO ");
 	printk(");");
 
-	printk(" SCSISIG (");
+	printk(" SCSISIG(");
 	s = GETPORT(SCSISIG);
 	switch (s & P_MASK) {
 	case P_DATAO:
@@ -2726,7 +3038,7 @@
 
 	printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
 
-	printk("SSTAT (");
+	printk("SSTAT( ");
 	s = GETPORT(SSTAT0);
 	if (s & TARGET)
 		printk("TARGET ");
@@ -2765,7 +3077,7 @@
 	printk("); ");
 
 
-	printk("SSTAT (");
+	printk("SSTAT( ");
 
 	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
 
@@ -2806,7 +3118,7 @@
 		printk("REQINIT ");
 	printk("); ");
 
-	printk("SXFRCTL0 (");
+	printk("SXFRCTL0( ");
 
 	s = GETPORT(SXFRCTL0);
 	if (s & SCSIEN)
@@ -2823,24 +3135,26 @@
 		printk("CLRCH1 ");
 	printk("); ");
 
-	printk("SIGNAL (");
+	printk("SIGNAL( ");
 
 	s = GETPORT(SCSISIG);
-	if (s & ATNI)
+	if (s & SIG_ATNI)
 		printk("ATNI ");
-	if (s & SELI)
+	if (s & SIG_SELI)
 		printk("SELI ");
-	if (s & BSYI)
+	if (s & SIG_BSYI)
 		printk("BSYI ");
-	if (s & REQI)
+	if (s & SIG_REQI)
 		printk("REQI ");
-	if (s & ACKI)
+	if (s & SIG_ACKI)
 		printk("ACKI ");
 	printk("); ");
 
 	printk("SELID (%02x), ", GETPORT(SELID));
 
-	printk("SSTAT2 (");
+	printk("STCNT (%d), ", GETSTCNT());
+	
+	printk("SSTAT2( ");
 
 	s = GETPORT(SSTAT2);
 	if (s & SOFFSET)
@@ -2854,7 +3168,7 @@
 	s = GETPORT(SSTAT3);
 	printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
 
-	printk("SSTAT4 (");
+	printk("SSTAT4( ");
 	s = GETPORT(SSTAT4);
 	if (s & SYNCERR)
 		printk("SYNCERR ");
@@ -2864,7 +3178,7 @@
 		printk("FRERR ");
 	printk("); ");
 
-	printk("DMACNTRL0 (");
+	printk("DMACNTRL0( ");
 	s = GETPORT(DMACNTRL0);
 	printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
 	printk("%s ", s & DMA ? "DMA" : "PIO");
@@ -2879,7 +3193,7 @@
 		printk("SWINT ");
 	printk("); ");
 
-	printk("DMASTAT (");
+	printk("DMASTAT( ");
 	s = GETPORT(DMASTAT);
 	if (s & ATDONE)
 		printk("ATDONE ");
@@ -2889,9 +3203,7 @@
 		printk("DFIFOFULL ");
 	if (s & DFIFOEMP)
 		printk("DFIFOEMP ");
-	printk(")");
-
-	printk("\n");
+	printk(")\n");
 #endif
 }
 
@@ -2902,7 +3214,7 @@
 {
 	int s;
 
-	printk("enabled interrupts (");
+	printk(KERN_DEBUG "enabled interrupts ( ");
 
 	s = GETPORT(SIMODE0);
 	if (s & ENSELDO)
@@ -2938,100 +3250,38 @@
 	printk(")\n");
 }
 
-#if defined(DEBUG_RACE)
-
-static const char *should_leave;
-static int in_driver = 0;
-
-/*
- * Only one routine can be in the driver at once.
- */
-static void enter_driver(const char *func)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	printk("aha152x: entering %s() (%x)\n", func, jiffies);
-	if (in_driver) {
-		printk("%s should leave first.\n", should_leave);
-		panic("aha152x: already in driver\n");
-	}
-	in_driver++;
-	should_leave = func;
-	restore_flags(flags);
-}
-
-static void leave_driver(const char *func)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
-	if (!in_driver) {
-		printk("aha152x: %s already left.\n", should_leave);
-		panic("aha152x: %s already left driver.\n");
-	}
-	in_driver--;
-	should_leave = func;
-	restore_flags(flags);
-}
-#endif
-
 /*
  * Show the command data of a command
  */
-static void show_command(Scsi_Cmnd * ptr)
+static void show_command(Scsi_Cmnd *ptr)
 {
-	printk("0x%08x: target=%d; lun=%d; cmnd=(",
+	printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
 	       (unsigned int) ptr, ptr->target, ptr->lun);
 
 	print_command(ptr->cmnd);
 
-	printk("); residual=%d; buffers=%d; phase |",
-	       ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+	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 & in_selection)
-		printk("in selection|");
+	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 & sent_ident)
-		printk("send_ident|");
-	if (ptr->SCp.phase & in_other) {
-		printk("; in other(");
-		switch ((ptr->SCp.phase >> 16) & 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("*illegal*");
-			break;
-		}
-		printk(")");
-		if (ptr->SCp.phase & (1 << 16))
-			printk("; phaseend");
-	}
-	printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+	if (ptr->SCp.phase & resetted)
+		printk("resetted|");
+	printk("; next=0x%p\n", SCNEXT(ptr));
 }
 
 /*
@@ -3039,33 +3289,27 @@
  */
 static void show_queues(struct Scsi_Host *shpnt)
 {
-	unsigned long flags;
 	Scsi_Cmnd *ptr;
+	unsigned long flags;
 
-	save_flags(flags);
-	cli();
-	printk("QUEUE STATUS:\nissue_SC:\n");
-	for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+	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("current_SC:\n");
+	printk(KERN_DEBUG "current_SC:\n");
 	if (CURRENT_SC)
 		show_command(CURRENT_SC);
 	else
-		printk("none\n");
+		printk(KERN_DEBUG "none\n");
 
-	printk("disconnected_SC:\n");
-	for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+	printk(KERN_DEBUG "disconnected_SC:\n");
+	for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
 		show_command(ptr);
 
 	disp_ports(shpnt);
 	disp_enintr(shpnt);
-	restore_flags(flags);
-}
-
-int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
-{
-	return (-ENOSYS);	/* Currently this is a no-op */
 }
 
 #undef SPRINTF
@@ -3082,49 +3326,26 @@
 	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
 		SPRINTF("0x%02x ", ptr->cmnd[i]);
 
-	SPRINTF("); residual=%d; buffers=%d; phase |",
-		ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+	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 & in_selection)
-		SPRINTF("in selection|");
+	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 & sent_ident)
-		SPRINTF("send_ident|");
-	if (ptr->SCp.phase & in_other) {
-		SPRINTF("; in other(");
-		switch ((ptr->SCp.phase >> 16) & 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("*illegal*");
-			break;
-		}
-		SPRINTF(")");
-		if (ptr->SCp.phase & (1 << 16))
-			SPRINTF("; phaseend");
-	}
-	SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+	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);
 }
@@ -3134,15 +3355,10 @@
 	char *start = pos;
 	int s;
 
-#ifdef SKIP_PORTS
-	if (HOSTDATA(shpnt)->debug & debug_skipports)
-		return;
-#endif
-
-	SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+	SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
 
 	s = GETPORT(SCSISEQ);
-	SPRINTF("SCSISEQ (");
+	SPRINTF("SCSISEQ( ");
 	if (s & TEMODEO)
 		SPRINTF("TARGET MODE ");
 	if (s & ENSELO)
@@ -3161,7 +3377,7 @@
 		SPRINTF("SCSIRSTO ");
 	SPRINTF(");");
 
-	SPRINTF(" SCSISIG (");
+	SPRINTF(" SCSISIG(");
 	s = GETPORT(SCSISIG);
 	switch (s & P_MASK) {
 	case P_DATAO:
@@ -3191,7 +3407,7 @@
 
 	SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
 
-	SPRINTF("SSTAT (");
+	SPRINTF("SSTAT( ");
 	s = GETPORT(SSTAT0);
 	if (s & TARGET)
 		SPRINTF("TARGET ");
@@ -3230,7 +3446,7 @@
 	SPRINTF("); ");
 
 
-	SPRINTF("SSTAT (");
+	SPRINTF("SSTAT( ");
 
 	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
 
@@ -3271,7 +3487,7 @@
 		SPRINTF("REQINIT ");
 	SPRINTF("); ");
 
-	SPRINTF("SXFRCTL0 (");
+	SPRINTF("SXFRCTL0( ");
 
 	s = GETPORT(SXFRCTL0);
 	if (s & SCSIEN)
@@ -3288,24 +3504,26 @@
 		SPRINTF("CLRCH1 ");
 	SPRINTF("); ");
 
-	SPRINTF("SIGNAL (");
+	SPRINTF("SIGNAL( ");
 
 	s = GETPORT(SCSISIG);
-	if (s & ATNI)
+	if (s & SIG_ATNI)
 		SPRINTF("ATNI ");
-	if (s & SELI)
+	if (s & SIG_SELI)
 		SPRINTF("SELI ");
-	if (s & BSYI)
+	if (s & SIG_BSYI)
 		SPRINTF("BSYI ");
-	if (s & REQI)
+	if (s & SIG_REQI)
 		SPRINTF("REQI ");
-	if (s & ACKI)
+	if (s & SIG_ACKI)
 		SPRINTF("ACKI ");
 	SPRINTF("); ");
 
-	SPRINTF("SELID (%02x), ", GETPORT(SELID));
+	SPRINTF("SELID(%02x), ", GETPORT(SELID));
+
+	SPRINTF("STCNT(%d), ", GETSTCNT());
 
-	SPRINTF("SSTAT2 (");
+	SPRINTF("SSTAT2( ");
 
 	s = GETPORT(SSTAT2);
 	if (s & SOFFSET)
@@ -3319,7 +3537,7 @@
 	s = GETPORT(SSTAT3);
 	SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
 
-	SPRINTF("SSTAT4 (");
+	SPRINTF("SSTAT4( ");
 	s = GETPORT(SSTAT4);
 	if (s & SYNCERR)
 		SPRINTF("SYNCERR ");
@@ -3329,7 +3547,7 @@
 		SPRINTF("FRERR ");
 	SPRINTF("); ");
 
-	SPRINTF("DMACNTRL0 (");
+	SPRINTF("DMACNTRL0( ");
 	s = GETPORT(DMACNTRL0);
 	SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
 	SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
@@ -3344,7 +3562,7 @@
 		SPRINTF("SWINT ");
 	SPRINTF("); ");
 
-	SPRINTF("DMASTAT (");
+	SPRINTF("DMASTAT( ");
 	s = GETPORT(DMASTAT);
 	if (s & ATDONE)
 		SPRINTF("ATDONE ");
@@ -3354,9 +3572,9 @@
 		SPRINTF("DFIFOFULL ");
 	if (s & DFIFOEMP)
 		SPRINTF("DFIFOEMP ");
-	SPRINTF(")\n\n");
+	SPRINTF(")\n");
 
-	SPRINTF("enabled interrupts (");
+	SPRINTF("enabled interrupts( ");
 
 	s = GETPORT(SIMODE0);
 	if (s & ENSELDO)
@@ -3394,8 +3612,52 @@
 	return (pos - start);
 }
 
+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)
+#define SPRINTF(args...) \
+	do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
 
 int aha152x_proc_info(char *buffer, char **start,
 		      off_t offset, int length, int hostno, int inout)
@@ -3403,48 +3665,39 @@
 	int i;
 	char *pos = buffer;
 	struct Scsi_Host *shpnt;
-	unsigned long flags;
 	Scsi_Cmnd *ptr;
+	unsigned long flags;
+	int thislength;
 
 	for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++)
 		if (aha152x_host[i] && aha152x_host[i]->host_no == hostno)
 			shpnt = aha152x_host[i];
 
 	if (!shpnt)
-		return (-ESRCH);
+		return -ESRCH;
 
-	if (inout)		/* Has data been written to the file ? */
-		return (aha152x_set_info(buffer, length, shpnt));
+	DPRINTK(debug_procinfo, 
+	       KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
+	       buffer, offset, length, hostno, inout);
 
-	SPRINTF(AHA152X_REVID "\n");
 
-	save_flags(flags);
-	cli();
+	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",
-		HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled");
+		RECONNECT ? "enabled" : "disabled");
 	SPRINTF("parity checking %s\n",
-		HOSTDATA(shpnt)->parity ? "enabled" : "disabled");
+		PARITY ? "enabled" : "disabled");
 	SPRINTF("synchronous transfers %s\n",
-		HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
+		SYNCHRONOUS ? "enabled" : "disabled");
 	SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
 
-	if (HOSTDATA(shpnt)->synchronous) {
-#if 0
-		SPRINTF("synchronously operating targets (tick=%ld ns):\n",
-			250000000 / loops_per_sec);
-		for (i = 0; i < 8; i++)
-			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
-				SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n",
-					i,
-					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
-					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) *
-					250000000 / loops_per_sec,
-				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
-#else
+	if(SYNCHRONOUS) {
 		SPRINTF("synchronously operating targets (tick=50 ns):\n");
 		for (i = 0; i < 8; i++)
 			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
@@ -3453,14 +3706,14 @@
 					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
 					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
 				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
-#endif
 	}
-#ifdef DEBUG_AHA152X
-#define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
+#if defined(AHA152X_DEBUG)
+#define PDEBUG(flags,txt) \
+	if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
 
 	SPRINTF("enabled debugging options: ");
 
-	PDEBUG(debug_skipports, "skip ports");
+	PDEBUG(debug_procinfo, "procinfo");
 	PDEBUG(debug_queue, "queue");
 	PDEBUG(debug_intr, "interrupt");
 	PDEBUG(debug_selection, "selection");
@@ -3470,23 +3723,22 @@
 	PDEBUG(debug_cmd, "command");
 	PDEBUG(debug_datai, "data in");
 	PDEBUG(debug_datao, "data out");
-	PDEBUG(debug_abort, "abort");
-	PDEBUG(debug_done, "done");
-	PDEBUG(debug_biosparam, "bios parameters");
+	PDEBUG(debug_eh, "eh");
+	PDEBUG(debug_locks, "locks");
 	PDEBUG(debug_phases, "phases");
-	PDEBUG(debug_queues, "queues");
-	PDEBUG(debug_reset, "reset");
 
 	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 = (Scsi_Cmnd *) ptr->host_scribble)
+		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");
@@ -3496,25 +3748,62 @@
 
 	if (DISCONNECTED_SC) {
 		SPRINTF("disconnected commands:\n");
-		for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
 			pos += get_command(pos, ptr);
 	} else
 		SPRINTF("no disconnected commands\n");
 
-	restore_flags(flags);
-
 	pos += get_ports(shpnt, pos);
 
-	*start = buffer + offset;
-	if (pos - buffer < offset)
+#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 = 0;
 		return 0;
-	else if (pos - buffer - offset < length)
-		return pos - buffer - offset;
-	else
-		return length;
+	}
+
+	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;
 }
 
-#ifdef MODULE
+#if defined(MODULE)
 /* Eventually this will go into an include file, but this will be later */
 Scsi_Host_Template driver_template = AHA152X;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)