Resent-Date: Thu, 10 Dec 1998 16:25:15 +0100 (MET)
Date: Thu, 10 Dec 1998 16:25:02 +0100
From: Kars de Jong <jongk@cs.utwente.nl>
To: linux-m68k <linux-m68k@lists.linux-m68k.org>
Subject: Re: NCR53C9x...
Mail-Followup-To: linux-m68k <linux-m68k@lists.linux-m68k.org>
References: <19981208134834.A2738@cs.utwente.nl> <Pine.LNX.3.96.981209163033.26228A-100000@ap031.experimentalphysik.uni-kiel.de>
In-Reply-To: <Pine.LNX.3.96.981209163033.26228A-100000@ap031.experimentalphysik.uni-kiel.de>; from Christian T. Steigies on Wed, Dec 09, 1998 at 04:33:30PM +0100
Resent-From: linux-m68k@phil.uni-sb.de

On Wed, Dec 09, 1998 at 04:33:30PM +0100, Christian T. Steigies wrote:
> Tested with Michaels patch also, only:
> Gross error is gone again? Well... copied several MB (kernel trees) to and
> from SCSI to IDE disk. No problems. Did not check CD-ROM, MO or other
> devices though.

Okay, thanks again. Here is a new version of the patch. It incorporates
Michaels patch, David Millers changes and my own. 
It replaces all previous patches, apply it to the clean (2.1.130) driver.
Please test this, especially to see if your chip is still detected correctly.
If not, please let me know the output from the kernel, especially the line
which mentions the family and version of the chip. For example, with me it
prints the following:

esp0: FAST chip is SYM53CF9x-2 (FSC) (family=20, version=2) 

I'm considering removing support for the fasHME chip from the driver, it
makes it very big and I don't think anyone outside the Sparc uses that chip.
I contacted David Miller and he doesn't feel like using the abstracted chip
driver.

Kars.
-- 
------------------------------------------------------------------------------
Kars de Jong             Signaalkamp rules the waves!       Turrican@Discworld
--------======]**-----|      jongk@cs.utwente.nl      |-----**[======---------

Index: linux/drivers/scsi/NCR53C9x.c
===================================================================
RCS file: /usr/src/CVS/linux/drivers/scsi/NCR53C9x.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 NCR53C9x.c
--- NCR53C9x.c	1998/12/02 09:54:20	1.1.1.1
+++ NCR53C9x.c	1998/12/10 12:21:33
@@ -2,7 +2,7 @@
  *
  * 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)
@@ -42,12 +42,6 @@
 #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>
@@ -91,6 +85,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
@@ -223,7 +228,6 @@
 		    "UNKNOWN"))))));
 }
 
-#if defined(DEBUG_STATE_MACHINE) || defined(DEBUG_ESP)
 static char *phase_string(int phase)
 {
 	switch(phase) {
@@ -279,26 +283,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
 	eregs->esp_cmd = cmd;
 }
+#else
+#define esp_cmd(__esp, __eregs, __cmd)	(__eregs)->esp_cmd = (__cmd)
+#endif
 
 /* How we use the various Linux SCSI data structures for operation.
  *
@@ -325,9 +334,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;
@@ -336,38 +343,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)
@@ -378,14 +375,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;
@@ -393,6 +389,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)
+		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
@@ -400,31 +398,40 @@
 	 */
 	esp->max_period = ((35 * esp->ccycle) / 1000);
 	if(esp->erev == fast) {
+		char *erev2string[] = {
+			"fas236",
+			"fas100a",
+			"fast",
+			"fasHME",
+			"fas216",
+			"SYM53CF9x-2 (FSC)",
+			"unknown!"
+		};
+			
 		version = 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)
+		} 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 == 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 {
@@ -433,8 +440,8 @@
 
 	/* Reload the configuration registers */
 	eregs->esp_cfact = esp->cfact;
-	eregs->esp_stp   = 0;
-	eregs->esp_soff  = 0;
+	eregs->esp_stp   = esp->prev_stp = 0;
+	eregs->esp_soff  = esp->prev_soff = 0;
 	eregs->esp_timeo = esp->neg_defp;
 	esp->max_period = (esp->max_period + 3)>>2;
 	esp->min_period = (esp->min_period + 3)>>2;
@@ -450,23 +457,29 @@
 	case esp236:
 		/* Slow 236 */
 		eregs->esp_cfg2 = esp->config2;
-		eregs->esp_cfg3 = esp->config3[0];
+		eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0];
 		break;
 	case fashme:
 		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
 		/* fallthrough... */
 	case fas216:	    
 	case fas236:
+	case fsc:
 		/* Fast 236 or HME */
 		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
+			if(esp->erev == fashme) {
+				unsigned char cfg3;
+
+				cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
+				if (esp->scsi_id >= 8)
+					cfg3 |= ESP_CONFIG3_IDBIT3;
+				esp->config3[i] |= cfg3;
+			} else {
 				esp->config3[i] |= ESP_CONFIG3_FCLK;
+			}
 		}
-		eregs->esp_cfg3 = esp->config3[0];
+		eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0];
 		if(esp->erev == fashme) {
 			esp->radelay = 80;
 		} else {
@@ -475,13 +488,22 @@
 			else
 				esp->radelay = 96;
 		}
+		if(esp->erev == fsc) {
+			/* Different timeout constant for FSC */
+			esp->neg_defp =
+				FSC_NEG_DEFP(esp->cfreq,
+					     (esp->cfact == ESP_CCF_F0 ?
+					      ESP_CCF_F7 + 1 : esp->cfact));
+			eregs->esp_timeo = esp->neg_defp;
+			eregs->esp_cfg4 = ESP_CONFIG4_EAN;
+		}
 		break;
 	case fas100a:
 		/* Fast 100a */
 		eregs->esp_cfg2 = esp->config2;
 		for(i=0; i<8; i++)
 			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
-		eregs->esp_cfg3 = esp->config3[0];
+		eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0];
 		esp->radelay = 32;
 		break;
 	default:
@@ -495,7 +517,7 @@
 }
 
 /* This places the ESP into a known state at boot time. */
-inline void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
+static void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	volatile unchar trash;
 
@@ -635,9 +657,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;
@@ -651,51 +673,41 @@
 	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
 	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
 	eregs->esp_cfg2 = esp->config2;
-#ifndef SYMBIOS_HACK
 	if((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
 		eregs->esp_cfg2 = esp->config2 = 0;
 		eregs->esp_cfg3 = 0;
-		eregs->esp_cfg3 = esp->config3[0] = 5;
-#ifndef SYMBIOS_HACK
+		eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0] = 5;
 		if(eregs->esp_cfg3 != 5) {
-			printk("NCR53C90A(esp100a) detected\n");
+			printk("NCR53C90A(esp100a)\n");
 			esp->erev = esp100a;
 		} else {
-#else
-		  {
-#endif
 			int target;
-			
+
 			for(target=0; target<8; target++)
 				esp->config3[target] = 0;
-			eregs->esp_cfg3 = 0;
-#ifndef SYMBIOS_HACK
+			eregs->esp_cfg3 = esp->prev_cfg3 = 0;
 			if(ccf > ESP_CCF_F5) {
-#endif
-				printk("NCR53C9XF(espfast) detected\n");
+				printk("NCR53C9XF(espfast)\n");
 				esp->erev = fast;
 				eregs->esp_cfg2 = esp->config2 = 0;
 				esp->sync_defp = SYNC_DEFP_FAST;
-#ifndef SYMBIOS_HACK
 			} else {
-				printk("NCR53C9x(esp236) detected\n");
+				printk("NCR53C9x(esp236)\n");
 				esp->erev = esp236;
 				eregs->esp_cfg2 = esp->config2 = 0;
 			}
 		}
-#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;
@@ -711,9 +723,13 @@
 	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;
+	esp->prev_hme_dmacsr = 0xffffffff;
+
 	/* Reset the thing before we try anything... */
 	esp_bootup_reset(esp, eregs);
-	
+
 	esps_in_use++;
 }
 
@@ -741,6 +757,8 @@
 		return "ESP366-HME";
 	case fas100a:
 		return "ESP100A-FAST";
+	case fsc:
+		return "FSC (SYM53CF9x-2)";
 	default:
 		panic("Bogon ESP revision");
 	};
@@ -828,6 +846,9 @@
 	case fashme:
 		copy_info(&info, "Happy Meal FAS\n");
 		break;
+	case fsc:
+		copy_info(&info, "FSC\n");
+		break;
 	case espunknown:
 	default:
 		copy_info(&info, "Unknown!\n");
@@ -915,6 +936,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.
@@ -984,7 +1059,7 @@
 	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;
@@ -994,15 +1069,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;
@@ -1045,7 +1123,7 @@
 
 	if(SDptr->sync) {
 		/* this targets sync is known */
-#ifdef CONFIG_SCSI_SUNESP
+#if defined(CONFIG_SCSI_SUNESP) || defined(CONFIG_SCSI_MAC_ESP)
 do_sync_known:
 #endif
 		if(SDptr->disconnect)
@@ -1101,6 +1179,19 @@
 			goto do_sync_known;
 		}
 #endif
+
+#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
@@ -1111,7 +1202,6 @@
 			   (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;
@@ -1125,8 +1215,8 @@
 			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 {
@@ -1163,13 +1253,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 {
@@ -1197,17 +1283,31 @@
 			(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
 	else
 		eregs->esp_busid = (target & 7);
-	eregs->esp_soff = SDptr->sync_max_offset;
-	eregs->esp_stp  = SDptr->sync_min_period;
-	if(esp->erev > esp100a)
-		eregs->esp_cfg3 = esp->config3[target];
-
+	if (esp->prev_soff != SDptr->sync_max_offset ||
+	    esp->prev_stp  != SDptr->sync_min_period ||
+	    (esp->erev > esp100a &&
+	     esp->prev_cfg3 != esp->config3[target])) {
+		eregs->esp_soff = esp->prev_soff = SDptr->sync_max_offset;
+		eregs->esp_stp  = esp->prev_stp  = SDptr->sync_min_period;
+		if(esp->erev > esp100a)
+			eregs->esp_cfg3 =
+				esp->prev_cfg3 =
+				esp->config3[target];
+	}
 	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++)
 			eregs->esp_fdata = esp->esp_command[j];
 		the_esp_command &= ~ESP_CMD_DMA;
@@ -1241,7 +1341,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;
@@ -1255,32 +1354,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;
@@ -1294,13 +1371,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;
 }
 
@@ -1316,7 +1390,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>]",
@@ -1325,8 +1399,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
@@ -1383,7 +1457,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);
@@ -1394,16 +1467,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.
@@ -1422,6 +1492,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)
@@ -1436,8 +1507,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
@@ -1446,20 +1520,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;
 }
 
@@ -1469,36 +1591,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.
@@ -1510,11 +1611,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);
@@ -1526,29 +1622,29 @@
 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;
-}
+#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
+#define sreg_dataoutp(__sreg) (((__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)
+/* Read any bytes found in the FAS366 fifo, storing them into
+ * the ESP driver software state structure.
+ */
+static void hme_fifo_read(struct NCR_ESP *esp,
+			  struct ESP_regs *eregs)
 {
+	unsigned long count = 0;
 	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)) {
+	/* Cannot safely frob the fifo for these following cases, but
+	 * we must always read the fifo when the reselect interrupt
+	 * is pending.
+	 */
+	if(((esp->ireg & ESP_INTR_RSEL) == 0)	&&
+	   (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 = eregs->esp_fflags & ESP_FF_FBYTES;
 
 		/* The HME stores bytes in multiples of 2 in the fifo. */
@@ -1569,9 +1665,9 @@
 		} else {
 			ESPHME(("no_xtra_byte"));
 		}
-		esp->hme_fifo_workaround_count = count;
-		ESPHME(("wkarnd_cnt=%d]", (int)count));
 	}
+	ESPHME(("wkarnd_cnt=%d]", (int)count));
+	esp->hme_fifo_workaround_count = count;
 }
 
 static inline void hme_fifo_push(struct NCR_ESP *esp, struct ESP_regs *eregs,
@@ -1596,7 +1692,10 @@
 
 	if(esp->dma_irq_p(esp)) {
 		/* Yes, we are able to save an interrupt. */
-		esp->sreg = eregs->esp_status;
+		if (esp->erev == fashme)
+			esp->sreg2 = eregs->esp_status2;
+		esp->sreg = (eregs->esp_status & ~(ESP_STAT_INTR));
+		esp->ireg = eregs->esp_intrpt;
 		if(esp->erev == fashme) {
 			/* This chip is really losing. */
 			ESPHME(("HME["));
@@ -1606,10 +1705,10 @@
 			 * Happy Meal indeed....
 			 */
 			ESPHME(("fifo_workaround]"));
-			hme_fifo_hwbug_workaround(esp, eregs);
+			if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+			   (esp->sreg2 & ESP_STAT2_F1BYTE))
+				hme_fifo_read(esp, eregs);
 		}
-		esp->ireg = eregs->esp_intrpt;
-		esp->sreg &= ~(ESP_STAT_INTR);
 		if(!(esp->ireg & ESP_INTR_SR))
 			return 0;
 		else
@@ -1630,7 +1729,10 @@
 		return 0;
 	if(esp->dma_irq_p(esp)) {
 		/* Yes, we are able to save an interrupt. */
-		esp->sreg = eregs->esp_status;
+		if (esp->erev == fashme)
+			esp->sreg2 = eregs->esp_status2;
+		esp->sreg = (eregs->esp_status & ~(ESP_STAT_INTR));
+		esp->ireg = eregs->esp_intrpt;
 		if(esp->erev == fashme) {
 			/* This chip is really losing. */
 			ESPHME(("HME["));
@@ -1641,10 +1743,10 @@
 			 * Happy Meal indeed....
 			 */
 			ESPHME(("fifo_workaround]"));
-			hme_fifo_hwbug_workaround(esp, eregs);
+			if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+			   (esp->sreg2 & ESP_STAT2_F1BYTE))
+				hme_fifo_read(esp, eregs);
 		}
-		esp->ireg = eregs->esp_intrpt;
-		esp->sreg &= ~(ESP_STAT_INTR);
 		if(!(esp->ireg & ESP_INTR_SR))
 			return 0;
 		else
@@ -1655,56 +1757,38 @@
 	return do_intr_end;
 }
 
-/* Misc. esp helper routines. */
-static inline void esp_setcount(struct ESP_regs *eregs, int cnt, int hme)
-{
-	eregs->esp_tclow = (cnt & 0xff);
-	eregs->esp_tcmed = ((cnt >> 8) & 0xff);
-	if(hme) {
-		eregs->fas_rlo = 0;
-		eregs->fas_rhi = 0;
-	}
-}
-
-static inline int esp_getcount(struct ESP_regs *eregs)
-{
-	return (((eregs->esp_tclow)&0xff) |
-		(((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 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 eregs->esp_fflags & ESP_FF_ONOTZERO;
-}
+/* Misc. esp helper macros. */
+#define esp_setcount(__eregs, __cnt, __hme) \
+	(__eregs)->esp_tclow = ((__cnt) & 0xff); \
+	(__eregs)->esp_tcmed = (((__cnt) >> 8) & 0xff); \
+	if(__hme) { \
+		(__eregs)->fas_rlo = 0; \
+		(__eregs)->fas_rhi = 0; \
+	}
+
+#define esp_getcount(__eregs) \
+	((((__eregs)->esp_tclow)&0xff) | \
+	 ((((__eregs)->esp_tcmed)&0xff) << 8))
+
+#define fcount(__esp, __eregs) \
+	(((__esp)->erev == fashme) ? \
+	  (__esp)->hme_fifo_workaround_count : \
+	  (__eregs)->esp_fflags & ESP_FF_FBYTES)
+
+#define fnzero(__esp, __eregs) \
+	(((__esp)->erev == fashme) ? 0 : \
+	 (__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
@@ -1797,10 +1881,19 @@
 		lun = esp->hme_fifo_workaround_buffer[1];
 	else
 		lun = 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;
 }
 
@@ -1811,13 +1904,18 @@
 			       Scsi_Cmnd *sp)
 {
 	Scsi_Device *dp = sp->device;
-	eregs->esp_soff = dp->sync_max_offset;
-	eregs->esp_stp  = dp->sync_min_period;
-	if(esp->erev > esp100a)
-		eregs->esp_cfg3 = esp->config3[sp->target];
-	if(esp->erev == fashme)
-		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])) {
+		eregs->esp_soff = esp->prev_soff = dp->sync_max_offset;
+		eregs->esp_stp  = esp->prev_stp = dp->sync_min_period;
+		if(esp->erev > esp100a)
+			eregs->esp_cfg3 =
+				esp->prev_cfg3 =
+				esp->config3[sp->target];
+	}
 	esp->current_SC = sp;
 }
 
@@ -1827,8 +1925,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;
@@ -1836,7 +1934,7 @@
 }
 
 /* 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) || !(eregs->esp_status2 & ESP_STAT2_FEMPTY))
@@ -1878,8 +1976,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;
@@ -1890,31 +1987,223 @@
 	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);
+	/*
+	 * 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;
+
+		if(esp->erev == fashme) {
+			/* Always set the ESP count registers first. */
+			esp_setcount(eregs, hmuch, 1);
+
+			/* Get the DMA csr computed. */
+
+			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);
+
+			if (thisphase == in_datain) {
+				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+			} else {
+				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+			}
+		} else {
+			esp_setcount(eregs, hmuch, 0);
+			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 = 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, 0);
-		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);
+
+		/* 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=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 = (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++] = eregs->esp_fdata;
+
+				ESPDATA(("(%d) ", i));
+
+				/* how many to go ?? */
+				hmuch -= fifocnt;
+
+				/* break if status phase !! */
+				if(newphase == ESP_STATP) {
+					/* clear int. */
+					esp->ireg = 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++)
+					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=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 = (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 = eregs->esp_intrpt;
+					break;
+				}
+
+			}
+
+			/* clear int. */
+			esp->ireg = 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;
@@ -1966,26 +2255,43 @@
 		ecount = esp_getcount(eregs);
 	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) {
+			ecount = esp_getcount(eregs);
+			bytes_sent -= ecount;
+		}
+
+		/* Always subtract any cruft remaining in the FIFO. */
+		if(esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
+			fifocnt <<= 1;
+		if(SCptr->SCp.phase == in_dataout)
 			bytes_sent -= fifocnt;
+
+		/* I have an IBM disk which exhibits the following
+		 * behavior during writes to it.  It disconnects in
+		 * the middle of a partial transfer, the current sglist
+		 * buffer is 1024 bytes, the disk stops data transfer
+		 * at 512 bytes.
+		 *
+		 * However the FAS366 reports that 32 more bytes were
+		 * transferred than really were.  This is precisely
+		 * the size of a fully loaded FIFO in wide scsi mode.
+		 * The FIFO state recorded indicates that it is empty.
+		 *
+		 * I have no idea if this is a bug in the FAS366 chip
+		 * or a bug in the firmware on this IBM disk.  In any
+		 * event the following seems to be a good workaround.  -DaveM
+		 */
+		if (bytes_sent != esp->current_transfer_size &&
+		    SCptr->SCp.phase == in_dataout) {
+			int mask = (64 - 1);
+
+			if((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0)
+				mask >>= 1;
+
+			if (bytes_sent & mask)
+				bytes_sent -= (bytes_sent & mask);
 		}
 	} else {
 		if(!(esp->sreg & ESP_STAT_TCNT))
@@ -2021,6 +2327,8 @@
 		 * 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",
@@ -2029,6 +2337,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;
 	}
 
@@ -2037,7 +2349,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;
 	}
 
@@ -2057,7 +2369,14 @@
 			advance_sg(esp, SCptr);
 		if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
 			ESPDATA(("to more data\n"));
-			return esp_do_data(esp, eregs);
+			/*
+			 * XXX MSch:
+			 *
+			 * required for proper termination of data transfer 
+			 * phase in PIO mode
+			 */
+			if (!((esp->sreg & ESP_STAT_PMASK) == ESP_STATP))
+				return esp_do_data(esp, eregs);
 		}
 		ESPDATA(("to new phase\n"));
 		return esp_do_phase_determine(esp, eregs);
@@ -2068,10 +2387,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;
@@ -2091,9 +2448,11 @@
 		if(esp->disconnected_SC || (esp->erev == fashme))
 			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
@@ -2110,15 +2469,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));
@@ -2145,9 +2496,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;
@@ -2167,13 +2552,8 @@
 	/* 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 {
+	/* Must not flush FIFO or DVMA on HME. */
+	if(esp->erev != fashme) {
 		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 		if(esp100_reconnect_hwbug(esp, eregs))
 			return do_reset_bus;
@@ -2181,39 +2561,19 @@
 	}
 
 	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. */
+	if(esp->erev == fashme)
+		eregs->esp_busid = (SCptr->target & 0xf) |
+			(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+
+	/* 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;
@@ -2335,119 +2695,134 @@
 	}
 }
 
-/* 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->eregs->esp_status & ESP_STAT_INTR));
+		esp->esp_command[0] = eregs->esp_fdata;
+                while(!(esp->eregs->esp_status & ESP_STAT_INTR));
+                esp->esp_command[1] = eregs->esp_fdata;
+	} else {
+		if(esp->erev != fashme) {
+			esp->esp_command[0] = esp->esp_command[1] = 0xff;
+			eregs->esp_tclow = 2;
+			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(!(esp->eregs->esp_status & ESP_STAT_INTR));
-				esp->esp_command[0] = eregs->esp_fdata;
-				while(!(esp->eregs->esp_status & ESP_STAT_INTR));
-				esp->esp_command[1] = eregs->esp_fdata;
-			} else {				
-				if(esp->erev != fashme) {
-					esp->esp_command[0] = 0xff;
-					esp->esp_command[1] = 0xff;
-					eregs->esp_tclow = 2;
-					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->erev == fashme))
+		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);
+}
 
-	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_cmd(struct NCR_ESP *esp,
+			 struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_cmdbegin);
+	return esp_do_cmdbegin(esp, eregs);
+}
+
+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)
 {
@@ -2636,9 +3011,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 */
@@ -2665,8 +3039,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
@@ -2728,14 +3102,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) {
@@ -2764,8 +3138,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:
@@ -2800,9 +3186,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 */
@@ -2819,7 +3205,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;
@@ -2840,20 +3226,26 @@
 		} 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;
@@ -2908,10 +3300,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--;
 			}
@@ -2922,7 +3311,7 @@
 
 			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 > esp236) {
 				if((esp->erev == fas100a) || (esp->erev == fashme))
 					bit = ESP_CONFIG3_FAST;
 				else
@@ -2931,10 +3320,10 @@
 					esp->config3[SCptr->target] |= bit;
 				else
 					esp->config3[SCptr->target] &= ~bit;
-				eregs->esp_cfg3 = esp->config3[SCptr->target];
+				eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target];
 			}
-			eregs->esp_soff = SDptr->sync_min_period;
-			eregs->esp_stp  = SDptr->sync_max_offset;
+			eregs->esp_soff = esp->prev_soff = SDptr->sync_min_period;
+			eregs->esp_stp  = esp->prev_stp  = SDptr->sync_max_offset;
 
 			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
 				SDptr->sync_max_offset,
@@ -2949,15 +3338,15 @@
 			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
 			SDptr->sync_max_offset = 0;
 			SDptr->sync_min_period = 0;
-			eregs->esp_soff = 0;
-			eregs->esp_stp = 0;
-			if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
+			eregs->esp_soff = esp->prev_soff = 0;
+			eregs->esp_stp = esp->prev_stp = 0;
+			if(esp->erev > esp236) {
 				if((esp->erev == fas100a) || (esp->erev == fashme))
 					bit = ESP_CONFIG3_FAST;
 				else
 					bit = ESP_CONFIG3_FSCSI;
 				esp->config3[SCptr->target] &= ~bit;
-				eregs->esp_cfg3 = esp->config3[SCptr->target];
+				eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target];
 			}
 		}
 
@@ -2982,32 +3371,30 @@
 
 		esp->wnip = 0;
 		if(esp->erev != fashme) {
-			printk("esp%d: AIEEE wide msg received and not HME.\n",
-			       esp->esp_id);
+			ESPLOG(("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);
+			ESPLOG(("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);
+					ESPLOG(("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);
 			}
-			eregs->esp_cfg3 = esp->config3[SCptr->target];
+			eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target];
 
 			/* Regardless, next try for sync transfers. */
 			build_sync_nego_msg(esp, esp->sync_defp, 15);
@@ -3122,15 +3509,17 @@
 		esp_cmd(esp, eregs, (ESP_CMD_DMA | ESP_CMD_TI));
 		esp->dma_init_write(esp, esp->esp_command_dvma, i);
 	} else {
+		unsigned char tmp;
 		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-		eregs->esp_fdata = *esp->esp_scmdp++;
+		tmp = *esp->esp_scmdp++;
 		esp->esp_scmdleft--;
+		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)
@@ -3244,8 +3633,8 @@
 	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);
@@ -3294,80 +3683,62 @@
 	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;
@@ -3416,7 +3787,7 @@
 			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;
 		}
 	}
 
@@ -3439,10 +3810,12 @@
 			esp->dma_reset(esp);
 
 		what_next = do_reset_bus;
-		goto again;
+		goto state_machine;
 	}
 #endif /* CONFIG_SCSI_SUNESP */
 
+	esp->ireg = eregs->esp_intrpt;   /* Unlatch intr and stat regs */
+
 	if(esp->erev == fashme) {
 		/* This chip is really losing. */
 		ESPHME(("HME["));
@@ -3455,17 +3828,12 @@
 		if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
 		   (esp->sreg2 & ESP_STAT2_F1BYTE)) {
 			ESPHME(("fifo_workaround]"));
-			hme_fifo_hwbug_workaround(esp, eregs);
+			hme_fifo_read(esp, eregs);
 		} else {
 			ESPHME(("no_fifo_workaround]"));
 		}
 	}
 
-	esp->ireg = 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.
 	 */
@@ -3504,10 +3872,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) {
@@ -3519,13 +3884,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));
@@ -3534,7 +3898,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. */
@@ -3549,94 +3912,24 @@
 			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);
-
-			SCptr->scsi_done(SCptr);
-		}
-		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);
-
-				SCptr->scsi_done(SCptr);
-			}
-		}
-		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__
@@ -3645,14 +3938,16 @@
 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;
@@ -3671,14 +3966,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! */
 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)) {
@@ -3690,10 +3988,12 @@
 				ESPIRQ((")"));
 
 				esp->dma_ints_on(esp);
-				return;
+				goto out;
 			}
 		}
 	}
+out:
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 #endif
 
@@ -3702,7 +4002,9 @@
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct NCR_ESP *esp = dev_id;
+	unsigned long flags;
 
+	spin_lock_irqsave(&io_request_lock, flags);
 	if(esp->dma_irq_p(esp)) {
 		esp->dma_ints_off(dregs);
 
@@ -3712,6 +4014,6 @@
 
 		esp->dma_ints_on(esp);
 	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
-
 #endif
Index: linux/drivers/scsi/NCR53C9x.h
===================================================================
RCS file: /usr/src/CVS/linux/drivers/scsi/NCR53C9x.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 NCR53C9x.h
--- NCR53C9x.h	1998/12/02 09:54:21	1.1.1.1
+++ NCR53C9x.h	1998/12/09 17:18:08
@@ -13,9 +13,16 @@
 
 #include <linux/config.h>
 
+/* djweis for mac driver */
+#if defined(CONFIG_MAC)
+#define PAD_SIZE 15
+#else
+#define PAD_SIZE 3
+#endif
+
 /* Macros for debugging messages */
 
-/* #define DEBUG_ESP */
+#define DEBUG_ESP
 /* #define DEBUG_ESP_HME */
 /* #define DEBUG_ESP_DATA */
 /* #define DEBUG_ESP_QUEUE */
@@ -101,21 +108,13 @@
 #define ESPMISC(foo)
 #endif
 
-#define INTERNAL_ESP_ERROR \
-        (panic ("Internal ESP driver error in file %s, line %d\n", \
-		__FILE__, __LINE__))
-
-#define INTERNAL_ESP_ERROR_NOPANIC \
-        (printk ("Internal ESP driver error in file %s, line %d\n", \
-		 __FILE__, __LINE__))
-
 /*
  * padding for register structure
  */
 #ifdef CONFIG_JAZZ_ESP
 #define EREGS_PAD(n)
 #else
-#define EREGS_PAD(n)    unchar n[3];
+#define EREGS_PAD(n)    unchar n[PAD_SIZE];
 #endif
 
 /* The ESP SCSI controllers have their register sets in three
@@ -166,9 +165,9 @@
 
     /* The following is only found on the 53C9X series SCSI chips */
     volatile unchar esp_cfg3;   /* rw  Third configuration register   0x30  */
-                                EREGS_PAD(holep);
-    volatile unchar esp_hole;   /* hole in register map               0x34  */
-                                EREGS_PAD(thpd);    
+                                EREGS_PAD(cf4pd);
+    volatile unchar esp_cfg4;   /* rw  Fourth configuration register  0x34  */
+                                EREGS_PAD(thpd);
     /* The following is found on all chips except the NCR53C90 (ESP100) */
     volatile unchar esp_tchi;   /* rw  High bits of transfer count    0x38  */
 #define esp_uid     esp_tchi    /* ro  Unique ID code                 0x38  */
@@ -187,8 +186,9 @@
   fas100a    = 0x04,
   fast       = 0x05,
   fashme     = 0x06,
-  fas216     = 0x07,    
-  espunknown = 0x08
+  fas216     = 0x07,
+  fsc        = 0x08,  /* NCR53C94-2 */
+  espunknown = 0x09
 };
 
 /* We get one of these for each ESP probed. */
@@ -233,10 +233,31 @@
   unchar seqreg;                          /* The ESP sequence register */
   unchar sreg2;                           /* Copy of HME status2 register */
 
+  /* To save register writes to the ESP, which can be expensive, we
+   * keep track of the previous value that various registers had for
+   * the last target we connected to.  If they are the same for the
+   * current target, we skip the register writes as they are not needed.
+   */
+  unchar prev_soff, prev_stp, prev_cfg3, __cache_pad;
+
+  /* We also keep a cache of the previous FAS/HME DMA CSR register value.  */
+  unsigned int prev_hme_dmacsr;
+
   /* The HME is the biggest piece of shit I have ever seen. */
   unchar hme_fifo_workaround_buffer[16 * 2]; /* 16-bit/entry fifo for wide scsi */
   unchar hme_fifo_workaround_count;
 
+  /* For each target we keep track of save/restore data
+   * pointer information.  This needs to be updated majorly
+   * when we add support for tagged queueing.  -DaveM
+   */
+  struct esp_pointers {
+	  char *saved_ptr;
+	  struct scatterlist *saved_buffer;
+	  int saved_this_residual;
+	  int saved_buffers_residual;
+  } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
+
   /* Clock periods, frequencies, synchronization, etc. */
   unsigned int cfreq;                    /* Clock frequency in HZ */
   unsigned int cfact;                    /* Clock conversion factor */
@@ -247,7 +268,6 @@
   unsigned int sync_defp;                /* Default sync transfer period */
   unsigned int max_period;               /* longest our period can be */
   unsigned int min_period;               /* shortest period we can withstand */
-  unsigned char ccf;			 /* Clock conversion factor */
   /* For slow to medium speed input clock rates we shoot for 5mb/s,
    * but for high input clock rates we try to do 10mb/s although I
    * don't think a transfer can even run that fast with an ESP even
@@ -335,39 +355,45 @@
 #define ESP_CONFIG1_SRRDISAB  0x40             /* Disable SCSI reset reports */
 #define ESP_CONFIG1_SLCABLE   0x80             /* Enable slow cable mode */
 
-/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
-#define ESP_CONFIG2_DMAPARITY 0x01             /* enable DMA Parity (200,236) */
-#define ESP_CONFIG2_REGPARITY 0x02             /* enable reg Parity (200,236) */
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236+fsc chips */
+#define ESP_CONFIG2_DMAPARITY 0x01             /* enable DMA Parity (200,236,fsc) */
+#define ESP_CONFIG2_REGPARITY 0x02             /* enable reg Parity (200,236,fsc) */
 #define ESP_CONFIG2_BADPARITY 0x04             /* Bad parity target abort  */
 #define ESP_CONFIG2_SCSI2ENAB 0x08             /* Enable SCSI-2 features (tmode only) */
 #define ESP_CONFIG2_HI        0x10             /* High Impedance DREQ ???  */
 #define ESP_CONFIG2_HMEFENAB  0x10             /* HME features enable */
-#define ESP_CONFIG2_BCM       0x20             /* Enable byte-ctrl (236)   */
+#define ESP_CONFIG2_BCM       0x20             /* Enable byte-ctrl (236,fsc)   */
 #define ESP_CONFIG2_DISPINT   0x20             /* Disable pause irq (hme) */
-#define ESP_CONFIG2_FENAB     0x40             /* Enable features (fas100,esp216)      */
+#define ESP_CONFIG2_FENAB     0x40             /* Enable features (fas100,esp216,fsc)      */
 #define ESP_CONFIG2_SPL       0x40             /* Enable status-phase latch (esp236)   */
 #define ESP_CONFIG2_MKDONE    0x40             /* HME magic feature */
+#define ESP_CONFIG2_RFB       0x80             /* Reserve FIFO byte (fsc) */
 #define ESP_CONFIG2_HME32     0x80             /* HME 32 extended */
 #define ESP_CONFIG2_MAGIC     0xe0             /* Invalid bits... */
 
-/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme+fsc chips */
 #define ESP_CONFIG3_FCLOCK    0x01             /* FAST SCSI clock rate (esp100a/hme) */
-#define ESP_CONFIG3_TEM       0x01             /* Enable thresh-8 mode (esp/fas236)  */
+#define ESP_CONFIG3_TEM       0x01             /* Enable thresh-8 mode (esp/fas236/fsc)  */
 #define ESP_CONFIG3_FAST      0x02             /* Enable FAST SCSI     (esp100a/hme) */
-#define ESP_CONFIG3_ADMA      0x02             /* Enable alternate-dma (esp/fas236)  */
+#define ESP_CONFIG3_ADMA      0x02             /* Enable alternate-dma (esp/fas236/fsc)  */
 #define ESP_CONFIG3_TENB      0x04             /* group2 SCSI2 support (esp100a/hme) */
-#define ESP_CONFIG3_SRB       0x04             /* Save residual byte   (esp/fas236)  */
+#define ESP_CONFIG3_SRB       0x04             /* Save residual byte   (esp/fas236/fsc)  */
 #define ESP_CONFIG3_TMS       0x08             /* Three-byte msg's ok  (esp100a/hme) */
-#define ESP_CONFIG3_FCLK      0x08             /* Fast SCSI clock rate (esp/fas236)  */
+#define ESP_CONFIG3_FCLK      0x08             /* Fast SCSI clock rate (esp/fas236/fsc)  */
 #define ESP_CONFIG3_IDMSG     0x10             /* ID message checking  (esp100a/hme) */
-#define ESP_CONFIG3_FSCSI     0x10             /* Enable FAST SCSI     (esp/fas236)  */
-#define ESP_CONFIG3_GTM       0x20             /* group2 SCSI2 support (esp/fas236)  */
-#define ESP_CONFIG3_BIGID     0x20             /* SCSI-ID's are 4bits  (hme)         */
-#define ESP_CONFIG3_TBMS      0x40             /* Three-byte msg's ok  (esp/fas236)  */
+#define ESP_CONFIG3_FSCSI     0x10             /* Enable FAST SCSI     (esp/fas236/fsc)  */
+#define ESP_CONFIG3_GTM       0x20             /* group2 SCSI2 support (esp/fas236/fsc)  */
+#define ESP_CONFIG3_IDBIT3    0x20             /* Bit 3 of HME SCSI-ID (hme)         */
+#define ESP_CONFIG3_TBMS      0x40             /* Three-byte msg's ok  (esp/fas236/fsc)  */
 #define ESP_CONFIG3_EWIDE     0x40             /* Enable Wide-SCSI     (hme)         */
-#define ESP_CONFIG3_IMS       0x80             /* ID msg chk'ng        (esp/fas236)  */
+#define ESP_CONFIG3_IMS       0x80             /* ID msg chk'ng        (esp/fas236/fsc)  */
 #define ESP_CONFIG3_OBPUSH    0x80             /* Push odd-byte to dma (hme)         */
 
+/* ESP config register 4 read-write, found only on fsc chips */
+#define ESP_CONFIG4_BBTE      0x01;            /* Back-to-Back transfer enable */
+#define ESP_CONFIG4_TEST      0x02;            /* Transfer counter test mode */
+#define ESP_CONFIG4_EAN       0x04;            /* Enable Active Negotiation */
+
 /* ESP command register read-write */
 /* Group 1 commands:  These may be sent at any point in time to the ESP
  *                    chip.  None of them can generate interrupts 'cept
@@ -490,22 +516,24 @@
 #define ESP_STEP_FINI5        0x05
 #define ESP_STEP_FINI6        0x06
 #define ESP_STEP_FINI7        0x07
+#define ESP_STEP_SOM          0x08             /* Synchronous Offset Max */
 
 /* ESP chip-test register read-write */
 #define ESP_TEST_TARG         0x01             /* Target test mode */
 #define ESP_TEST_INI          0x02             /* Initiator test mode */
 #define ESP_TEST_TS           0x04             /* Tristate test mode */
 
-/* ESP unique ID register read-only, found on fas236+fas100a only */
+/* ESP unique ID register read-only, found on fas236+fas100a+fsc only */
 #define ESP_UID_F100A         0x00             /* ESP FAS100A  */
 #define ESP_UID_F236          0x02             /* ESP FAS236   */
+#define ESP_UID_FSC           0xa2             /* NCR53CF9x-2  */
 #define ESP_UID_REV           0x07             /* ESP revision */
 #define ESP_UID_FAM           0xf8             /* ESP family   */
 
 /* ESP fifo flags register read-only */
 /* Note that the following implies a 16 byte FIFO on the ESP. */
 #define ESP_FF_FBYTES         0x1f             /* Num bytes in FIFO */
-#define ESP_FF_ONOTZERO       0x20             /* offset ctr not zero (esp100) */
+#define ESP_FF_ONOTZERO       0x20             /* offset ctr not zero (esp100,fsc) */
 #define ESP_FF_SSTEP          0xe0             /* Sequence step */
 
 /* ESP clock conversion factor register write-only */
@@ -524,8 +552,11 @@
 
 #define ESP_BUS_TIMEOUT        275             /* In milli-seconds */
 #define ESP_TIMEO_CONST       8192
+#define FSC_TIMEO_CONST       7668
 #define ESP_NEG_DEFP(mhz, cfact) \
         ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define FSC_NEG_DEFP(mhz, cfact) \
+        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (7668 * (cfact)))
 #define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
 #define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
 

