patch-2.3.14 linux/drivers/scsi/NCR53C9x.c

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

diff -u --recursive --new-file v2.3.13/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c
@@ -2,12 +2,12 @@
  *
  * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
  *
  * Most DMA dependencies put in driver specific files by 
  * Jesper Skov (jskov@cygnus.co.uk)
  *
- * Set up to use GETREG/SETREG (preprocessor macros in NCR53c9x.h) by
+ * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by
  * Tymm Twillman (tymm@coe.missouri.edu)
  */
 
@@ -21,6 +21,10 @@
  * 4) Maybe change use of "esp" to something more "NCR"'ish.
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -30,28 +34,12 @@
 #include <linux/blk.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
-
 #include <linux/init.h>
 
 #include "scsi.h"
 #include "hosts.h"
 #include "NCR53C9x.h"
 
-#ifdef CONFIG_SCSI_SUNESP
-#include "sparc_esp.h"
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/machines.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#endif
-
-#if defined(CONFIG_BLZ1230_SCSI)||defined(CONFIG_BLZ2060_SCSI)||defined(CONFIG_CYBERSTORMII_SCSI)
-#define SYMBIOS_HACK
-#else
-#undef SYMBIOS_HACK
-#endif
-
 #include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
@@ -95,6 +83,17 @@
 	in_tgterror   = 0x84,  /* Target did something stupid           */
 };
 
+enum {
+	/* Zero has special meaning, see skipahead[12]. */
+/*0*/	do_never,
+
+/*1*/	do_phase_determine,
+/*2*/	do_reset_bus,
+/*3*/	do_reset_complete,
+/*4*/	do_work_bus,
+/*5*/	do_intr_end
+};
+
 struct proc_dir_entry proc_scsi_esp = {
 	PROC_SCSI_ESP, 3, "esp",
 	S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -227,7 +226,6 @@
 		    "UNKNOWN"))))));
 }
 
-#if defined(DEBUG_STATE_MACHINE) || defined(DEBUG_ESP)
 static char *phase_string(int phase)
 {
 	switch(phase) {
@@ -283,26 +281,31 @@
 		return "UNKNOWN";
 	};
 }
-#endif
 
+#ifdef DEBUG_STATE_MACHINE
 static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase)
 {
-#ifdef DEBUG_STATE_MACHINE
 	ESPLOG(("<%s>", phase_string(newphase)));
-#endif
 	s->SCp.sent_command = s->SCp.phase;
 	s->SCp.phase = newphase;
 }
+#else
+#define esp_advance_phase(__s, __newphase) \
+	(__s)->SCp.sent_command = (__s)->SCp.phase; \
+	(__s)->SCp.phase = (__newphase);
+#endif
 
+#ifdef DEBUG_ESP_CMDS
 extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
 			   unchar cmd)
 {
-#ifdef DEBUG_ESP_CMDS
 	esp->espcmdlog[esp->espcmdent] = cmd;
 	esp->espcmdent = (esp->espcmdent + 1) & 31;
-#endif
-	SETREG(eregs->esp_cmnd, cmd);
+	esp_write(eregs->esp_cmnd, cmd);
 }
+#else
+#define esp_cmd(__esp, __eregs, __cmd)	esp_write((__eregs)->esp_cmnd, (__cmd))
+#endif
 
 /* How we use the various Linux SCSI data structures for operation.
  *
@@ -320,7 +323,6 @@
  *   the disconnect flag.
  */
 
-
 /* Manipulation of the ESP command queues.  Thanks to the aha152x driver
  * and its author, Juergen E. Fischer, for the methods used here.
  * Note that these are per-ESP queues, not global queues like
@@ -329,9 +331,7 @@
 static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
 {
 	Scsi_Cmnd *end;
-	unsigned long flags;
 
-	save_flags(flags); cli();
 	new_SC->host_scribble = (unsigned char *) NULL;
 	if(!*SC)
 		*SC = new_SC;
@@ -340,38 +340,28 @@
 			;
 		end->host_scribble = (unsigned char *) new_SC;
 	}
-	restore_flags(flags);
 }
 
 static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
 {
-	unsigned long flags;
-
-	save_flags(flags); cli();
 	new_SC->host_scribble = (unsigned char *) *SC;
 	*SC = new_SC;
-	restore_flags(flags);
 }
 
 static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
 {
 	Scsi_Cmnd *ptr;
-	unsigned long flags;
 
-	save_flags(flags); cli();
 	ptr = *SC;
 	if(ptr)
 		*SC = (Scsi_Cmnd *) (*SC)->host_scribble;
-	restore_flags(flags);
 	return ptr;
 }
 
 static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun)
 {
 	Scsi_Cmnd *ptr, *prev;
-	unsigned long flags;
 
-	save_flags(flags); cli();
 	for(ptr = *SC, prev = NULL;
 	    ptr && ((ptr->target != target) || (ptr->lun != lun));
 	    prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
@@ -382,14 +372,13 @@
 		else
 			*SC=(Scsi_Cmnd *)ptr->host_scribble;
 	}
-	restore_flags(flags);
 	return ptr;
 }
 
 /* Resetting various pieces of the ESP scsi driver chipset */
 
 /* Reset the ESP chip, _not_ the SCSI bus. */
-static inline void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	int family_code, version, i;
 	volatile int trash;
@@ -397,6 +386,8 @@
 	/* Now reset the ESP chip */
 	esp_cmd(esp, eregs, ESP_CMD_RC);
 	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+	if(esp->erev == fast)
+		esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB);
 	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
 
 	/* This is the only point at which it is reliable to read
@@ -404,31 +395,45 @@
 	 */
 	esp->max_period = ((35 * esp->ccycle) / 1000);
 	if(esp->erev == fast) {
-		version = GETREG(eregs->esp_uid);
+		char *erev2string[] = {
+			"Emulex FAS236",
+			"Emulex FPESP100A",
+			"fast",
+			"QLogic FAS366",
+			"Emulex FAS216",
+			"Symbios Logic 53CF9x-2",
+			"unknown!"
+		};
+			
+		version = esp_read(eregs->esp_uid);
 		family_code = (version & 0xf8) >> 3;
-#ifdef SYMBIOS_HACK
-		if (version == 0 && family_code == 0)
-		  {
-		    printk ("Detected SymBIOS chip with no family code.\n");
-		    version = 3;
-		    family_code = 2;
-		  }
-#endif
-		if(family_code == 0x02)
+		if(family_code == 0x02) {
 		        if ((version & 7) == 2)
 			        esp->erev = fas216;	
                         else
 			        esp->erev = fas236;
-		else if(family_code == 0x0a)
-			esp->erev = fashme; /* Version is usually '5'. */
-		else
-			esp->erev = fas100a;
-		printk("esp%d: FAST chip is %s (family=%d, version=%d)\n",
-		       esp->esp_id,
-		       (esp->erev == fas236) ? "fas236" :
-		       ((esp->erev == fas216) ? "fas216" :		       
-		       (((esp->erev == fas100a) ? "fas100a" :
-		       "fasHME"))), family_code, (version & 7));
+		} else if(family_code == 0x0a)
+			esp->erev = fas366; /* Version is usually '5'. */
+		else if(family_code == 0x00) {
+			if ((version & 7) == 2)
+				esp->erev = fas100a; /* NCR53C9X */
+			else
+				esp->erev = espunknown;
+		} else if(family_code == 0x14) {
+			if ((version & 7) == 2)
+				esp->erev = fsc;
+		        else
+				esp->erev = espunknown;
+		} else if(family_code == 0x00) {
+			if ((version & 7) == 2)
+				esp->erev = fas100a; /* NCR53C9X */
+			else
+				esp->erev = espunknown;
+		} else
+			esp->erev = espunknown;
+		ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
+			esp->esp_id, erev2string[esp->erev - fas236],
+			family_code, (version & 7)));
 
 		esp->min_period = ((4 * esp->ccycle) / 1000);
 	} else {
@@ -436,56 +441,63 @@
 	}
 
 	/* Reload the configuration registers */
-	SETREG(eregs->esp_cfact, esp->cfact);
-	SETREG(eregs->esp_stp, 0);
-	SETREG(eregs->esp_soff, 0);
-	SETREG(eregs->esp_timeo, esp->neg_defp);
+	esp_write(eregs->esp_cfact, esp->cfact);
+	esp->prev_stp = 0;
+	esp_write(eregs->esp_stp, 0);
+	esp->prev_soff = 0;
+	esp_write(eregs->esp_soff, 0);
+	esp_write(eregs->esp_timeo, esp->neg_defp);
 	esp->max_period = (esp->max_period + 3)>>2;
 	esp->min_period = (esp->min_period + 3)>>2;
 
-	SETREG(eregs->esp_cfg1, esp->config1);
+	esp_write(eregs->esp_cfg1, esp->config1);
 	switch(esp->erev) {
 	case esp100:
 		/* nothing to do */
 		break;
 	case esp100a:
-		SETREG(eregs->esp_cfg2, esp->config2);
+		esp_write(eregs->esp_cfg2, esp->config2);
 		break;
 	case esp236:
 		/* Slow 236 */
-		SETREG(eregs->esp_cfg2, esp->config2);
-		SETREG(eregs->esp_cfg3, esp->config3[0]);
+		esp_write(eregs->esp_cfg2, esp->config2);
+		esp->prev_cfg3 = esp->config3[0];
+		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		break;
+	case fas366:
+		panic("esp: FAS366 support not present, please notify "
+		      "jongk@cs.utwente.nl");
 		break;
-	case fashme:
-		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
-		/* fallthrough... */
-	case fas216:	    
+	case fas216:
 	case fas236:
-		/* Fast 236 or HME */
-		SETREG(eregs->esp_cfg2, esp->config2);
-		for(i=0; i<8; i++) {
-			if(esp->erev == fashme)
-				esp->config3[i] |=
-					(ESP_CONFIG3_FCLOCK | ESP_CONFIG3_BIGID | ESP_CONFIG3_OBPUSH);
-			else
-				esp->config3[i] |= ESP_CONFIG3_FCLK;
-		}
-		SETREG(eregs->esp_cfg3, esp->config3[0]);
-		if(esp->erev == fashme) {
-			esp->radelay = 80;
-		} else {
-			if(esp->diff)
-				esp->radelay = 0;
-			else
-				esp->radelay = 96;
-		}
+	case fsc:
+		/* Fast ESP variants */
+		esp_write(eregs->esp_cfg2, esp->config2);
+		for(i=0; i<8; i++)
+			esp->config3[i] |= ESP_CONFIG3_FCLK;
+		esp->prev_cfg3 = esp->config3[0];
+		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		if(esp->diff)
+			esp->radelay = 0;
+		else
+			esp->radelay = 16;
+		/* Different timeout constant for these chips */
+		esp->neg_defp =
+			FSC_NEG_DEFP(esp->cfreq,
+				     (esp->cfact == ESP_CCF_F0 ?
+				      ESP_CCF_F7 + 1 : esp->cfact));
+		esp_write(eregs->esp_timeo, esp->neg_defp);
+		/* Enable Active Negotiation if possible */
+		if((esp->erev == fsc) && !esp->diff)
+			esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN);
 		break;
 	case fas100a:
 		/* Fast 100a */
-		SETREG(eregs->esp_cfg2, esp->config2);
+		esp_write(eregs->esp_cfg2, esp->config2);
 		for(i=0; i<8; i++)
 			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
-		SETREG(eregs->esp_cfg3, esp->config3[0]);
+		esp->prev_cfg3 = esp->config3[0];
+		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
 		esp->radelay = 32;
 		break;
 	default:
@@ -494,12 +506,12 @@
 	};
 
 	/* Eat any bitrot in the chip */
-	trash = GETREG(eregs->esp_intrpt);
+	trash = esp_read(eregs->esp_intrpt);
 	udelay(100);
 }
 
 /* This places the ESP into a known state at boot time. */
-inline void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
+void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	volatile unchar trash;
 
@@ -511,13 +523,13 @@
 	esp_reset_esp(esp, eregs);
 
 	/* Reset the SCSI bus, but tell ESP not to generate an irq */
-	SETREG(eregs->esp_cfg1, GETREG(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB);
+	esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB));
 	esp_cmd(esp, eregs, ESP_CMD_RS);
 	udelay(400);
-	SETREG(eregs->esp_cfg1, esp->config1);
+	esp_write(eregs->esp_cfg1, esp->config1);
 
 	/* Eat any bitrot in the chip and we are done... */
-	trash = GETREG(eregs->esp_intrpt);
+	trash = esp_read(eregs->esp_intrpt);
 }
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
@@ -538,6 +550,9 @@
 	esp->edev = esp_dev;
 	esp->esp_id = nesps++;
 
+	/* Set bitshift value (only used on Amiga with multiple ESPs) */
+	esp->shift = 2;
+
 	/* Put into the chain of esp chips detected */
 	if(espchain) {
 		elink = espchain;
@@ -551,6 +566,20 @@
 	return esp;
 }
 
+void esp_deallocate(struct NCR_ESP *esp)
+{
+	struct NCR_ESP *elink;
+
+	if(espchain == esp) {
+		espchain = 0;
+	} else {
+		for(elink = espchain; elink && (elink->next != esp); elink = elink->next);
+		if(elink) 
+			elink->next = esp->next;
+	}
+	nesps--;
+}
+
 /* Complete initialization of ESP structure and device
  * Caller must have initialized appropriate parts of the ESP structure
  * between the call to esp_allocate and this function.
@@ -639,9 +668,9 @@
 	esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
 	esp->sync_defp = SYNC_DEFP_SLOW;
 
-	printk("SCSI ID %d  Clock %d MHz CCF=%d Time-Out %d ",
+	printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ",
 	       esp->scsi_id, (esp->cfreq / 1000000),
-	       esp->ccf, (int) esp->neg_defp);
+	       ccf, (int) esp->neg_defp);
 
 	/* Fill in ehost data */
 	esp->ehost->base = (unsigned char *) eregs;
@@ -654,61 +683,46 @@
 	/* Probe the revision of this esp */
 	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
 	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
-	SETREG(eregs->esp_cfg2, esp->config2);
-#ifndef SYMBIOS_HACK
-	if((GETREG(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
+	esp_write(eregs->esp_cfg2, esp->config2);
+	if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
 	   (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
-		printk("NCR53C90(esp100) detected\n");
+		printk("NCR53C90(esp100)\n");
 		esp->erev = esp100;
 	} else {
-#endif
 		esp->config2 = 0;
-		SETREG(eregs->esp_cfg2, esp->config2);
-		SETREG(eregs->esp_cfg3, 0);
-		esp->config3[0] = 5;
-		SETREG(eregs->esp_cfg3, esp->config3[0]);
-#ifndef SYMBIOS_HACK
-		if(GETREG(eregs->esp_cfg3) != 5) {
-			printk("NCR53C90A(esp100a) detected\n");
+		esp_write(eregs->esp_cfg2, 0);
+		esp_write(eregs->esp_cfg3, 5);
+		if(esp_read(eregs->esp_cfg3) != 5) {
+			printk("NCR53C90A(esp100a)\n");
 			esp->erev = esp100a;
 		} else {
-#else
-		  {
-#endif
 			int target;
-			
+
 			for(target=0; target<8; target++)
 				esp->config3[target] = 0;
-			SETREG(eregs->esp_cfg3, 0);
-#ifndef SYMBIOS_HACK
+			esp->prev_cfg3 = 0;
+			esp_write(eregs->esp_cfg3, 0);
 			if(ccf > ESP_CCF_F5) {
-#endif
-				printk("NCR53C9XF(espfast) detected\n");
+				printk("NCR53C9XF(espfast)\n");
 				esp->erev = fast;
-				esp->config2 = 0;
-				SETREG(eregs->esp_cfg2, esp->config2);
 				esp->sync_defp = SYNC_DEFP_FAST;
-#ifndef SYMBIOS_HACK
 			} else {
-				printk("NCR53C9x(esp236) detected\n");
+				printk("NCR53C9x(esp236)\n");
 				esp->erev = esp236;
-				esp->config2 = 0;
-				SETREG(eregs->esp_cfg2, esp->config2);
 			}
 		}
-#endif
 	}				
-	
+
 	/* Initialize the command queues */
 	esp->current_SC = 0;
 	esp->disconnected_SC = 0;
 	esp->issue_SC = 0;
-	
+
 	/* Clear the state machines. */
 	esp->targets_present = 0;
 	esp->resetting_bus = 0;
 	esp->snip = 0;
-	esp->targets_present = 0;
+	esp->fas_premature_intr_workaround = 0;
 	for(i = 0; i < 32; i++)
 		esp->espcmdlog[i] = 0;
 	esp->espcmdent = 0;
@@ -719,9 +733,15 @@
 	esp->prevmsgout = esp->prevmsgin = 0;
 	esp->msgout_len = esp->msgin_len = 0;
 
+	/* Clear the one behind caches to hold unmatchable values. */
+	esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
+
 	/* Reset the thing before we try anything... */
 	esp_bootup_reset(esp, eregs);
-	
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
 	esps_in_use++;
 }
 
@@ -740,15 +760,17 @@
 	case esp100a:
 		return "ESP100A (NCR53C90A)";
 	case esp236:
-		return "ESP236";
+		return "ESP236 (NCR53C9x)";
 	case fas216:
-		return "ESP216-FAST";
+		return "Emulex FAS216";
 	case fas236:
-		return "ESP236-FAST";
-	case fashme:
-		return "ESP366-HME";
+		return "Emulex FAS236";
+	case fas366:
+		return "QLogic FAS366";
 	case fas100a:
-		return "ESP100A-FAST";
+		return "FPESP100A";
+	case fsc:
+		return "Symbios Logic 53CF9x-2";
 	default:
 		panic("Bogon ESP revision");
 	};
@@ -807,69 +829,41 @@
 	info.offset	= offset;
 	info.pos	= 0;
 
-	copy_info(&info, "Sparc ESP Host Adapter:\n");
-	copy_info(&info, "\tPROM node\t\t%08lx\n", (unsigned long) esp->prom_node);
-	copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
+	copy_info(&info, "ESP Host Adapter:\n");
 	copy_info(&info, "\tESP Model\t\t");
 	switch(esp->erev) {
 	case esp100:
-		copy_info(&info, "ESP100\n");
+		copy_info(&info, "ESP100 (NCR53C90)\n");
 		break;
 	case esp100a:
-		copy_info(&info, "ESP100A\n");
+		copy_info(&info, "ESP100A (NCR53C90A)\n");
 		break;
 	case esp236:
-		copy_info(&info, "ESP236\n");
+		copy_info(&info, "ESP236 (NCR53C9x)\n");
 		break;
 	case fas216:
-		copy_info(&info, "FAS216\n");
+		copy_info(&info, "Emulex FAS216\n");
 		break;
 	case fas236:
-		copy_info(&info, "FAS236\n");
+		copy_info(&info, "Emulex FAS236\n");
 		break;
 	case fas100a:
-		copy_info(&info, "FAS100A\n");
+		copy_info(&info, "FPESP100A\n");
 		break;
 	case fast:
-		copy_info(&info, "FAST\n");
-		break;
-	case fashme:
-		copy_info(&info, "Happy Meal FAS\n");
-		break;
-	case espunknown:
-	default:
-		copy_info(&info, "Unknown!\n");
-		break;
-	};
-#ifdef CONFIG_SCSI_SUNESP
-	copy_info(&info, "\tDMA Revision\t\t");
-	switch(((struct Linux_SBus_DMA*) (esp->dma))->revision) {
-	case dvmarev0:
-		copy_info(&info, "Rev 0\n");
-		break;
-	case dvmaesc1:
-		copy_info(&info, "ESC Rev 1\n");
-		break;
-	case dvmarev1:
-		copy_info(&info, "Rev 1\n");
-		break;
-	case dvmarev2:
-		copy_info(&info, "Rev 2\n");
+		copy_info(&info, "Generic FAST\n");
 		break;
-	case dvmarev3:
-		copy_info(&info, "Rev 3\n");
+	case fas366:
+		copy_info(&info, "QLogic FAS366\n");
 		break;
-	case dvmarevplus:
-		copy_info(&info, "Rev 1+\n");
-		break;
-	case dvmahme:
-		copy_info(&info, "Rev HME/FAS\n");
+	case fsc:
+		copy_info(&info, "Symbios Logic 53C9x-2\n");
 		break;
+	case espunknown:
 	default:
 		copy_info(&info, "Unknown!\n");
 		break;
 	};
-#endif
 	copy_info(&info, "\tLive Targets\t\t[ ");
 	for(i = 0; i < 15; i++) {
 		if(esp->targets_present & (1 << i))
@@ -878,7 +872,7 @@
 	copy_info(&info, "]\n\n");
 	
 	/* Now describe the state of each existing target. */
-	copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
+	copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n");
 	for(i = 0; i < 15; i++) {
 		if(esp->targets_present & (1 << i)) {
 			Scsi_Device *SDptr = esp->ehost->host_queue;
@@ -892,9 +886,7 @@
 			copy_info(&info, "%08lx\t", esp->config3[i]);
 			copy_info(&info, "[%02lx,%02lx]\t\t\t", SDptr->sync_max_offset,
 				  SDptr->sync_min_period);
-			copy_info(&info, "%s\t\t", SDptr->disconnect ? "yes" : "no");
-			copy_info(&info, "%s\n",
-				  (esp->config3[i] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
+			copy_info(&info, "%s\n", SDptr->disconnect ? "yes" : "no");
 		}
 	}
 
@@ -923,6 +915,60 @@
 	return esp_host_info(esp, buffer, offset, length);
 }
 
+static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	if(sp->use_sg == 0) {
+		sp->SCp.this_residual = sp->request_bufflen;
+		sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
+		sp->SCp.buffers_residual = 0;
+		if (esp->dma_mmu_get_scsi_one)
+			esp->dma_mmu_get_scsi_one(esp, sp);
+		else
+			sp->SCp.have_data_in = (int) sp->SCp.ptr =
+				(char *) virt_to_phys(sp->request_buffer);
+	} else {
+		sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+		sp->SCp.buffers_residual = sp->use_sg - 1;
+		sp->SCp.this_residual = sp->SCp.buffer->length;
+		if (esp->dma_mmu_get_scsi_sgl)
+			esp->dma_mmu_get_scsi_sgl(esp, sp);
+		else
+			sp->SCp.ptr =
+				(char *) virt_to_phys(sp->SCp.buffer->address);
+	}
+}
+
+static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	if(sp->use_sg == 0) {
+		if (esp->dma_mmu_release_scsi_one)
+			esp->dma_mmu_release_scsi_one(esp, sp);
+	} else {
+		if (esp->dma_mmu_release_scsi_sgl)
+			esp->dma_mmu_release_scsi_sgl(esp, sp);
+	}
+}
+
+static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	struct esp_pointers *ep = &esp->data_pointers[sp->target];
+
+	sp->SCp.ptr = ep->saved_ptr;
+	sp->SCp.buffer = ep->saved_buffer;
+	sp->SCp.this_residual = ep->saved_this_residual;
+	sp->SCp.buffers_residual = ep->saved_buffers_residual;
+}
+
+static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	struct esp_pointers *ep = &esp->data_pointers[sp->target];
+
+	ep->saved_ptr = sp->SCp.ptr;
+	ep->saved_buffer = sp->SCp.buffer;
+	ep->saved_this_residual = sp->SCp.this_residual;
+	ep->saved_buffers_residual = sp->SCp.buffers_residual;
+}
+
 /* Some rules:
  *
  *   1) Never ever panic while something is live on the bus.
@@ -970,29 +1016,7 @@
 	esp->msgout_len = 5;
 }
 
-/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
-static inline void build_wide_nego_msg(struct NCR_ESP *esp, int size)
-{
-	esp->cur_msgout[0] = EXTENDED_MESSAGE;
-	esp->cur_msgout[1] = 2;
-	esp->cur_msgout[2] = EXTENDED_WDTR;
-	switch(size) {
-	case 32:
-		esp->cur_msgout[3] = 2;
-		break;
-	case 16:
-		esp->cur_msgout[3] = 1;
-		break;
-	case 8:
-	default:
-		esp->cur_msgout[3] = 0;
-		break;
-	};
-
-	esp->msgout_len = 4;
-}
-
-static inline void esp_exec_cmd(struct NCR_ESP *esp)
+static void esp_exec_cmd(struct NCR_ESP *esp)
 {
 	struct ESP_regs *eregs = esp->eregs;
 	Scsi_Cmnd *SCptr;
@@ -1002,15 +1026,18 @@
 	int lun, target;
 	int i;
 
-	/* Hold off if we've been reselected or an IRQ is showing... */
-	if(esp->disconnected_SC || esp->dma_irq_p(esp))
+	/* Hold off if we have disconnected commands and
+	 * an IRQ is showing...
+	 */
+	if(esp->disconnected_SC && esp->dma_irq_p(esp))
 		return;
 
 	/* Grab first member of the issue queue. */
 	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
 
 	/* Safe to panic here because current_SC is null. */
-	if(!SCptr) panic("esp: esp_exec_cmd and issue queue is NULL");
+	if(!SCptr)
+		panic("esp: esp_exec_cmd and issue queue is NULL");
 
 	SDptr = SCptr->device;
 	lun = SCptr->lun;
@@ -1053,7 +1080,7 @@
 
 	if(SDptr->sync) {
 		/* this targets sync is known */
-#ifdef CONFIG_SCSI_SUNESP
+#ifdef CONFIG_SCSI_MAC_ESP
 do_sync_known:
 #endif
 		if(SDptr->disconnect)
@@ -1090,51 +1117,28 @@
 	} else {
 		int toshiba_cdrom_hwbug_wkaround = 0;
 
-#ifdef CONFIG_SCSI_SUNESP
-		/* Never allow disconnects or synchronous transfers on
-		 * SparcStation1 and SparcStation1+.  Allowing those
-		 * to be enabled seems to lockup the machine completely.
-		 */
-		if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-		   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-			/* But we are nice and allow tapes to disconnect. */
-			if(SDptr->type == TYPE_TAPE)
-				SDptr->disconnect = 1;
-			else
-				SDptr->disconnect = 0;
-			SDptr->sync_max_offset = 0;
-			SDptr->sync_min_period = 0;
-			SDptr->sync = 1;
-			esp->snip = 0;
-			goto do_sync_known;
-		}
+#ifdef CONFIG_SCSI_MAC_ESP
+		/* Never allow synchronous transfers (disconnect OK) on
+		 * Macintosh. Well, maybe later when we figured out how to 
+		 * do DMA on the machines that support it ...
+		 */
+		SDptr->disconnect = 1;
+		SDptr->sync_max_offset = 0;
+		SDptr->sync_min_period = 0;
+		SDptr->sync = 1;
+		esp->snip = 0;
+		goto do_sync_known;
 #endif
 		/* We've talked to this guy before,
-		 * but never negotiated.  Let's try,
-		 * need to attempt WIDE first, before
-		 * sync nego, as per SCSI 2 standard.
-		 */
-		if(esp->erev == fashme && !SDptr->wide) {
-			if(!SDptr->borken &&
-			   (SDptr->type != TYPE_ROM ||
-			    strncmp(SDptr->vendor, "TOSHIBA", 7))) {
-				build_wide_nego_msg(esp, 16);
-				esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
-				SDptr->wide = 1;
-				esp->wnip = 1;
-				goto after_nego_msg_built;
-			} else {
-				SDptr->wide = 1;
-				/* Fall through and try sync. */
-			}
-		}
-
+		 * but never negotiated.  Let's try
+		 * sync negotiation.
+		 */
 		if(!SDptr->borken) {
 			if((SDptr->type == TYPE_ROM) &&
 			   (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {
 				/* Nice try sucker... */
-				printk(KERN_INFO "esp%d: Disabling sync for buggy "
-				       "Toshiba CDROM.\n", esp->esp_id);
+				ESPMISC(("esp%d: Disabling sync for buggy "
+					 "Toshiba CDROM.\n", esp->esp_id));
 				toshiba_cdrom_hwbug_wkaround = 1;
 				build_sync_nego_msg(esp, 0, 0);
 			} else {
@@ -1146,7 +1150,6 @@
 		SDptr->sync = 1;
 		esp->snip = 1;
 
-after_nego_msg_built:
 		/* A fix for broken SCSI1 targets, when they disconnect
 		 * they lock up the bus and confuse ESP.  So disallow
 		 * disconnects for SCSI1 targets for now until we
@@ -1171,13 +1174,9 @@
 		 *           thank you very much. ;-)
 		 */
 		if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
-#if 1 /* Until I find out why HME barfs with disconnects enabled... */
-		   toshiba_cdrom_hwbug_wkaround || SDptr->borken || esp->erev == fashme) {
-#else
 		   toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
-#endif
-			printk(KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
-			       "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun);
+			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+				 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
 			SDptr->disconnect = 0;
 			*cmdp++ = IDENTIFY(0, lun);
 		} else {
@@ -1199,49 +1198,48 @@
 		for(i = 0; i < SCptr->cmd_len; i++)
 			*cmdp++ = SCptr->cmnd[i];
 
-	/* HME sucks... */
-	if(esp->erev == fashme)
-		SETREG(eregs->esp_busid, (target & 0xf) |
-			(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT));
-	else
-		SETREG(eregs->esp_busid, (target & 7));
-	SETREG(eregs->esp_soff, SDptr->sync_max_offset);
-	SETREG(eregs->esp_stp, SDptr->sync_min_period);
-	if(esp->erev > esp100a)
-		SETREG(eregs->esp_cfg3, esp->config3[target]);
-
+	esp_write(eregs->esp_busid, (target & 7));
+	if (esp->prev_soff != SDptr->sync_max_offset ||
+	    esp->prev_stp  != SDptr->sync_min_period ||
+	    (esp->erev > esp100a &&
+	     esp->prev_cfg3 != esp->config3[target])) {
+		esp->prev_soff = SDptr->sync_max_offset;
+		esp_write(eregs->esp_soff, esp->prev_soff);
+		esp->prev_stp = SDptr->sync_min_period;
+		esp_write(eregs->esp_stp, esp->prev_stp); 
+		if(esp->erev > esp100a) {
+			esp->prev_cfg3 = esp->config3[target];
+			esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		}
+	}
 	i = (cmdp - esp->esp_command);
 
 	/* Set up the DMA and ESP counters */
 	if(esp->do_pio_cmds){
 		int j = 0;
 
+		/* 
+		 * XXX MSch:
+		 *
+		 * It seems this is required, at least to clean up
+		 * after failed commands when using PIO mode ...
+		 */
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
 		for(;j<i;j++)
-			SETREG(eregs->esp_fdata, esp->esp_command[j]);
+			esp_write(eregs->esp_fdata, esp->esp_command[j]);
 		the_esp_command &= ~ESP_CMD_DMA;
 
 		/* Tell ESP to "go". */
 		esp_cmd(esp, eregs, the_esp_command);
 	} else {
-		if(esp->erev == fashme) {
-			esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* Grrr! */
-
-			/* Set up the HME counters */
-			SETREG(eregs->esp_tclow, i);
-			SETREG(eregs->esp_tcmed, 0);
-			SETREG(eregs->fas_rlo, 0);
-			SETREG(eregs->fas_rhi, 0);
-			esp_cmd(esp, eregs, the_esp_command);
-			esp->dma_init_write(esp, esp->esp_command_dvma, 16);
-		} else {
-			/* Set up the ESP counters */
-			SETREG(eregs->esp_tclow, i);
-			SETREG(eregs->esp_tcmed, 0);
-			esp->dma_init_write(esp, esp->esp_command_dvma, i);
+		/* Set up the ESP counters */
+		esp_write(eregs->esp_tclow, i);
+		esp_write(eregs->esp_tcmed, 0);
+		esp->dma_init_write(esp, esp->esp_command_dvma, i);
 
-			/* Tell ESP to "go". */
-			esp_cmd(esp, eregs, the_esp_command);
-		}
+		/* Tell ESP to "go". */
+		esp_cmd(esp, eregs, the_esp_command);
 	}
 }
 
@@ -1249,7 +1247,6 @@
 int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 	struct NCR_ESP *esp;
-	unsigned long flags;
 
 	/* Set up func ptr and initial driver cmd-phase. */
 	SCpnt->scsi_done = done;
@@ -1263,32 +1260,10 @@
 	/* We use the scratch area. */
 	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
 	ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
-	if(!SCpnt->use_sg) {
-		ESPQUEUE(("!use_sg\n"));
-		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
-		SCpnt->SCp.buffer           =
-			(struct scatterlist *) SCpnt->request_buffer;
-		SCpnt->SCp.buffers_residual = 0;
-	        if (esp->dma_mmu_get_scsi_one)
-		        esp->dma_mmu_get_scsi_one (esp, SCpnt);
-	        else
-		        SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
-		                (char *) virt_to_phys(SCpnt->request_buffer);
-	} else {
-		ESPQUEUE(("use_sg "));
-#ifdef DEBUG_ESP_SG
-		printk("esp%d: sglist at %p with %d buffers\n",
-		       esp->esp_id, SCpnt->buffer, SCpnt->use_sg);
-#endif
-		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->buffer;
-		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-	        if (esp->dma_mmu_get_scsi_sgl)
-		        esp->dma_mmu_get_scsi_sgl (esp, SCpnt);
-	        else
-		        SCpnt->SCp.ptr = 
-		                (char *) virt_to_phys(SCpnt->SCp.buffer->address);
-	}
+
+	esp_get_dmabufs(esp, SCpnt);
+	esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
+
 	SCpnt->SCp.Status           = CHECK_CONDITION;
 	SCpnt->SCp.Message          = 0xff;
 	SCpnt->SCp.sent_command     = 0;
@@ -1302,13 +1277,10 @@
 		append_SC(&esp->issue_SC, SCpnt);
 	}
 
- 	save_and_cli(flags);
-
 	/* Run it now if we can. */
 	if(!esp->current_SC && !esp->resetting_bus)
 		esp_exec_cmd(esp);
 
-	restore_flags(flags);
 	return 0;
 }
 
@@ -1324,7 +1296,7 @@
 }
 
 /* Dump driver state. */
-static inline void esp_dump_cmd(Scsi_Cmnd *SCptr)
+static void esp_dump_cmd(Scsi_Cmnd *SCptr)
 {
 	ESPLOG(("[tgt<%02x> lun<%02x> "
 		"pphase<%s> cphase<%s>]",
@@ -1333,8 +1305,8 @@
 		phase_string(SCptr->SCp.phase)));
 }
 
-static inline void esp_dump_state(struct NCR_ESP *esp, 
-				  struct ESP_regs *eregs)
+static void esp_dump_state(struct NCR_ESP *esp, 
+			   struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
 #ifdef DEBUG_ESP_CMDS
@@ -1349,8 +1321,8 @@
 	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
 		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
 	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
-		esp->esp_id, GETREG(eregs->esp_status), 
-		GETREG(eregs->esp_sstep), GETREG(eregs->esp_intrpt)));
+		esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep),
+		esp_read(eregs->esp_intrpt)));
 #ifdef DEBUG_ESP_CMDS
 	printk("esp%d: last ESP cmds [", esp->esp_id);
 	i = (esp->espcmdent - 1) & 31;
@@ -1392,7 +1364,6 @@
 	struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;
 	struct ESP_regs *eregs = esp->eregs;
 	int don;
-	unsigned long flags;
 
 	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
 	esp_dump_state(esp, eregs);
@@ -1403,16 +1374,13 @@
 	 * in the driver and timeout because the eventual phase change
 	 * will cause the ESP to (eventually) give an interrupt.
 	 */
-	save_and_cli(flags);
 	if(esp->current_SC == SCptr) {
 		esp->cur_msgout[0] = ABORT;
 		esp->msgout_len = 1;
 		esp->msgout_ctr = 0;
 		esp_cmd(esp, eregs, ESP_CMD_SATN);
-		restore_flags(flags);
 		return SCSI_ABORT_PENDING;
 	}
-	restore_flags(flags);
 
 	/* If it is still in the issue queue then we can safely
 	 * call the completion routine and report abort success.
@@ -1431,6 +1399,7 @@
 			if(this == SCptr) {
 				*prev = (Scsi_Cmnd *) this->host_scribble;
 				this->host_scribble = NULL;
+				esp_release_dmabufs(esp, this);
 				this->result = DID_ABORT << 16;
 				this->done(this);
 				if(don)
@@ -1445,8 +1414,11 @@
 	 * on the bus at this time.  So, we let the SCSI code wait
 	 * a little bit and try again later.
 	 */
-	if(esp->current_SC)
+	if(esp->current_SC) {
+		if(don)
+			esp->dma_ints_on(esp);
 		return SCSI_ABORT_BUSY;
+	}
 
 	/* It's disconnected, we have to reconnect to re-establish
 	 * the nexus and tell the device to abort.  However, we really
@@ -1455,20 +1427,68 @@
 	 * happens, we are really hung so reset the bus.
 	 */
 
+	if(don)
+		esp->dma_ints_on(esp);
 	return SCSI_ABORT_SNOOZE;
 }
 
+/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
+ * arrived indicating the end of the SCSI bus reset.  Our job
+ * is to clean out the command queues and begin re-execution
+ * of SCSI commands once more.
+ */
+static int esp_finish_reset(struct NCR_ESP *esp,
+			    struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *sp = esp->current_SC;
+
+	/* Clean up currently executing command, if any. */
+	if (sp != NULL) {
+		esp_release_dmabufs(esp, sp);
+		sp->result = (DID_RESET << 16);
+		sp->scsi_done(sp);
+		esp->current_SC = NULL;
+	}
+
+	/* Clean up disconnected queue, they have been invalidated
+	 * by the bus reset.
+	 */
+	if (esp->disconnected_SC) {
+		while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
+			esp_release_dmabufs(esp, sp);
+			sp->result = (DID_RESET << 16);
+			sp->scsi_done(sp);
+		}
+	}
+
+	/* SCSI bus reset is complete. */
+	esp->resetting_bus = 0;
+
+	/* Ok, now it is safe to get commands going once more. */
+	if(esp->issue_SC)
+		esp_exec_cmd(esp);
+
+	return do_intr_end;
+}
+
+static int esp_do_resetbus(struct NCR_ESP *esp,
+			   struct ESP_regs *eregs)
+{
+	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+	esp->resetting_bus = 1;
+	esp_cmd(esp, eregs, ESP_CMD_RS);
+
+	return do_intr_end;
+}
+
 /* Reset ESP chip, reset hanging bus, then kill active and
  * disconnected commands for targets without soft reset.
  */
 int esp_reset(Scsi_Cmnd *SCptr, unsigned int how)
 {
 	struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;
-	struct ESP_regs *eregs = esp->eregs;
 
-	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
-	esp->resetting_bus = 1;
-	esp_cmd(esp, eregs, ESP_CMD_RS);
+	(void) esp_do_resetbus(esp, esp->eregs);
 	return SCSI_RESET_PENDING;
 }
 
@@ -1478,36 +1498,15 @@
 	Scsi_Cmnd *done_SC;
 
 	if(esp->current_SC) {
-		unsigned long flags;
-
 		done_SC = esp->current_SC;
 		esp->current_SC = NULL;
-
-		/* Free dvma entry. */
-		if(!done_SC->use_sg) {
-		        if (esp->dma_mmu_release_scsi_one)
-			        esp->dma_mmu_release_scsi_one (esp, done_SC);
-		} else {
-#ifdef DEBUG_ESP_SG
-			printk("esp%d: unmapping sg ", esp->esp_id);
-#endif
-		        if (esp->dma_mmu_release_scsi_sgl)
-			        esp->dma_mmu_release_scsi_sgl (esp, done_SC);
-#ifdef DEBUG_ESP_SG
-			printk("done.\n");
-#endif
-		}
-
+		esp_release_dmabufs(esp, done_SC);
 		done_SC->result = error;
 		done_SC->scsi_done(done_SC);
 
-		save_and_cli(flags);
-
 		/* Bus is free, issue any commands in the queue. */
 		if(esp->issue_SC && !esp->current_SC)
 			esp_exec_cmd(esp);
-
-		restore_flags(flags);
 	} else {
 		/* Panic is safe as current_SC is null so we may still
 		 * be able to accept more commands to sync disk buffers.
@@ -1519,11 +1518,6 @@
 
 /* Wheee, ESP interrupt engine. */  
 
-enum {
-	do_phase_determine, do_reset_bus, do_reset_complete,
-	do_work_bus, do_intr_end,
-};
-
 /* Forward declarations. */
 static int esp_do_phase_determine(struct NCR_ESP *esp, 
 				  struct ESP_regs *eregs);
@@ -1535,67 +1529,8 @@
 static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs);
 static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs);
 
-static inline int sreg_datainp(unchar sreg)
-{
-	return (sreg & ESP_STAT_PMASK) == ESP_DIP;
-}
-
-static inline int sreg_dataoutp(unchar sreg)
-{
-	return (sreg & ESP_STAT_PMASK) == ESP_DOP;
-}
-
-/* Did they drop these fabs on the floor or what?!?!! */
-static inline void hme_fifo_hwbug_workaround(struct NCR_ESP *esp,
-					     struct ESP_regs *eregs)
-{
-	unchar status = esp->sreg;
-
-	/* Cannot safely frob the fifo for these following cases. */
-	if(sreg_datainp(status) || sreg_dataoutp(status) ||
-	   (esp->current_SC && esp->current_SC->SCp.phase == in_data_done)) {
-		ESPHME(("<wkaround_skipped>"));
-		return;
-	} else {
-		unsigned long count = 0;
-		unsigned long fcnt = GETREG(eregs->esp_fflags) & ESP_FF_FBYTES;
-
-		/* The HME stores bytes in multiples of 2 in the fifo. */
-		ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
-		while(fcnt) {
-			esp->hme_fifo_workaround_buffer[count++] = 
-			 GETREG(eregs->esp_fdata);
-			esp->hme_fifo_workaround_buffer[count++] = 
-			 GETREG(eregs->esp_fdata);
-			ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
-			fcnt--;
-		}
-		if(GETREG(eregs->esp_status2) & ESP_STAT2_F1BYTE) {
-			ESPHME(("<poke_byte>"));
-			SETREG(eregs->esp_fdata, 0);
-			esp->hme_fifo_workaround_buffer[count++] = 
-			 GETREG(eregs->esp_fdata);
-			ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
-			ESPHME(("CMD_FLUSH"));
-			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		} else {
-			ESPHME(("no_xtra_byte"));
-		}
-		esp->hme_fifo_workaround_count = count;
-		ESPHME(("wkarnd_cnt=%d]", (int)count));
-	}
-}
-
-static inline void hme_fifo_push(struct NCR_ESP *esp, struct ESP_regs *eregs,
-				 unchar *bytes, unchar count)
-{
-	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-	while(count) {
-		SETREG(eregs->esp_fdata, *bytes++);
-		SETREG(eregs->esp_fdata, 0);
-		count--;
-	}
-}
+#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
+#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
 
 /* We try to avoid some interrupts by jumping ahead and see if the ESP
  * has gotten far enough yet.  Hence the following.
@@ -1608,20 +1543,8 @@
 
 	if(esp->dma_irq_p(esp)) {
 		/* Yes, we are able to save an interrupt. */
-		esp->sreg = GETREG(eregs->esp_status);
-		if(esp->erev == fashme) {
-			/* This chip is really losing. */
-			ESPHME(("HME["));
-			/* Must latch fifo before reading the interrupt
-			 * register else garbage ends up in the FIFO
-			 * which confuses the driver utterly.
-			 * Happy Meal indeed....
-			 */
-			ESPHME(("fifo_workaround]"));
-			hme_fifo_hwbug_workaround(esp, eregs);
-		}
-		esp->ireg = GETREG(eregs->esp_intrpt);
-		esp->sreg &= ~(ESP_STAT_INTR);
+		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
+		esp->ireg = esp_read(eregs->esp_intrpt);
 		if(!(esp->ireg & ESP_INTR_SR))
 			return 0;
 		else
@@ -1642,21 +1565,8 @@
 		return 0;
 	if(esp->dma_irq_p(esp)) {
 		/* Yes, we are able to save an interrupt. */
-		esp->sreg = GETREG(eregs->esp_status);
-		if(esp->erev == fashme) {
-			/* This chip is really losing. */
-			ESPHME(("HME["));
-
-			/* Must latch fifo before reading the interrupt
-			 * register else garbage ends up in the FIFO
-			 * which confuses the driver utterly.
-			 * Happy Meal indeed....
-			 */
-			ESPHME(("fifo_workaround]"));
-			hme_fifo_hwbug_workaround(esp, eregs);
-		}
-		esp->ireg = GETREG(eregs->esp_intrpt);
-		esp->sreg &= ~(ESP_STAT_INTR);
+		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
+		esp->ireg = esp_read(eregs->esp_intrpt);
 		if(!(esp->ireg & ESP_INTR_SR))
 			return 0;
 		else
@@ -1667,56 +1577,31 @@
 	return do_intr_end;
 }
 
-/* Misc. esp helper routines. */
-static inline void esp_setcount(struct ESP_regs *eregs, int cnt, int hme)
-{
-	SETREG(eregs->esp_tclow, (cnt & 0xff));
-	SETREG(eregs->esp_tcmed, ((cnt >> 8) & 0xff));
-	if(hme) {
-		SETREG(eregs->fas_rlo, 0);
-		SETREG(eregs->fas_rhi, 0);
-	}
-}
-
-static inline int esp_getcount(struct ESP_regs *eregs)
-{
-	return (((GETREG(eregs->esp_tclow))&0xff) |
-		(((GETREG(eregs->esp_tcmed))&0xff) << 8));
-}
+/* Misc. esp helper macros. */
+#define esp_setcount(__eregs, __cnt) \
+	esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \
+	esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))
+
+#define esp_getcount(__eregs) \
+	((esp_read((__eregs)->esp_tclow)&0xff) | \
+	 ((esp_read((__eregs)->esp_tcmed)&0xff) << 8))
 
-static inline int fcount(struct NCR_ESP *esp, struct ESP_regs *eregs)
-{
-	if(esp->erev == fashme)
-		return esp->hme_fifo_workaround_count;
-	else
-		return GETREG(eregs->esp_fflags) & ESP_FF_FBYTES;
-}
+#define fcount(__esp, __eregs) \
+	(esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES)
 
-static inline int fnzero(struct NCR_ESP *esp, struct ESP_regs *eregs)
-{
-	if(esp->erev == fashme)
-		return 0;
-	else
-		return GETREG(eregs->esp_fflags) & ESP_FF_ONOTZERO;
-}
+#define fnzero(__esp, __eregs) \
+	(esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO)
 
 /* XXX speculative nops unnecessary when continuing amidst a data phase
  * XXX even on esp100!!!  another case of flooding the bus with I/O reg
  * XXX writes...
  */
-static inline void esp_maybe_nop(struct NCR_ESP *esp, struct ESP_regs *eregs)
-{
-	if(esp->erev == esp100)
-		esp_cmd(esp, eregs, ESP_CMD_NULL);
-}
+#define esp_maybe_nop(__esp, __eregs) \
+	if((__esp)->erev == esp100) \
+		esp_cmd((__esp), (__eregs), ESP_CMD_NULL)
 
-static inline int sreg_to_dataphase(unchar sreg)
-{
-	if((sreg & ESP_STAT_PMASK) == ESP_DOP)
-		return in_dataout;
-	else
-		return in_datain;
-}
+#define sreg_to_dataphase(__sreg) \
+	((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
 
 /* The ESP100 when in synchronous data phase, can mistake a long final
  * REQ pulse from the target as an extra byte, it places whatever is on
@@ -1731,8 +1616,8 @@
 {
 	/* Do not touch this piece of code. */
 	if((!(esp->erev == esp100)) ||
-	   (!(sreg_datainp((esp->sreg = GETREG(eregs->esp_status))) && !fifocnt)
-	    && !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
+	   (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) &&
+	    !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
 		if(sp->SCp.phase == in_dataout)
 			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 		return 0;
@@ -1759,7 +1644,7 @@
 
 	if(esp->erev != esp100)
 		return 0;
-	junk = GETREG(eregs->esp_intrpt);
+	junk = esp_read(eregs->esp_intrpt);
 
 	if(junk & ESP_INTR_SR)
 		return 1;
@@ -1775,24 +1660,14 @@
 
 	if(2 != fcount(esp, eregs))
 		return -1;
-	if(esp->erev == fashme) {
-		/* HME does not latch it's own BUS ID bits during
-		 * a reselection.  Also the target number is given
-		 * as an unsigned char, not as a sole bit number
-		 * like the other ESP's do.
-		 * Happy Meal indeed....
-		 */
-		targ = esp->hme_fifo_workaround_buffer[0];
-	} else {
-		it = GETREG(eregs->esp_fdata);
-		if(!(it & me))
-			return -1;
-		it &= ~me;
-		if(it & (it - 1))
-			return -1;
-		while(!(it & 1))
-			targ++, it >>= 1;
-	}
+	it = esp_read(eregs->esp_fdata);
+	if(!(it & me))
+		return -1;
+	it &= ~me;
+	if(it & (it - 1))
+		return -1;
+	while(!(it & 1))
+		targ++, it >>= 1;
 	return targ;
 }
 
@@ -1805,14 +1680,20 @@
 
 	if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
 		return -1;
-	if(esp->erev == fashme)
-		lun = esp->hme_fifo_workaround_buffer[1];
-	else
-		lun = GETREG(eregs->esp_fdata);
+	lun = esp_read(eregs->esp_fdata);
+
+	/* Yes, you read this correctly.  We report lun of zero
+	 * if we see parity error.  ESP reports parity error for
+	 * the lun byte, and this is the only way to hope to recover
+	 * because the target is connected.
+	 */
 	if(esp->sreg & ESP_STAT_PERR)
 		return 0;
+
+	/* Check for illegal bits being set in the lun. */
 	if((lun & 0x40) || !(lun & 0x80))
 		return -1;
+
 	return lun & 7;
 }
 
@@ -1823,13 +1704,20 @@
 			       Scsi_Cmnd *sp)
 {
 	Scsi_Device *dp = sp->device;
-	SETREG(eregs->esp_soff, dp->sync_max_offset);
-	SETREG(eregs->esp_stp, dp->sync_min_period);
-	if(esp->erev > esp100a)
-		SETREG(eregs->esp_cfg3, esp->config3[sp->target]);
-	if(esp->erev == fashme)
-		SETREG(eregs->esp_busid, (sp->target & 0xf) |
-			(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT));
+
+	if(esp->prev_soff  != dp->sync_max_offset ||
+	   esp->prev_stp   != dp->sync_min_period ||
+	   (esp->erev > esp100a &&
+	    esp->prev_cfg3 != esp->config3[sp->target])) {
+		esp->prev_soff = dp->sync_max_offset;
+		esp_write(eregs->esp_soff, esp->prev_soff);
+		esp->prev_stp = dp->sync_min_period;
+		esp_write(eregs->esp_stp, esp->prev_stp);
+		if(esp->erev > esp100a) {
+			esp->prev_cfg3 = esp->config3[sp->target];
+			esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		} 
+	}
 	esp->current_SC = sp;
 }
 
@@ -1839,8 +1727,8 @@
 static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
 	if(!esp->disconnected_SC)
-		printk("esp%d: Weird, being reselected but disconnected "
-		       "command queue is empty.\n", esp->esp_id);
+		ESPLOG(("esp%d: Weird, being reselected but disconnected "
+			"command queue is empty.\n", esp->esp_id));
 	esp->snip = 0;
 	esp->current_SC = 0;
 	sp->SCp.phase = not_issued;
@@ -1848,12 +1736,9 @@
 }
 
 /* Begin message in phase. */
-static inline int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
-	/* Must be very careful with the fifo on the HME */
-	if((esp->erev != fashme) || !(GETREG(eregs->esp_status2) & 
-	 ESP_STAT2_FEMPTY))
-		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 	esp_maybe_nop(esp, eregs);
 	esp_cmd(esp, eregs, ESP_CMD_TI);
 	esp->msgin_len = 1;
@@ -1867,10 +1752,10 @@
 	++sp->SCp.buffer;
 	--sp->SCp.buffers_residual;
 	sp->SCp.this_residual = sp->SCp.buffer->length;
-        if (esp->dma_advance_sg)
-	       esp->dma_advance_sg (sp);
-        else
-	       sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);
+	if (esp->dma_advance_sg)
+		esp->dma_advance_sg (sp);
+	else
+		sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);
 }
 
 /* Please note that the way I've coded these routines is that I _always_
@@ -1891,8 +1776,7 @@
  * within a buffer or sub-buffer should not upset us at all no matter
  * how bad the target and/or ESP fucks things up.
  */
-
-static inline int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
 	int thisphase, hmuch;
@@ -1903,31 +1787,204 @@
 	esp_advance_phase(SCptr, thisphase);
 	ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
 	hmuch = esp->dma_can_transfer(esp, SCptr);
-	ESPDATA(("hmuch<%d> ", hmuch));
-	esp->current_transfer_size = hmuch;
-	if(esp->erev == fashme) {
-		/* Touchy chip, this stupid HME scsi adapter... */
-		esp_setcount(eregs, hmuch, 1);
-		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 
-		if(thisphase == in_datain)
-			esp->dma_init_read(esp, (__u32)((unsigned long)SCptr->SCp.ptr), hmuch);
-		else
-			esp->dma_init_write(esp, (__u32)((unsigned long)SCptr->SCp.ptr), hmuch);
-	} else {
-		esp_setcount(eregs, hmuch, 0);
-		esp->dma_setup(esp, 
-			       (__u32)((unsigned long)SCptr->SCp.ptr), 
+	/*
+	 * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0
+	 */
+	if (hmuch) {	/* DMA */
+		/*
+		 * DMA
+		 */
+		ESPDATA(("hmuch<%d> ", hmuch));
+		esp->current_transfer_size = hmuch;
+		esp_setcount(eregs, (esp->fas_premature_intr_workaround ?
+				     (hmuch + 0x40) : hmuch));
+		esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), 
 			       hmuch, (thisphase == in_datain));
 		ESPDATA(("DMA|TI --> do_intr_end\n"));
 		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
-	}
+		return do_intr_end;
+		/*
+		 * end DMA
+		 */
+	} else {
+		/*
+		 * PIO
+		 */
+		int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */
+		int fifocnt = 0;
+
+		oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK;
+
+		/*
+		 * polled transfer; ugly, can we make this happen in a DRQ 
+		 * interrupt handler ??
+		 * requires keeping track of state information in host or 
+		 * command struct!
+		 * Problem: I've never seen a DRQ happen on Mac, not even
+		 * with ESP_CMD_DMA ...
+		 */
+
+		/* figure out how much needs to be transfered */
+		hmuch = SCptr->SCp.this_residual;
+		ESPDATA(("hmuch<%d> pio ", hmuch));
+		esp->current_transfer_size = hmuch;
+
+		/* tell the ESP ... */
+		esp_setcount(eregs, hmuch);
+
+		/* loop */
+		while (hmuch) {
+			int j, fifo_stuck = 0, newphase;
+			unsigned long flags, timeout;
+#if 0
+			if ( i % 10 )
+				ESPDATA(("\r"));
+			else
+				ESPDATA(( /*"\n"*/ "\r"));
+#endif
+			save_flags(flags);
+#if 0
+			cli();
+#endif
+			if(thisphase == in_datain) {
+				/* 'go' ... */ 
+				esp_cmd(esp, eregs, ESP_CMD_TI);
+
+				/* wait for data */
+				timeout = 1000000;
+				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+					udelay(2);
+				if (timeout == 0)
+					printk("DRQ datain timeout! \n");
+
+				newphase = esp->sreg & ESP_STAT_PMASK;
+
+				/* see how much we got ... */
+				fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+
+				if (!fifocnt)
+					fifo_stuck++;
+				else
+					fifo_stuck = 0;
+
+				ESPDATA(("\rgot %d st %x ph %x", fifocnt, esp->sreg, newphase));
+
+				/* read fifo */
+				for(j=0;j<fifocnt;j++)
+					SCptr->SCp.ptr[i++] = esp_read(eregs->esp_fdata);
+
+				ESPDATA(("(%d) ", i));
+
+				/* how many to go ?? */
+				hmuch -= fifocnt;
+
+				/* break if status phase !! */
+				if(newphase == ESP_STATP) {
+					/* clear int. */
+					esp->ireg = esp_read(eregs->esp_intrpt);
+					break;
+				}
+			} else {
+#define MAX_FIFO 8
+				/* how much will fit ? */
+				int this_count = MAX_FIFO - fifocnt;
+				if (this_count > hmuch)
+					this_count = hmuch;
+
+				/* fill fifo */
+				for(j=0;j<this_count;j++)
+					esp_write(eregs->esp_fdata, SCptr->SCp.ptr[i++]);
+
+				/* how many left if this goes out ?? */
+				hmuch -= this_count;
+
+				/* 'go' ... */ 
+				esp_cmd(esp, eregs, ESP_CMD_TI);
+
+				/* wait for 'got it' */
+				timeout = 1000000;
+				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+					udelay(2);
+				if (timeout == 0)
+					printk("DRQ dataout timeout!  \n");
+
+				newphase = esp->sreg & ESP_STAT_PMASK;
+
+				/* need to check how much was sent ?? */
+				fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+
+				ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase));
+
+				ESPDATA(("(%d) ", i));
+
+				/* break if status phase !! */
+				if(newphase == ESP_STATP) {
+					/* clear int. */
+					esp->ireg = esp_read(eregs->esp_intrpt);
+					break;
+				}
+
+			}
+
+			/* clear int. */
+			esp->ireg = esp_read(eregs->esp_intrpt);
+
+			ESPDATA(("ir %x ... ", esp->ireg));
+
+			if (hmuch == 0)
+				ESPDATA(("done! \n"));
+
+			restore_flags(flags);
+
+			/* check new bus phase */
+			if (newphase != oldphase && i < esp->current_transfer_size) {
+				/* something happened; disconnect ?? */
+				ESPDATA(("phase change, dropped out with %d done ... ", i));
+				break;
+			}
+
+			/* check int. status */
+			if (esp->ireg & ESP_INTR_DC) {
+				/* disconnect */
+				ESPDATA(("disconnect; %d transfered ... ", i));
+				break;
+			} else if (esp->ireg & ESP_INTR_FDONE) {
+				/* function done */
+				ESPDATA(("function done; %d transfered ... ", i));
+				break;
+			}
+
+			/* XXX fixme: bail out on stall */
+			if (fifo_stuck > 10) {
+				/* we're stuck */
+				ESPDATA(("fifo stall; %d transfered ... ", i));
+				break;
+			}
+		}
+
+		ESPDATA(("\n"));
+		/* check successful completion ?? */
+
+		if (thisphase == in_dataout)
+			hmuch += fifocnt; /* stuck?? adjust data pointer ...*/
+
+		/* tell do_data_finale how much was transfered */
+		esp->current_transfer_size -= hmuch;
+
+		/* still not completely sure on this one ... */		
+		return /*do_intr_end*/ do_work_bus /*do_phase_determine*/ ;
+
+		/*
+		 * end PIO
+		 */
+	}
 	return do_intr_end;
 }
 
 /* See how successful the data transfer was. */
-static inline int esp_do_data_finale(struct NCR_ESP *esp,
-				     struct ESP_regs *eregs)
+static int esp_do_data_finale(struct NCR_ESP *esp,
+			      struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
 	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
@@ -1963,77 +2020,83 @@
 		return esp_do_phase_determine(esp, eregs);
 	}	
 
-	/* Check for partial transfers and other horrible events.
-	 * Note, here we read the real fifo flags register even
-	 * on HME broken adapters because we skip the HME fifo
-	 * workaround code in esp_handle() if we are doing data
-	 * phase things.  We don't want to fuck directly with
-	 * the fifo like that, especially if doing syncronous
-	 * transfers!  Also, will need to double the count on
-	 * HME if we are doing wide transfers, as the HME fifo
-	 * will move and count 16-bit quantities during wide data.
-	 * SMCC _and_ Qlogic can both bite me.
-	 */
-	fifocnt = GETREG(eregs->esp_fflags) & ESP_FF_FBYTES;
-	if(esp->erev != fashme)
-		ecount = esp_getcount(eregs);
+	/* Check for partial transfers and other horrible events. */
+	fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+	ecount = esp_getcount(eregs);
+	if(esp->fas_premature_intr_workaround)
+		ecount -= 0x40;
 	bytes_sent = esp->current_transfer_size;
 
-	/* Uhhh, might not want both of these conditionals to run
-	 * at once on HME due to the fifo problems it has.  Consider
-	 * changing it to:
-	 *
-	 * 	if(!(esp->sreg & ESP_STAT_TCNT)) {
-	 * 		bytes_sent -= ecount;
-	 * 	} else if(SCptr->SCp.phase == in_dataout) {
-	 * 		bytes_sent -= fifocnt;
-	 *	}
-	 *
-	 * But only for the HME case, leave the current code alone
-	 * for all other ESP revisions as we know the existing code
-	 * works just fine for them.
-	 */
 	ESPDATA(("trans_sz=%d, ", bytes_sent));
-	if(esp->erev == fashme) {
-		if(!(esp->sreg & ESP_STAT_TCNT)) {
-			bytes_sent -= esp_getcount(eregs);
-		} else if(SCptr->SCp.phase == in_dataout) {
-			bytes_sent -= fifocnt;
-		}
-	} else {
-		if(!(esp->sreg & ESP_STAT_TCNT))
-			bytes_sent -= ecount;
-		if(SCptr->SCp.phase == in_dataout)
-			bytes_sent -= fifocnt;
-	}
+	if(!(esp->sreg & ESP_STAT_TCNT))
+		bytes_sent -= ecount;
+	if(SCptr->SCp.phase == in_dataout)
+		bytes_sent -= fifocnt;
 
-	ESPDATA(("bytes_sent=%d, ", bytes_sent));
+	ESPDATA(("bytes_sent=%d (ecount=%d, fifocnt=%d), ", bytes_sent,
+		 ecount, fifocnt));
 
 	/* If we were in synchronous mode, check for peculiarities. */
-	if(esp->erev == fashme) {
-		if(SCptr->device->sync_max_offset) {
-			if(SCptr->SCp.phase == in_dataout)
-				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		} else {
-			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		}
-	} else {
-		if(SCptr->device->sync_max_offset)
-			bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
-		else
-			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-	}
+	if(SCptr->device->sync_max_offset)
+		bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
+	else
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 
 	/* Until we are sure of what has happened, we are certainly
 	 * in the dark.
 	 */
 	esp_advance_phase(SCptr, in_the_dark);
 
+	/* Check for premature interrupt condition. Can happen on FAS2x6
+	 * chips. QLogic recommends a workaround by overprogramming the
+	 * transfer counters, but this makes doing scatter-gather impossible.
+	 * Until there is a way to disable scatter-gather for a single target,
+	 * and not only for the entire host adapter as it is now, the workaround
+	 * is way to expensive performance wise.
+	 * Instead, it turns out that when this happens the target has disconnected
+	 * allready but it doesn't show in the interrupt register. Compensate for
+	 * that here to try and avoid a SCSI bus reset.
+	 */
+	if(!esp->fas_premature_intr_workaround && (fifocnt == 1) &&
+	   sreg_dataoutp(esp->sreg)) {
+		ESPLOG(("esp%d: Premature interrupt, enabling workaround\n",
+			esp->esp_id));
+#if 0
+		/* Disable scatter-gather operations, they are not possible
+		 * when using this workaround.
+		 */
+		esp->ehost->sg_tablesize = 0;
+		esp->ehost->use_clustering = ENABLE_CLUSTERING;
+		esp->fas_premature_intr_workaround = 1;
+		bytes_sent = 0;
+		if(SCptr->use_sg) {
+			ESPLOG(("esp%d: Aborting scatter-gather operation\n",
+				esp->esp_id));
+			esp->cur_msgout[0] = ABORT;
+			esp->msgout_len = 1;
+			esp->msgout_ctr = 0;
+			esp_cmd(esp, eregs, ESP_CMD_SATN);
+			esp_setcount(eregs, 0xffff);
+			esp_cmd(esp, eregs, ESP_CMD_NULL);
+			esp_cmd(esp, eregs, ESP_CMD_TPAD | ESP_CMD_DMA);
+			return do_intr_end;
+		}
+#else
+		/* Just set the disconnected bit. That's what appears to
+		 * happen anyway. The state machine will pick it up when
+		 * we return.
+		 */
+		esp->ireg |= ESP_INTR_DC;
+#endif
+        }
+
 	if(bytes_sent < 0) {
 		/* I've seen this happen due to lost state in this
 		 * driver.  No idea why it happened, but allowing
 		 * this value to be negative caused things to
 		 * lock up.  This allows greater chance of recovery.
+		 * In fact every time I've seen this, it has been
+		 * a driver bug without question.
 		 */
 		ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
 		ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
@@ -2042,6 +2105,10 @@
 		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
 			esp->esp_id,
 			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+		ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, 
+			SCptr->target));
+		SCptr->device->borken = 1;
+		SCptr->device->sync = 0;
 		bytes_sent = 0;
 	}
 
@@ -2050,7 +2117,7 @@
 	SCptr->SCp.this_residual -= bytes_sent;
 	if(SCptr->SCp.this_residual < 0) {
 		/* shit */
-		printk("esp%d: Data transfer overrun.\n", esp->esp_id);
+		ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
 		SCptr->SCp.this_residual = 0;
 	}
 
@@ -2066,13 +2133,15 @@
 		 * imagine the hell I went through trying to
 		 * figure this out.
 		 */
-		if(SCptr->use_sg && !SCptr->SCp.this_residual)
+		if(!SCptr->SCp.this_residual && SCptr->SCp.buffers_residual)
 			advance_sg(esp, SCptr);
+#ifdef DEBUG_ESP_DATA
 		if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
 			ESPDATA(("to more data\n"));
-			return esp_do_data(esp, eregs);
+		} else {
+			ESPDATA(("to new phase\n"));
 		}
-		ESPDATA(("to new phase\n"));
+#endif
 		return esp_do_phase_determine(esp, eregs);
 	}
 	/* Bogus data, just wait for next interrupt. */
@@ -2081,10 +2150,48 @@
 	return do_intr_end;
 }
 
+/* We received a non-good status return at the end of
+ * running a SCSI command.  This is used to decide if
+ * we should clear our synchronous transfer state for
+ * such a device when that happens.
+ *
+ * The idea is that when spinning up a disk or rewinding
+ * a tape, we don't want to go into a loop re-negotiating
+ * synchronous capabilities over and over.
+ */
+static int esp_should_clear_sync(Scsi_Cmnd *sp)
+{
+	unchar cmd1 = sp->cmnd[0];
+	unchar cmd2 = sp->data_cmnd[0];
+
+	/* These cases are for spinning up a disk and
+	 * waiting for that spinup to complete.
+	 */
+	if(cmd1 == START_STOP ||
+	   cmd2 == START_STOP)
+		return 0;
+
+	if(cmd1 == TEST_UNIT_READY ||
+	   cmd2 == TEST_UNIT_READY)
+		return 0;
+
+	/* One more special case for SCSI tape drives,
+	 * this is what is used to probe the device for
+	 * completion of a rewind or tape load operation.
+	 */
+	if(sp->device->type == TYPE_TAPE) {
+		if(cmd1 == MODE_SENSE ||
+		   cmd2 == MODE_SENSE)
+			return 0;
+	}
+
+	return 1;
+}
+
 /* Either a command is completing or a target is dropping off the bus
  * to continue the command in the background so we can do other work.
  */
-static inline int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
 	int rval;
@@ -2101,12 +2208,14 @@
 	esp->prevmsgout = NOP;
 	if(esp->prevmsgin == COMMAND_COMPLETE) {
 		/* Normal end of nexus. */
-		if(esp->disconnected_SC || (esp->erev == fashme))
+		if(esp->disconnected_SC)
 			esp_cmd(esp, eregs, ESP_CMD_ESEL);
 
-		if(SCptr->SCp.Status != GOOD && SCptr->SCp.Status != CONDITION_GOOD &&
+		if(SCptr->SCp.Status != GOOD &&
+		   SCptr->SCp.Status != CONDITION_GOOD &&
 		   ((1<<SCptr->target) & esp->targets_present) &&
-		   SCptr->device->sync && SCptr->device->sync_max_offset) {
+		   SCptr->device->sync &&
+		   SCptr->device->sync_max_offset) {
 			/* SCSI standard says that the synchronous capabilities
 			 * should be renegotiated at this point.  Most likely
 			 * we are about to request sense from this target
@@ -2123,15 +2232,7 @@
 			 * can report not ready many times right after
 			 * loading up a tape.
 			 */
-			if(SCptr->cmnd[0] != START_STOP &&
-			   SCptr->data_cmnd[0] != START_STOP &&
-			   SCptr->cmnd[0] != TEST_UNIT_READY &&
-			   SCptr->data_cmnd[0] != TEST_UNIT_READY &&
-			   !(SCptr->device->type == TYPE_TAPE &&
-			     (SCptr->cmnd[0] == TEST_UNIT_READY ||
-			      SCptr->data_cmnd[0] == TEST_UNIT_READY ||
-			      SCptr->cmnd[0] == MODE_SENSE ||
-			      SCptr->data_cmnd[0] == MODE_SENSE)))
+			if(esp_should_clear_sync(SCptr) != 0)
 				SCptr->device->sync = 0;
 		}
 		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
@@ -2158,9 +2259,43 @@
 	return do_intr_end;
 }
 
+/* When a reselect occurs, and we cannot find the command to
+ * reconnect to in our queues, we do this.
+ */
+static int esp_bad_reconnect(struct NCR_ESP *esp)
+{
+	Scsi_Cmnd *sp;
+
+	ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+		esp->esp_id));
+	ESPLOG(("QUEUE DUMP\n"));
+	sp = esp->issue_SC;
+	ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+	while(sp) {
+		ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+		sp = (Scsi_Cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	sp = esp->current_SC;
+	ESPLOG(("esp%d: current_SC[", esp->esp_id));
+	while(sp) {
+		ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+		sp = (Scsi_Cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	sp = esp->disconnected_SC;
+	ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+	while(sp) {
+		ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+		sp = (Scsi_Cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	return do_reset_bus;
+}
+
 /* Do the needy when a target tries to reconnect to us. */
-static inline int esp_do_reconnect(struct NCR_ESP *esp, 
-				   struct ESP_regs *eregs)
+static int esp_do_reconnect(struct NCR_ESP *esp, 
+			    struct ESP_regs *eregs)
 {
 	int lun, target;
 	Scsi_Cmnd *SCptr;
@@ -2180,53 +2315,21 @@
 	/* Things look ok... */
 	ESPDISC(("R<%02x,%02x>", target, lun));
 
-	/* Must flush both FIFO and the DVMA on HME. */
-	if(esp->erev == fashme) {
-		/* XXX this still doesn't fix the problem... */
-		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		if(esp->dma_invalidate)
-			esp->dma_invalidate(esp);
-	} else {
-		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		if(esp100_reconnect_hwbug(esp, eregs))
-			return do_reset_bus;
-		esp_cmd(esp, eregs, ESP_CMD_NULL);
-	}
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	if(esp100_reconnect_hwbug(esp, eregs))
+		return do_reset_bus;
+	esp_cmd(esp, eregs, ESP_CMD_NULL);
 
 	SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun);
-	if(!SCptr) {
-		Scsi_Cmnd *sp;
+	if(!SCptr)
+		return esp_bad_reconnect(esp);
 
-		ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
-			esp->esp_id));
-		ESPLOG(("QUEUE DUMP\n"));
-		sp = esp->issue_SC;
-		ESPLOG(("esp%d: issue_SC[", esp->esp_id));
-		while(sp) {
-			ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
-			sp = (Scsi_Cmnd *) sp->host_scribble;
-		}
-		ESPLOG(("]\n"));
-		sp = esp->current_SC;
-		ESPLOG(("esp%d: current_SC[", esp->esp_id));
-		while(sp) {
-			ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
-			sp = (Scsi_Cmnd *) sp->host_scribble;
-		}
-		ESPLOG(("]\n"));
-		sp = esp->disconnected_SC;
-		ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
-		while(sp) {
-			ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
-			sp = (Scsi_Cmnd *) sp->host_scribble;
-		}
-		ESPLOG(("]\n"));
-		return do_reset_bus;
-	}
 	esp_connect(esp, eregs, SCptr);
 	esp_cmd(esp, eregs, ESP_CMD_MOK);
 
-	/* No need for explicit restore pointers operation. */
+	/* Reconnect implies a restore pointers operation. */
+	esp_restore_pointers(esp, SCptr);
+
 	esp->snip = 0;
 	esp_advance_phase(SCptr, in_the_dark);
 	return do_intr_end;
@@ -2348,121 +2451,132 @@
 	}
 }
 
-/* The target has control of the bus and we have to see where it has
- * taken us.
- */
-static int esp_do_phase_determine(struct NCR_ESP *esp,
-				  struct ESP_regs *eregs)
+static int esp_enter_status(struct NCR_ESP *esp,
+			    struct ESP_regs *eregs)
 {
-	Scsi_Cmnd *SCptr = esp->current_SC;
+	unchar thecmd = ESP_CMD_ICCSEQ;
 
-	ESPPHASE(("esp_do_phase_determine: "));
-	if(!(esp->ireg & ESP_INTR_DC)) {
-		switch(esp->sreg & ESP_STAT_PMASK) {
-		case ESP_DOP:
-		case ESP_DIP:
-			ESPPHASE(("to data phase\n"));
-			return esp_do_data(esp, eregs);
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 
-		case ESP_STATP:
-			/* Whee, status phase, finish up the command. */
-			ESPPHASE(("to status phase\n"));
+	if(esp->do_pio_cmds) {
+		esp_advance_phase(esp->current_SC, in_status);
+		esp_cmd(esp, eregs, thecmd);
+		while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
+		esp->esp_command[0] = esp_read(eregs->esp_fdata);
+                while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
+                esp->esp_command[1] = esp_read(eregs->esp_fdata);
+	} else {
+		esp->esp_command[0] = esp->esp_command[1] = 0xff;
+		esp_write(eregs->esp_tclow, 2);
+		esp_write(eregs->esp_tcmed, 0);
+		esp->dma_init_read(esp, esp->esp_command_dvma, 2);
+		thecmd |= ESP_CMD_DMA;
+		esp_cmd(esp, eregs, thecmd);
+		esp_advance_phase(esp->current_SC, in_status);
+	}
 
-			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	return esp_do_status(esp, eregs);
+}
 
-			if(esp->do_pio_cmds){
-				esp_advance_phase(SCptr, in_status);
-				esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
-				while(!(GETREG(esp->eregs->esp_status)
-				 & ESP_STAT_INTR));
-				esp->esp_command[0] = GETREG(eregs->esp_fdata);
-				while(!(GETREG(esp->eregs->esp_status)
-				 & ESP_STAT_INTR));
-				esp->esp_command[1] = GETREG(eregs->esp_fdata);
-			} else {				
-				if(esp->erev != fashme) {
-					esp->esp_command[0] = 0xff;
-					esp->esp_command[1] = 0xff;
-					SETREG(eregs->esp_tclow, 2);
-					SETREG(eregs->esp_tcmed, 0);
-					esp->dma_init_read(esp, esp->esp_command_dvma, 2);
-					esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
-				} else {
-					/* Using DVMA for status/message bytes is
-					 * unreliable on HME, nice job QLogic.
-					 * Happy Meal indeed....
-					 */
-					esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
-				}
-				esp_advance_phase(SCptr, in_status);
-			}
-			return esp_do_status(esp, eregs);
+static int esp_disconnect_amidst_phases(struct NCR_ESP *esp,
+					struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *sp = esp->current_SC;
+	Scsi_Device *dp = sp->device;
 
-		case ESP_MOP:
-			ESPPHASE(("to msgout phase\n"));
-			esp_advance_phase(SCptr, in_msgout);
-			return esp_do_msgout(esp, eregs);
-
-		case ESP_MIP:
-			ESPPHASE(("to msgin phase\n"));
-			esp_advance_phase(SCptr, in_msgin);
-			return esp_do_msgin(esp, eregs);
-
-		case ESP_CMDP:
-			/* Ugh, we're running a non-standard command the
-			 * ESP doesn't understand, one byte at a time.
-			 */
-			ESPPHASE(("to cmd phase\n"));
-			esp_advance_phase(SCptr, in_cmdbegin);
-			return esp_do_cmdbegin(esp, eregs);
-		};
-	} else {
-		Scsi_Device *dp = SCptr->device;
+	/* This means real problems if we see this
+	 * here.  Unless we were actually trying
+	 * to force the device to abort/reset.
+	 */
+	ESPLOG(("esp%d: Disconnect amidst phases, ", esp->esp_id));
+	ESPLOG(("pphase<%s> cphase<%s>, ",
+		phase_string(sp->SCp.phase),
+		phase_string(sp->SCp.sent_command)));
 
-		/* This means real problems if we see this
-		 * here.  Unless we were actually trying
-		 * to force the device to abort/reset.
-		 */
-		ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
-		ESPLOG(("pphase<%s> cphase<%s>, ",
-			phase_string(SCptr->SCp.phase),
-			phase_string(SCptr->SCp.sent_command)));
-		if(esp->disconnected_SC || (esp->erev == fashme))
-			esp_cmd(esp, eregs, ESP_CMD_ESEL);
+	if(esp->disconnected_SC)
+		esp_cmd(esp, eregs, ESP_CMD_ESEL);
 
-		switch(esp->cur_msgout[0]) {
-		default:
-			/* We didn't expect this to happen at all. */
-			ESPLOG(("device is bolixed\n"));
-			esp_advance_phase(SCptr, in_tgterror);
-			esp_done(esp, (DID_ERROR << 16));
-			break;
+	switch(esp->cur_msgout[0]) {
+	default:
+		/* We didn't expect this to happen at all. */
+		ESPLOG(("device is bolixed\n"));
+		esp_advance_phase(sp, in_tgterror);
+		esp_done(esp, (DID_ERROR << 16));
+		break;
+
+	case BUS_DEVICE_RESET:
+		ESPLOG(("device reset successful\n"));
+		dp->sync_max_offset = 0;
+		dp->sync_min_period = 0;
+		dp->sync = 0;
+		esp_advance_phase(sp, in_resetdev);
+		esp_done(esp, (DID_RESET << 16));
+		break;
+
+	case ABORT:
+		ESPLOG(("device abort successful\n"));
+		esp_advance_phase(sp, in_abortone);
+		esp_done(esp, (DID_ABORT << 16));
+		break;
 
-		case BUS_DEVICE_RESET:
-			ESPLOG(("device reset successful\n"));
-			dp->sync_max_offset = 0;
-			dp->sync_min_period = 0;
-			dp->sync = 0;
-			esp_advance_phase(SCptr, in_resetdev);
-			esp_done(esp, (DID_RESET << 16));
-			break;
+	};
+	return do_intr_end;
+}
 
-		case ABORT:
-			ESPLOG(("device abort successful\n"));
-			esp_advance_phase(SCptr, in_abortone);
-			esp_done(esp, (DID_ABORT << 16));
-			break;
+static int esp_enter_msgout(struct NCR_ESP *esp,
+			    struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_msgout);
+	return esp_do_msgout(esp, eregs);
+}
 
-		};
-		return do_intr_end;
-	}
+static int esp_enter_msgin(struct NCR_ESP *esp,
+			   struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_msgin);
+	return esp_do_msgin(esp, eregs);
+}
+
+static int esp_enter_cmd(struct NCR_ESP *esp,
+			 struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_cmdbegin);
+	return esp_do_cmdbegin(esp, eregs);
+}
 
-	ESPLOG(("esp%d: to unknown phase\n", esp->esp_id));
-	printk("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
-	       esp->sreg & ESP_STAT_PMASK);
+static int esp_enter_badphase(struct NCR_ESP *esp,
+			      struct ESP_regs *eregs)
+{
+	ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+		esp->sreg & ESP_STAT_PMASK));
 	return do_reset_bus;
 }
 
+typedef int (*espfunc_t)(struct NCR_ESP *,
+			 struct ESP_regs *);
+
+static espfunc_t phase_vector[] = {
+	esp_do_data,		/* ESP_DOP */
+	esp_do_data,		/* ESP_DIP */
+	esp_enter_cmd,		/* ESP_CMDP */
+	esp_enter_status,	/* ESP_STATP */
+	esp_enter_badphase,	/* ESP_STAT_PMSG */
+	esp_enter_badphase,	/* ESP_STAT_PMSG | ESP_STAT_PIO */
+	esp_enter_msgout,	/* ESP_MOP */
+	esp_enter_msgin,	/* ESP_MIP */
+};
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct NCR_ESP *esp,
+				  struct ESP_regs *eregs)
+{
+	if ((esp->ireg & ESP_INTR_DC) != 0)
+		return esp_disconnect_amidst_phases(esp, eregs);
+	return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs);
+}
+
 /* First interrupt after exec'ing a cmd comes here. */
 static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
@@ -2470,12 +2584,7 @@
 	Scsi_Device *SDptr = SCptr->device;
 	int cmd_bytes_sent, fcnt;
 
-	if(esp->erev != fashme)
-		esp->seqreg = (GETREG(eregs->esp_sstep) & ESP_STEP_VBITS);
-	if(esp->erev == fashme)
-		fcnt = esp->hme_fifo_workaround_count;
-	else
-		fcnt = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES);
+	fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
 	cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt);
 	if(esp->dma_invalidate)
 		esp->dma_invalidate(esp);
@@ -2583,14 +2692,12 @@
 			if(SCptr->SCp.phase == in_slct_norm)
 				cmd_bytes_sent -= 1;
 		};
-		if(esp->erev != fashme)
-			esp_cmd(esp, eregs, ESP_CMD_NULL);
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
 
 		/* Be careful, we could really get fucked during synchronous
 		 * data transfers if we try to flush the fifo now.
 		 */
-		if((esp->erev != fashme) && /* not a Happy Meal and... */
-		   !fcnt && /* Fifo is empty and... */
+		if(!fcnt && /* Fifo is empty and... */
 		   /* either we are not doing synchronous transfers or... */
 		   (!SDptr->sync_max_offset ||
 		    /* We are not going into data in phase. */
@@ -2651,9 +2758,8 @@
 		    SCptr->SCp.phase == in_slct_stop)) {
 			/* shit */
 			esp->snip = 0;
-			printk("esp%d: Failed synchronous negotiation for target %d "
-			       "lun %d\n",
-			       esp->esp_id, SCptr->target, SCptr->lun);
+			ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
+				"lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
 			SDptr->sync_max_offset = 0;
 			SDptr->sync_min_period = 0;
 			SDptr->sync = 1; /* so we don't negotiate again */
@@ -2680,8 +2786,8 @@
 		 * But first make sure that is really what is happening.
 		 */
 		if(((1<<SCptr->target) & esp->targets_present)) {
-			printk("esp%d: Warning, live target %d not responding to "
-			       "selection.\n", esp->esp_id, SCptr->target);
+			ESPLOG(("esp%d: Warning, live target %d not responding to "
+				"selection.\n", esp->esp_id, SCptr->target));
 
 			/* This _CAN_ happen.  The SCSI standard states that
 			 * the target is to _not_ respond to selection if
@@ -2710,9 +2816,9 @@
 	esp_print_seqreg(esp->seqreg);
 	printk("\n");
 	printk("esp%d: New -- ", esp->esp_id);
-	esp->sreg = GETREG(eregs->esp_status);
-	esp->seqreg = GETREG(eregs->esp_sstep);
-	esp->ireg = GETREG(eregs->esp_intrpt);
+	esp->sreg = esp_read(eregs->esp_status);
+	esp->seqreg = esp_read(eregs->esp_sstep);
+	esp->ireg = esp_read(eregs->esp_intrpt);
 	esp_print_ireg(esp->ireg);
 	printk(" ");
 	esp_print_statreg(esp->sreg);
@@ -2743,14 +2849,14 @@
 		 * have miscoded something..... so, try to
 		 * recover as best we can.
 		 */
-		printk("esp%d: message in mis-carriage.\n", esp->esp_id);
+		ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
 	}
 	esp_advance_phase(esp->current_SC, in_the_dark);
 	return do_phase_determine;
 }
 
-static inline int check_singlebyte_msg(struct NCR_ESP *esp,
-				       struct ESP_regs *eregs)
+static int check_singlebyte_msg(struct NCR_ESP *esp,
+				struct ESP_regs *eregs)
 {
 	esp->prevmsgin = esp->cur_msgin[0];
 	if(esp->cur_msgin[0] & 0x80) {
@@ -2779,8 +2885,20 @@
 		return 0;
 
 	case RESTORE_POINTERS:
+		/* In this case we might also have to backup the
+		 * "slow command" pointer.  It is rare to get such
+		 * a save/restore pointer sequence so early in the
+		 * bus transition sequences, but cover it.
+		 */
+		if(esp->esp_slowcmd) {
+			esp->esp_scmdleft = esp->current_SC->cmd_len;
+			esp->esp_scmdp = &esp->current_SC->cmnd[0];
+		}
+		esp_restore_pointers(esp, esp->current_SC);
+		return 0;
+
 	case SAVE_POINTERS:
-		/* We handle this all automatically. */
+		esp_save_pointers(esp, esp->current_SC);
 		return 0;
 
 	case COMMAND_COMPLETE:
@@ -2815,9 +2933,9 @@
  * the SCSI2 standard specifically recommends against targets doing
  * this because so many initiators cannot cope with this occuring.
  */
-static inline int target_with_ants_in_pants(struct NCR_ESP *esp,
-					    Scsi_Cmnd *SCptr,
-					    Scsi_Device *SDptr)
+static int target_with_ants_in_pants(struct NCR_ESP *esp,
+				     Scsi_Cmnd *SCptr,
+				     Scsi_Device *SDptr)
 {
 	if(SDptr->sync || SDptr->borken) {
 		/* sorry, no can do */
@@ -2834,7 +2952,7 @@
 	return 0;
 }
 
-static inline void sync_report(struct NCR_ESP *esp)
+static void sync_report(struct NCR_ESP *esp)
 {
 	int msg3, msg4;
 	char *type;
@@ -2845,30 +2963,31 @@
 		int hz = 1000000000 / (msg3 * 4);
 		int integer = hz / 1000000;
 		int fraction = (hz - (integer * 1000000)) / 10000;
-		if((esp->erev == fashme) &&
-		   (esp->config3[esp->current_SC->target] & ESP_CONFIG3_EWIDE)) {
-			type = "FAST-WIDE";
-			integer <<= 1;
-			fraction <<= 1;
-		} else if((msg3 * 4) < 200) {
+		if((msg3 * 4) < 200) {
 			type = "FAST";
 		} else {
 			type = "synchronous";
 		}
-		printk(KERN_INFO "esp%d: target %d [period %dns offset %d %d.%02dMHz %s SCSI%s]\n",
-		       esp->esp_id, esp->current_SC->target,
-		       (int) msg3 * 4,
-		       (int) msg4,
-		       integer, fraction, type,
-		       (((msg3 * 4) < 200) ? "-II" : ""));
+
+		/* Do not transform this back into one big printk
+		 * again, it triggers a bug in our sparc64-gcc272
+		 * sibling call optimization.  -DaveM
+		 */
+		ESPLOG((KERN_INFO "esp%d: target %d ",
+			esp->esp_id, esp->current_SC->target));
+		ESPLOG(("[period %dns offset %d %d.%02dMHz ",
+			(int) msg3 * 4, (int) msg4,
+			integer, fraction));
+		ESPLOG(("%s SCSI%s]\n", type,
+			(((msg3 * 4) < 200) ? "-II" : "")));
 	} else {
-		printk(KERN_INFO "esp%d: target %d asynchronous\n",
-		       esp->esp_id, esp->current_SC->target);
+		ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
+			esp->esp_id, esp->current_SC->target));
 	}
 }
 
-static inline int check_multibyte_msg(struct NCR_ESP *esp,
-				       struct ESP_regs *eregs)
+static int check_multibyte_msg(struct NCR_ESP *esp,
+			       struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
 	Scsi_Device *SDptr = SCptr->device;
@@ -2923,10 +3042,7 @@
 			ESPSDTR(("period is ok, "));
 			tmp = esp->ccycle / 1000;
 			regval = (((period << 2) + tmp - 1) / tmp);
-			if(regval && ((esp->erev == fas100a ||
-				       esp->erev == fas216 ||				       
-				       esp->erev == fas236 ||
-				       esp->erev == fashme))) {
+			if(regval && (esp->erev > esp236)) {
 				if(period >= 50)
 					regval--;
 			}
@@ -2937,8 +3053,8 @@
 
 			SDptr->sync_min_period = (regval & 0x1f);
 			SDptr->sync_max_offset = (offset | esp->radelay);
-			if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
-				if((esp->erev == fas100a) || (esp->erev == fashme))
+			if(esp->erev > esp236) {
+				if(esp->erev == fas100a)
 					bit = ESP_CONFIG3_FAST;
 				else
 					bit = ESP_CONFIG3_FSCSI;
@@ -2946,11 +3062,13 @@
 					esp->config3[SCptr->target] |= bit;
 				else
 					esp->config3[SCptr->target] &= ~bit;
-				SETREG(eregs->esp_cfg3,
-				 esp->config3[SCptr->target]);
+				esp->prev_cfg3 = esp->config3[SCptr->target];
+				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
 			}
-			SETREG(eregs->esp_soff, SDptr->sync_min_period);
-			SETREG(eregs->esp_stp, SDptr->sync_max_offset);
+			esp->prev_soff = SDptr->sync_min_period;
+			esp_write(eregs->esp_soff, esp->prev_soff);
+			esp->prev_stp = SDptr->sync_max_offset;
+			esp_write(eregs->esp_stp, esp->prev_stp);
 
 			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
 				SDptr->sync_max_offset,
@@ -2965,16 +3083,18 @@
 			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
 			SDptr->sync_max_offset = 0;
 			SDptr->sync_min_period = 0;
-			SETREG(eregs->esp_soff, 0);
-			SETREG(eregs->esp_stp, 0);
-			if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
-				if((esp->erev == fas100a) || (esp->erev == fashme))
+			esp->prev_soff = 0;
+			esp_write(eregs->esp_soff, 0);
+			esp->prev_stp = 0;
+			esp_write(eregs->esp_stp, 0);
+			if(esp->erev > esp236) {
+				if(esp->erev == fas100a)
 					bit = ESP_CONFIG3_FAST;
 				else
 					bit = ESP_CONFIG3_FSCSI;
 				esp->config3[SCptr->target] &= ~bit;
-				SETREG(eregs->esp_cfg3,
-				 esp->config3[SCptr->target]);
+				esp->prev_cfg3 = esp->config3[SCptr->target];
+				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
 			}
 		}
 
@@ -2995,48 +3115,12 @@
 		esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
 		return 0;
 	} else if(esp->cur_msgin[2] == EXTENDED_WDTR) {
-		int size = 8 << esp->cur_msgin[3];
-
-		esp->wnip = 0;
-		if(esp->erev != fashme) {
-			printk("esp%d: AIEEE wide msg received and not HME.\n",
-			       esp->esp_id);
-			message_out = MESSAGE_REJECT;
-		} else if(size > 16) {
-			printk("esp%d: AIEEE wide transfer for %d size not supported.\n",
-			       esp->esp_id, size);
-			message_out = MESSAGE_REJECT;
-		} else {
-			/* Things look good; let's see what we got. */
-			if(size == 16) {
-				/* Set config 3 register for this target. */
-				printk("esp%d: 16 byte WIDE transfers enabled for target %d.\n",
-				       esp->esp_id, SCptr->target);
-				esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
-			} else {
-				/* Just make sure it was one byte sized. */
-				if(size != 8) {
-					printk("esp%d: Aieee, wide nego of %d size.\n",
-					       esp->esp_id, size);
-					message_out = MESSAGE_REJECT;
-					goto finish;
-				}
-				/* Pure paranoia. */
-				esp->config3[SCptr->target] &= ~(ESP_CONFIG3_EWIDE);
-			}
-			SETREG(eregs->esp_cfg3, esp->config3[SCptr->target]);
-
-			/* Regardless, next try for sync transfers. */
-			build_sync_nego_msg(esp, esp->sync_defp, 15);
-			SDptr->sync = 1;
-			esp->snip = 1;
-			message_out = EXTENDED_MESSAGE;
-		}
+		ESPLOG(("esp%d: AIEEE wide msg received\n", esp->esp_id));
+		message_out = MESSAGE_REJECT;
 	} else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
 		ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
 		message_out = MESSAGE_REJECT;
 	}
-finish:
 	esp_advance_phase(SCptr, in_the_dark);
 	return message_out;
 }
@@ -3054,26 +3138,17 @@
 			if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
 				message_out = MSG_PARITY_ERROR;
 				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-			} else if(esp->erev != fashme &&
-				  (it = (GETREG(eregs->esp_fflags)
-				  & ESP_FF_FBYTES))!=1) {
+			} else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) {
 				/* We certainly dropped the ball somewhere. */
 				message_out = INITIATOR_ERROR;
 				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 			} else if(!esp->msgin_len) {
-				if(esp->erev == fashme)
-					it = esp->hme_fifo_workaround_buffer[0];
-				else
-					it = GETREG(eregs->esp_fdata);
+				it = esp_read(eregs->esp_fdata);
 				esp_advance_phase(SCptr, in_msgincont);
 			} else {
 				/* it is ok and we want it */
-				if(esp->erev == fashme)
-					it = esp->cur_msgin[esp->msgin_ctr] =
-						esp->hme_fifo_workaround_buffer[0];
-				else
-					it = esp->cur_msgin[esp->msgin_ctr] =
-						GETREG(eregs->esp_fdata);
+				it = esp->cur_msgin[esp->msgin_ctr] =
+					esp_read(eregs->esp_fdata);
 				esp->msgin_ctr++;
 			}
 		} else {
@@ -3114,7 +3189,7 @@
 		esp_advance_phase(SCptr, in_the_dark);
 		esp->msgin_len = 0;
 	}
-	esp->sreg = GETREG(eregs->esp_status);
+	esp->sreg = esp_read(eregs->esp_status);
 	esp->sreg &= ~(ESP_STAT_INTR);
 	if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
 		esp_cmd(esp, eregs, ESP_CMD_MOK);
@@ -3126,35 +3201,21 @@
 
 static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
+	unsigned char tmp;
 	Scsi_Cmnd *SCptr = esp->current_SC;
 
 	esp_advance_phase(SCptr, in_cmdend);
-	if(esp->erev == fashme) {
-		int i;
-
-		for(i = 0; i < esp->esp_scmdleft; i++)
-			esp->esp_command[i] = *esp->esp_scmdp++;
-		esp->esp_scmdleft = 0;
-		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		esp_setcount(eregs, i, 1);
-		esp_cmd(esp, eregs, (ESP_CMD_DMA | ESP_CMD_TI));
-		esp->dma_init_write(esp, esp->esp_command_dvma, i);
-	} else {
-		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		SETREG(eregs->esp_fdata, *esp->esp_scmdp++);
-		esp->esp_scmdleft--;
-		esp_cmd(esp, eregs, ESP_CMD_TI);
-	}
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	tmp = *esp->esp_scmdp++;
+	esp->esp_scmdleft--;
+	esp_write(eregs->esp_fdata, tmp);
+	esp_cmd(esp, eregs, ESP_CMD_TI);
 	return do_intr_end;
 }
 
-static inline int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
-	if(esp->erev == fashme){
-		if(esp->dma_invalidate)
-			esp->dma_invalidate(esp);
-	} else
-		esp_cmd(esp, eregs, ESP_CMD_NULL);
+	esp_cmd(esp, eregs, ESP_CMD_NULL);
 	if(esp->ireg & ESP_INTR_BSERV) {
 		esp_advance_phase(esp->current_SC, in_the_dark);
 		return esp_do_phase_determine(esp, eregs);
@@ -3169,79 +3230,61 @@
 	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 	switch(esp->msgout_len) {
 	case 1:
-		if(esp->erev == fashme)
-			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
-		else
-			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+		esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
 		esp_cmd(esp, eregs, ESP_CMD_TI);
 		break;
 
 	case 2:
 		if(esp->do_pio_cmds){
-			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			esp->esp_command[0] = esp->cur_msgout[0];
 			esp->esp_command[1] = esp->cur_msgout[1];
-			if(esp->erev == fashme) {
-				hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 2);
-				esp_cmd(esp, eregs, ESP_CMD_TI);
-			} else {
-				esp->dma_setup(esp, esp->esp_command_dvma, 2, 0);
-				esp_setcount(eregs, 2, 0);
-				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
-			}
+			esp->dma_setup(esp, esp->esp_command_dvma, 2, 0);
+			esp_setcount(eregs, 2);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
 		break;
 
 	case 4:
 		esp->snip = 1;
 		if(esp->do_pio_cmds){
-			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[2]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[3]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			esp->esp_command[0] = esp->cur_msgout[0];
 			esp->esp_command[1] = esp->cur_msgout[1];
 			esp->esp_command[2] = esp->cur_msgout[2];
 			esp->esp_command[3] = esp->cur_msgout[3];
-			if(esp->erev == fashme) {
-				hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 4);
-				esp_cmd(esp, eregs, ESP_CMD_TI);
-			} else {
-				esp->dma_setup(esp, esp->esp_command_dvma, 4, 0);
-				esp_setcount(eregs, 4, 0);
-				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
-			}
+			esp->dma_setup(esp, esp->esp_command_dvma, 4, 0);
+			esp_setcount(eregs, 4);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
 		break;
 
 	case 5:
 		esp->snip = 1;
 		if(esp->do_pio_cmds){
-			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[2]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[3]);
-			SETREG(eregs->esp_fdata, esp->cur_msgout[4]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[4]);
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
-			SETREG(esp->esp_command[0], esp->cur_msgout[0]);
-			SETREG(esp->esp_command[1], esp->cur_msgout[1]);
-			SETREG(esp->esp_command[2], esp->cur_msgout[2]);
-			SETREG(esp->esp_command[3], esp->cur_msgout[3]);
-			SETREG(esp->esp_command[4], esp->cur_msgout[4]);
-			if(esp->erev == fashme) {
-				hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 5);
-				esp_cmd(esp, eregs, ESP_CMD_TI);
-			} else {
-				esp->dma_setup(esp, esp->esp_command_dvma, 5, 0);
-				esp_setcount(eregs, 5, 0);
-				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
-			}
+			esp->esp_command[0] = esp->cur_msgout[0];
+			esp->esp_command[1] = esp->cur_msgout[1];
+			esp->esp_command[2] = esp->cur_msgout[2];
+			esp->esp_command[3] = esp->cur_msgout[3];
+			esp->esp_command[4] = esp->cur_msgout[4];
+			esp->dma_setup(esp, esp->esp_command_dvma, 5, 0);
+			esp_setcount(eregs, 5);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
 		break;
 
@@ -3249,11 +3292,7 @@
 		/* whoops */
 		ESPMISC(("bogus msgout sending NOP\n"));
 		esp->cur_msgout[0] = NOP;
-		if(esp->erev == fashme) {
-			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
-		} else {
-			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
-		}
+		esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
 		esp->msgout_len = 1;
 		esp_cmd(esp, eregs, ESP_CMD_TI);
 		break;
@@ -3262,15 +3301,14 @@
 	return do_intr_end;
 }
 
-static inline int esp_do_msgoutdone(struct NCR_ESP *esp, 
-				    struct ESP_regs *eregs)
+static int esp_do_msgoutdone(struct NCR_ESP *esp, 
+			     struct ESP_regs *eregs)
 {
 	if((esp->msgout_len > 1) && esp->dma_barrier)
 		esp->dma_barrier(esp);
 
 	if(!(esp->ireg & ESP_INTR_DC)) {
-		if(esp->erev != fashme)
-			esp_cmd(esp, eregs, ESP_CMD_NULL);
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
 		switch(esp->sreg & ESP_STAT_PMASK) {
 		case ESP_MOP:
 			/* whoops, parity error */
@@ -3285,17 +3323,12 @@
 			break;
 
 		default:
-			/* Happy Meal fifo is touchy... */
-			if((esp->erev != fashme) &&
-			   !fcount(esp, eregs) &&
+			if(!fcount(esp, eregs) &&
 			   !(esp->current_SC->device->sync_max_offset))
 				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 			break;
 
 		};
-	} else {
-		ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
-		return do_reset_bus;
 	}
 
 	/* If we sent out a synchronous negotiation message, update
@@ -3312,89 +3345,66 @@
 	return esp_do_phase_determine(esp, eregs);
 }
 
+static int esp_bus_unexpected(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	ESPLOG(("esp%d: command in weird state %2x\n",
+		esp->esp_id, esp->current_SC->SCp.phase));
+	return do_reset_bus;
+}
+
+static espfunc_t bus_vector[] = {
+	esp_do_data_finale,
+	esp_do_data_finale,
+	esp_bus_unexpected,
+	esp_do_msgin,
+	esp_do_msgincont,
+	esp_do_msgindone,
+	esp_do_msgout,
+	esp_do_msgoutdone,
+	esp_do_cmdbegin,
+	esp_do_cmddone,
+	esp_do_status,
+	esp_do_freebus,
+	esp_do_phase_determine,
+	esp_bus_unexpected,
+	esp_bus_unexpected,
+	esp_bus_unexpected,
+};
+
 /* This is the second tier in our dual-level SCSI state machine. */
-static inline int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
+	unsigned int phase;
 
 	ESPBUS(("esp_work_bus: "));
 	if(!SCptr) {
 		ESPBUS(("reconnect\n"));
 		return esp_do_reconnect(esp, eregs);
 	}
-
-	switch(SCptr->SCp.phase) {
-	case in_the_dark:
-		ESPBUS(("in the dark\n"));
-		return esp_do_phase_determine(esp, eregs);
-
-	case in_slct_norm:
-	case in_slct_stop:
-	case in_slct_msg:
-	case in_slct_tag:
-	case in_slct_sneg:
-		ESPBUS(("finish selection\n"));
+	phase = SCptr->SCp.phase;
+	if ((phase & 0xf0) == in_phases_mask)
+		return bus_vector[(phase & 0x0f)](esp, eregs);
+	else if((phase & 0xf0) == in_slct_mask)
 		return esp_select_complete(esp, eregs);
-
-	case in_datain:
-	case in_dataout:
-		ESPBUS(("finish data\n"));
-		return esp_do_data_finale(esp, eregs);
-
-	case in_msgout:
-		ESPBUS(("message out "));
-		return esp_do_msgout(esp, eregs);
-
-	case in_msgoutdone:
-		ESPBUS(("finish message out "));
-		return esp_do_msgoutdone(esp, eregs);
-
-	case in_msgin:
-		ESPBUS(("message in "));
-		return esp_do_msgin(esp, eregs);
-
-	case in_msgincont:
-		ESPBUS(("continue message in "));
-		return esp_do_msgincont(esp, eregs);
-
-	case in_msgindone:
-		ESPBUS(("finish message in "));
-		return esp_do_msgindone(esp, eregs);
-
-	case in_status:
-		ESPBUS(("status phase "));
-		return esp_do_status(esp, eregs);
-
-	case in_freeing:
-		ESPBUS(("freeing the bus "));
-		return esp_do_freebus(esp, eregs);
-
-	case in_cmdbegin:
-		ESPBUS(("begin slow cmd "));
-		return esp_do_cmdbegin(esp, eregs);
-
-	case in_cmdend:
-		ESPBUS(("end slow cmd "));
-		return esp_do_cmddone(esp, eregs);
-
-	default:
-		printk("esp%d: command in weird state %2x\n",
-		       esp->esp_id, esp->current_SC->SCp.phase);
-		return do_reset_bus;
-	};
+	else
+		return esp_bus_unexpected(esp, eregs);
 }
 
+static espfunc_t isvc_vector[] = {
+	0,
+	esp_do_phase_determine,
+	esp_do_resetbus,
+	esp_finish_reset,
+	esp_work_bus
+};
+
 /* Main interrupt handler for an esp adapter. */
-inline void esp_handle(struct NCR_ESP *esp)
+void esp_handle(struct NCR_ESP *esp)
 {
 	struct ESP_regs *eregs;
 	Scsi_Cmnd *SCptr;
 	int what_next = do_intr_end;
-	unsigned long flags;
-#ifdef CONFIG_SCSI_SUNESP
-	struct sparc_dma_registers *dregs = 
-	  (struct sparc_dma_registers*) esp->dregs;
-#endif
 	eregs = esp->eregs;
 	SCptr = esp->current_SC;
 
@@ -3402,12 +3412,12 @@
 		esp->dma_irq_entry(esp);
 
 	/* Check for errors. */
-	esp->sreg = GETREG(eregs->esp_status);
+	esp->sreg = esp_read(eregs->esp_status);
 	esp->sreg &= (~ESP_STAT_INTR);
-	if(esp->erev == fashme) {
-		esp->sreg2 = GETREG(eregs->esp_status2);
-		esp->seqreg = (GETREG(eregs->esp_sstep) & ESP_STEP_VBITS);
-	}
+	esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS);
+	esp->ireg = esp_read(eregs->esp_intrpt);   /* Unlatch intr and stat regs */
+	ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->sreg, esp->seqreg, esp->ireg));
 	if(esp->sreg & (ESP_STAT_SPAM)) {
 		/* Gross error, could be due to one of:
 		 *
@@ -3435,56 +3445,10 @@
 			ESPLOG(("esp%d: No current cmd during gross error, "
 				"resetting bus\n", esp->esp_id));
 			what_next = do_reset_bus;
-			goto again;
+			goto state_machine;
 		}
 	}
 
-#ifdef CONFIG_SCSI_SUNESP
-	if(dregs->cond_reg & DMA_HNDL_ERROR) {
-		/* A DMA gate array error.  Here we must
-		 * be seeing one of two things.  Either the
-		 * virtual to physical address translation
-		 * on the SBUS could not occur, else the
-		 * translation it did get pointed to a bogus
-		 * page.  Ho hum...
-		 */
-		ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
-			dregs->cond_reg));
-
-		/* DMA gate array itself must be reset to clear the
-		 * error condition.
-		 */
-		if(esp->dma_reset)
-			esp->dma_reset(esp);
-
-		what_next = do_reset_bus;
-		goto again;
-	}
-#endif /* CONFIG_SCSI_SUNESP */
-
-	if(esp->erev == fashme) {
-		/* This chip is really losing. */
-		ESPHME(("HME["));
-
-		ESPHME(("sreg2=%02x,", esp->sreg2));
-		/* Must latch fifo before reading the interrupt
-		 * register else garbage ends up in the FIFO
-		 * which confuses the driver utterly.
-		 */
-		if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
-		   (esp->sreg2 & ESP_STAT2_F1BYTE)) {
-			ESPHME(("fifo_workaround]"));
-			hme_fifo_hwbug_workaround(esp, eregs);
-		} else {
-			ESPHME(("no_fifo_workaround]"));
-		}
-	}
-
-	esp->ireg = GETREG(eregs->esp_intrpt);   /* Unlatch intr and stat regs */
-
-	/* This cannot be done until this very moment. -DaveM */
-	synchronize_irq();
-
 	/* No current cmd is only valid at this point when there are
 	 * commands off the bus or we are trying a reset.
 	 */
@@ -3497,7 +3461,7 @@
 	if(esp->ireg & (ESP_INTR_IC)) {
 		/* Illegal command fed to ESP.  Outside of obvious
 		 * software bugs that could cause this, there is
-		 * a condition with esp100 where we can confuse the
+		 * a condition with ESP100 where we can confuse the
 		 * ESP into an erroneous illegal command interrupt
 		 * because it does not scrape the FIFO properly
 		 * for reselection.  See esp100_reconnect_hwbug()
@@ -3523,10 +3487,7 @@
 		}
 
 		what_next = do_reset_bus;
-		goto again;
-	}
-
-	if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+	} else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
 		int phase;
 
 		if(SCptr) {
@@ -3538,13 +3499,12 @@
 			} else {
 				ESPLOG(("esp%d: interrupt for no good reason...\n",
 					esp->esp_id));
-				goto esp_handle_done;
+				what_next = do_intr_end;
 			}
 		} else {
 			ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
 				esp->esp_id));
 			what_next = do_reset_bus;
-			goto again;
 		}
 	} else if(esp->ireg & ESP_INTR_SR) {
 		ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
@@ -3553,7 +3513,6 @@
 		ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
 			esp->esp_id));
 		what_next = do_reset_bus;
-		goto again;
 	} else if(esp->ireg & ESP_INTR_RSEL) {
 		if(!SCptr) {
 			/* This is ok. */
@@ -3568,114 +3527,40 @@
 			ESPLOG(("esp%d: Reselected while bus is busy\n",
 				esp->esp_id));
 			what_next = do_reset_bus;
-			goto again;
 		}
 	}
 
-	/* We're trying to fight stack problems, and inline as much as
-	 * possible without making this driver a mess. hate hate hate
-	 * This is tier-one in our dual level SCSI state machine.
-	 */
-again:
-	switch(what_next) {
-	case do_intr_end:
-		goto esp_handle_done;
-
-	case do_work_bus:
-		what_next = esp_work_bus(esp, eregs);
-		break;
-
-	case do_phase_determine:
-		what_next = esp_do_phase_determine(esp, eregs);
-		break;
-
-	case do_reset_bus:
-		ESPLOG(("esp%d: resetting bus...\n", esp->esp_id));
-		esp->resetting_bus = 1;
-		esp_cmd(esp, eregs, ESP_CMD_RS);
-		goto esp_handle_done;
-
-	case do_reset_complete:
-		/* Tricky, we don't want to cause any more commands to
-		 * go out until we clear all the live cmds by hand.
-		 */
-		if(esp->current_SC) {
-			Scsi_Cmnd *SCptr = esp->current_SC;
-
-			if(!SCptr->use_sg) {
-			        if (esp->dma_mmu_release_scsi_one)
-			                esp->dma_mmu_release_scsi_one (esp, SCptr);
-			} else {
-			        if (esp->dma_mmu_release_scsi_sgl)
-			                esp->dma_mmu_release_scsi_sgl (esp, SCptr);
-			}
-			SCptr->result = (DID_RESET << 16);
-
-			spin_lock_irqsave(&io_request_lock,flags);
-			SCptr->scsi_done(SCptr);
-			spin_unlock_irqrestore(&io_request_lock, flags);
-		}
-		esp->current_SC = NULL;
-		if(esp->disconnected_SC) {
-			Scsi_Cmnd *SCptr;
-			while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
-				if(!SCptr->use_sg) {
-			                if (esp->dma_mmu_release_scsi_one)
-			                        esp->dma_mmu_release_scsi_one (esp, SCptr);
-				} else {
-			                if (esp->dma_mmu_release_scsi_sgl)
-			                        esp->dma_mmu_release_scsi_sgl (esp, SCptr);
-				}
-				SCptr->result = (DID_RESET << 16);
-
-				spin_lock_irqsave(&io_request_lock,flags);
-				SCptr->scsi_done(SCptr);
-				spin_unlock_irqrestore(&io_request_lock, flags);
-			}
-		}
-		esp->resetting_bus = 0;
-
-		if(esp->current_SC) {
-			printk("esp%d: weird weird weird, current_SC not NULL after "
-			       "SCSI bus reset.\n", esp->esp_id);
-			goto esp_handle_done;
+	/* This is tier-one in our dual level SCSI state machine. */
+state_machine:
+	while(what_next != do_intr_end) {
+		if (what_next >= do_phase_determine &&
+		    what_next < do_intr_end)
+			what_next = isvc_vector[what_next](esp, eregs);
+		else {
+			/* state is completely lost ;-( */
+			ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
 		}
-
-		/* Now it is safe to execute more things. */
-		if(esp->issue_SC)
-			esp_exec_cmd(esp);
-		goto esp_handle_done;
-
-	default:
-		/* state is completely lost ;-( */
-		ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
-			esp->esp_id));
-		what_next = do_reset_bus;
-		break;
-
-	};
-	goto again;
-
-esp_handle_done:
+	}
 	if(esp->dma_irq_exit)
 		esp->dma_irq_exit(esp);
-	return;
 }
 
-#ifndef __sparc_v9__
-
 #ifndef __SMP__
 void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct NCR_ESP *esp;
+	unsigned long flags;
 	int again;
 
 	/* Handle all ESP interrupts showing at this IRQ level. */
+	spin_lock_irqsave(&io_request_lock, flags);
 repeat:
 	again = 0;
 	for_each_esp(esp) {
 #ifndef __mips__	    
-		if(((esp)->irq & 0xf) == irq) {
+		if(((esp)->irq & 0xff) == irq) {
 #endif		    
 			if(esp->dma_irq_p(esp)) {
 				again = 1;
@@ -3694,14 +3579,17 @@
 	}
 	if(again)
 		goto repeat;
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 #else
 /* For SMP we only service one ESP on the list list at our IRQ level! */
-void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct NCR_ESP *esp;
+	unsigned long flags;
 
 	/* Handle all ESP interrupts showing at this IRQ level. */
+	spin_lock_irqsave(&io_request_lock, flags);
 	for_each_esp(esp) {
 		if(((esp)->irq & 0xf) == irq) {
 			if(esp->dma_irq_p(esp)) {
@@ -3713,28 +3601,22 @@
 				ESPIRQ((")"));
 
 				esp->dma_ints_on(esp);
-				return;
+				goto out;
 			}
 		}
 	}
+out:
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 #endif
 
-#else /* __sparc_v9__ */
-
-static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+#ifdef MODULE
+int init_module(void) { return 0; }
+void cleanup_module(void) {}
+void esp_release(void)
 {
-	struct NCR_ESP *esp = dev_id;
-
-	if(esp->dma_irq_p(esp)) {
-		esp->dma_ints_off(dregs);
-
-		ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
-		esp_handle(esp);
-		ESPIRQ((")"));
-
-		esp->dma_ints_on(esp);
-	}
+	MOD_DEC_USE_COUNT;
+	esps_in_use--;
+	esps_running = esps_in_use;
 }
-
 #endif

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