Resent-Date: Thu, 3 Dec 1998 04:09:49 +0100 (MET)
Date: Wed, 02 Dec 1998 19:11:52 -0800
From: Michael Schmitz <mschmitz@lbl.gov>
Organization: Tinoco Lab, UC Berkeley
X-Accept-Language: en
To: Kars de Jong <jongk@cs.utwente.nl>
CC: linux-m68k@lists.linux-m68k.org
Subject: Re: NCR53C9x...
References: <13922.23872.54554.700982@lassi.cygnus.co.uk> <Pine.SGI.4.02.9812011222410.7637-100000@tiger.coe.missouri.edu> <13924.22641.377651.945519@lassi.cygnus.co.uk> <19981202164458.A2605@cs.utwente.nl>
Resent-From: linux-m68k@phil.uni-sb.de

This is a multi-part message in MIME format.
--------------17693FAD22255A9AE180BA0E
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Kars de Jong wrote:
> Could all of you with this chip try this patch?
> That's people with a CyberStorm, CyberStorm II, Blizzard 2060,
> Blizzard 1230/40/60, Fastlane and Macs with ESP I guess. And Sparc and Jazz
> too, but I don't expect them to be reading this list ;)

Tested on Mac Quadra 800 (after applying the attached patch for PIO
operation), 
copied a few megs across disks and it didn't freeze or act up. Good job!

I'm going to post that kernel for further tests on other Macs to see if
my 
experience was a random exception, I'll notify you if any problems show
up. 

Short note on the patch (I sure hope it's not garbled again...): 

First two hunks: handle Macs similar to one of the Sparc machines, i.e. don't
try sync negotiation because of the PIO transfer (the disk would accept
sync but the ESP would mess up, I've tried that). But do allow disconnects.
Maybe that could be merged with the Sparc clause except for the
disconnect ...

Third hunk: it seems necessary to flush the ESP fifo at least after a 
previous PIO command failed. Should not hurt on other machines, except
for performance hit (so maybe #ifdef CONFIG_SCSI_MAC_ESP). Without that bit,
the ESP would get all confused during debugging the driver. I'll try without
it now that the driver works sometime though.

Next big hunk: implement PIO mode transfers; the arch specific part of
the driver 
should return 0 in dma_can_transfer() to use PIO. In the 'normal' case of
DMA operation, this won't be used (but can be #ifdef'ed as well). The
two #if 0
sections in there can go, as can the obsolete save_flags() and restore_flags()
(interrupts are disabled on interrupt entry anyway). I'm not sure if
we'd need 
to enable interrupts here to get timeouts in case something goes wrong
with 
the target; normal disconnects are detected OK as far as I can tell.
Tunables: I've restricted the dataout fifo usage to 8, 16 should be
possible 
with the NCR53C9[46] I think. I don't have a datasheet :-(

Fifth hunk: force target to async if it messed up (from the 2.1.124 CVS diff,
I didn't see where that was handled in the new code so I included it).
DaveM 
may think it should go away, ask him.

Sixth hunk: that appears required for PIO mode transfer; the status byte
is eaten 
as data byte otherwise. I don't know if that case ever happens on DMA
machines, 
the end of DMA interrupt may prevent this. Please test carefully, if
this breaks
DMA operation we'll have to add a esp->pio_data field and use that to protect
the DMA operation.

Seventh hunk: again taken from the CVS diff, didn't hurt but may be obsolete
(never change a winning team :-)

Last hunk: fix bogus iorequest_lock (the unlock call and all other inthandlers
use io_request_lock so I decided to go with the majority) and mask off irq
with 0xff (the Mac SCSI interrupt is # 19...).

Please test this patch (on top of Kars' 53C9x patch) on Amiga (and Sparc
and Jazz 
:-) and tell me if it works ...

	Michael
--------------17693FAD22255A9AE180BA0E
Content-Type: application/gzip; x-mac-type="477A6970"; x-mac-creator="477A6970";
 name="mac-2.1.130-NCR93C9x-kars.dgz"
Content-Transfer-Encoding: x-uuencode
Content-Description: Document
Content-Disposition: inline;
 filename="mac-2.1.130-NCR93C9x-kars.dgz"

--- drivers/scsi/NCR53C9x.c.kars	Wed Dec  2 11:56:04 1998
+++ drivers/scsi/NCR53C9x.c	Wed Dec  2 12:27:56 1998
@@ -1109,7 +1109,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)
@@ -1165,6 +1165,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
@@ -1273,6 +1286,14 @@
 	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;
@@ -1953,33 +1974,219 @@
 	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) {
-		/* Always set the ESP count registers first. */
-		esp_setcount(eregs, hmuch, 1);
 
-		/* Get the DMA csr computed. */
+	/*
+	 * 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 (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(esp->erev == fashme) {
+			/* Always set the ESP count registers first. */
+			esp_setcount(eregs, hmuch, 1);
 
-		if (thisphase == in_datain) {
-			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+			/* 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. */
@@ -2118,6 +2325,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;
 	}
 
@@ -2146,7 +2357,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);
@@ -3282,9 +3500,11 @@
 		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;
@@ -3713,12 +3933,12 @@
 	int again;
 
 	/* Handle all ESP interrupts showing at this IRQ level. */
-	spin_lock_irqsave(&iorequest_lock, flags);
+	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;

--------------17693FAD22255A9AE180BA0E--

