Resent-Date: Wed, 27 Jan 1999 21:39:00 +0100 (MET)
To: linux-m68k@lists.linux-m68k.org
X-Gateway: ZCONNECT UE chessy.aworld.de [PolyNet zTOr V4.901 Serie: "light"]
Subject: Oktagon patch (NCR53C9x)
Date: Tue, 27 Jan 99  7:21:44 GMT
X-ZC-TELEFON: 02267-828226
From: OTTER@chessy.aworld.de (Andreas Schmitz)
Resent-From: linux-m68k@phil.uni-sb.de

Hi,

what follows is a driver for the Amiga-Oktagon-HA.

a) The main work was done by Carsten Pluntke.
b) The m68k-Assembler in oktagon_io.S was done by Kevin Cozens.
c) What I have done:
1) replaced esp_write/read with SETREG/GETREG (as in the native tree)
2) added a member "shift" to the NCR_ESP-struct
3) For the case of 2 Amiga-HA with different PAD_SIZES make use of the
   shift value.

The Oktagon-driver works fine. Also with the cyberstorm.c compiled in, too.

All other drivers that use NCR53C9x.c should consequently use SET/GETREG
(I have done this only for oktagon_esp.c and cyberstorm.c)

I would like people to test this driver in combination with other
HAs. Does your ESP-driver work on your system with Oktagon compiled in?

PS: Why has the outb macro arguments changed relatively to x86?

...snip...

diff -urN linux-2.2.0pre7.org/arch/m68k/config.in linux-2.2.0pre7/arch/m68k/config.in
--- linux-2.2.0pre7.org/arch/m68k/config.in	Mon Jan 18 17:10:51 1999
+++ linux-2.2.0pre7/arch/m68k/config.in	Tue Jan 26 20:40:28 1999
@@ -147,6 +147,7 @@
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
     bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI
+    bool 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI
 #    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
 #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
diff -urN linux-2.2.0pre7.org/drivers/scsi/Makefile linux-2.2.0pre7/drivers/scsi/Makefile
--- linux-2.2.0pre7.org/drivers/scsi/Makefile	Thu Jan  7 11:56:59 1999
+++ linux-2.2.0pre7/drivers/scsi/Makefile	Sat Jan 23 14:08:20 1999
@@ -18,7 +18,10 @@
 CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
 .SUFFIXES:
-.SUFFIXES: .c .o .h .a
+.SUFFIXES: .c .o .h .a .S
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ -c $< -o $*.o
 
 ifeq (${CFLAGS},)
 CFLAGS = -D__KERNEL__=1 \
@@ -254,6 +257,14 @@
 else
   ifeq ($(CONFIG_FASTLANE_SCSI),m)
   M_OBJS += NCR53C9x.o fastlane.o
+  endif
+endif
+
+ifeq ($(CONFIG_OKTAGON_SCSI),y)
+L_OBJS += NCR53C9x.o oktagon_esp.o oktagon_io.o
+else
+  ifeq ($(CONFIG_OKTAGON_SCSI),m)
+  M_OBJS += NCR53C9x.o oktagon_esp.o oktagon_io.o
   endif
 endif
 
diff -urN linux-2.2.0pre7.org/drivers/scsi/NCR53C9x.c linux-2.2.0pre7/drivers/scsi/NCR53C9x.c
--- linux-2.2.0pre7.org/drivers/scsi/NCR53C9x.c	Mon Jan 11 18:49:01 1999
+++ linux-2.2.0pre7/drivers/scsi/NCR53C9x.c	Tue Jan 26 08:23:16 1999
@@ -6,6 +6,9 @@
  *
  * Most DMA dependencies put in driver specific files by 
  * Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Set up to use GETREG/SETREG (preprocessor macros in NCR53c9x.h) by
+ * Tymm Twillman (tymm@coe.missouri.edu)
  */
 
 /* TODO:
@@ -298,10 +301,10 @@
 {
 	esp->espcmdlog[esp->espcmdent] = cmd;
 	esp->espcmdent = (esp->espcmdent + 1) & 31;
-	esp_write(eregs->esp_cmnd, cmd);
+	SETREG(eregs->esp_cmnd, cmd);
 }
 #else
-#define esp_cmd(__esp, __eregs, __cmd)	esp_write((__eregs)->esp_cmnd, (__cmd))
+#define esp_cmd(__esp, __eregs, __cmd)	SETREG((__eregs)->esp_cmnd, (__cmd))
 #endif
 
 /* How we use the various Linux SCSI data structures for operation.
@@ -384,7 +387,7 @@
 	esp_cmd(esp, eregs, ESP_CMD_RC);
 	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
 	if(esp->erev == fast)
-		esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB);
+		SETREG(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
@@ -402,7 +405,7 @@
 			"unknown!"
 		};
 			
-		version = esp_read(eregs->esp_uid);
+		version = GETREG(eregs->esp_uid);
 		family_code = (version & 0xf8) >> 3;
 		if(family_code == 0x02) {
 		        if ((version & 7) == 2)
@@ -438,28 +441,28 @@
 	}
 
 	/* Reload the configuration registers */
-	esp_write(eregs->esp_cfact, esp->cfact);
+	SETREG(eregs->esp_cfact, esp->cfact);
 	esp->prev_stp = 0;
-	esp_write(eregs->esp_stp, 0);
+	SETREG(eregs->esp_stp, 0);
 	esp->prev_soff = 0;
-	esp_write(eregs->esp_soff, 0);
-	esp_write(eregs->esp_timeo, esp->neg_defp);
+	SETREG(eregs->esp_soff, 0);
+	SETREG(eregs->esp_timeo, esp->neg_defp);
 	esp->max_period = (esp->max_period + 3)>>2;
 	esp->min_period = (esp->min_period + 3)>>2;
 
-	esp_write(eregs->esp_cfg1, esp->config1);
+	SETREG(eregs->esp_cfg1, esp->config1);
 	switch(esp->erev) {
 	case esp100:
 		/* nothing to do */
 		break;
 	case esp100a:
-		esp_write(eregs->esp_cfg2, esp->config2);
+		SETREG(eregs->esp_cfg2, esp->config2);
 		break;
 	case esp236:
 		/* Slow 236 */
-		esp_write(eregs->esp_cfg2, esp->config2);
+		SETREG(eregs->esp_cfg2, esp->config2);
 		esp->prev_cfg3 = esp->config3[0];
-		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 		break;
 	case fas366:
 		panic("esp: FAS366 support not present, please notify "
@@ -469,11 +472,11 @@
 	case fas236:
 	case fsc:
 		/* Fast ESP variants */
-		esp_write(eregs->esp_cfg2, esp->config2);
+		SETREG(eregs->esp_cfg2, esp->config2);
 		for(i=0; i<8; i++)
 			esp->config3[i] |= ESP_CONFIG3_FCLK;
 		esp->prev_cfg3 = esp->config3[0];
-		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 		if(esp->diff)
 			esp->radelay = 0;
 		else
@@ -483,18 +486,18 @@
 			FSC_NEG_DEFP(esp->cfreq,
 				     (esp->cfact == ESP_CCF_F0 ?
 				      ESP_CCF_F7 + 1 : esp->cfact));
-		esp_write(eregs->esp_timeo, esp->neg_defp);
+		SETREG(eregs->esp_timeo, esp->neg_defp);
 		/* Enable Active Negotiation if possible */
 		if((esp->erev == fsc) && !esp->diff)
-			esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN);
+			SETREG(eregs->esp_cfg4, ESP_CONFIG4_EAN);
 		break;
 	case fas100a:
 		/* Fast 100a */
-		esp_write(eregs->esp_cfg2, esp->config2);
+		SETREG(eregs->esp_cfg2, esp->config2);
 		for(i=0; i<8; i++)
 			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
 		esp->prev_cfg3 = esp->config3[0];
-		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 		esp->radelay = 32;
 		break;
 	default:
@@ -503,12 +506,12 @@
 	};
 
 	/* Eat any bitrot in the chip */
-	trash = esp_read(eregs->esp_intrpt);
+	trash = GETREG(eregs->esp_intrpt);
 	udelay(100);
 }
 
 /* This places the ESP into a known state at boot time. */
-static void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
+void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	volatile unchar trash;
 
@@ -520,13 +523,13 @@
 	esp_reset_esp(esp, eregs);
 
 	/* Reset the SCSI bus, but tell ESP not to generate an irq */
-	esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB));
+	SETREG(eregs->esp_cfg1, (GETREG(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB));
 	esp_cmd(esp, eregs, ESP_CMD_RS);
 	udelay(400);
-	esp_write(eregs->esp_cfg1, esp->config1);
+	SETREG(eregs->esp_cfg1, esp->config1);
 
 	/* Eat any bitrot in the chip and we are done... */
-	trash = esp_read(eregs->esp_intrpt);
+	trash = GETREG(eregs->esp_intrpt);
 }
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
@@ -547,6 +550,9 @@
 	esp->edev = esp_dev;
 	esp->esp_id = nesps++;
 
+	/* Set bitshift value (only used on Amiga with multiple ESPs) */
+	esp->shift=2;
+
 	/* Put into the chain of esp chips detected */
 	if(espchain) {
 		elink = espchain;
@@ -663,16 +669,16 @@
 	/* Probe the revision of this esp */
 	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
 	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
-	esp_write(eregs->esp_cfg2, esp->config2);
-	if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
+	SETREG(eregs->esp_cfg2, esp->config2);
+	if((GETREG(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
 	   (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
 		printk("NCR53C90(esp100)\n");
 		esp->erev = esp100;
 	} else {
 		esp->config2 = 0;
-		esp_write(eregs->esp_cfg2, 0);
-		esp_write(eregs->esp_cfg3, 5);
-		if(esp_read(eregs->esp_cfg3) != 5) {
+		SETREG(eregs->esp_cfg2, 0);
+		SETREG(eregs->esp_cfg3, 5);
+		if(GETREG(eregs->esp_cfg3) != 5) {
 			printk("NCR53C90A(esp100a)\n");
 			esp->erev = esp100a;
 		} else {
@@ -681,7 +687,7 @@
 			for(target=0; target<8; target++)
 				esp->config3[target] = 0;
 			esp->prev_cfg3 = 0;
-			esp_write(eregs->esp_cfg3, 0);
+			SETREG(eregs->esp_cfg3, 0);
 			if(ccf > ESP_CCF_F5) {
 				printk("NCR53C9XF(espfast)\n");
 				esp->erev = fast;
@@ -1178,18 +1184,18 @@
 		for(i = 0; i < SCptr->cmd_len; i++)
 			*cmdp++ = SCptr->cmnd[i];
 
-	esp_write(eregs->esp_busid, (target & 7));
+	SETREG(eregs->esp_busid, (target & 7));
 	if (esp->prev_soff != SDptr->sync_max_offset ||
 	    esp->prev_stp  != SDptr->sync_min_period ||
 	    (esp->erev > esp100a &&
 	     esp->prev_cfg3 != esp->config3[target])) {
 		esp->prev_soff = SDptr->sync_max_offset;
-		esp_write(eregs->esp_soff, esp->prev_soff);
+		SETREG(eregs->esp_soff, esp->prev_soff);
 		esp->prev_stp = SDptr->sync_min_period;
-		esp_write(eregs->esp_stp, esp->prev_stp); 
+		SETREG(eregs->esp_stp, esp->prev_stp); 
 		if(esp->erev > esp100a) {
 			esp->prev_cfg3 = esp->config3[target];
-			esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+			SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 		}
 	}
 	i = (cmdp - esp->esp_command);
@@ -1207,15 +1213,15 @@
 		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 
 		for(;j<i;j++)
-			esp_write(eregs->esp_fdata, esp->esp_command[j]);
+			SETREG(eregs->esp_fdata, esp->esp_command[j]);
 		the_esp_command &= ~ESP_CMD_DMA;
 
 		/* Tell ESP to "go". */
 		esp_cmd(esp, eregs, the_esp_command);
 	} else {
 		/* Set up the ESP counters */
-		esp_write(eregs->esp_tclow, i);
-		esp_write(eregs->esp_tcmed, 0);
+		SETREG(eregs->esp_tclow, i);
+		SETREG(eregs->esp_tcmed, 0);
 		esp->dma_init_write(esp, esp->esp_command_dvma, i);
 
 		/* Tell ESP to "go". */
@@ -1301,8 +1307,8 @@
 	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
 		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
 	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
-		esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep),
-		esp_read(eregs->esp_intrpt)));
+		esp->esp_id, GETREG(eregs->esp_status), GETREG(eregs->esp_sstep),
+		GETREG(eregs->esp_intrpt)));
 #ifdef DEBUG_ESP_CMDS
 	printk("esp%d: last ESP cmds [", esp->esp_id);
 	i = (esp->espcmdent - 1) & 31;
@@ -1523,8 +1529,8 @@
 
 	if(esp->dma_irq_p(esp)) {
 		/* Yes, we are able to save an interrupt. */
-		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
-		esp->ireg = esp_read(eregs->esp_intrpt);
+		esp->sreg = (GETREG(eregs->esp_status) & ~(ESP_STAT_INTR));
+		esp->ireg = GETREG(eregs->esp_intrpt);
 		if(!(esp->ireg & ESP_INTR_SR))
 			return 0;
 		else
@@ -1545,8 +1551,8 @@
 		return 0;
 	if(esp->dma_irq_p(esp)) {
 		/* Yes, we are able to save an interrupt. */
-		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
-		esp->ireg = esp_read(eregs->esp_intrpt);
+		esp->sreg = (GETREG(eregs->esp_status) & ~(ESP_STAT_INTR));
+		esp->ireg = GETREG(eregs->esp_intrpt);
 		if(!(esp->ireg & ESP_INTR_SR))
 			return 0;
 		else
@@ -1559,18 +1565,18 @@
 
 /* Misc. esp helper macros. */
 #define esp_setcount(__eregs, __cnt) \
-	esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \
-	esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))
+	SETREG((__eregs)->esp_tclow, ((__cnt) & 0xff)); \
+	SETREG((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))
 
 #define esp_getcount(__eregs) \
-	((esp_read((__eregs)->esp_tclow)&0xff) | \
-	 ((esp_read((__eregs)->esp_tcmed)&0xff) << 8))
+	((GETREG((__eregs)->esp_tclow)&0xff) | \
+	 ((GETREG((__eregs)->esp_tcmed)&0xff) << 8))
 
 #define fcount(__esp, __eregs) \
-	(esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES)
+	(GETREG((__eregs)->esp_fflags) & ESP_FF_FBYTES)
 
 #define fnzero(__esp, __eregs) \
-	(esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO)
+	(GETREG((__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
@@ -1596,7 +1602,7 @@
 {
 	/* Do not touch this piece of code. */
 	if((!(esp->erev == esp100)) ||
-	   (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) &&
+	   (!(sreg_datainp((esp->sreg = GETREG(eregs->esp_status))) && !fifocnt) &&
 	    !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
 		if(sp->SCp.phase == in_dataout)
 			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
@@ -1624,7 +1630,7 @@
 
 	if(esp->erev != esp100)
 		return 0;
-	junk = esp_read(eregs->esp_intrpt);
+	junk = GETREG(eregs->esp_intrpt);
 
 	if(junk & ESP_INTR_SR)
 		return 1;
@@ -1640,7 +1646,7 @@
 
 	if(2 != fcount(esp, eregs))
 		return -1;
-	it = esp_read(eregs->esp_fdata);
+	it = GETREG(eregs->esp_fdata);
 	if(!(it & me))
 		return -1;
 	it &= ~me;
@@ -1660,7 +1666,7 @@
 
 	if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
 		return -1;
-	lun = esp_read(eregs->esp_fdata);
+	lun = GETREG(eregs->esp_fdata);
 
 	/* Yes, you read this correctly.  We report lun of zero
 	 * if we see parity error.  ESP reports parity error for
@@ -1690,12 +1696,12 @@
 	   (esp->erev > esp100a &&
 	    esp->prev_cfg3 != esp->config3[sp->target])) {
 		esp->prev_soff = dp->sync_max_offset;
-		esp_write(eregs->esp_soff, esp->prev_soff);
+		SETREG(eregs->esp_soff, esp->prev_soff);
 		esp->prev_stp = dp->sync_min_period;
-		esp_write(eregs->esp_stp, esp->prev_stp);
+		SETREG(eregs->esp_stp, esp->prev_stp);
 		if(esp->erev > esp100a) {
 			esp->prev_cfg3 = esp->config3[sp->target];
-			esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+			SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 		} 
 	}
 	esp->current_SC = sp;
@@ -1794,7 +1800,7 @@
 		int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */
 		int fifocnt = 0;
 
-		oldphase = eregs->esp_status & ESP_STAT_PMASK;
+		oldphase = GETREG(eregs->esp_status) & ESP_STAT_PMASK;
 
 		/*
 		 * polled transfer; ugly, can we make this happen in a DRQ 
@@ -1833,7 +1839,7 @@
 
 				/* wait for data */
 				timeout = 1000000;
-				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+				while (!((esp->sreg=GETREG(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
 					udelay(2);
 				if (timeout == 0)
 					printk("DRQ datain timeout! \n");
@@ -1841,7 +1847,7 @@
 				newphase = esp->sreg & ESP_STAT_PMASK;
 
 				/* see how much we got ... */
-				fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+				fifocnt = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES);
 
 				if (!fifocnt)
 					fifo_stuck++;
@@ -1852,7 +1858,7 @@
 
 				/* read fifo */
 				for(j=0;j<fifocnt;j++)
-					SCptr->SCp.ptr[i++] = esp_read(eregs->esp_fdata);
+					SCptr->SCp.ptr[i++] = GETREG(eregs->esp_fdata);
 
 				ESPDATA(("(%d) ", i));
 
@@ -1862,7 +1868,7 @@
 				/* break if status phase !! */
 				if(newphase == ESP_STATP) {
 					/* clear int. */
-					esp->ireg = esp_read(eregs->esp_intrpt);
+					esp->ireg = GETREG(eregs->esp_intrpt);
 					break;
 				}
 			} else {
@@ -1874,7 +1880,7 @@
 
 				/* fill fifo */
 				for(j=0;j<this_count;j++)
-					esp_write(eregs->esp_fdata, SCptr->SCp.ptr[i++]);
+					SETREG(eregs->esp_fdata, SCptr->SCp.ptr[i++]);
 
 				/* how many left if this goes out ?? */
 				hmuch -= this_count;
@@ -1884,7 +1890,7 @@
 
 				/* wait for 'got it' */
 				timeout = 1000000;
-				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+				while (!((esp->sreg=GETREG(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
 					udelay(2);
 				if (timeout == 0)
 					printk("DRQ dataout timeout!  \n");
@@ -1892,7 +1898,7 @@
 				newphase = esp->sreg & ESP_STAT_PMASK;
 
 				/* need to check how much was sent ?? */
-				fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+				fifocnt = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES);
 
 				ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase));
 
@@ -1901,14 +1907,14 @@
 				/* break if status phase !! */
 				if(newphase == ESP_STATP) {
 					/* clear int. */
-					esp->ireg = esp_read(eregs->esp_intrpt);
+					esp->ireg = GETREG(eregs->esp_intrpt);
 					break;
 				}
 
 			}
 
 			/* clear int. */
-			esp->ireg = esp_read(eregs->esp_intrpt);
+			esp->ireg = GETREG(eregs->esp_intrpt);
 
 			ESPDATA(("ir %x ... ", esp->ireg));
 
@@ -2001,7 +2007,7 @@
 	}	
 
 	/* Check for partial transfers and other horrible events. */
-	fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+	fifocnt = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES);
 	ecount = esp_getcount(eregs);
 	if(esp->fas_premature_intr_workaround)
 		ecount -= 0x40;
@@ -2441,14 +2447,14 @@
 	if(esp->do_pio_cmds) {
 		esp_advance_phase(esp->current_SC, in_status);
 		esp_cmd(esp, eregs, thecmd);
-		while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
-		esp->esp_command[0] = esp_read(eregs->esp_fdata);
-                while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
-                esp->esp_command[1] = esp_read(eregs->esp_fdata);
+		while(!(GETREG(esp->eregs->esp_status) & ESP_STAT_INTR));
+		esp->esp_command[0] = GETREG(eregs->esp_fdata);
+                while(!(GETREG(esp->eregs->esp_status) & ESP_STAT_INTR));
+                esp->esp_command[1] = GETREG(eregs->esp_fdata);
 	} else {
 		esp->esp_command[0] = esp->esp_command[1] = 0xff;
-		esp_write(eregs->esp_tclow, 2);
-		esp_write(eregs->esp_tcmed, 0);
+		SETREG(eregs->esp_tclow, 2);
+		SETREG(eregs->esp_tcmed, 0);
 		esp->dma_init_read(esp, esp->esp_command_dvma, 2);
 		thecmd |= ESP_CMD_DMA;
 		esp_cmd(esp, eregs, thecmd);
@@ -2564,7 +2570,7 @@
 	Scsi_Device *SDptr = SCptr->device;
 	int cmd_bytes_sent, fcnt;
 
-	fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+	fcnt = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES);
 	cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt);
 	if(esp->dma_invalidate)
 		esp->dma_invalidate(esp);
@@ -2796,9 +2802,9 @@
 	esp_print_seqreg(esp->seqreg);
 	printk("\n");
 	printk("esp%d: New -- ", esp->esp_id);
-	esp->sreg = esp_read(eregs->esp_status);
-	esp->seqreg = esp_read(eregs->esp_sstep);
-	esp->ireg = esp_read(eregs->esp_intrpt);
+	esp->sreg = GETREG(eregs->esp_status);
+	esp->seqreg = GETREG(eregs->esp_sstep);
+	esp->ireg = GETREG(eregs->esp_intrpt);
 	esp_print_ireg(esp->ireg);
 	printk(" ");
 	esp_print_statreg(esp->sreg);
@@ -3043,12 +3049,12 @@
 				else
 					esp->config3[SCptr->target] &= ~bit;
 				esp->prev_cfg3 = esp->config3[SCptr->target];
-				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+				SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 			}
 			esp->prev_soff = SDptr->sync_min_period;
-			esp_write(eregs->esp_soff, esp->prev_soff);
+			SETREG(eregs->esp_soff, esp->prev_soff);
 			esp->prev_stp = SDptr->sync_max_offset;
-			esp_write(eregs->esp_stp, esp->prev_stp);
+			SETREG(eregs->esp_stp, esp->prev_stp);
 
 			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
 				SDptr->sync_max_offset,
@@ -3064,9 +3070,9 @@
 			SDptr->sync_max_offset = 0;
 			SDptr->sync_min_period = 0;
 			esp->prev_soff = 0;
-			esp_write(eregs->esp_soff, 0);
+			SETREG(eregs->esp_soff, 0);
 			esp->prev_stp = 0;
-			esp_write(eregs->esp_stp, 0);
+			SETREG(eregs->esp_stp, 0);
 			if(esp->erev > esp236) {
 				if(esp->erev == fas100a)
 					bit = ESP_CONFIG3_FAST;
@@ -3074,7 +3080,7 @@
 					bit = ESP_CONFIG3_FSCSI;
 				esp->config3[SCptr->target] &= ~bit;
 				esp->prev_cfg3 = esp->config3[SCptr->target];
-				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+				SETREG(eregs->esp_cfg3, esp->prev_cfg3);
 			}
 		}
 
@@ -3118,17 +3124,17 @@
 			if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
 				message_out = MSG_PARITY_ERROR;
 				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
-			} else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) {
+			} else if((it = (GETREG(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) {
 				/* We certainly dropped the ball somewhere. */
 				message_out = INITIATOR_ERROR;
 				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 			} else if(!esp->msgin_len) {
-				it = esp_read(eregs->esp_fdata);
+				it = GETREG(eregs->esp_fdata);
 				esp_advance_phase(SCptr, in_msgincont);
 			} else {
 				/* it is ok and we want it */
 				it = esp->cur_msgin[esp->msgin_ctr] =
-					esp_read(eregs->esp_fdata);
+					GETREG(eregs->esp_fdata);
 				esp->msgin_ctr++;
 			}
 		} else {
@@ -3169,7 +3175,7 @@
 		esp_advance_phase(SCptr, in_the_dark);
 		esp->msgin_len = 0;
 	}
-	esp->sreg = esp_read(eregs->esp_status);
+	esp->sreg = GETREG(eregs->esp_status);
 	esp->sreg &= ~(ESP_STAT_INTR);
 	if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
 		esp_cmd(esp, eregs, ESP_CMD_MOK);
@@ -3188,7 +3194,7 @@
 	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 	tmp = *esp->esp_scmdp++;
 	esp->esp_scmdleft--;
-	esp_write(eregs->esp_fdata, tmp);
+	SETREG(eregs->esp_fdata, tmp);
 	esp_cmd(esp, eregs, ESP_CMD_TI);
 	return do_intr_end;
 }
@@ -3210,14 +3216,14 @@
 	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 	switch(esp->msgout_len) {
 	case 1:
-		esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+		SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
 		esp_cmd(esp, eregs, ESP_CMD_TI);
 		break;
 
 	case 2:
 		if(esp->do_pio_cmds){
-			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			esp->esp_command[0] = esp->cur_msgout[0];
@@ -3231,10 +3237,10 @@
 	case 4:
 		esp->snip = 1;
 		if(esp->do_pio_cmds){
-			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[2]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[3]);
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			esp->esp_command[0] = esp->cur_msgout[0];
@@ -3250,11 +3256,11 @@
 	case 5:
 		esp->snip = 1;
 		if(esp->do_pio_cmds){
-			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
-			esp_write(eregs->esp_fdata, esp->cur_msgout[4]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[1]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[2]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[3]);
+			SETREG(eregs->esp_fdata, esp->cur_msgout[4]);
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			esp->esp_command[0] = esp->cur_msgout[0];
@@ -3272,7 +3278,7 @@
 		/* whoops */
 		ESPMISC(("bogus msgout sending NOP\n"));
 		esp->cur_msgout[0] = NOP;
-		esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+		SETREG(eregs->esp_fdata, esp->cur_msgout[0]);
 		esp->msgout_len = 1;
 		esp_cmd(esp, eregs, ESP_CMD_TI);
 		break;
@@ -3392,10 +3398,10 @@
 		esp->dma_irq_entry(esp);
 
 	/* Check for errors. */
-	esp->sreg = esp_read(eregs->esp_status);
+	esp->sreg = GETREG(eregs->esp_status);
 	esp->sreg &= (~ESP_STAT_INTR);
-	esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS);
-	esp->ireg = eregs->esp_intrpt;   /* Unlatch intr and stat regs */
+	esp->seqreg = (GETREG(eregs->esp_sstep) & ESP_STEP_VBITS);
+	esp->ireg = GETREG(eregs->esp_intrpt);   /* Unlatch intr and stat regs */
 	ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
 		esp->sreg, esp->seqreg, esp->ireg));
 	if(esp->sreg & (ESP_STAT_SPAM)) {
diff -urN linux-2.2.0pre7.org/drivers/scsi/NCR53C9x.h linux-2.2.0pre7/drivers/scsi/NCR53C9x.h
--- linux-2.2.0pre7.org/drivers/scsi/NCR53C9x.h	Mon Jan 11 18:49:03 1999
+++ linux-2.2.0pre7/drivers/scsi/NCR53C9x.h	Tue Jan 26 20:27:29 1999
@@ -6,6 +6,8 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
  * Generalization by Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org)
  */
 
 #ifndef NCR53C9X_H
@@ -20,6 +22,22 @@
 #define PAD_SIZE 3
 #endif
 
+/* Handle multiple Hostadaptors on Amiga
+ * generally PAD_SIZE = 3
+ * but one exception: Oktagon (PAD_SIZE = 1) */
+#if defined(CONFIG_AMIGA)
+#ifndef CONFIG_OKTAGON_SCSI
+#define PAD_SIZE 3
+#else
+#if defined(CONFIG_BLZ1230_SCSI) || defined(CONFIG_BLZ2060_SCSI) || defined (CONFIG_CYBERSTORM_SCSI) || defined(CONFIG_CYBERSTORMII_SCSI) || defined(CONFIG_FASTLANE_SCSI)
+#undef PAD_SIZE
+#define MULTIPLE_PAD_SIZES
+#else
+#define PAD_SIZE 1
+#endif
+#endif
+#endif
+
 /* Macros for debugging messages */
 
 #define DEBUG_ESP
@@ -107,8 +125,10 @@
 #ifdef CONFIG_JAZZ_ESP
 #define EREGS_PAD(n)
 #else
+#ifndef MULTIPLE_PAD_SIZES
 #define EREGS_PAD(n)    unchar n[PAD_SIZE];
 #endif
+#endif
 
 /* The ESP SCSI controllers have their register sets in three
  * "classes":
@@ -126,8 +146,10 @@
 
 #ifndef __i386__
 
-#define esp_write(__reg, __val) ((__reg) = (__val))
-#define esp_read(__reg) (__reg)
+#ifndef MULTIPLE_PAD_SIZES
+
+#define SETREG(reg, val) ((reg) = (val))
+#define GETREG(reg) (reg)
 
 struct ESP_regs {
                                 /* Access    Description              Offset */
@@ -172,10 +194,47 @@
     volatile unchar esp_fgrnd;  /* rw  Data base for fifo             0x3c  */
 };
 
+#else /* multiple PAD_SIZES */
+
+#define SETREG(reg, val) (*(reg) = (val))
+#define GETREG(reg) (*(reg))
+
+struct ESP_regs {
+    unsigned char io_addr[64]; /* dummy */
+                                               /* Access    Description              Offset */
+#define esp_tclow   io_addr                    /* rw  Low bits of the transfer count 0x00   */
+#define esp_tcmed   io_addr + (1<<(esp->shift))  /* rw  Mid bits of the transfer count 0x04   */
+#define esp_fdata   io_addr + (2<<(esp->shift))  /* rw  FIFO data bits                 0x08   */
+#define esp_cmnd    io_addr + (3<<(esp->shift))  /* rw  SCSI command bits              0x0c   */
+#define esp_status  io_addr + (4<<(esp->shift))  /* ro  ESP status register            0x10   */
+#define esp_busid   esp_status                 /* wo  Bus ID for select/reselect     0x10   */
+#define esp_intrpt  io_addr + (5<<(esp->shift))  /* ro  Kind of interrupt              0x14   */
+#define esp_timeo   esp_intrpt                 /* wo  Timeout value for select/resel 0x14   */
+#define esp_sstep   io_addr + (6<<(esp->shift))  /* ro  Sequence step register         0x18   */
+#define esp_stp     esp_sstep                  /* wo  Transfer period per sync       0x18   */
+#define esp_fflags  io_addr + (7<<(esp->shift))  /* ro  Bits of current FIFO info      0x1c   */
+#define esp_soff    esp_fflags                 /* wo  Sync offset                    0x1c   */
+#define esp_cfg1    io_addr + (8<<(esp->shift))  /* rw  First configuration register   0x20   */
+#define esp_cfact   io_addr + (9<<(esp->shift))  /* wo  Clock conversion factor        0x24   */
+#define esp_ctest   io_addr + (10<<(esp->shift)) /* wo  Chip test register             0x28   */
+#define esp_cfg2    io_addr + (11<<(esp->shift)) /* rw  Second configuration register  0x2c   */
+
+    /* The following is only found on the 53C9X series SCSI chips */
+#define esp_cfg3    io_addr + (12<<(esp->shift)) /* rw  Third configuration register   0x30  */
+#define esp_cfg4    io_addr + (13<<(esp->shift)) /* rw  Fourth configuration register  0x34  */
+
+    /* The following is found on all chips except the NCR53C90 (ESP100) */
+#define esp_tchi    io_addr + (14<<(esp->shift)) /* rw  High bits of transfer count    0x38  */
+#define esp_uid     esp_tchi                   /* ro  Unique ID code                 0x38  */
+#define esp_fgrnd   io_addr + (15<<(esp->shift)) /* rw  Data base for fifo             0x3c  */
+};
+
+#endif
+
 #else /* !defined __i386__ */
 
-#define esp_write(__reg, __val) outb((__reg), (__val))
-#define esp_read(__reg) inb((__reg))
+#define SETREG(reg, val) outb((reg), (val))
+#define GETREG(reg) inb((reg))
 
 struct ESP_regs {
     unsigned int io_addr;
@@ -338,6 +397,9 @@
   unchar resetting_bus;
 
   unchar do_pio_cmds;		/* Do command transfer with pio */
+
+  /* How much bits do we have to shift the registers */
+  unsigned char shift;
 
   /* Functions handling DMA
    */ 
diff -urN linux-2.2.0pre7.org/drivers/scsi/cyberstorm.c linux-2.2.0pre7/drivers/scsi/cyberstorm.c
--- linux-2.2.0pre7.org/drivers/scsi/cyberstorm.c	Mon Jan 11 18:49:05 1999
+++ linux-2.2.0pre7/drivers/scsi/cyberstorm.c	Mon Jan 25 20:51:24 1999
@@ -265,7 +265,7 @@
 static int dma_irq_p(struct NCR_ESP *esp)
 {
 	/* It's important to check the DMA IRQ bit in the correct way! */
-	return ((esp->eregs->esp_status & ESP_STAT_INTR) &&
+	return ((GETREG(esp->eregs->esp_status) & ESP_STAT_INTR) &&
 		((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) &
 		 CYBER_DMA_HNDL_INTR));
 }
diff -urN linux-2.2.0pre7.org/drivers/scsi/hosts.c linux-2.2.0pre7/drivers/scsi/hosts.c
--- linux-2.2.0pre7.org/drivers/scsi/hosts.c	Mon Jan 18 17:11:01 1999
+++ linux-2.2.0pre7/drivers/scsi/hosts.c	Sat Jan 23 14:11:25 1999
@@ -95,6 +95,10 @@
 #include "fastlane.h"
 #endif
 
+#ifdef CONFIG_OKTAGON_SCSI
+#include "oktagon_esp.h"
+#endif
+
 #ifdef CONFIG_ATARI_SCSI
 #include "atari_scsi.h"
 #endif
@@ -389,6 +393,9 @@
 #endif
 #ifdef CONFIG_FASTLANE_SCSI
 	SCSI_FASTLANE,
+#endif
+#ifdef CONFIG_OKTAGON_SCSI
+	SCSI_OKTAGON_ESP,
 #endif
 #endif
 
diff -urN linux-2.2.0pre7.org/drivers/scsi/oktagon_esp.c linux-2.2.0pre7/drivers/scsi/oktagon_esp.c
--- linux-2.2.0pre7.org/drivers/scsi/oktagon_esp.c	Thu Jan  1 01:00:00 1970
+++ linux-2.2.0pre7/drivers/scsi/oktagon_esp.c	Tue Jan 26 20:21:42 1999
@@ -0,0 +1,591 @@
+/*
+ * Oktagon_esp.c -- Driver for bsc Oktagon
+ *
+ * Written by Carsten Pluntke 1998
+ *
+ * Based on cyber_esp.c
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS)
+#define USE_BOTTOM_HALF
+#endif
+
+#define __KERNEL_SYSCALLS__
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/reboot.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "NCR53C9x.h"
+#include "oktagon_esp.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include <asm/pgtable.h>
+
+#ifdef USE_BOTTOM_HALF
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#endif
+
+#include <linux/unistd.h>
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static void dma_irq_exit(struct NCR_ESP *esp);
+static void dma_invalidate(struct NCR_ESP *esp);
+
+static void dma_mmu_get_scsi_one(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_mmu_get_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_mmu_release_scsi_one(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_mmu_release_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_advance_sg(Scsi_Cmnd *);
+static int  oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x);
+
+void esp_bootup_reset(struct NCR_ESP *esp,struct ESP_regs *eregs);
+
+#ifdef USE_BOTTOM_HALF
+static void dma_commit(void *opaque);
+
+long oktag_to_io(long *paddr, long *addr, long len);
+long oktag_from_io(long *addr, long *paddr, long len);
+
+static struct tq_struct tq_fake_dma = { NULL, 0, dma_commit, NULL };
+
+#define DMA_MAXTRANSFER 0x8000
+
+#else
+
+/*
+ * No bottom half. Use transfer directly from IRQ. Find a narrow path
+ * between too much IRQ overhead and clogging the IRQ for too long.
+ */
+
+#define DMA_MAXTRANSFER 0x1000
+
+#endif
+
+static struct notifier_block oktagon_notifier = { 
+	oktagon_notify_reboot,
+	NULL,
+	0
+};
+
+static long *paddress;
+static long *address;
+static long len;
+static long dma_on;
+static int direction;
+static struct NCR_ESP *current_esp;
+
+
+volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are trasfered to the ESP chip
+				 * via PIO.
+				 */
+
+/***************************************************************** Detection */
+int oktagon_oktag_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	const struct ConfigDev *esp_dev;
+	int key;
+	unsigned long address;
+	struct ESP_regs *eregs;
+
+	if((key = zorro_find(ZORRO_PROD_BSC_OKTAGON_2008, 0, 0))){
+		esp_dev = zorro_get_board(key);
+
+		/*
+		 * It is a SCSI controller.
+		 * Hardwire Host adapter to SCSI ID 7
+		 */
+		
+		address = (unsigned long)ZTWO_VADDR(esp_dev->cd_BoardAddr);
+		eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
+
+		/* This line was 5 lines lower */
+		esp = esp_allocate(tpnt, (void *) esp_dev);
+
+		/* we have to shift the registers only one bit for oktagon */
+		esp->shift=1;
+
+		SETREG(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
+		udelay(5);
+		if(GETREG(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
+			return 0; /* Bail out if address did not hold data */
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = &dma_invalidate;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = &dma_irq_exit;
+		esp->dma_led_on = &dma_led_on;
+		esp->dma_led_off = &dma_led_off;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+		esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+		esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one;
+		esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl;
+		esp->dma_advance_sg = &dma_advance_sg;
+
+		/* SCSI chip speed */
+		/* Looking at the quartz of the SCSI board... */
+		esp->cfreq = 25000000;
+
+		/* The DMA registers on the CyberStorm are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		esp->dregs = (void *)(address + OKTAGON_DMA_ADDR);
+
+		paddress = (long *) esp->dregs;
+
+		/* ESP register base */
+		esp->eregs = eregs;
+		
+		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
+
+		/* Yes, the virtual address. See below. */
+		esp->esp_command_dvma = (__u32) cmd_buffer;
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		request_irq(IRQ_AMIGA_PORTS, esp_intr, 0, "BSC Oktagon SCSI", esp_intr);
+
+		/* Figure out our scsi ID on the bus */
+		esp->scsi_id = 7;
+		
+		/* Check for differential SCSI-bus */
+		/* What is this stuff? */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		zorro_config_board(key, 0);
+		printk("ESP_Oktagon Driver 1.1"
+#ifdef USE_BOTTOM_HALF
+		       " [BOTTOM_HALF]"
+#else
+		       " [IRQ]"
+#endif
+		       " registered.\n");
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use);
+		esps_running = esps_in_use;
+		current_esp = esp;
+		register_reboot_notifier(&oktagon_notifier);
+		return esps_in_use;
+	}
+	return 0;
+}
+
+
+/*
+ * On certain configurations the SCSI equipment gets confused on reboot,
+ * so we have to reset it then.
+ */
+
+static int
+oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+  struct NCR_ESP *esp;
+  
+  if((code == SYS_DOWN || code == SYS_HALT) && (esp = current_esp))
+   {
+    esp_bootup_reset(esp,esp->eregs);
+    udelay(500); /* Settle time. Maybe unneccessary. */
+   }
+  return NOTIFY_DONE;
+}
+    
+
+	
+#ifdef USE_BOTTOM_HALF
+
+
+/*
+ * The bsc Oktagon controller has no real DMA, so we have to do the 'DMA
+ * transfer' in the interrupt (Yikes!) or use a bottom half to not to clutter
+ * IRQ's for longer-than-good.
+ *
+ * FIXME
+ * BIG PROBLEM: 'len' is usually the buffer length, not the expected length
+ * of the data. So DMA may finish prematurely, further reads lead to
+ * 'machine check' on APUS systems (don't know about m68k systems, AmigaOS
+ * deliberately ignores the bus faults) and a normal copy-loop can't
+ * be exited prematurely just at the right moment by the dma_invalidate IRQ.
+ * So do it the hard way, write an own copier in assembler and
+ * catch the exception.
+ *                                     -- Carsten
+ */
+ 
+ 
+static void dma_commit(void *opaque)
+{
+    long wait,len2,pos;
+    struct NCR_ESP *esp;
+
+    ESPDATA(("Transfer: %ld bytes, Address 0x%08lX, Direction: %d\n",
+         len,(long) address,direction));
+    dma_ints_off(current_esp);
+
+    pos = 0;
+    wait = 1;
+    if(direction) /* write? (memory to device) */
+     {
+      while(len > 0)
+       {
+        len2 = oktag_to_io(paddress, address+pos, len);
+	if(!len2)
+	 {
+	  if(wait > 1000)
+	   {
+	    printk("Expedited DMA exit (writing) %ld\n",len);
+	    break;
+	   }
+	  mdelay(wait);
+	  wait *= 2;
+	 }
+	pos += len2;
+	len -= len2*sizeof(long);
+       }
+     } else {
+      while(len > 0)
+       {
+        len2 = oktag_from_io(address+pos, paddress, len);
+	if(!len2)
+	 {
+	  if(wait > 1000)
+	   {
+	    printk("Expedited DMA exit (reading) %ld\n",len);
+	    break;
+	   }
+	  mdelay(wait);
+	  wait *= 2;
+	 }
+	pos += len2;
+	len -= len2*sizeof(long);
+       }
+     }
+
+    /* to make esp->shift work */
+    esp=current_esp;
+
+#if 0
+    len2 = (GETREG(current_esp->eregs->esp_tclow) & 0xff) |
+           ((GETREG(current_esp->eregs->esp_tcmed) & 0xff) << 8);
+
+    /*
+     * Uh uh. If you see this, len and transfer count registers were out of
+     * sync. That means really serious trouble.
+     */
+
+    if(len2)
+      printk("Eeeek!! Transfer count still %ld!\n",len2);
+#endif
+
+    /*
+     * Normally we just need to exit and wait for the interrupt to come.
+     * But at least one device (my Microtek ScanMaker 630) regularly mis-
+     * calculates the bytes it should send which is really ugly because
+     * it locks up the SCSI bus if not accounted for.
+     */
+
+    if(!(GETREG(current_esp->eregs->esp_status) & ESP_STAT_INTR))
+     {
+      long len = 100;
+      long trash[10];
+
+      /*
+       * Interrupt bit was not set. Either the device is just plain lazy
+       * so we give it a 10 ms chance or...
+       */
+      while(len-- && (!(GETREG(current_esp->eregs->esp_status) & ESP_STAT_INTR)))
+        udelay(100);
+
+
+      if(!(GETREG(current_esp->eregs->esp_status) & ESP_STAT_INTR))
+       {
+        /*
+	 * So we think that the transfer count is out of sync. Since we
+	 * have all we want we are happy and can ditch the trash.
+	 */
+	 
+        len = DMA_MAXTRANSFER;
+
+        while(len-- && (!(GETREG(current_esp->eregs->esp_status) & ESP_STAT_INTR)))
+          oktag_from_io(trash,paddress,2);
+
+        if(!(GETREG(current_esp->eregs->esp_status) & ESP_STAT_INTR))
+         {
+          /*
+           * Things really have gone wrong. If we leave the system in that
+           * state, the SCSI bus is locked forever. I hope that this will
+           * turn the system in a more or less running state.
+           */
+          printk("Device is bolixed, trying bus reset...\n");
+	  esp_bootup_reset(current_esp,current_esp->eregs);
+         }
+       }
+     }
+
+    ESPDATA(("Transfer_finale: do_data_finale should come\n"));
+
+    len = 0;
+    dma_on = 0;
+    dma_ints_on(current_esp);
+}
+
+#endif
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > DMA_MAXTRANSFER)
+		sz = DMA_MAXTRANSFER;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+}
+
+/*
+ * What the f$@& is this?
+ *
+ * Some SCSI devices (like my Microtek ScanMaker 630 scanner) want to transfer
+ * more data than requested. How much? Dunno. So ditch the bogus data into
+ * the sink, hoping the device will advance to the next phase sooner or later.
+ *
+ *                         -- Carsten
+ */
+
+static long oktag_eva_buffer[16]; /* The data sink */
+
+static void oktag_check_dma(void)
+{
+  struct NCR_ESP *esp;
+
+  esp=current_esp;
+  if(!len)
+   {
+    address = oktag_eva_buffer;
+    len = 2;
+    /* esp_do_data sets them to zero like len */
+    SETREG(current_esp->eregs->esp_tclow,2);
+    SETREG(current_esp->eregs->esp_tcmed,0);
+   }
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	/* Zorro is noncached, everything else done using processor. */
+	/* cache_clear(addr, length); */
+	
+	if(dma_on)
+	  panic("dma_init_read while dma process is initialized/running!\n");
+	direction = 0;
+	address = (long *) vaddress;
+	current_esp = esp;
+	len = length;
+	oktag_check_dma();
+        dma_on = 1;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	/* cache_push(addr, length); */
+
+	if(dma_on)
+	  panic("dma_init_write while dma process is initialized/running!\n");
+	direction = 1;
+	address = (long *) vaddress;
+	current_esp = esp;
+	len = length;
+	oktag_check_dma();
+	dma_on = 1;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	/* It's important to check the DMA IRQ bit in the correct way! */
+	return (GETREG(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+/*
+ * IRQ entry when DMA transfer is ready to be started
+ */
+
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+#ifdef USE_BOTTOM_HALF
+	if(dma_on)
+	 {
+	  tq_fake_dma.sync = 0;
+	  queue_task(&tq_fake_dma,&tq_immediate);
+	  mark_bh(IMMEDIATE_BH);
+	 }
+#else
+	while(len && !dma_irq_p(esp))
+	 {
+	  if(direction)
+	    *paddress = *address++;
+	   else
+	    *address++ = *paddress;
+	  len -= (sizeof(long));
+	 }
+	len = 0;
+        dma_on = 0;
+#endif
+}
+
+/*
+ * IRQ entry when DMA has just finished
+ */
+
+static void dma_invalidate(struct NCR_ESP *esp)
+{
+}
+
+/*
+ * Since the processor does the data transfer we have to use the custom
+ * mmu interface to pass the virtual address, not the physical.
+ */
+
+void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+        sp->SCp.have_data_in = (int) sp->SCp.ptr =
+                sp->request_buffer;
+}
+
+void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+        sp->SCp.ptr = 
+                sp->SCp.buffer->address;
+}
+
+void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+}
+
+void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+}
+
+void dma_advance_sg(Scsi_Cmnd *sp)
+{
+  sp->SCp.ptr = sp->SCp.buffer->address;
+}
+
+#ifdef MODULE
+
+#define HOSTS_C
+
+Scsi_Host_Template driver_template = SCSI_OKTAGON_ESP;
+
+#include "scsi_module.c"
+
+#endif
+
+int oktagon_oktag_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	free_irq(IRQ_AMIGA_PORTS, oktag_esp_intr);
+	unregister_reboot_notifier(&oktagon_notifier);
+#endif
+	return 1;
+}
diff -urN linux-2.2.0pre7.org/drivers/scsi/oktagon_esp.h linux-2.2.0pre7/drivers/scsi/oktagon_esp.h
--- linux-2.2.0pre7.org/drivers/scsi/oktagon_esp.h	Thu Jan  1 01:00:00 1970
+++ linux-2.2.0pre7/drivers/scsi/oktagon_esp.h	Sat Jan 23 14:56:49 1999
@@ -0,0 +1,56 @@
+/* oktagon_esp.h: Defines and structures for the CyberStorm SCSI Mk II driver.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cs.auc.dk)
+ */
+
+#include "NCR53C9x.h"
+
+#ifndef OKTAGON_ESP_H
+#define OKTAGON_ESP_H
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define OKTAGON_ESP_ADDR 0x03000
+#define OKTAGON_DMA_ADDR 0x01000
+
+
+/* The CyberStorm II DMA interface */
+struct oktagon_dma_registers {
+	volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x000] */
+#define ctrl_reg  cond_reg			/* DMA control (wo)  [0x000] */
+	unsigned char dmapad4[0x3f];
+	volatile unsigned char dma_addr0;	/* DMA address (MSB) [0x040] */
+	unsigned char dmapad1[3];
+	volatile unsigned char dma_addr1;	/* DMA address       [0x044] */
+	unsigned char dmapad2[3];
+	volatile unsigned char dma_addr2;	/* DMA address       [0x048] */
+	unsigned char dmapad3[3];
+	volatile unsigned char dma_addr3;	/* DMA address (LSB) [0x04c] */
+};
+
+extern int oktagon_oktag_esp_detect(struct SHT *);
+extern int oktagon_oktag_esp_release(struct Scsi_Host *);
+extern const char *oktag_esp_info(struct Scsi_Host *);
+extern int oktag_esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int oktag_esp_command(Scsi_Cmnd *);
+extern int oktag_esp_abort(Scsi_Cmnd *);
+extern int oktag_esp_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_OKTAGON_ESP {        \
+   proc_dir:            &proc_scsi_esp,          \
+   proc_info:           NULL,                          \
+   name:                "BSC Oktagon SCSI",            \
+   detect:              oktagon_oktag_esp_detect,      \
+   release:             oktagon_oktag_esp_release,     \
+   queuecommand:        esp_queue,               \
+   abort:               esp_abort,               \
+   reset:               esp_reset,               \
+   can_queue:           8,                             \
+   this_id:             7,                             \
+   sg_tablesize:        SG_ALL,                        \
+   cmd_per_lun:         1,                             \
+   use_clustering:      DISABLE_CLUSTERING }
+
+#endif /* OKTAGON_ESP_H */
+
diff -urN linux-2.2.0pre7.org/drivers/scsi/oktagon_io.S linux-2.2.0pre7/drivers/scsi/oktagon_io.S
--- linux-2.2.0pre7.org/drivers/scsi/oktagon_io.S	Thu Jan  1 01:00:00 1970
+++ linux-2.2.0pre7/drivers/scsi/oktagon_io.S	Sat Jan  9 16:17:25 1999
@@ -0,0 +1,194 @@
+/* -*- mode: asm -*-
+ * Due to problems while transferring data I've put these routines as assembly
+ * code.
+ * Since I'm no PPC assembler guru, the code is just the assembler version of
+
+int oktag_to_io(long *paddr,long *addr,long len)
+{
+  long *addr2 = addr;
+  for(len=(len+sizeof(long)-1)/sizeof(long);len--;)
+    *paddr = *addr2++;
+  return addr2 - addr;
+}
+
+int oktag_from_io(long *addr,long *paddr,long len)
+{
+  long *addr2 = addr;
+  for(len=(len+sizeof(long)-1)/sizeof(long);len--;)
+    *addr2++ = *paddr;
+  return addr2 - addr;
+}
+
+ * assembled using gcc -O2 -S, with two exception catch points where data
+ * is moved to/from the IO register.
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_APUS
+
+	.file	"oktagon_io.c"
+
+gcc2_compiled.:
+/*
+	.section ".text"
+*/
+	.align 2
+	.globl oktag_to_io
+	.type	 oktag_to_io,@function
+oktag_to_io:
+	addi 5,5,3
+	srwi 5,5,2
+	cmpwi 1,5,0
+	mr 9,3
+	mr 3,4
+	addi 5,5,-1
+	bc 12,6,.L3
+.L5:
+	cmpwi 1,5,0
+	lwz 0,0(3)
+	addi 3,3,4
+	addi 5,5,-1
+exp1:	stw 0,0(9)
+	bc 4,6,.L5
+.L3:
+ret1:	subf 3,4,3
+	srawi 3,3,2
+	blr
+.Lfe1:
+	.size	 oktag_to_io,.Lfe1-oktag_to_io
+	.align 2
+	.globl oktag_from_io
+	.type	 oktag_from_io,@function
+oktag_from_io:
+	addi 5,5,3
+	srwi 5,5,2
+	cmpwi 1,5,0
+	mr 9,3
+	addi 5,5,-1
+	bc 12,6,.L9
+.L11:
+	cmpwi 1,5,0
+exp2:	lwz 0,0(4)
+	addi 5,5,-1
+	stw 0,0(3)
+	addi 3,3,4
+	bc 4,6,.L11
+.L9:
+ret2:	subf 3,9,3
+	srawi 3,3,2
+	blr
+.Lfe2:
+	.size	 oktag_from_io,.Lfe2-oktag_from_io
+	.ident	"GCC: (GNU) egcs-2.90.29 980515 (egcs-1.0.3 release)"
+
+/*
+ * Exception table.
+ * Second longword shows where to jump when an exception at the addr the first
+ * longword is pointing to is caught.
+ */
+
+.section __ex_table,"a"
+	.align	2
+oktagon_except:
+	.long	exp1,ret1
+	.long	exp2,ret2
+
+#endif
+
+/*
+The code which follows is for 680x0 based assembler and is meant for
+Linux/m68k. It was created by cross compiling the code using the
+instructions given above. I then added the four labels used in the
+exception handler table at the bottom of this file.
+- Kevin <kcozens@interlog.com>
+*/
+
+#ifdef CONFIG_AMIGA
+
+	.file	"oktagon_io.c"
+	.version	"01.01"
+gcc2_compiled.:
+.text
+	.align 	2
+.globl oktag_to_io
+	.type	 oktag_to_io,@function
+oktag_to_io:
+	link.w %a6,#0
+	move.l %d2,-(%sp)
+	move.l 8(%a6),%a1
+	move.l 12(%a6),%d1
+	move.l %d1,%a0
+	move.l 16(%a6),%d0
+	addq.l #3,%d0
+	lsr.l #2,%d0
+	subq.l #1,%d0
+	moveq.l #-1,%d2
+	cmp.l %d0,%d2
+	jbeq .L3
+.L5:
+exp1:
+	move.l (%a0)+,(%a1)
+	dbra %d0,.L5
+	clr.w %d0
+	subq.l #1,%d0
+	jbcc .L5
+.L3:
+ret1:
+	move.l %a0,%d0
+	sub.l %d1,%d0
+	asr.l #2,%d0
+	move.l -4(%a6),%d2
+	unlk %a6
+	rts
+
+.Lfe1:
+	.size	 oktag_to_io,.Lfe1-oktag_to_io
+	.align 	2
+.globl oktag_from_io
+	.type	 oktag_from_io,@function
+oktag_from_io:
+	link.w %a6,#0
+	move.l %d2,-(%sp)
+	move.l 8(%a6),%d1
+	move.l 12(%a6),%a1
+	move.l %d1,%a0
+	move.l 16(%a6),%d0
+	addq.l #3,%d0
+	lsr.l #2,%d0
+	subq.l #1,%d0
+	moveq.l #-1,%d2
+	cmp.l %d0,%d2
+	jbeq .L9
+.L11:
+exp2:
+	move.l (%a1),(%a0)+
+	dbra %d0,.L11
+	clr.w %d0
+	subq.l #1,%d0
+	jbcc .L11
+.L9:
+ret2:
+	move.l %a0,%d0
+	sub.l %d1,%d0
+	asr.l #2,%d0
+	move.l -4(%a6),%d2
+	unlk %a6
+	rts
+.Lfe2:
+	.size	 oktag_from_io,.Lfe2-oktag_from_io
+	.ident	"GCC: (GNU) 2.7.2.1"
+
+/*
+ * Exception table.
+ * Second longword shows where to jump when an exception at the addr the first
+ * longword is pointing to is caught.
+ */
+
+.section __ex_table,"a"
+	.align	2
+oktagon_except:
+	.long	exp1,ret1
+	.long	exp2,ret2
+
+#endif
size 13683

- Andreas - Voice:02267/828226 - Computer:Amiga 4000/40 - Auto:Polo 45PS -
email to Uni: schmitz@theorie.physik.uni-wuppertal.de
http://www.theorie.physik.uni-wuppertal.de/~schmitz

