diff -u --recursive --new-file v2.1.39/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.39/linux/Documentation/Configure.help	Tue May 13 22:40:59 1997
+++ linux/Documentation/Configure.help	Sun May 18 16:38:34 1997
@@ -4650,6 +4650,40 @@
   also controls the radio tuner on this card, however this is not
   yet supported in this software.
 
+Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
+CONFIG_AEDSP16
+  Answer Y if you have a Gallant's Audio Excel DSP 16 card. This card
+  emulate an SBPro or a Microsoft Sound System card.
+  You must select one of the Sound Blaster or Microsoft Sound System
+  drivers before select this menu item.
+  Read the drivers/sound/lowlevel/README.aedsp16 file and the head of
+  drivers/sound/lowlevel/aedsp16.c to have more informations about
+  this driver and its configuration.
+
+  If you are changing the card configuration, please, undefine all
+  the old Audio Excel parameters because leaving it defined while
+  selecting the alternate emulation, may screw up your .config file.
+
+  !!!NOTE!!!
+  The driver supports Audio Excel DSP 16 but not the III version of
+  this card. Read drivers/sound/lowlevel/Readme.aedsp16 if you want
+  to know something more on how to use the III version with this sound
+  driver.
+
+SC-6600 based audio cards (new Audio Excel DSP 16)
+CONFIG_SC6600
+  The SC6600 is the new version of DSP mounted on the Audio Excel DSP 16
+  cards. Check the FCC ID of your audio card and answer Y if you have an
+  SC6600 DSP.
+
+Audio Excel DSP 16 (MSS emulation)
+CONFIG_AEDSP16_MSS
+  Answer Y if you want your audio card emulate Microsoft Sound System.
+
+Audio Excel DSP 16 (SBPro emulation)
+CONFIG_AEDSP16_SBPRO
+  Answer Y if you want your audio card emulate Sound Blaster Pro.
+
 Kernel profiling support
 CONFIG_PROFILE
   This is for kernel hackers who want to know how much time the kernel
diff -u --recursive --new-file v2.1.39/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.1.39/linux/Documentation/devices.tex	Tue May 13 22:40:59 1997
+++ linux/Documentation/devices.tex	Tue May 20 15:00:01 1997
@@ -47,7 +47,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: May 1, 1997}
+\date{Last revised: May 20, 1997}
 \maketitle
 %
 \noindent
@@ -212,7 +212,8 @@
 \major{81}{}{char }{Brooktree Bt848 frame grabbers}
 \major{82}{}{char }{WiNRADiO communications receiver card}
 \major{83}{}{char }{Teletext/videotext interfaces}
-\major{84}{--119}{}{Unallocated}
+\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
+\major{85}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
 \major{128}{--239}{}{Unallocated}
 \major{240}{--254}{}{Local/experimental use}
@@ -492,6 +493,7 @@
 	\minor{6}{/dev/sunmouse}{Sun mouse}
 	\minor{7}{/dev/amigamouse1}{Second Amiga mouse}
 	\minor{8}{/dev/smouse}{Simple serial mouse driver}
+	\minor{9}{/dev/pc110pad}{IBM PC-110 digitizer pad}
 	\minor{128}{/dev/beep}{Fancy beep device}
 	\minor{129}{/dev/modreq}{Kernel module load request}
 	\minor{130}{/dev/watchdog}{Watchdog timer port}
@@ -1418,7 +1420,13 @@
 on {\url http://home.pages.de/~videotext/\/}.
 
 \begin{devicelist}
-\major{84}{--119}{}{Unallocated}
+\major{84}{}{char }{Ikon 1011[57] Versatec Greensheet Interface}
+	\minor{0}{/dev/ihcp0}{First Greensheet port}
+	\minor{1}{/dev/ihcp1}{Second Greensheet port}
+\end{devicelist}
+
+\begin{devicelist}
+\major{85}{--119}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
diff -u --recursive --new-file v2.1.39/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.1.39/linux/Documentation/devices.txt	Tue May 13 22:40:59 1997
+++ linux/Documentation/devices.txt	Tue May 20 15:00:01 1997
@@ -1,7 +1,7 @@
 		       LINUX ALLOCATED DEVICES
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		      Last revised: May 1, 1997
+		      Last revised: May 20, 1997
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -273,6 +273,7 @@
 		  6 = /dev/sunmouse	Sun mouse
 		  7 = /dev/amigamouse1	Second Amiga mouse
 		  8 = /dev/smouse	Simple serial mouse driver
+		  9 = /dev/pc110pad	IBM PC-110 digitizer pad
 		128 = /dev/beep		Fancy beep device
 		129 = /dev/modreq	Kernel module load request
 		130 = /dev/watchdog	Watchdog timer port
@@ -997,7 +998,11 @@
                 Devices for the driver contained in the VideoteXt package.
                 More information on http://home.pages.de/~videotext/
 
- 84-119		UNALLOCATED
+ 84 char	Ikon 1011[57] Versatec Greensheet Interface
+                  0 = /dev/ihcp0        First Greensheet port
+                  1 = /dev/ihcp1        Second Greensheet port
+
+ 85-119		UNALLOCATED
 
 120-127		LOCAL/EXPERIMENTAL USE
 
diff -u --recursive --new-file v2.1.39/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.39/linux/MAINTAINERS	Tue May 13 22:41:00 1997
+++ linux/MAINTAINERS	Sun May 18 17:10:37 1997
@@ -234,6 +234,13 @@
 L:	isdn4linux@hub-wue.franken.de
 S:	Maintained
 
+M68K:
+P:	Jes Sorensen
+M:	Jes.Sorensen@cern.ch
+W:	http://www.clark.net/pub/lawrencc/linux/index.html
+L:	linux-m68k@phil.uni-sb.de
+S:	Maintained
+
 MODULE SUPPORT [GENERAL], KERNELD
 P:	Bjorn Ekwall
 M:	bj0rn@blox.se
diff -u --recursive --new-file v2.1.39/linux/Makefile linux/Makefile
--- v2.1.39/linux/Makefile	Mon May 19 12:57:38 1997
+++ linux/Makefile	Wed May 21 18:50:15 1997
@@ -1,8 +1,8 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 39
+SUBLEVEL = 40
 
-ARCH := $(shell uname -m | sed s/i.86/i386/)
+ARCH := $(shell uname -m | sed s/i.86/i386/ | sed s/sun4u/sparc64/)
 
 #
 # For SMP kernels, set this. We don't want to have this in the config file
diff -u --recursive --new-file v2.1.39/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.1.39/linux/arch/alpha/kernel/ptrace.c	Tue May 13 22:41:00 1997
+++ linux/arch/alpha/kernel/ptrace.c	Sun May 18 18:05:13 1997
@@ -161,7 +161,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -171,7 +171,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -181,7 +181,7 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
@@ -212,7 +212,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -222,7 +222,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir, addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -232,12 +232,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		do_wp_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
diff -u --recursive --new-file v2.1.39/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.39/linux/arch/i386/kernel/i386_ksyms.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/kernel/i386_ksyms.c	Sun May 18 17:10:37 1997
@@ -19,6 +19,11 @@
 extern int dump_fpu(elf_fpregset_t *);
 extern void __lock_kernel(void);
 
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
+extern struct drive_info_struct drive_info;
+EXPORT_SYMBOL(drive_info);
+#endif
+
 /* platform dependent support */
 EXPORT_SYMBOL(EISA_bus);
 EXPORT_SYMBOL(MCA_bus);
diff -u --recursive --new-file v2.1.39/linux/arch/i386/lib/locks.S linux/arch/i386/lib/locks.S
--- v2.1.39/linux/arch/i386/lib/locks.S	Tue May 13 22:41:01 1997
+++ linux/arch/i386/lib/locks.S	Tue May 20 09:23:15 1997
@@ -14,6 +14,7 @@
 	lock
 	btsl	$0, SYMBOL_NAME(kernel_flag)
 	jnc	3f
+	sti
 2:
 	btl	%dl, SYMBOL_NAME(smp_invalidate_needed)
 	jnc	0f
@@ -27,6 +28,7 @@
 0:
 	btl	$0, SYMBOL_NAME(kernel_flag)
 	jc	2b
+	cli
 	jmp	1b
 
 3:
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.1.39/linux/arch/m68k/Makefile	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/Makefile	Sun May 18 17:10:37 1997
@@ -26,7 +26,7 @@
 
 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
 
-CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce
+CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
 
 ifdef CONFIG_OPTIMIZE_040
 CFLAGS := $(CFLAGS) -m68040
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/amiga/retz3fb.c linux/arch/m68k/amiga/retz3fb.c
--- v2.1.39/linux/arch/m68k/amiga/retz3fb.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/amiga/retz3fb.c	Sun May 18 17:10:37 1997
@@ -32,6 +32,7 @@
 #include <linux/fb.h>
 #include <linux/zorro.h>
 #include <linux/init.h>
+
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v2.1.39/linux/arch/m68k/atari/ataints.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/ataints.c	Sun May 18 17:10:37 1997
@@ -163,15 +163,19 @@
 
 #define	MFP_MK_BASE	"0xfa13"
 
-/* This must agree with head.S.  */
-#define ORIG_DO "0x20"
-#define FORMATVEC "0x2E"
-#define SR "0x28"
+/* This must agree with entry.S.  */
+#define ORIG_DO "0x24"
+#define FORMATVEC "0x32"
+#define SR "0x2C"
 #define SAVE_ALL				\
 	"clrl	%%sp@-;"    /* stk_adj */	\
 	"pea	-1:w;"	    /* orig d0 = -1 */	\
 	"movel	%%d0,%%sp@-;" /* d0 */		\
-	"moveml	%%d1-%%d5/%%a0-%%a1,%%sp@-"
+	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-"
+#define GET_CURRENT(tmp) \
+	"movel	%%sp,"#tmp";" \
+	"andw	#-8192,"#tmp";" \
+	"movel	"#tmp",%%a2"
 
 #define	BUILD_SLOW_IRQ(n)						   \
 asmlinkage void IRQ_NAME(n);						   \
@@ -181,6 +185,7 @@
 SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t"			   \
 "	addql	#1,"SYMBOL_NAME_STR(local_irq_count)"\n"		   \
 	SAVE_ALL "\n"							   \
+	GET_CURRENT(%%d0) "\n"						   \
 "	andb	#~(1<<(" #n "&7)),"	/* mask this interrupt */	   \
 	"("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n"	   \
 "	bfextu	%%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \
@@ -283,7 +288,8 @@
 	orw 	#0x700,%%sr		/* disable all interrupts */
 "SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t
 	addql	#1,"SYMBOL_NAME_STR(local_irq_count)"\n"
-	SAVE_ALL "
+	SAVE_ALL "\n"
+	GET_CURRENT(%%d0) "
 	/* get vector number from stack frame and convert to source */
 	bfextu	%%sp@(" FORMATVEC "){#4,#10},%%d0
 	subw	#(0x40-8),%%d0
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S
--- v2.1.39/linux/arch/m68k/fpsp040/skeleton.S	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/fpsp040/skeleton.S	Sun May 18 17:10:37 1997
@@ -51,13 +51,23 @@
  
 	.include "fpsp.h"
 
-LOFF_ORIG_D0	= 0x20
+/*
+ * This has to match entry.S
+ */
+LOFF_ORIG_D0	= 0x24
+
+#define curptr a2
 
 #define SAVE_ALL				\
 	clrl	%sp@-;     /* stk_adj */	\
 	movel	%d0,%sp@-; /* orig d0 */	\
 	movel	%d0,%sp@-; /* d0 */		\
-	moveml	%d1-%d5/%a0-%a1,%sp@-
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;
+
+#define GET_CURRENT(tmp) \
+	movel	%sp,tmp; \
+	andw	&-8192,tmp; \
+	movel	tmp,%curptr;
 
 	|xref	b1238_fix
 
@@ -81,6 +91,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -175,6 +186,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -204,6 +216,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -233,6 +246,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -258,6 +272,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -283,6 +298,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -314,6 +330,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -338,6 +355,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -363,6 +381,7 @@
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -419,6 +438,7 @@
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
+	GET_CURRENT(%d0)
 	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
 
 
@@ -497,7 +517,7 @@
 	movel	%d0,-(%sp)
 	movel	%a1,-(%sp)
 	movel	%a0,-(%sp)
-	jsr		copyin
+	jsr	copyin
 	addw	#12,%sp
 	movel	(%sp)+,%d1
 	rts
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- v2.1.39/linux/arch/m68k/ifpsp060/iskeleton.S	Wed Sep 25 00:47:39 1996
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Sun May 18 17:10:37 1997
@@ -36,13 +36,23 @@
 
 #include <linux/linkage.h>
 
-LOFF_ORIG_D0	= 0x20
+/*
+ * This has to match entry.S
+ */
+LOFF_ORIG_D0	= 0x24
+
+#define curptr a2
 
 #define SAVE_ALL				\
 	clrl	%sp@-;     /* stk_adj */	\
 	movel	%d0,%sp@-; /* orig d0 */	\
 	movel	%d0,%sp@-; /* d0 */		\
-	moveml	%d1-%d5/%a0-%a1,%sp@-
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;
+
+#define GET_CURRENT(tmp) \
+	movel	%sp,tmp; \
+	andw	&-8192,tmp; \
+	movel	tmp,%curptr;
 
 |################################
 | (1) EXAMPLE CALL-OUTS 	#
@@ -85,6 +95,7 @@
 	SAVE_ALL
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
+	GET_CURRENT(%d0)
 	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
 
 |
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.1.39/linux/arch/m68k/kernel/entry.S	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/entry.S	Sun May 18 17:10:37 1997
@@ -33,12 +33,13 @@
  *	10(sp) - d5
  *	14(sp) - a0
  *	18(sp) - a1
- *	1C(sp) - d0
- *	20(sp) - orig_d0
- *	24(sp) - stack adjustment
- *	28(sp) - sr
- *	2A(sp) - pc
- *	2E(sp) - format & vector
+ *	1C(sp) - a2
+ *	20(sp) - d0
+ *	24(sp) - orig_d0
+ *	28(sp) - stack adjustment
+ *	2C(sp) - sr
+ *	2E(sp) - pc
+ *	32(sp) - format & vector
  */
 
 /*
@@ -47,6 +48,11 @@
  *               number 0 in the 'current_set' list.
  */
 
+/*
+ * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
+ *		     the whole kernel.
+ */
+
 #include <linux/sys.h>
 #include <linux/config.h>
 #include <linux/linkage.h>
@@ -57,6 +63,8 @@
 .globl SYMBOL_NAME(kgdb_registers)
 #endif
 
+#define curptr a2
+
 LENOSYS = 38
 
 /*
@@ -80,15 +88,15 @@
 #define	MAX_NOINT_IPL	0
 #endif /* machine compilation types */ 
 
-LD0		= 0x1C
-LORIG_D0	= 0x20
-LSR		= 0x28
-LFORMATVEC	= 0x2E
+LD0		= 0x20
+LORIG_D0	= 0x24
+LSR		= 0x2C
+LFORMATVEC	= 0x32
 
 /*
  * This defines the normal kernel pt-regs layout.
  *
- * regs are a2-a6 and d6-d7 preserved by C code
+ * regs a3-a6 and d6-d7 are preserved by C code
  * the kernel doesn't mess with usp unless it needs to
  */
 #ifndef CONFIG_KGDB
@@ -96,7 +104,7 @@
 	clrl	%sp@-;    /* stk_adj */	\
 	movel	%d0,%sp@-; /* orig d0 */	\
 	movel	%d0,%sp@-; /* d0 */	\
-	moveml	%d1-%d5/%a0-%a1,%sp@-
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;
 #else
 /* Need to save the "missing" registers for kgdb...
  */
@@ -104,25 +112,30 @@
 	clrl	%sp@-;    /* stk_adj */				\
 	movel	%d0,%sp@-; /* orig d0 */			\
 	movel	%d0,%sp@-; /* d0 */				\
-	moveml	%d1-%d5/%a0-%a1,%sp@-;				\
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;			\
 	moveml	%d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6;	\
-	moveml	%a2-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A2
+	moveml	%a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3;
 #endif
 
 #define RESTORE_ALL			\
-	moveml	%sp@+,%a0-%a1/%d1-%d5;	\
+	moveml	%sp@+,%a0-%a1/%curptr/%d1-%d5;	\
 	movel	%sp@+,%d0;		\
 	addql	#4,%sp;	 /* orig d0 */	\
 	addl	%sp@+,%sp; /* stk adj */	\
 	rte
 
-#define SWITCH_STACK_SIZE (7*4+4)	/* includes return address */
+#define SWITCH_STACK_SIZE (6*4+4)	/* includes return address */
 
 #define SAVE_SWITCH_STACK \
-	moveml	%a2-%a6/%d6-%d7,%sp@-
+	moveml	%a3-%a6/%d6-%d7,%sp@-
 
 #define RESTORE_SWITCH_STACK \
-	moveml	%sp@+,%a2-%a6/%d6-%d7
+	moveml	%sp@+,%a3-%a6/%d6-%d7
+
+#define GET_CURRENT(tmp) \
+	movel	%sp,tmp; \
+	andw	&-8192,tmp; \
+	movel	tmp,%curptr;
 
 .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
 .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
@@ -139,6 +152,7 @@
 					| signifies that the stack frame
 					| is NOT for syscall
 
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(buserr_c)
 	addql	#4,%sp
@@ -150,6 +164,7 @@
 	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
 	addql	#4,%sp
@@ -190,6 +205,7 @@
 	SAVE_ALL
 	movel	%d0,%d2
 
+	GET_CURRENT(%d0)
 	| save top of frame
 	pea	%sp@
 	jbsr	SYMBOL_NAME(set_esp0)
@@ -197,8 +213,7 @@
 
 	cmpl	#NR_syscalls,%d2
 	jcc	badsys
-	movel	SYMBOL_NAME(current_set),%a0
-	btst	#5,%a0@(LTASK_FLAGS+3)	| PF_TRACESYS
+	btst	#5,%curptr@(LTASK_FLAGS+3)	| PF_TRACESYS
 	jne	do_trace
 	jbsr	@(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
 	movel	%d0,%sp@(LD0)		| save the return value
@@ -208,24 +223,23 @@
 	bnes	2f			| if so, skip resched, signals
 	tstl	SYMBOL_NAME(need_resched)
 	jne	SYMBOL_NAME(reschedule)
-	movel	SYMBOL_NAME(current_set),%a0
-	cmpl	#SYMBOL_NAME(task),%a0	| task[0] cannot have signals
+	cmpl	#SYMBOL_NAME(task),%curptr	| task[0] cannot have signals
 	jeq	2f
-	bclr	#5,%a0@(LTASK_FLAGS+1)	| check for delayed trace
+	bclr	#5,%curptr@(LTASK_FLAGS+1)	| check for delayed trace
 	jne	do_delayed_trace
 5:
-	tstl	%a0@(LTASK_STATE)	| state
+	tstl	%curptr@(LTASK_STATE)	| state
 	jne	SYMBOL_NAME(reschedule)
-	tstl	%a0@(LTASK_COUNTER)	| counter
+	tstl	%curptr@(LTASK_COUNTER)	| counter
 	jeq	SYMBOL_NAME(reschedule)
 
-	movel	%a0@(LTASK_BLOCKED),%d0
+	movel	%curptr@(LTASK_BLOCKED),%d0
 	movel	%d0,%d1			| save blocked in d1 for sig handling
 	notl	%d0
-	btst	#4,%a0@(LTASK_FLAGS+3)	| PF_PTRACED
+	btst	#4,%curptr@(LTASK_FLAGS+3)	| PF_PTRACED
 	jeq	1f
 	moveq	#-1,%d0			| let the debugger see all signals
-1:	andl	%a0@(LTASK_SIGNAL),%d0
+1:	andl	%curptr@(LTASK_SIGNAL),%d0
 	jne	Lsignal_return
 2:	RESTORE_ALL
 
@@ -248,7 +262,6 @@
 	jbsr	SYMBOL_NAME(send_sig)
 	addql	#8,%sp
 	addql	#4,%sp
-	movel	SYMBOL_NAME(current_set),%a0
 	jra	5b
 
 /*
@@ -260,6 +273,7 @@
 	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
 					| signifies that the stack frame
 					| is NOT for syscall
+	GET_CURRENT(%d0)
 	addql	#1,SYMBOL_NAME(local_irq_count)
 					|  put exception # in d0
 	bfextu %sp@(LFORMATVEC){#4,#10},%d0
@@ -270,28 +284,31 @@
 	addql	#8,%sp			|  pop parameters off stack
 
 SYMBOL_NAME_LABEL(ret_from_interrupt)
-	/* check if we need to do software interrupts */
-	movel	SYMBOL_NAME(local_irq_count),%d1
-	subql	#1,%d1
-	jne	4f
-#if 0
-		bfextu  %sp@(LSR){#5,#3},%d0    | Check for nested interrupt.
+	subql	#1,SYMBOL_NAME(local_irq_count)
+	jeq	1f
+2:	
+	RESTORE_ALL
+1:
+#if 1
+	bfextu  %sp@(LSR){#5,#3},%d0    | Check for nested interrupt.
 #if MAX_NOINT_IPL > 0
 	cmpiw	#MAX_NOINT_IPL,%d0
 #endif
-	jhi	4f
+	jhi	2b
 #endif
+	/* Let the rest run with interrupts allowed.  This is safe since
+	   the kernel never uses a non-standard ipl and this is the outer
+	   level interrupt. */
+	andw	#ALLOWINT,%sr
+
+	/* check if we need to do software interrupts */
+	
 	movel	SYMBOL_NAME(bh_active),%d0
 	andl	SYMBOL_NAME(bh_mask),%d0
-	jeq	3f
+	jeq	SYMBOL_NAME(ret_from_exception)
 
-	jbsr	SYMBOL_NAME(do_bottom_half)
-3:	
-	clrl	SYMBOL_NAME(local_irq_count)
-	jra	SYMBOL_NAME(ret_from_exception)
-4:
-	movel	%d1,SYMBOL_NAME(local_irq_count)
-	RESTORE_ALL
+	pea	SYMBOL_NAME(ret_from_exception)
+	jra	SYMBOL_NAME(do_bottom_half)
 
 
 /* Handler for uninitialized and spurious interrupts */
@@ -398,7 +415,7 @@
 3:
 
 	/* get pointer to tss struct (a1 contains new task) */
-	movel	%a1,SYMBOL_NAME(current_set)
+	movel	%a1,%curptr
 	addl	%d1,%a1
 
 	/* Skip address space switching if they are the same. */
@@ -419,7 +436,7 @@
 	movec	%cacr,%d0
 	oriw	#LFLUSH_I_AND_D,%d0
 	movec	%d0,%cacr
-	
+
 	/* switch the root pointer */
 	pmove	%a1@(LTSS_CRP),%crp
 #endif
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.1.39/linux/arch/m68k/kernel/head.S	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/head.S	Sun May 18 17:10:37 1997
@@ -223,17 +223,9 @@
 	movel	%d0,%a0@		/* save cache mode for page tables */
 
 /*
- * raise interrupt level with MASTER bit set, copy isp to msp (if not 68060)
+ * raise interrupt level
  */
-#ifdef FROM_PL9
-	movew	#0x3700,%sr
-	is_060(1f)
-	movec	%isp,%d0
-	movel	%d0,%sp
-1:
-#else
 	movew	#0x2700,%sr
-#endif
 
 /*
    If running on an Atari, determine the I/O base of the
@@ -896,8 +888,10 @@
 
 /*
  * Setup initial stack pointer
+ * We need to get current loaded up with our first task...
  */
-	lea	SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp
+	lea	SYMBOL_NAME(init_task_union),%a2
+	lea	8192(%a2),%sp
 
 /* jump to the kernel start */
 	putr()
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.39/linux/arch/m68k/kernel/process.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/process.c	Sun May 18 17:10:37 1997
@@ -30,6 +30,7 @@
 #include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/setup.h>
+#include <asm/pgtable.h>
 
 /*
  * Initial task structure. Make this a per-architecture thing,
@@ -37,15 +38,15 @@
  * alignment requirements and potentially different initial
  * setup.
  */
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
-
 struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
+
+union task_union init_task_union
+	__attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
+	= { task: INIT_TASK };
 
 asmlinkage void ret_from_exception(void);
 
@@ -71,6 +72,7 @@
 #else /* portable version */
 			__asm__("stop #0x2000" : : : "cc");
 #endif /* machine compilation types */ 
+		run_task_queue(&tq_scheduler);
 		schedule();
 	}
 	ret = 0;
@@ -101,8 +103,8 @@
 	printk("\n");
 	printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x\n",
 	       regs->format, regs->vector, regs->pc, regs->sr);
-	printk("ORIG_D0: %08lx  D0: %08lx  A1: %08lx\n",
-	       regs->orig_d0, regs->d0, regs->a1);
+	printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
+	       regs->orig_d0, regs->d0, regs->a2, regs->a1);
 	printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
 	       regs->a0, regs->d5, regs->d4);
 	printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
@@ -169,8 +171,8 @@
 	struct switch_stack * childstack, *stack;
 	unsigned long stack_offset, *retp;
 
-	stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
-	childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+	stack_offset = 2*PAGE_SIZE - sizeof(struct pt_regs);
+	childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
 
 	*childregs = *regs;
 	childregs->d0 = 0;
@@ -256,7 +258,7 @@
 	dump->regs.d7 = sw->d7;
 	dump->regs.a0 = regs->a0;
 	dump->regs.a1 = regs->a1;
-	dump->regs.a2 = sw->a2;
+	dump->regs.a2 = regs->a2;
 	dump->regs.a3 = sw->a3;
 	dump->regs.a4 = sw->a4;
 	dump->regs.a5 = sw->a5;
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.1.39/linux/arch/m68k/kernel/ptrace.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/ptrace.c	Sun May 18 17:10:37 1997
@@ -47,7 +47,7 @@
 static int regoff[] = {
 	PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
 	PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
-	PT_REG(a1), SW_REG(a2), SW_REG(a3), SW_REG(a4),
+	PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
 	SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
 	PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
 };
@@ -104,7 +104,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -114,7 +114,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir,addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -125,7 +125,7 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
@@ -156,7 +156,7 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
@@ -166,7 +166,7 @@
 	}
 	pgmiddle = pmd_offset(pgdir,addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
@@ -177,12 +177,12 @@
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		do_wp_page(tsk, vma, addr, 2);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.1.39/linux/arch/m68k/kernel/sys_m68k.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/sys_m68k.c	Sun May 18 17:10:37 1997
@@ -532,12 +532,15 @@
 		 */
 		vma = find_vma (current->mm, addr);
 		ret = -EINVAL;
+		/* Check for overflow.  */
+		if (addr + len < addr)
+			goto out;
 		if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
 			goto out;
 	}
 
 	if (CPU_IS_020_OR_030) {
-		if (scope == FLUSH_SCOPE_LINE) {
+		if (scope == FLUSH_SCOPE_LINE && len < 256) {
 			unsigned long cacr;
 			__asm__ ("movec %%cacr, %0" : "=r" (cacr));
 			if (cache & FLUSH_CACHE_INSN)
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.1.39/linux/arch/m68k/kernel/traps.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/traps.c	Sun May 18 17:10:37 1997
@@ -933,16 +933,15 @@
 #endif
 	console_verbose();
 	printk("%s: %08x\n",str,nr);
-	printk("PC: [<%08lx>]\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
+	printk("PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
+	       fp->pc, fp->sr, fp, fp->a2);
 	printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
 	       fp->d0, fp->d1, fp->d2, fp->d3);
 	printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
 	       fp->d4, fp->d5, fp->a0, fp->a1);
 
-	if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
-		printk("Corrupted stack page\n");
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
-		current->comm, current->pid, current->kernel_stack_page);
+		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
 #ifdef CONFIG_KGDB
 	}
 #endif
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/lib/semaphore.S linux/arch/m68k/lib/semaphore.S
--- v2.1.39/linux/arch/m68k/lib/semaphore.S	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/lib/semaphore.S	Sun May 18 17:10:37 1997
@@ -19,8 +19,7 @@
 	movel %a1,-(%sp)
 	jbsr SYMBOL_NAME(__down)
 	movel (%sp)+,%a1
-	movel (%sp)+,%d0
-	movel (%sp)+,%d1
+	moveml (%sp)+,%a0/%d0/%d1
 	rts
 
 ENTRY(__down_failed_interruptible)
@@ -30,6 +29,7 @@
 	jbsr SYMBOL_NAME(__down_interruptible)
 	movel (%sp)+,%a1
 	movel (%sp)+,%d1
+	movel (%sp)+,%a0
 	rts
 
 ENTRY(__up_wakeup)
@@ -37,6 +37,5 @@
 	movel %a1,-(%sp)
 	jbsr SYMBOL_NAME(__up)
 	movel (%sp)+,%a1
-	movel (%sp)+,%d0
-	movel (%sp)+,%d1
+	moveml (%sp)+,%a0/%d0/%d1
 	rts
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.1.39/linux/arch/m68k/mm/fault.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/m68k/mm/fault.c	Sun May 18 17:10:37 1997
@@ -32,14 +32,10 @@
 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
 			      unsigned long error_code)
 {
-	void (*handler)(struct task_struct *,
-			struct vm_area_struct *,
-			unsigned long,
-			int);
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
 	struct vm_area_struct * vma;
-	unsigned long fixup, fault_pc;
+	unsigned long fixup;
 	int write;
 
 #ifdef DEBUG
@@ -73,10 +69,8 @@
  */
 good_area:
 	write = 0;
-	handler = do_no_page;
 	switch (error_code & 3) {
 		default:	/* 3: write, present */
-			handler = do_wp_page;
 			/* fall through */
 		case 2:		/* write, not present */
 			if (!(vma->vm_flags & VM_WRITE))
@@ -89,7 +83,7 @@
 			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 				goto bad_area;
 	}
-	handler(tsk, vma, address, write);
+	handle_mm_fault(current, vma, address, write);
 	up(&mm->mmap_sem);
 
 	/* There seems to be a missing invalidate somewhere in do_no_page.
@@ -108,10 +102,10 @@
 	up(&mm->mmap_sem);
 
 	/* Are we prepared to handle this fault?  */
-	fault_pc = regs->pc;
-	if ((fixup = search_exception_table(fault_pc)) != 0) {
+	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		struct pt_regs *tregs;
-		printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", fault_pc, fixup);
+		printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+		       current->comm, regs->pc, fixup);
 		/* Create a new four word stack frame, discarding the old
 		   one.  */
 		regs->stkadj = frame_extra_sizes[regs->format];
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.39/linux/arch/m68k/mm/init.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/mm/init.c	Sun May 18 17:10:37 1997
@@ -491,8 +491,6 @@
 		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
 		free_page(addr);
 	}
-	printk ("Freeing unused kernel memory: %dk freed\n",
-		(&__init_end - &__init_begin) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.1.39/linux/arch/m68k/mm/memory.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/m68k/mm/memory.c	Sun May 18 17:10:37 1997
@@ -280,6 +280,8 @@
     return( (vaddr & mask) == (base & mask) );
 }
 
+static unsigned long mm_vtop_fallback (unsigned long);
+
 /*
  * The following two routines map from a physical address to a kernel
  * virtual address and vice versa.
@@ -301,7 +303,13 @@
 			offset += m68k_memory[i].size;
 		i++;
 	}while (i < m68k_num_memory);
+	return mm_vtop_fallback(vaddr);
+}
 
+/* Separate function to make the common case faster (needs to save less
+   registers) */
+static unsigned long mm_vtop_fallback (unsigned long vaddr)
+{
 	/* not in one of the memory chunks; test for applying transparent
 	 * translation */
 
diff -u --recursive --new-file v2.1.39/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- v2.1.39/linux/arch/m68k/vmlinux.lds	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/vmlinux.lds	Sun May 18 17:10:37 1997
@@ -9,6 +9,7 @@
   .text : {
 	*(.text)
 	*(.fixup)
+	*(.text.lock)		/* out-of-line lock text */
 	*(.gnu.warning)
 	} = 0x4e75
   .rodata : { *(.rodata) }
@@ -29,6 +30,9 @@
 	*(.data)
 	CONSTRUCTORS
 	}
+
+  . = ALIGN(8192);
+  init_task : { *(init_task) }	/* The initial task and kernel stack */
 
   _edata = .;			/* End of data section */
 
diff -u --recursive --new-file v2.1.39/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.39/linux/arch/sparc/mm/srmmu.c	Thu May 15 16:48:02 1997
+++ linux/arch/sparc/mm/srmmu.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.145 1997/05/04 10:02:15 ecd Exp $
+/* $Id: srmmu.c,v 1.146 1997/05/18 21:11:09 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -2255,7 +2255,7 @@
 					start += PAGE_SIZE;
 				}
 			}
-		} while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+		} while ((vmaring = vmaring->vm_next_share) != NULL);
 
 		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = srmmu_pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.1.39/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.1.39/linux/arch/sparc/mm/sun4c.c	Tue May 13 22:41:03 1997
+++ linux/arch/sparc/mm/sun4c.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.147 1997/05/01 08:53:42 davem Exp $
+/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2467,7 +2467,7 @@
 					start += PAGE_SIZE;
 				}
 			}
-		} while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+		} while ((vmaring = vmaring->vm_next_share) != NULL);
 
 		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = sun4c_pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.1.39/linux/arch/sparc64/kernel/Makefile	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/kernel/Makefile	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.17 1997/05/04 07:20:58 davem Exp $
+# $Id: Makefile,v 1.20 1997/05/18 08:42:11 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -18,7 +18,7 @@
 O_TARGET := kernel.o
 O_OBJS   := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \
 	    systbls.o traps.o entry.o devices.o auxio.o ioport.o \
-	    irq.o time.o sys_sparc.o
+	    irq.o time.o sys_sparc.o signal.o winfixup.o
 OX_OBJS  := sparc64_ksyms.o
 
 ifdef CONFIG_SPARC32_COMPAT
@@ -26,11 +26,16 @@
 endif
 
 ifdef CONFIG_BINFMT_ELF32
-  O_OBJS += sparcelf32.o
+  O_OBJS += binfmt_elf32.o
 endif
 
 head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S
 	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+
+#
+# This is just to get the dependencies...
+#
+binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
 
 check_asm: dummy
 	@echo "#include <linux/sched.h>" > tmp.c
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/binfmt_elf32.c linux/arch/sparc64/kernel/binfmt_elf32.c
--- v2.1.39/linux/arch/sparc64/kernel/binfmt_elf32.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/binfmt_elf32.c	Sun May 18 17:10:37 1997
@@ -0,0 +1,34 @@
+/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+ *
+ */
+
+#define ELF_ARCH		EM_SPARC
+#define ELF_CLASS		ELFCLASS32
+#define ELF_DATA		ELFDATA2MSB;
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define elf_addr_t	u32
+#define elf_caddr_t	u32
+#undef start_thread
+#define start_thread start_thread32
+#define init_elf_binfmt init_elf32_binfmt
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
+#endif
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
+#endif
+#define ELF_FLAGS_INIT	current->tss.flags |= SPARC_FLAG_32BIT
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
+MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S
--- v2.1.39/linux/arch/sparc64/kernel/dtlb_prot.S	Mon Apr 14 16:28:09 1997
+++ linux/arch/sparc64/kernel/dtlb_prot.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $
+/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
  * dtlb_prot.S:	Data TLB protection code, this is included directly
  *              into the trap table.
  *
@@ -18,30 +18,30 @@
   /*0x04*/	srlx		%g1, 8, %g3			! Position PGD offset
   /*0x08*/	sllx		%g1, 2, %g4			! Position PMD offset
   /*0x0c*/	and		%g3, %g2, %g3			! Mask PGD offset
-  /*0x10*/	and		%g4, %g2, %g3			! Mask PMD offset
+  /*0x10*/	and		%g4, %g2, %g4			! Mask PMD offset
   /*0x14*/	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5	! Load PGD
-  /*0x18*/	ldxa		[%g5 + %g3] ASI_PHYS_USE_EC, %g4	! Load PMD
+  /*0x18*/	ldxa		[%g5 + %g4] ASI_PHYS_USE_EC, %g4	! Load PMD
   /*0x1c*/	ldxa		[%g0] ASI_DMMU_TSB_8KB_PTR, %g1		! For PTE offset
 
 				/* ICACHE line 2 */
   /*0x20*/	srlx		%g1, 1, %g1				! PTE offset
   /*0x24*/	ldxa		[%g4 + %g1] ASI_PHYS_USE_EC, %g3	! Load PTE
   /*0x28*/	andcc		%g3, _PAGE_WRITE, %g0			! Writable?
-  /*0x2c*/	be,pt		%xcc, sparc64_dtlb_fault		! Nope...
+  /*0x2c*/	be,pt		%xcc, sparc64_dtlb_prot_catch		! Nope...
   /*0x30*/	 or		%g3, (MODIFIED_BITS), %g3		! Yes it is
   /*0x34*/	mov		TLB_TAG_ACCESS, %g5			! Get the page
-  /*0x38*/	ldxa		[%g5] ASI_DMMU, %g1			! From MMU
-  /*0x3c*/	add		%g2, 7, %g5				! Compute mask
+  /*0x38*/	add		%g1, %g4, %g1				! to get a tmpreg
+  /*0x3c*/	ldxa		[%g5] ASI_DMMU, %g4			! From MMU
 
 				/* ICACHE line 3 */
-  /*0x40*/	andn		%g1, %g5, %g1				! Mask page
-  /*0x44*/	or		%g1, 0x10, %g1				! 2ndary Context
-  /*0x48*/	stxa		%g0, [%g1] ASI_DMMU_DEMAP		! TLB flush page
-  /*0x4c*/	membar		#Sync					! Synchronize
-  /*0x50*/	stxa		%g3, [%g4 + %g1] ASI_PHYS_USE_EC	! Update sw PTE
-  /*0x54*/	stxa		%g3, [%g0] ASI_DTLB_DATA_IN		! TLB load
-  /*0x58*/	retry							! Trap return
-  /*0x5c*/	nop
+  /*0x40*/	add		%g2, 7, %g5				! Compute mask
+  /*0x44*/	andn		%g4, %g5, %g4				! Mask page
+  /*0x48*/	or		%g4, 0x10, %g4				! 2ndary Context
+  /*0x4c*/	stxa		%g0, [%g4] ASI_DMMU_DEMAP		! TLB flush page
+  /*0x50*/	membar		#Sync					! Synchronize
+  /*0x54*/	stxa		%g3, [%g1] ASI_PHYS_USE_EC		! Update sw PTE
+  /*0x58*/	stxa		%g3, [%g0] ASI_DTLB_DATA_IN		! TLB load
+  /*0x5c*/	retry							! Trap return
 
 				/* ICACHE line 4 */
   /*0x60*/	nop
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.39/linux/arch/sparc64/kernel/entry.S	Tue May 13 22:41:04 1997
+++ linux/arch/sparc64/kernel/entry.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.15 1997/04/28 14:57:08 davem Exp $
+/* $Id: entry.S,v 1.21 1997/05/18 10:04:44 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -24,35 +24,55 @@
 
 	.text
         .align  4
-/* FIXME: This is still debugging hack */
-	.globl	sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch
-sparc64_dtlb_fault:
-	rdpr	%pstate, %g1
-	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
-	ba,pt	%xcc, etrap
-	 rd	%pc, %g7
-	call	sparc64_dtlb_fault_handler
-	 nop
+	.globl	sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch
+	.globl	sparc64_itlb_refbit_catch
 
 	/* Note, DMMU SFAR not updated for fast tlb data access miss
 	 * traps, so we must use tag access to find the right page.
+	 * However for DMMU fast protection traps it is updated so
+	 * we use, but we must also clear it _before_ we enable interrupts
+	 * and save state because there is a race where we can push a user
+	 * window right now in etrap, a protection fault happens (for example
+	 * to update the dirty bit) and since we left crap in the sfsr
+	 * it will not get updated properly.
 	 */
-sparc64_dtlb_refbit_catch:
+sparc64_dtlb_prot_catch:
 	wr	%g0, ASI_DMMU, %asi
 	rdpr	%pstate, %g1
 	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
+	rdpr	%tl, %g2
 	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g5
-	srlx	%g5, PAGE_SHIFT, %g5
 	ldxa	[%g0 + TLB_SFSR] %asi, %g4
-	sllx	%g5, PAGE_SHIFT, %g5
+	cmp	%g2, 1
+	stxa	%g0, [%g0 + TLB_SFSR] %asi
+	bgu,a	%icc, winfix_trampoline
+	 rdpr	%tpc, %g5
 	ba,pt	%xcc, etrap
 	 rd	%pc, %g7
+	b,a,pt	%xcc, 1f
 
+sparc64_dtlb_refbit_catch:
+	wr	%g0, ASI_DMMU, %asi
+	rdpr	%pstate, %g1
+	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
+	rdpr	%tl, %g2
+	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g5
+	cmp	%g2, 1
+	clr	%g4				! sfsr not updated for tlb misses
+	bgu,a	%icc, winfix_trampoline
+	 rdpr	%tpc, %g5
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+1:
+	mov	%l5, %o4				! raw tag access
+	mov	%l4, %o5				! raw sfsr
+	srlx	%l5, PAGE_SHIFT, %o3
 	clr	%o1					! text_fault == 0
-	mov	%l5, %o3				! address == sfar
+	sllx	%o3, PAGE_SHIFT, %o3			! address
 	and	%l4, 0x4, %o2				! write == sfsr.W
 	call	do_sparc64_fault
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
+	ba,a,pt	%xcc, rtrap
 
 sparc64_itlb_refbit_catch:
 	rdpr	%pstate, %g1
@@ -63,8 +83,11 @@
 	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
 	mov	1, %o1					! text_fault == 1
 	clr	%o2					! write == 0
+	clr	%o4					! tag access (N/A)
+	clr	%o5					! raw sfsr (N/A)
 	call	do_sparc64_fault
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
+	ba,a,pt	%xcc, rtrap
 
 	/* Note check out head.h, this code isn't even used for UP,
 	 * for SMP things will be different.  In particular the data
@@ -137,6 +160,7 @@
 	ba,a,pt	%xcc, rtrap
 
 	.globl	sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+	.globl	sys_sigsuspend, sys_sigreturn
 
 sys_pipe:
 	sethi	%hi(sparc_pipe), %g1
@@ -163,12 +187,35 @@
 	
 	ld	[%curptr + AOFF_task_flags], %l5
 	andcc	%l5, 0x20, %g0
+	be,pt	%icc, rtrap
+	 nop
+	call	syscall_trace
+	 nop
+	ba,a,pt	%xcc, rtrap
+
+sys_sigsuspend:
+	call	do_sigsuspend
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	
+	ld	[%curptr + AOFF_task_flags], %l5
+	andcc	%l5, 0x20, %g0
 	be,pt	%icc, ret_sys_call
-	 clr	%o0
+	 nop
 	call	syscall_trace
 	 nop
-	ba,pt	%xcc, ret_sys_call
-	 clr	%o0
+	ba,a,pt	%xcc, rtrap
+	
+sys_sigreturn:
+	call	do_sigreturn
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	
+	ld	[%curptr + AOFF_task_flags], %l5
+	andcc	%l5, 0x20, %g0
+	be,pt	%icc, ret_sys_call
+	 nop
+	call	syscall_trace
+	 nop
+	ba,a,pt	%xcc, rtrap
 
 	/* This is how fork() was meant to be done, 11 instruction entry. -DaveM */
 	.globl	sys_fork, sys_vfork, sys_clone
@@ -216,7 +263,7 @@
 	.globl	ret_from_syscall
 ret_from_syscall:
 	ba,pt	%xcc, ret_sys_call
-	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0
+	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 
 	/* Linux native and SunOS system calls enter here... */
 	.align	4
@@ -248,13 +295,18 @@
 	call	%l7
 	 mov	%i5, %o5
 
-	stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
-
+	stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+#if 0
+	/* Debugging... */
+	call	syscall_trace_exit
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+#endif
 	.globl	ret_sys_call
 ret_sys_call:
 	ldx	[%curptr + AOFF_task_flags], %l6
 	mov	%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %g3
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
 	cmp	%o0, -ENOIOCTLCMD
 	sllx	%g2, 32, %g2
 	bgeu,pn	%xcc, 1f
@@ -263,34 +315,34 @@
 	/* System call success, clear Carry condition code. */
 	andn	%g3, %g2, %g3
 	clr	%l6
-	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]	
+	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
 	bne,pn	%icc, linux_syscall_trace2
-	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
 	add	%l1, 0x4, %l2				      /* npc = npc+4 */
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
 	ba,pt	%xcc, rtrap
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 1:
 	/* System call failure, set Carry condition code.
 	 * Also, get abs(errno) to return to the process.
 	 */
 	sub	%g0, %o0, %o0
 	or	%g3, %g2, %g3
-	stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+	stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 	mov	1, %l6
-	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
 	bne,pn	%icc, linux_syscall_trace2
-	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
 	add	%l1, 0x4, %l2				      /* npc = npc+4 */
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
 	ba,pt	%xcc, rtrap
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 
 linux_syscall_trace2:
 	call	syscall_trace
 	 add	%l1, 0x4, %l2			/* npc = npc+4 */
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
 	ba,pt	%xcc, rtrap
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 
 /* End of entry.S */
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.1.39/linux/arch/sparc64/kernel/etrap.S	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/kernel/etrap.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.13 1997/05/04 07:21:00 davem Exp $
+/* $Id: etrap.S,v 1.17 1997/05/18 22:52:09 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -50,27 +50,11 @@
 	mov		SECONDARY_CONTEXT, %g1
 	stxa		%g2, [%g1] ASI_DMMU
 
-	rdpr		%wstate, %g1
-	sll		%g1, 3, %g1
-	wrpr		%g1, %wstate
-
-	sethi		%uhi(KERNBASE), %g2
-	or		%g2, %ulo(KERNBASE), %g2
-	sethi		%hi(current_set), %g1
-	or		%g1, %lo(current_set), %g1
-	sllx		%g2, 32, %g2
-	ldx		[%g1 + %g2], %g1
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
-	rdpr		%canrestore, %g2
-	wrpr		%g0, 0, %canrestore
-	wrpr		%g2, 0, %otherwin
-
-	mov		1, %g2
-	sllx		%g2, (PAGE_SHIFT + 1), %g2
-	sub		%g2, (TRACEREG_SZ + REGWIN_SZ), %g2
+	rd		%pic, %g1
+	sethi		%hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
+	or		%g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2
 	add		%g1, %g2, %g2
+	rdpr		%tstate, %g1
 1:
 	stx		%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]
 	rdpr		%tpc, %g1
@@ -81,9 +65,23 @@
 	stx		%g1, [%g2 + REGWIN_SZ + PT_V9_Y]
 
 	wrpr		%g0, 0x0, %tl
-
 	rdpr		%pstate, %g1
 	save		%g2, -STACK_BIAS, %sp
+
+	/* Must guarentee that here andcc of TSTATE_PRIV at the top is
+	 * still valid in %ccr register.  Don't show this trick to your
+	 * mom. -DaveM
+	 */
+	bne,pn		%xcc, 1f
+	 rdpr		%canrestore, %g3
+	wrpr		%g0, 0, %canrestore
+	wrpr		%g3, 0, %otherwin
+
+	rdpr		%wstate, %g6
+	sll		%g6, 3, %g6
+	wrpr		%g6, %wstate
+
+1:
 	mov		%g1, %l1
 	mov		%g4, %l4
 	mov		%g5, %l5
@@ -105,15 +103,10 @@
 	stx		%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
 	stx		%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
-	sethi		%uhi(KERNBASE), %g4
-	or		%g4, %ulo(KERNBASE), %g4
-	srlx		%sp, (PAGE_SHIFT + 1), %g6
-	sllx		%g4, 32, %g4
+	srlx		%sp, 43, %g4
+	rd		%pic, %g6
 	jmpl		%l2 + 0x4, %g0
-	 sllx		%g6, (PAGE_SHIFT + 1), %g6
-#ifdef __SMP__
-/* FIXME: Fix the above insn for SMP */
-#endif
+	 sllx		%g4, 43, %g4
 
 	.globl	etraptl1
 etraptl1:
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S
--- v2.1.39/linux/arch/sparc64/kernel/hack.S	Mon Apr 14 16:28:09 1997
+++ linux/arch/sparc64/kernel/hack.S	Sun May 18 17:10:37 1997
@@ -4,8 +4,6 @@
    to compile... */
 	.text
 	.align	8
-	.globl	_sigpause_common
-_sigpause_common:	retl;nop
 	.globl	breakpoint
 breakpoint:	retl;nop
 	.globl	do_cee
@@ -36,8 +34,6 @@
 do_iae:	retl;nop
 	.globl	do_iae_tl1
 do_iae_tl1:	retl;nop
-	.globl	do_ill
-do_ill:	retl;nop
 	.globl	do_ill_tl1
 do_ill_tl1:	retl;nop
 	.globl	do_irq
@@ -48,8 +44,6 @@
 do_lddfmna:	retl;nop
 	.globl	do_lddfmna_tl1
 do_lddfmna_tl1:	retl;nop
-	.globl	do_mna
-do_mna:	retl;nop
 	.globl	do_mna_tl1
 do_mna_tl1:	retl;nop
 	.globl	do_paw
@@ -60,8 +54,6 @@
 do_privact:	retl;nop
 	.globl	do_privop
 do_privop:	retl;nop
-	.globl	do_signal
-do_signal:	retl;nop
 	.globl	do_stdfmna
 do_stdfmna:	retl;nop
 	.globl	do_stdfmna_tl1
@@ -200,15 +192,7 @@
 sunos_writev:	retl;nop
 	.globl	sys_ptrace
 sys_ptrace:	retl;nop
-	.globl	sys_sigreturn
-sys_sigreturn:	retl;nop
-	.globl	sys_sigstack
-sys_sigstack:	retl;nop
-	.globl	sys_sigsuspend
-sys_sigsuspend:	retl;nop
 	.globl	syscall_trace
 syscall_trace:	retl;nop
 	.globl	sys32_ptrace
 sys32_ptrace:	retl;nop
-	.globl	do_sigpause
-do_sigpause:	retl;nop
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.1.39/linux/arch/sparc64/kernel/head.S	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/kernel/head.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.28 1997/05/04 07:21:02 davem Exp $
+/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -268,6 +268,10 @@
 	mov	%sp, %l6
 	mov	%o4, %l7
 
+	/* Setup "Linux Current Register", thanks Sun 8-) */
+	wr	%g0, 0x1, %pcr
+	wr	%g6, 0x0, %pic
+
 	mov	1, %g5
 	sllx	%g5, (PAGE_SHIFT + 1), %g5
 	sub	%g5, (REGWIN_SZ + STACK_BIAS), %g5
@@ -289,14 +293,20 @@
 	add	%l2, 1, %l2
 	add	%l0, %g4, %o0
 1:
-	call	bzero_1page
+	clr	%o1
+	sethi	%hi(PAGE_SIZE), %o2
+	or	%o2, %lo(PAGE_SIZE), %o2
+	call	__memset
 	 add	%l0, %l2, %l0
 	cmp	%l0, %l1
 	blu,pt	%xcc, 1b
 	 add	%l0, %g4, %o0
 
 	/* Now clear empty_zero_page */
-	call	bzero_1page
+	clr	%o1
+	sethi	%hi(PAGE_SIZE), %o2
+	or	%o2, %lo(PAGE_SIZE), %o2
+	call	__memset
 	 mov	%g4, %o0
 
 	mov	%l6, %o1			! OpenPROM stack
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.39/linux/arch/sparc64/kernel/process.c	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/kernel/process.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.8 1997/05/14 20:45:06 davem Exp $
+/*  $Id: process.c,v 1.11 1997/05/18 22:52:19 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -37,8 +37,6 @@
 #include <asm/elf.h>
 #include <asm/fpumacro.h>
 
-struct task_struct *current_set[NR_CPUS] = {&init_task, };
-
 #ifndef __SMP__
 
 /*
@@ -348,7 +346,14 @@
 	}
 	
 	/* Now, this task is no longer a kernel thread. */
-	current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+		current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+
+		/* exec_mmap() set context to NO_CONTEXT, here is
+		 * where we grab a new one.
+		 */
+		get_mmu_context(current);
+	}
 	current->tss.current_ds = USER_DS;
 }
 
@@ -418,6 +423,64 @@
 	return sp;
 }
 
+/* Standard stuff. */
+static inline void shift_window_buffer(int first_win, int last_win,
+				       struct thread_struct *tp)
+{
+	int i;
+
+	for(i = first_win; i < last_win; i++) {
+		tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
+		memcpy(&tp->reg_window[i], &tp->reg_window[i+1],
+		       sizeof(struct reg_window));
+	}
+}
+
+void synchronize_user_stack(void)
+{
+	struct thread_struct *tp = &current->tss;
+	unsigned long window = tp->w_saved;
+
+	flush_user_windows();
+	if(window) {
+		int winsize = REGWIN_SZ;
+
+		if(tp->flags & SPARC_FLAG_32BIT)
+			winsize = REGWIN32_SZ;
+
+		window -= 1;
+		do {
+			unsigned long sp = tp->rwbuf_stkptrs[window];
+			struct reg_window *rwin = &tp->reg_window[window];
+
+			if(!copy_to_user((char *)sp, rwin, winsize)) {
+				shift_window_buffer(window, tp->w_saved - 1, tp);
+				tp->w_saved--;
+			}
+		} while(window--);
+	}
+}
+
+void fault_in_user_windows(struct pt_regs *regs)
+{
+	struct thread_struct *tp = &current->tss;
+	unsigned long window = tp->w_saved;
+	int winsize = REGWIN_SZ;
+
+	if(tp->flags & SPARC_FLAG_32BIT)
+		winsize = REGWIN32_SZ;
+	if(window) {
+		window -= 1;
+		do {
+			unsigned long sp = tp->rwbuf_stkptrs[window];
+			struct reg_window *rwin = &tp->reg_window[window];
+
+			if(copy_to_user((char *)sp, rwin, winsize))
+				do_exit(SIGILL);
+		} while(window--);
+	}
+	current->tss.w_saved = 0;
+}
 
 /* Copy a Sparc thread.  The fork() return value conventions
  * under SunOS are nothing short of bletcherous:
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.1.39/linux/arch/sparc64/kernel/rtrap.S	Mon Apr 14 16:28:09 1997
+++ linux/arch/sparc64/kernel/rtrap.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $
+/* $Id: rtrap.S,v 1.14 1997/05/18 08:42:14 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -71,12 +71,11 @@
 	/* We came here from to_user, ie. we have now AG.
 	 * Also have to push user context back into primary.
 	 */
-	restore
-
 	mov	SECONDARY_CONTEXT, %g6
 	mov	PRIMARY_CONTEXT, %g7
 	ldxa	[%g6] ASI_DMMU, %g4
 	stxa	%g4, [%g7] ASI_DMMU
+	membar	#Sync			/* XXX flushi would be better -DaveM */
 
 	rdpr	%wstate, %g1
 	rdpr	%otherwin, %g2
@@ -84,7 +83,6 @@
 	wrpr	%g2, %g0, %canrestore
 	wrpr	%g1, %g0, %wstate
 	wrpr	%g0, %g0, %otherwin
-	retry
 1:
 	restore
 	retry
@@ -101,9 +99,14 @@
 	ldx	[%g6 + AOFF_task_blocked], %o0
 	or	%l7, PSTATE_AG, %l7		! Will need this for setting back wstate
 	andncc	%l0, %o0, %g0
-	be,pt	%xcc, 3b
+	be,pt	%xcc, check_user_wins
 	 mov	%l5, %o2  
 	mov	%l6, %o3
-	add	%sp, STACK_BIAS + REGWIN_SZ, %o1
 	call	do_signal
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+check_user_wins:
+	ldx	[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+	brz,pt	%o2, 3b
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+	call	fault_in_user_windows
 	 add	%o7, 3b-.-4, %o7
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.1.39/linux/arch/sparc64/kernel/signal.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/signal.c	Sun May 18 17:10:37 1997
@@ -0,0 +1,438 @@
+/*  $Id: signal.c,v 1.2 1997/05/18 08:42:15 davem Exp $
+ *  arch/sparc64/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
+ *  Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+#include <asm/svr4.h>
+#include <asm/pgtable.h>
+#include <asm/fpumacro.h>
+#include <asm/smp_lock.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
+			 int options, unsigned long *ru);
+
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+			 unsigned long orig_o0, int ret_from_syscall);
+
+/* This turned off for production... */
+/* #define DEBUG_SIGNALS 1 */
+
+/* 
+ * The new signal frame, intended to be used for Linux applications only
+ * (we have enough in there to work with clone).
+ * All the interesting bits are in the info field.
+ */
+
+struct new_signal_frame {
+	struct sparc_stackf	ss;
+	__siginfo_t		info;
+	__siginfo_fpu_t *	fpu_save;
+	unsigned int		insns [2];
+	__siginfo_fpu_t		fpu_state;
+};
+
+/* Align macros */
+#define NF_ALIGNEDSZ  (((sizeof(struct new_signal_frame) + 7) & (~7)))
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ * This is really tricky on the Sparc, watch out...
+ */
+asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
+{
+	unsigned int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+	if (current->tss.flags & SPARC_FLAG_32BIT) {
+		extern asmlinkage void _sigpause32_common(unsigned int, struct pt_regs *);
+		_sigpause32_common(set, regs);
+		return;
+	}
+#endif
+	spin_lock_irq(&current->sigmask_lock);
+	mask = current->blocked;
+	current->blocked = set & _BLOCKABLE;
+	spin_unlock_irq(&current->sigmask_lock);
+	
+	regs->tpc = regs->tnpc;
+	regs->tnpc += 4;
+
+	/* Condition codes and return value where set here for sigpause,
+	 * and so got used by setup_frame, which again causes sigreturn()
+	 * to return -EINTR.
+	 */
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		/*
+		 * Return -EINTR and set condition code here,
+		 * so the interrupted system call actually returns
+		 * these.
+		 */
+		regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+		regs->u_regs[UREG_I0] = EINTR;
+		if (do_signal(mask, regs, 0, 0))
+			return;
+	}
+}
+
+asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
+{
+	_sigpause_common(set, regs);
+}
+
+asmlinkage void do_sigsuspend(struct pt_regs *regs)
+{
+	_sigpause_common(regs->u_regs[UREG_I0], regs);
+}
+
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU)
+		regs->tstate &= ~(TSTATE_PEF);
+#else
+	if (current == last_task_used_math) {
+		last_task_used_math = 0;
+		regs->tstate &= ~(TSTATE_PEF);
+	}
+#endif
+	current->used_math = 1;
+	current->flags &= ~PF_USEDFPU;
+
+	copy_from_user(&current->tss.float_regs[0],
+		       &fpu->si_float_regs[0],
+		       (sizeof(unsigned int) * 64));
+	__get_user(current->tss.fsr, &fpu->si_fsr);
+}
+
+void do_sigreturn(struct pt_regs *regs)
+{
+	struct new_signal_frame *sf;
+	unsigned long tpc, tnpc, tstate;
+	__siginfo_fpu_t *fpu_save;
+	int mask;
+
+#ifdef CONFIG_SPARC32_COMPAT
+	if (current->tss.flags & SPARC_FLAG_32BIT) {
+		extern asmlinkage void do_sigreturn32(struct pt_regs *);
+		do_sigreturn32(regs);
+		return;
+	}
+#endif	
+	synchronize_user_stack ();
+	sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
+	/* 1. Make sure we are not getting garbage from the user */
+	if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
+		goto segv;
+	}
+	if (((unsigned long) sf) & 3){
+		goto segv;
+	}
+	get_user(tpc, &sf->info.si_regs.tpc);
+	__get_user(tnpc, &sf->info.si_regs.tnpc);
+	if ((tpc | tnpc) & 3){
+		goto segv;
+	}
+	regs->tpc = tpc;
+	regs->tnpc = tnpc;
+
+	/* 2. Restore the state */
+	__get_user(regs->y, &sf->info.si_regs.y);
+	__get_user(tstate, &sf->info.si_regs.tstate);
+	copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
+
+	/* User can only change condition codes and FPU enabling in %tstate. */
+	regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
+	regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_PEF));
+
+	__get_user(fpu_save, &sf->fpu_save);
+	if (fpu_save)
+		restore_fpu_state(regs, &sf->fpu_state);
+	__get_user(mask, &sf->info.si_mask);
+	current->blocked = mask & _BLOCKABLE;
+	return;
+segv:
+	lock_kernel();
+	do_exit(SIGSEGV);
+}
+
+/* Checks if the fp is valid */
+static int invalid_frame_pointer(void *fp, int fplen)
+{
+	if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x80000000000ULL - fplen)
+		return 1;
+	return 0;
+}
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+	if (current->flags & PF_USEDFPU) {
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr);
+		regs->tstate &= ~(TSTATE_PEF);
+		current->flags &= ~(PF_USEDFPU);
+	}
+#else
+	if (current == last_task_used_math) {
+		fpsave((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+		last_task_used_math = 0;
+		regs->tstate &= ~(TSTATE_PEF);
+	}
+#endif
+	copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+		     (sizeof(unsigned int) * 64));
+	__put_user(current->tss.fsr, &fpu->si_fsr);
+	current->used_math = 0;
+}
+
+static inline void
+new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
+		  int signo, unsigned long oldmask)
+{
+	struct new_signal_frame *sf;
+	int sigframe_size;
+	unsigned long tmp;
+	int i;
+
+	/* 1. Make sure everything is clean */
+	synchronize_user_stack();
+	sigframe_size = NF_ALIGNEDSZ;
+	if (!current->used_math)
+		sigframe_size -= sizeof(__siginfo_fpu_t);
+
+	sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+	
+	if (invalid_frame_pointer (sf, sigframe_size)){
+		lock_kernel ();
+		do_exit(SIGILL);
+	}
+
+	if (current->tss.w_saved != 0){
+		printk ("%s[%d]: Invalid user stack frame for "
+			"signal delivery.\n", current->comm, current->pid);
+		lock_kernel ();
+		do_exit (SIGILL);
+	}
+
+	/* 2. Save the current process state */
+	copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
+
+	if (current->used_math) {
+		save_fpu_state(regs, &sf->fpu_state);
+		__put_user((u64)&sf->fpu_state, &sf->fpu_save);
+	} else {
+		__put_user(0, &sf->fpu_save);
+	}
+
+	__put_user(oldmask, &sf->info.si_mask);
+	for (i = 0; i < sizeof(struct reg_window)/8; i++) {
+		__get_user(tmp, (((u64 *)regs->u_regs[UREG_FP])+i));
+		__put_user(tmp, (((u64 *)sf)+i));
+	}
+	
+	/* 3. return to kernel instructions */
+	__put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+	__put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */
+
+	/* 4. signal handler back-trampoline and parameters */
+	regs->u_regs[UREG_FP] = (unsigned long) sf;
+	regs->u_regs[UREG_I0] = signo;
+	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+	regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+	/* 5. signal handler */
+	regs->tpc = (unsigned long) sa->sa_handler;
+	regs->tnpc = (regs->tpc + 4);
+
+	/* Flush instruction space. */
+	__asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0])));
+		
+}
+
+static inline void handle_signal(unsigned long signr, struct sigaction *sa,
+				 unsigned long oldmask, struct pt_regs *regs)
+{
+	new_setup_frame(sa, regs, signr, oldmask);
+	if(sa->sa_flags & SA_ONESHOT)
+		sa->sa_handler = NULL;
+	if(!(sa->sa_flags & SA_NOMASK))
+		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+}
+
+static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
+				     struct sigaction *sa)
+{
+	switch(regs->u_regs[UREG_I0]) {
+		case ERESTARTNOHAND:
+		no_system_call_restart:
+			regs->u_regs[UREG_I0] = EINTR;
+			regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+			break;
+		case ERESTARTSYS:
+			if(!(sa->sa_flags & SA_RESTART))
+				goto no_system_call_restart;
+		/* fallthrough */
+		case ERESTARTNOINTR:
+			regs->u_regs[UREG_I0] = orig_i0;
+			regs->tpc -= 4;
+			regs->tnpc -= 4;
+	}
+}
+
+/* Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+			   unsigned long orig_i0, int restart_syscall)
+{
+	unsigned long signr, mask = ~current->blocked;
+	struct sigaction *sa;
+
+#ifdef CONFIG_SPARC32_COMPAT
+	if (current->tss.flags & SPARC_FLAG_32BIT) {
+		extern asmlinkage int do_signal32(unsigned long, struct pt_regs *,
+						  unsigned long, int);
+		return do_signal32(oldmask, regs, orig_i0, restart_syscall);
+	}
+#endif	
+	while ((signr = current->signal & mask) != 0) {
+		signr = ffz(~signr);
+		clear_bit(signr, &current->signal);
+		sa = current->sig->action + signr;
+		signr++;
+		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+			current->exit_code = signr;
+			current->state = TASK_STOPPED;
+			notify_parent(current);
+			schedule();
+			if (!(signr = current->exit_code))
+				continue;
+			current->exit_code = 0;
+			if (signr == SIGSTOP)
+				continue;
+			if (_S(signr) & current->blocked) {
+				current->signal |= _S(signr);
+				continue;
+			}
+			sa = current->sig->action + signr - 1;
+		}
+		if(sa->sa_handler == SIG_IGN) {
+			if(signr != SIGCHLD)
+				continue;
+
+                        /* sys_wait4() grabs the master kernel lock, so
+                         * we need not do so, that sucker should be
+                         * threaded and would not be that difficult to
+                         * do anyways.
+                         */
+                        while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+                                ;
+			continue;
+		}
+		if(sa->sa_handler == SIG_DFL) {
+			if(current->pid == 1)
+				continue;
+			switch(signr) {
+			case SIGCONT: case SIGCHLD: case SIGWINCH:
+				continue;
+
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+
+			case SIGSTOP:
+				if (current->flags & PF_PTRACED)
+					continue;
+				current->state = TASK_STOPPED;
+				current->exit_code = signr;
+				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+				     SA_NOCLDSTOP))
+					notify_parent(current);
+				schedule();
+				continue;
+
+			case SIGQUIT: case SIGILL: case SIGTRAP:
+			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
+				if(current->binfmt && current->binfmt->core_dump) {
+					if(current->binfmt->core_dump(signr, regs))
+						signr |= 0x80;
+				}
+#ifdef DEBUG_SIGNALS
+				/* Very useful to debug dynamic linker problems */
+				printk ("Sig ILL going...\n");
+				show_regs (regs);
+#endif
+				/* fall through */
+			default:
+				current->signal |= _S(signr & 0x7f);
+				current->flags |= PF_SIGNALED;
+				do_exit(signr);
+			}
+		}
+		if(restart_syscall)
+			syscall_restart(orig_i0, regs, sa);
+		handle_signal(signr, sa, oldmask, regs);
+		return 1;
+	}
+	if(restart_syscall &&
+	   (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+	    regs->u_regs[UREG_I0] == ERESTARTSYS ||
+	    regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+		/* replay the system call when we are done */
+		regs->u_regs[UREG_I0] = orig_i0;
+		regs->tpc -= 4;
+		regs->tnpc -= 4;
+	}
+	return 0;
+}
+
+asmlinkage int
+sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
+{
+	int ret = -EFAULT;
+
+	lock_kernel();
+	/* First see if old state is wanted. */
+	if(ossptr) {
+		if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
+		    __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
+			goto out;
+	}
+
+	/* Now see if we want to update the new state. */
+	if(ssptr) {
+		if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
+		    __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
+			goto out;
+	}
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.39/linux/arch/sparc64/kernel/signal32.c	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc64/kernel/signal32.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.6 1997/04/16 10:27:17 jj Exp $
+/*  $Id: signal32.c,v 1.8 1997/05/18 08:42:15 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -30,8 +30,6 @@
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
-#define synchronize_user_stack() do { } while (0)
-
 asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
 			 int options, unsigned long *ru);
 
@@ -117,17 +115,6 @@
 	}
 }
 
-asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs)
-{
-	_sigpause32_common(set, regs);
-}
-
-asmlinkage void do_sigsuspend32(struct pt_regs *regs)
-{
-	_sigpause32_common(regs->u_regs[UREG_I0], regs);
-}
-
-
 static inline void
 restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
 {
@@ -248,7 +235,9 @@
 {
 	struct signal_sframe32 *sframep;
 	struct sigcontext32 *sc;
+#if 0	
 	int window = 0;
+#endif	
 	int old_status = current->tss.sstk_info.cur_status;
 	unsigned psr;
 	int i;
@@ -424,7 +413,9 @@
 	svr4_mcontext_t *mc;
 	svr4_gwindows_t *gw;
 	svr4_ucontext_t *uc;
+#if 0	
 	int window = 0;
+#endif	
 	unsigned psr;
 	int i;
 
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/sparcelf32.c linux/arch/sparc64/kernel/sparcelf32.c
--- v2.1.39/linux/arch/sparc64/kernel/sparcelf32.c	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/kernel/sparcelf32.c	Wed Dec 31 16:00:00 1969
@@ -1,1281 +0,0 @@
-/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra.
- *
- * This is just binfmt_elf.c with hooks so that the types are those
- * for a 32-bit ELF binaries.
- */
-
-/* This makes it work. */
-#define ELF_ARCH	EM_SPARC
-#define ELF_CLASS	ELFCLASS32
-#define ELF_DATA	ELFDATA2MSB;
-
-/*
- * linux/fs/binfmt_elf.c
- *
- * These are the functions used to load ELF format executables as used
- * on SVr4 machines.  Information on the format may be found in the book
- * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
- * Tools".
- *
- * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-#include <linux/elfcore.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-#include <linux/config.h>
-
-#define DLINFO_ITEMS 12
-
-#include <linux/elf.h>
-
-static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs);
-static int load_elf32_library(int fd);
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
-extern void dump_thread(struct pt_regs *, struct user *);
-
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-
-/*
- * If we don't support core dumping, then supply a NULL so we
- * don't even try.
- */
-#ifdef USE_ELF_CORE_DUMP
-static int elf32_core_dump(long signr, struct pt_regs * regs);
-#else
-#define elf32_core_dump	NULL
-#endif
-
-#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
-#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-
-static struct linux_binfmt elf32_format = {
-#ifndef MODULE
-	NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump
-#else
-	NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump
-#endif
-};
-
-static void set_brk(unsigned long start, unsigned long end)
-{
-	start = PAGE_ALIGN(start);
-	end = PAGE_ALIGN(end);
-	if (end <= start)
-		return;
-	do_mmap(NULL, start, end - start,
-		PROT_READ | PROT_WRITE | PROT_EXEC,
-		MAP_FIXED | MAP_PRIVATE, 0);
-}
-
-
-/* We need to explicitly zero any fractional pages
-   after the data section (i.e. bss).  This would
-   contain the junk from the file that should not
-   be in memory */
-
-
-static void padzero(unsigned long elf_bss)
-{
-	unsigned long nbyte;
-
-	nbyte = elf_bss & (PAGE_SIZE-1);
-	if (nbyte) {
-		nbyte = PAGE_SIZE - nbyte;
-		clear_user((void *) elf_bss, nbyte);
-	}
-}
-
-__u32 *create_elf32_tables(char *p, int argc, int envc,
-			   struct elfhdr * exec,
-			   unsigned long load_addr,
-			   unsigned long interp_load_addr, int ibcs)
-{
-	__u32 *argv, *envp;
-	__u32 *sp, *csp;
-
-	/*
-	 * Force 16 byte alignment here for generality.
-	 */
-	sp = (__u32 *) (~15UL & (unsigned long) p);
-	csp = sp;
-	csp -= exec ? DLINFO_ITEMS*2 : 2;
-	csp -= envc+1;
-	csp -= argc+1;
-	if (!(((unsigned long) csp) & 4))
-		sp--;
-
-	/*
-	 * Put the ELF interpreter info on the stack
-	 */
-#define NEW_AUX_ENT(nr, id, val) \
-	  __put_user ((id), sp+(nr*2)); \
-	  __put_user ((val), sp+(nr*2+1)); \
-
-	sp -= 2;
-	NEW_AUX_ENT(0, AT_NULL, 0);
-
-	if (exec) {
-		sp -= 11*2;
-
-	  NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
-	  NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
-	  NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
-	  NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
-	  NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
-	  NEW_AUX_ENT (5, AT_FLAGS, 0);
-	  NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry);
-	  NEW_AUX_ENT (7, AT_UID, (__u32) current->uid);
-	  NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid);
-	  NEW_AUX_ENT (9, AT_GID, (__u32) current->gid);
-	  NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid);
-	}
-#undef NEW_AUX_ENT
-
-	sp -= envc+1;
-	envp = (__u32 *) sp;
-	sp -= argc+1;
-	argv = (__u32 *) sp;
-	if (!ibcs) {
-		__put_user(((__u32)(long) envp),--sp);
-		__put_user(((__u32)(long) argv),--sp);
-	}
-
-	__put_user((__u32)argc,--sp);
-	current->mm->arg_start = (unsigned long) p;
-	while (argc-->0) {
-		__put_user(((__u32)(long)p),argv++);
-		p += strlen_user(p);
-	}
-	__put_user(NULL, argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-	while (envc-->0) {
-		__put_user(((__u32)(long)p),envp++);
-		p += strlen_user(p);
-	}
-	__put_user(NULL, envp);
-	current->mm->env_end = (unsigned long) p;
-	return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
-   so we keep this separate.  Technically the library read function
-   is only provided so that we can read a.out libraries that have
-   an ELF header */
-
-static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex,
-				       struct inode * interpreter_inode,
-				       unsigned long *interp_load_addr)
-{
-	struct file * file;
-	struct elf_phdr *elf_phdata  =  NULL;
-	struct elf_phdr *eppnt;
-	unsigned long load_addr;
-	int load_addr_set = 0;
-	int elf_exec_fileno;
-	int retval;
-	unsigned long last_bss, elf_bss;
-	unsigned long error;
-	int i;
-
-	elf_bss = 0;
-	last_bss = 0;
-	error = load_addr = 0;
-
-	/* First of all, some simple consistency checks */
-	if ((interp_elf_ex->e_type != ET_EXEC &&
-	    interp_elf_ex->e_type != ET_DYN) ||
-	   !elf_check_arch(interp_elf_ex->e_machine) ||
-	   (!interpreter_inode->i_op ||
-	    !interpreter_inode->i_op->default_file_ops->mmap)){
-		return ~0UL;
-	}
-
-	/* Now read in all of the header information */
-
-	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
-	    return ~0UL;
-
-	elf_phdata =  (struct elf_phdr *)
-		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
-			GFP_KERNEL);
-	if (!elf_phdata)
-	  return ~0UL;
-
-	/*
-	 * If the size of this structure has changed, then punt, since
-	 * we will be doing the wrong thing.
-	 */
-	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
-	  {
-	    kfree(elf_phdata);
-	    return ~0UL;
-	  }
-
-	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
-			   (char *) elf_phdata,
-			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
-
-	if (retval < 0) {
-		kfree (elf_phdata);
-		return retval;
- 	}
-
-	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
-	if (elf_exec_fileno < 0) {
-	  kfree(elf_phdata);
-	  return ~0UL;
-	}
-
-	file = current->files->fd[elf_exec_fileno];
-
-	eppnt = elf_phdata;
-	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-	  if (eppnt->p_type == PT_LOAD) {
-	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-	    int elf_prot = 0;
-	    unsigned long vaddr = 0;
-	    unsigned long k;
-
-	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-	    	elf_type |= MAP_FIXED;
-	    	vaddr = eppnt->p_vaddr;
-	    } else {
-		load_addr = get_unmapped_area(0, eppnt->p_filesz +
-					ELF_PAGEOFFSET(eppnt->p_vaddr));
-	    }
-
-	    error = do_mmap(file,
-			    load_addr + ELF_PAGESTART(vaddr),
-			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
-			    elf_prot,
-			    elf_type,
-			    eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-
-	    if (error > -1024UL) {
-	      /* Real error */
-	      sys_close(elf_exec_fileno);
-	      kfree(elf_phdata);
-	      return ~0UL;
-	    }
-
-	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-	      load_addr = error;
-	      load_addr_set = 1;
-	    }
-
-	    /*
-	     * Find the end of the file  mapping for this phdr, and keep
-	     * track of the largest address we see for this.
-	     */
-	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-	    if (k > elf_bss) elf_bss = k;
-
-	    /*
-	     * Do the same thing for the memory mapping - between
-	     * elf_bss and last_bss is the bss section.
-	     */
-	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-	    if (k > last_bss) last_bss = k;
-	  }
-
-	/* Now use mmap to map the library into memory. */
-
-	sys_close(elf_exec_fileno);
-
-	/*
-	 * Now fill out the bss section.  First pad the last page up
-	 * to the page boundary, and then perform a mmap to make sure
-	 * that there are zeromapped pages up to and including the last
-	 * bss page.
-	 */
-	padzero(elf_bss);
-	elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
-
-	/* Map the last of the bss segment */
-	if (last_bss > elf_bss)
-	  do_mmap(NULL, elf_bss, last_bss-elf_bss,
-		  PROT_READ|PROT_WRITE|PROT_EXEC,
-		  MAP_FIXED|MAP_PRIVATE, 0);
-	kfree(elf_phdata);
-
-	*interp_load_addr = load_addr;
-	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned long load_aout32_interp(struct exec * interp_ex,
-			     struct inode * interpreter_inode)
-{
-  int retval;
-  unsigned long elf_entry;
-
-  current->mm->brk = interp_ex->a_bss +
-    (current->mm->end_data = interp_ex->a_data +
-     (current->mm->end_code = interp_ex->a_text));
-  elf_entry = interp_ex->a_entry;
-
-
-  if (N_MAGIC(*interp_ex) == OMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-	    PROT_READ|PROT_WRITE|PROT_EXEC,
-	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode, 32, (char *) 0,
-		       interp_ex->a_text+interp_ex->a_data, 0);
-  } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-	    PROT_READ|PROT_WRITE|PROT_EXEC,
-	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode,
-		       N_TXTOFF(*interp_ex) ,
-		       (char *) N_TXTADDR(*interp_ex),
-		       interp_ex->a_text+interp_ex->a_data, 0);
-  } else
-    retval = -1;
-
-  if (retval >= 0)
-    do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
-	    interp_ex->a_bss,
-	    PROT_READ|PROT_WRITE|PROT_EXEC,
-	    MAP_FIXED|MAP_PRIVATE, 0);
-  if (retval < 0) return ~0UL;
-  return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries.  There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-static inline int
-do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
-	struct elfhdr elf_ex;
-	struct elfhdr interp_elf_ex;
-	struct file * file;
-  	struct exec interp_ex;
-	struct inode *interpreter_inode;
-	unsigned long load_addr;
-	int load_addr_set = 0;
-	unsigned int interpreter_type = INTERPRETER_NONE;
-	unsigned char ibcs2_interpreter;
-	int i;
-	int old_fs;
-	int error;
-	struct elf_phdr * elf_ppnt, *elf_phdata;
-	int elf_exec_fileno;
-	unsigned long elf_bss, k, elf_brk;
-	int retval;
-	char * elf_interpreter;
-	unsigned long elf_entry, interp_load_addr = 0;
-	int status;
-	unsigned long start_code, end_code, end_data;
-	unsigned long elf_stack;
-	char passed_fileno[6];
-
-	ibcs2_interpreter = 0;
-	status = 0;
-	load_addr = 0;
-	elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
-
-	if (elf_ex.e_ident[0] != 0x7f ||
-	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
-		return  -ENOEXEC;
-	}
-
-
-	/* First of all, some simple consistency checks */
-	if ((elf_ex.e_type != ET_EXEC &&
-	    elf_ex.e_type != ET_DYN) ||
-	   (! elf_check_arch(elf_ex.e_machine)) ||
-	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-	    !bprm->inode->i_op->default_file_ops->mmap)){
-		return -ENOEXEC;
-	}
-
-	/* Now read in all of the header information */
-
-	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
-						 elf_ex.e_phnum, GFP_KERNEL);
-	if (elf_phdata == NULL) {
-		return -ENOMEM;
-	}
-
-	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
-			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
-	if (retval < 0) {
-		kfree (elf_phdata);
-		return retval;
-	}
-
-	elf_ppnt = elf_phdata;
-
-	elf_bss = 0;
-	elf_brk = 0;
-
-	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
-	if (elf_exec_fileno < 0) {
-		kfree (elf_phdata);
-		return elf_exec_fileno;
-	}
-
-	file = current->files->fd[elf_exec_fileno];
-
-	elf_stack = ~0UL;
-	elf_interpreter = NULL;
-	start_code = ~0UL;
-	end_code = 0;
-	end_data = 0;
-
-	for(i=0;i < elf_ex.e_phnum; i++){
-		if (elf_ppnt->p_type == PT_INTERP) {
-		  	if ( elf_interpreter != NULL )
-			{
-				kfree (elf_phdata);
-				kfree(elf_interpreter);
-				sys_close(elf_exec_fileno);
-				return -EINVAL;
-			}
-
-			/* This is the program interpreter used for
-			 * shared libraries - for now assume that this
-			 * is an a.out format binary
-			 */
-
-			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
-							   GFP_KERNEL);
-			if (elf_interpreter == NULL) {
-				kfree (elf_phdata);
-				sys_close(elf_exec_fileno);
-				return -ENOMEM;
-			}
-
-			retval = read_exec(bprm->inode,elf_ppnt->p_offset,
-					   elf_interpreter,
-					   elf_ppnt->p_filesz, 1);
-			/* If the program interpreter is one of these two,
-			   then assume an iBCS2 image. Otherwise assume
-			   a native linux image. */
-			if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-			    strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
-			  ibcs2_interpreter = 1;
-#if 0
-			printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
-			if (retval >= 0) {
-				old_fs = get_fs(); /* This could probably be optimized */
-				set_fs(get_ds());
-				retval = open_namei(elf_interpreter, 0, 0,
-						    &interpreter_inode, NULL);
-				set_fs(old_fs);
-			}
-
-			if (retval >= 0)
-				retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
-
-			if (retval >= 0) {
-				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
-				interp_elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
-
-			}
-			if (retval < 0) {
-				kfree (elf_phdata);
-				kfree(elf_interpreter);
-				sys_close(elf_exec_fileno);
-				return retval;
-			}
-		}
-		elf_ppnt++;
-	}
-
-	/* Some simple consistency checks for the interpreter */
-	if (elf_interpreter){
-		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
-		/* Now figure out which format our binary is */
-		if ((N_MAGIC(interp_ex) != OMAGIC) &&
-		    (N_MAGIC(interp_ex) != ZMAGIC) &&
-		    (N_MAGIC(interp_ex) != QMAGIC))
-		  interpreter_type = INTERPRETER_ELF;
-
-		if (interp_elf_ex.e_ident[0] != 0x7f ||
-		    strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
-		  interpreter_type &= ~INTERPRETER_ELF;
-
-		if (!interpreter_type)
-		  {
-		    kfree(elf_interpreter);
-		    kfree(elf_phdata);
-		    sys_close(elf_exec_fileno);
-		    return -ELIBBAD;
-		  }
-	}
-
-	/* OK, we are done with that, now set up the arg stuff,
-	   and then start this sucker up */
-
-	if (!bprm->sh_bang) {
-		char * passed_p;
-
-		if (interpreter_type == INTERPRETER_AOUT) {
-		  sprintf(passed_fileno, "%d", elf_exec_fileno);
-		  passed_p = passed_fileno;
-
-		  if (elf_interpreter) {
-		    bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
-		    bprm->argc++;
-		  }
-		}
-		if (!bprm->p) {
-			if (elf_interpreter) {
-			      kfree(elf_interpreter);
-			}
-			kfree (elf_phdata);
-			sys_close(elf_exec_fileno);
-			return -E2BIG;
-		}
-	}
-
-	/* OK, This is the point of no return */
-	flush_old_exec(bprm);
-
-	current->mm->end_data = 0;
-	current->mm->end_code = 0;
-	current->mm->start_mmap = ELF_START_MMAP;
-	current->mm->mmap = NULL;
-	elf_entry = (unsigned long) elf_ex.e_entry;
-
-	/* Do this so that we can load the interpreter, if need be.  We will
-	   change some of these later */
-	current->mm->rss = 0;
-	current->tss.flags |= SPARC_FLAG_32BIT;
-	bprm->p = setup_arg_pages(bprm->p, bprm);
-	current->mm->start_stack = bprm->p;
-
-	/* Now we do a little grungy work by mmaping the ELF image into
-	   the correct location in memory.  At this point, we assume that
-	   the image should be loaded at fixed address, not at a variable
-	   address. */
-
-	old_fs = get_fs();
-	set_fs(get_ds());
-	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
-		if (elf_ppnt->p_type == PT_LOAD) {
-			int elf_prot = 0;
-			if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
-			if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-			if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-
-			error = do_mmap(file,
-					ELF_PAGESTART(elf_ppnt->p_vaddr),
-					(elf_ppnt->p_filesz +
-					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
-					elf_prot,
-					(MAP_FIXED | MAP_PRIVATE |
-					 MAP_DENYWRITE | MAP_EXECUTABLE),
-					(elf_ppnt->p_offset -
-					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-
-#ifdef LOW_ELF_STACK
-			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
-				elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
-#endif
-
-			if (!load_addr_set) {
-			  load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
-			  load_addr_set = 1;
-			}
-			k = elf_ppnt->p_vaddr;
-			if (k < start_code) start_code = k;
-			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-			if (k > elf_bss) elf_bss = k;
-#if 1
-			if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
-#else
-			if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
-#endif
-				end_code = k;
-			if (end_data < k) end_data = k;
-			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-			if (k > elf_brk) elf_brk = k;
-		}
-	}
-	set_fs(old_fs);
-
-	if (elf_interpreter) {
-		if (interpreter_type & 1)
-			elf_entry = load_aout32_interp(&interp_ex,
-						       interpreter_inode);
-		else if (interpreter_type & 2)
-			elf_entry = load_elf32_interp(&interp_elf_ex,
-						      interpreter_inode,
-						      &interp_load_addr);
-
-		iput(interpreter_inode);
-		kfree(elf_interpreter);
-
-		if (elf_entry == ~0UL) {
-			printk("Unable to load interpreter\n");
-			kfree(elf_phdata);
-			send_sig(SIGSEGV, current, 0);
-			return 0;
-		}
-	}
-
-	kfree(elf_phdata);
-
-	if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
-	current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-
-	if (current->exec_domain && current->exec_domain->module)
-		__MOD_DEC_USE_COUNT(current->exec_domain->module);
-	if (current->binfmt && current->binfmt->module)
-		__MOD_DEC_USE_COUNT(current->binfmt->module);
-	current->exec_domain = lookup_exec_domain(current->personality);
-	current->binfmt = &elf32_format;
-	if (current->exec_domain && current->exec_domain->module)
-		__MOD_INC_USE_COUNT(current->exec_domain->module);
-	if (current->binfmt && current->binfmt->module)
-		__MOD_INC_USE_COUNT(current->binfmt->module);
-
-#ifndef VM_STACK_FLAGS
-	current->executable = bprm->inode;
-	bprm->inode->i_count++;
-#endif
-#ifdef LOW_ELF_STACK
-	current->start_stack = bprm->p = elf_stack - 4;
-#endif
-	current->suid = current->euid = current->fsuid = bprm->e_uid;
-	current->sgid = current->egid = current->fsgid = bprm->e_gid;
-	current->flags &= ~PF_FORKNOEXEC;
-	bprm->p = (unsigned long)
-	  create_elf32_tables((char *)bprm->p,
-			      bprm->argc,
-			      bprm->envc,
-			      (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
-			      load_addr,
-			      interp_load_addr,
-			      (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
-	if (interpreter_type == INTERPRETER_AOUT)
-	  current->mm->arg_start += strlen(passed_fileno) + 1;
-	current->mm->start_brk = current->mm->brk = elf_brk;
-	current->mm->end_code = end_code;
-	current->mm->start_code = start_code;
-	current->mm->end_data = end_data;
-	current->mm->start_stack = bprm->p;
-
-	/* Calling set_brk effectively mmaps the pages that we need for the bss and break
-	   sections */
-	set_brk(elf_bss, elf_brk);
-
-	padzero(elf_bss);
-
-#if 0
-	printk("(start_brk) %x\n" , current->mm->start_brk);
-	printk("(end_code) %x\n" , current->mm->end_code);
-	printk("(start_code) %x\n" , current->mm->start_code);
-	printk("(end_data) %x\n" , current->mm->end_data);
-	printk("(start_stack) %x\n" , current->mm->start_stack);
-	printk("(brk) %x\n" , current->mm->brk);
-#endif
-
-	if ( current->personality == PER_SVR4 )
-	{
-		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
-		   and some applications "depend" upon this behavior.
-		   Since we do not have the power to recompile these, we
-		   emulate the SVr4 behavior.  Sigh.  */
-		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
-				MAP_FIXED | MAP_PRIVATE, 0);
-	}
-
-#ifdef ELF_PLAT_INIT
-	/*
-	 * The ABI may specify that certain registers be set up in special
-	 * ways (on i386 %edx is the address of a DT_FINI function, for
-	 * example.  This macro performs whatever initialization to
-	 * the regs structure is required.
-	 */
-	ELF_PLAT_INIT(regs);
-#endif
-
-
-	start_thread32(regs, elf_entry, bprm->p);
-	if (current->flags & PF_PTRACED)
-		send_sig(SIGTRAP, current, 0);
-	return 0;
-}
-
-static int
-load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
-	int retval;
-
-	MOD_INC_USE_COUNT;
-	retval = do_load_elf32_binary(bprm, regs);
-	MOD_DEC_USE_COUNT;
-	return retval;
-}
-
-/* This is really simpleminded and specialized - we are loading an
-   a.out library that is given an ELF header. */
-
-static inline int
-do_load_elf32_library(int fd){
-	struct file * file;
-	struct elfhdr elf_ex;
-	struct elf_phdr *elf_phdata  =  NULL;
-	struct  inode * inode;
-	unsigned long len;
-	int elf_bss;
-	int retval;
-	unsigned long bss;
-	int error;
-	int i,j, k;
-
-	len = 0;
-	file = current->files->fd[fd];
-	inode = file->f_inode;
-	elf_bss = 0;
-
-	if (!file || !file->f_op)
-		return -EACCES;
-
-	/* seek to the beginning of the file */
-	if (file->f_op->llseek) {
-		if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
-			return -ENOEXEC;
-	} else
-		file->f_pos = 0;
-
-	set_fs(KERNEL_DS);
-	error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
-	set_fs(USER_DS);
-	if (error != sizeof(elf_ex))
-		return -ENOEXEC;
-
-	if (elf_ex.e_ident[0] != 0x7f ||
-	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
-		return -ENOEXEC;
-
-	/* First of all, some simple consistency checks */
-	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
-	   !elf_check_arch(elf_ex.e_machine) ||
-	   (!inode->i_op || !inode->i_op->default_file_ops->mmap))
-		return -ENOEXEC;
-
-	/* Now read in all of the header information */
-
-	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
-		return -ENOEXEC;
-
-	elf_phdata =  (struct elf_phdr *)
-		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
-	if (elf_phdata == NULL)
-		return -ENOMEM;
-
-	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
-			   sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
-
-	j = 0;
-	for(i=0; i<elf_ex.e_phnum; i++)
-		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
-
-	if (j != 1)  {
-		kfree(elf_phdata);
-		return -ENOEXEC;
-	}
-
-	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-
-	/* Now use mmap to map the library into memory. */
-	error = do_mmap(file,
-			ELF_PAGESTART(elf_phdata->p_vaddr),
-			(elf_phdata->p_filesz +
-			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
-			PROT_READ | PROT_WRITE | PROT_EXEC,
-			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
-			(elf_phdata->p_offset -
-			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
-
-	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
-	if (k > elf_bss) elf_bss = k;
-
-	if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
-		kfree(elf_phdata);
-		return error;
-	}
-
-	padzero(elf_bss);
-
-	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
-	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
-	if (bss > len)
-	  do_mmap(NULL, len, bss-len,
-		  PROT_READ|PROT_WRITE|PROT_EXEC,
-		  MAP_FIXED|MAP_PRIVATE, 0);
-	kfree(elf_phdata);
-	return 0;
-}
-
-static int load_elf32_library(int fd)
-{
-	int retval;
-
-	MOD_INC_USE_COUNT;
-	retval = do_load_elf32_library(fd);
-	MOD_DEC_USE_COUNT;
-	return retval;
-}
-
-/*
- * Note that some platforms still use traditional core dumps and not
- * the ELF core dump.  Each platform can select it as appropriate.
- */
-#ifdef USE_ELF_CORE_DUMP
-
-/*
- * ELF core dumper
- *
- * Modelled on fs/exec.c:aout_core_dump()
- * Jeremy Fitzhardinge <jeremy@sw.oz.au>
- */
-/*
- * These are the only things you should do on a core-file: use only these
- * functions to write out all the necessary info.
- */
-static int dump_write(struct file *file, const void *addr, int nr)
-{
-	return file->f_op->write(file->f_inode, file, addr, nr) == nr;
-}
-
-static int dump_seek(struct file *file, off_t off)
-{
-	if (file->f_op->llseek) {
-		if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
-			return 0;
-	} else
-		file->f_pos = off;
-	return 1;
-}
-
-/*
- * Decide whether a segment is worth dumping; default is yes to be
- * sure (missing info is worse than too much; etc).
- * Personally I'd include everything, and use the coredump limit...
- *
- * I think we should skip something. But I am not sure how. H.J.
- */
-static inline int maydump(struct vm_area_struct *vma)
-{
-	if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
-		return 0;
-#if 1
-	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
-		return 1;
-	if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
-		return 0;
-#endif
-	return 1;
-}
-
-#define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
-
-/* An ELF note in memory */
-struct memelfnote
-{
-	const char *name;
-	int type;
-	unsigned int datasz;
-	void *data;
-};
-
-static int notesize(struct memelfnote *en)
-{
-	int sz;
-
-	sz = sizeof(struct elf_note);
-	sz += roundup(strlen(en->name), 4);
-	sz += roundup(en->datasz, 4);
-
-	return sz;
-}
-
-/* #define DEBUG */
-
-#define DUMP_WRITE(addr, nr)	\
-	do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
-#define DUMP_SEEK(off)	\
-	do { if (!dump_seek(file, (off))) return 0; } while(0)
-
-static int writenote(struct memelfnote *men, struct file *file)
-{
-	struct elf_note en;
-
-	en.n_namesz = strlen(men->name);
-	en.n_descsz = men->datasz;
-	en.n_type = men->type;
-
-	DUMP_WRITE(&en, sizeof(en));
-	DUMP_WRITE(men->name, en.n_namesz);
-	/* XXX - cast from long long to long to avoid need for libgcc.a */
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
-	DUMP_WRITE(men->data, men->datasz);
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
-
-	return 1;
-}
-#undef DUMP_WRITE
-#undef DUMP_SEEK
-
-#define DUMP_WRITE(addr, nr)	\
-	if (!dump_write(&file, (addr), (nr))) \
-		goto close_coredump;
-#define DUMP_SEEK(off)	\
-	if (!dump_seek(&file, (off))) \
-		goto close_coredump;
-/*
- * Actual dumper
- *
- * This is a two-pass process; first we find the offsets of the bits,
- * and then they are actually written out.  If we run out of core limit
- * we just truncate.
- */
-static int elf32_core_dump(long signr, struct pt_regs * regs)
-{
-	int has_dumped = 0;
-	struct file file;
-	struct inode *inode;
-	unsigned short fs;
-	char corefile[6+sizeof(current->comm)];
-	int segs;
-	int i;
-	size_t size;
-	struct vm_area_struct *vma;
-	struct elfhdr elf;
-	off_t offset = 0, dataoff;
-	int limit = current->rlim[RLIMIT_CORE].rlim_cur;
-	int numnote = 4;
-	struct memelfnote notes[4];
-	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
-	elf_fpregset_t fpu;		/* NT_PRFPREG */
-	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
-
-	if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
-		return 0;
-	current->dumpable = 0;
-
-#ifndef CONFIG_BINFMT_ELF32
-	MOD_INC_USE_COUNT;
-#endif
-
-	/* Count what's needed to dump, up to the limit of coredump size */
-	segs = 0;
-	size = 0;
-	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
-		if (maydump(vma))
-		{
-			int sz = vma->vm_end-vma->vm_start;
-
-			if (size+sz >= limit)
-				break;
-			else
-				size += sz;
-		}
-
-		segs++;
-	}
-#ifdef DEBUG
-	printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
-#endif
-
-	/* Set up header */
-	memcpy(elf.e_ident, ELFMAG, SELFMAG);
-	elf.e_ident[EI_CLASS] = ELF_CLASS;
-	elf.e_ident[EI_DATA] = ELF_DATA;
-	elf.e_ident[EI_VERSION] = EV_CURRENT;
-	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-
-	elf.e_type = ET_CORE;
-	elf.e_machine = ELF_ARCH;
-	elf.e_version = EV_CURRENT;
-	elf.e_entry = 0;
-	elf.e_phoff = sizeof(elf);
-	elf.e_shoff = 0;
-	elf.e_flags = 0;
-	elf.e_ehsize = sizeof(elf);
-	elf.e_phentsize = sizeof(struct elf_phdr);
-	elf.e_phnum = segs+1;		/* Include notes */
-	elf.e_shentsize = 0;
-	elf.e_shnum = 0;
-	elf.e_shstrndx = 0;
-
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	memcpy(corefile,"core.",5);
-#if 0
-	memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
-	corefile[4] = '\0';
-#endif
-	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
-		inode = NULL;
-		goto end_coredump;
-	}
-	if (!S_ISREG(inode->i_mode))
-		goto end_coredump;
-	if (!inode->i_op || !inode->i_op->default_file_ops)
-		goto end_coredump;
-	file.f_mode = 3;
-	file.f_flags = 0;
-	file.f_count = 1;
-	file.f_inode = inode;
-	file.f_pos = 0;
-	file.f_reada = 0;
-	file.f_op = inode->i_op->default_file_ops;
-	if (file.f_op->open)
-		if (file.f_op->open(inode,&file))
-			goto end_coredump;
-	if (!file.f_op->write)
-		goto close_coredump;
-	has_dumped = 1;
-	current->flags |= PF_DUMPCORE;
-
-	DUMP_WRITE(&elf, sizeof(elf));
-	offset += sizeof(elf);				/* Elf header */
-	offset += (segs+1) * sizeof(struct elf_phdr);	/* Program headers */
-
-	/*
-	 * Set up the notes in similar form to SVR4 core dumps made
-	 * with info from their /proc.
-	 */
-	memset(&psinfo, 0, sizeof(psinfo));
-	memset(&prstatus, 0, sizeof(prstatus));
-
-	notes[0].name = "CORE";
-	notes[0].type = NT_PRSTATUS;
-	notes[0].datasz = sizeof(prstatus);
-	notes[0].data = &prstatus;
-	prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
-	prstatus.pr_sigpend = current->signal;
-	prstatus.pr_sighold = current->blocked;
-	psinfo.pr_pid = prstatus.pr_pid = current->pid;
-	psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
-	psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
-	psinfo.pr_sid = prstatus.pr_sid = current->session;
-	prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
-	prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
-	prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
-	prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
-	prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
-	prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
-	prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
-	prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
-
-	/*
-	 * This transfers the registers from regs into the standard
-	 * coredump arrangement, whatever that is.
-	 */
-#ifdef ELF_CORE_COPY_REGS
-	ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
-#else
-	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
-	{
-		printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
-			sizeof(elf_gregset_t), sizeof(struct pt_regs));
-	}
-	else
-		*(struct pt_regs *)&prstatus.pr_reg = *regs;
-#endif
-
-	notes[1].name = "CORE";
-	notes[1].type = NT_PRPSINFO;
-	notes[1].datasz = sizeof(psinfo);
-	notes[1].data = &psinfo;
-	psinfo.pr_state = current->state;
-	psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
-	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
-	psinfo.pr_nice = current->priority-15;
-	psinfo.pr_flag = current->flags;
-	psinfo.pr_uid = current->uid;
-	psinfo.pr_gid = current->gid;
-	{
-		int i, len;
-
-		set_fs(fs);
-
-		len = current->mm->arg_end - current->mm->arg_start;
-		len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
-		copy_from_user(&psinfo.pr_psargs,
-			      (const char *)current->mm->arg_start, len);
-		for(i = 0; i < len; i++)
-			if (psinfo.pr_psargs[i] == 0)
-				psinfo.pr_psargs[i] = ' ';
-		psinfo.pr_psargs[len] = 0;
-
-		set_fs(KERNEL_DS);
-	}
-	strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
-
-	notes[2].name = "CORE";
-	notes[2].type = NT_TASKSTRUCT;
-	notes[2].datasz = sizeof(*current);
-	notes[2].data = current;
-
-	/* Try to dump the fpu. */
-	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
-	if (!prstatus.pr_fpvalid)
-	{
-		numnote--;
-	}
-	else
-	{
-		notes[3].name = "CORE";
-		notes[3].type = NT_PRFPREG;
-		notes[3].datasz = sizeof(fpu);
-		notes[3].data = &fpu;
-	}
-	
-	/* Write notes phdr entry */
-	{
-		struct elf_phdr phdr;
-		int sz = 0;
-
-		for(i = 0; i < numnote; i++)
-			sz += notesize(&notes[i]);
-
-		phdr.p_type = PT_NOTE;
-		phdr.p_offset = offset;
-		phdr.p_vaddr = 0;
-		phdr.p_paddr = 0;
-		phdr.p_filesz = sz;
-		phdr.p_memsz = 0;
-		phdr.p_flags = 0;
-		phdr.p_align = 0;
-
-		offset += phdr.p_filesz;
-		DUMP_WRITE(&phdr, sizeof(phdr));
-	}
-
-	/* Page-align dumped data */
-	dataoff = offset = roundup(offset, PAGE_SIZE);
-
-	/* Write program headers for segments dump */
-	for(vma = current->mm->mmap, i = 0;
-		i < segs && vma != NULL; vma = vma->vm_next) {
-		struct elf_phdr phdr;
-		size_t sz;
-
-		i++;
-
-		sz = vma->vm_end - vma->vm_start;
-
-		phdr.p_type = PT_LOAD;
-		phdr.p_offset = offset;
-		phdr.p_vaddr = vma->vm_start;
-		phdr.p_paddr = 0;
-		phdr.p_filesz = maydump(vma) ? sz : 0;
-		phdr.p_memsz = sz;
-		offset += phdr.p_filesz;
-		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
-		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
-		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
-		phdr.p_align = PAGE_SIZE;
-
-		DUMP_WRITE(&phdr, sizeof(phdr));
-	}
-
-	for(i = 0; i < numnote; i++)
-		if (!writenote(&notes[i], &file))
-			goto close_coredump;
-
-	set_fs(fs);
-
-	DUMP_SEEK(dataoff);
-
-	for(i = 0, vma = current->mm->mmap;
-	    i < segs && vma != NULL;
-	    vma = vma->vm_next) {
-		unsigned long addr = vma->vm_start;
-		unsigned long len = vma->vm_end - vma->vm_start;
-
-		i++;
-		if (!maydump(vma))
-			continue;
-#ifdef DEBUG
-		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
-#endif
-		DUMP_WRITE((void *)addr, len);
-	}
-
-	if ((off_t) file.f_pos != offset) {
-		/* Sanity check */
-		printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
-		       (off_t) file.f_pos, offset);
-	}
-
- close_coredump:
-	if (file.f_op->release)
-		file.f_op->release(inode,&file);
-
- end_coredump:
-	set_fs(fs);
-	iput(inode);
-#ifndef CONFIG_BINFMT_ELF32
-	MOD_DEC_USE_COUNT;
-#endif
-	return has_dumped;
-}
-#endif		/* USE_ELF_CORE_DUMP */
-
-__initfunc(int init_elf32_binfmt(void))
-{
-	return register_binfmt(&elf32_format);
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	/* Install the COFF, ELF and XOUT loaders.
-	 * N.B. We *rely* on the table being the right size with the
-	 * right number of free slots...
-	 */
-	return init_elf32_binfmt();
-}
-
-
-void cleanup_module( void)
-{
-	/* Remove the COFF and ELF loaders. */
-	unregister_binfmt(&elf32_format);
-}
-#endif
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.39/linux/arch/sparc64/kernel/sys_sparc32.c	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.12 1997/05/14 14:50:58 jj Exp $
+/* $Id: sys_sparc32.c,v 1.13 1997/05/18 04:16:44 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -34,9 +34,12 @@
 #include <asm/ipc.h>
 #include <asm/uaccess.h>
 
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings */
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to
+ * unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to
+ * type (void *)((unsigned long)x) or instead of just (void *)x, which will
+ * produce warnings.
+ */
 #define A(x) ((unsigned long)x)
  
 extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.1.39/linux/arch/sparc64/kernel/traps.c	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/kernel/traps.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $
+/* $Id: traps.c,v 1.10 1997/05/18 08:42:16 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
+#include <asm/uaccess.h>
 
 /* #define TRAP_DEBUG */
 
@@ -42,6 +43,8 @@
 
 void syscall_trace_exit(struct pt_regs *regs)
 {
+	printk("Syscall return check, reg dump.\n");
+	show_regs(regs);
 }
 
 void sparc64_dtlb_fault_handler (void)
@@ -116,25 +119,45 @@
 	show_regs(regs);
 	printk("Instruction DUMP:");
 	instruction_dump ((unsigned int *) regs->tpc);
+	while(1)
+		barrier();
 	if(regs->tstate & TSTATE_PRIV)
 		do_exit(SIGKILL);
 	do_exit(SIGSEGV);
 }
 
-void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-			    unsigned long tstate)
+void do_illegal_instruction(struct pt_regs *regs)
 {
+	unsigned long pc = regs->tpc;
+	unsigned long tstate = regs->tstate;
+
 	lock_kernel();
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("Kernel illegal instruction", regs);
-#ifdef TRAP_DEBUG
-	printk("Ill instr. at pc=%016lx instruction is %08x\n",
-	       regs->tpc, *(unsigned int *)regs->tpc);
+#if 1
+	{
+		unsigned int insn;
+
+		printk("Ill instr. at pc=%016lx ", pc);
+		get_user(insn, ((unsigned int *)pc));
+		printk("insn=[%08x]\n", insn);
+	}
 #endif
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
 	unlock_kernel();
+
+	while(1)
+		barrier();
+}
+
+void do_mna(struct pt_regs *regs)
+{
+	printk("AIEEE: do_mna at %016lx\n", regs->tpc);
+	show_regs(regs);
+	while(1)
+		barrier();
 }
 
 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.1.39/linux/arch/sparc64/kernel/ttable.S	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/kernel/ttable.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $
+/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -13,7 +13,7 @@
 tl0_resv009:	BTRAP(0x9)
 tl0_iae:	TRAP(do_iae)
 tl0_resv00b:	BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
-tl0_ill:	TRAP(do_ill)
+tl0_ill:	TRAP(do_illegal_instruction)
 tl0_privop:	TRAP(do_privop)
 tl0_resv012:	BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
 tl0_resv018:	BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
@@ -226,27 +226,3 @@
 tl1_f5o:	FILL_5_OTHER
 tl1_f6o:	FILL_6_OTHER
 tl1_f7o:	FILL_7_OTHER
-
-#if 0
-/* Unless we are going to have software trap insns in the kernel code, we
- * don't need this. For now we just save 8KB.
- */
-
-#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7)
-
-tl1_sunos:	BTRAPTL1(0x100)
-tl1_bkpt:	BREAKPOINT_TRAP
-tl1_resv102:	BTRAPTL1(0x102)
-tl1_flushw:	FLUSH_WINDOW_TRAP
-tl1_resv104:	BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106)
-tl1_resv107:	BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a)
-tl1_resv10b:	BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e)
-tl1_resv10f:	BTRAPTL1(0x10f) 
-tl1_resv110:	BTRAPSTL1(0x110) BTRAPSTL1(0x118)
-tl1_resv120:	BTRAPSTL1(0x120) BTRAPSTL1(0x128)
-tl1_resv130:	BTRAPSTL1(0x130) BTRAPSTL1(0x138)
-tl1_resv140:	BTRAPSTL1(0x140) BTRAPSTL1(0x148)
-tl1_resv150:	BTRAPSTL1(0x150) BTRAPSTL1(0x158)
-tl1_resv160:	BTRAPSTL1(0x160) BTRAPSTL1(0x168)
-tl1_resv170:	BTRAPSTL1(0x170) BTRAPSTL1(0x178)
-#endif
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S
--- v2.1.39/linux/arch/sparc64/kernel/winfixup.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/winfixup.S	Sun May 18 17:10:37 1997
@@ -0,0 +1,101 @@
+/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $
+ *
+ * winfixup.S: Handle cases where user stack pointer is found to be bogus.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/asi.h>
+#include <asm/head.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/asm_offsets.h>
+
+	.text
+	.align	32
+
+	/* Here are the rules, pay attention.
+	 *
+	 * The kernel is disallowed from touching user space while
+	 * the trap level is greater than zero, except for from within
+	 * the window spill/fill handlers.  This must be followed
+	 * so that we can easily detect the case where we tried to
+	 * spill/fill with a bogus (or unmapped) user stack pointer.
+	 *
+	 * These are layed out in a special way for cache reasons,
+	 * don't touch...
+	 */
+	.globl	winfix_trampoline, fill_fixup, spill_fixup
+fill_fixup:
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	mov	%l5, %o4
+	mov	%l4, %o5
+	srlx	%l5, PAGE_SHIFT, %o3
+	clr	%o1
+	sllx	%o3, PAGE_SHIFT, %o3
+	and	%l4, 0x4, %o2
+
+	call	do_sparc64_fault
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,a,pt	%xcc, rtrap
+	nop
+winfix_trampoline:
+	andn		%g5, 0x7f, %g5
+	add		%g5, 0x7c, %g5
+	wrpr		%g5, %tnpc
+	done
+
+spill_fixup:
+	rd	%pic, %g1
+	ldx	[%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2
+	sll	%g2, 3, %g5
+	ldx	[%g1 + AOFF_task_tss + AOFF_thread_flags], %g7
+	add	%g1, %g5, %g5
+	andcc	%g7, SPARC_FLAG_32BIT, %g0
+	stx	%sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+	sll	%g2, 5, %g5
+
+	bne,pt	%xcc, 1f
+	 add	%g1, %g5, %g5
+	stx	%l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	stx	%l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	stx	%l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+	stx	%l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+	stx	%l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+	stx	%l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+	stx	%l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+	stx	%l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+	stx	%i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+	stx	%i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+	stx	%i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+	stx	%i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+	stx	%i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+	stx	%i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+	stx	%i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+	stx	%i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+	b,a,pt	%xcc, 2f
+	 add	%g2, 1, %g2
+1:
+	std	%l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	std	%l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	std	%l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+	std	%l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+	std	%i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+	std	%i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+	std	%i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+	std	%i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+	add	%g2, 1, %g2
+2:
+	stx	%g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+	rdpr	%tstate, %g1
+	nop
+
+	andcc	%g1, TSTATE_PRIV, %g0
+	be,pn	%xcc, fill_fixup
+	 saved
+	retry
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.1.39/linux/arch/sparc64/lib/blockops.S	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/lib/blockops.S	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $
+/* $Id: blockops.S,v 1.6 1997/05/18 04:16:49 davem Exp $
  * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -31,37 +31,8 @@
 	.text
 	.align	4
 
-	.globl		bzero_2page, bzero_1page
-bzero_2page:
-	/* %o0 = buf */
-	mov		%o0, %o1
-	wr		%g0, ASI_BLK_P, %asi
-	mov		0x10, %g2
-
-	membar		#Sync|#StoreLoad
-
-	fzero		%f48
-	fzero		%f50
-	fzero		%f52
-	fzero		%f54
-	fzero		%f56
-	fzero		%f58
-	fzero		%f60
-	fzero		%f62
-1:
-	BLAST_BLOCK(%o0, 0x000)
-	BLAST_BLOCK(%o0, 0x100)
-	BLAST_BLOCK(%o0, 0x200)
-	BLAST_BLOCK(%o0, 0x300)
-	subcc		%g2, 1, %g2
-	bne,pt		%icc, 1b
-	 add		%o0, 0x400, %o0
-
-	membar		#Sync|#LoadStore|#StoreStore
-
-	retl
-	 mov		%o1, %o0
-
+#if 0
+	.globl		bzero_1page
 bzero_1page:
 	/* %o0 = buf */
 	mov		%o0, %o1
@@ -89,9 +60,36 @@
 
 	retl
 	 mov		%o1, %o0
+#endif
 
 	.globl		__bfill64
 __bfill64:
+#if 1
+	/* %o0 = buf, %o1 = 64-bit pattern */
+#define FILL_BLOCK(buf, offset) \
+	stx	%o1, [buf + offset + 0x38]; \
+	stx	%o1, [buf + offset + 0x30]; \
+	stx	%o1, [buf + offset + 0x28]; \
+	stx	%o1, [buf + offset + 0x20]; \
+	stx	%o1, [buf + offset + 0x18]; \
+	stx	%o1, [buf + offset + 0x10]; \
+	stx	%o1, [buf + offset + 0x08]; \
+	stx	%o1, [buf + offset + 0x00];
+
+	mov	0x20, %g2
+1:
+	FILL_BLOCK(%o0, 0x00)
+	FILL_BLOCK(%o0, 0x40)
+	FILL_BLOCK(%o0, 0x80)
+	FILL_BLOCK(%o0, 0xc0)
+	subcc	%g2, 1, %g2
+	bne,pt	%icc, 1b
+	 add	%o0, 0x100, %o0
+	retl
+	 nop
+#undef FILL_BLOCK
+
+#else
 	/* %o0 = buf */
 	stx		%o1, [%sp + 0x7ff + 128]
 	wr		%g0, ASI_BLK_P, %asi
@@ -116,7 +114,9 @@
 
 	retl
 	 membar		#Sync|#LoadStore|#StoreStore
+#endif
 
+#if 0
 	.globl		__copy_1page
 __copy_1page:
 	/* %o0 = dst, %o1 = src */
@@ -135,4 +135,4 @@
 
 	retl
 	 membar		#Sync|#LoadStore|#StoreStore
-
+#endif
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/lib/strlen_user.S linux/arch/sparc64/lib/strlen_user.S
--- v2.1.39/linux/arch/sparc64/lib/strlen_user.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/strlen_user.S	Sun May 18 17:10:37 1997
@@ -8,6 +8,8 @@
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <asm/asi.h>
+
 #define LO_MAGIC 0x01010101
 #define HI_MAGIC 0x80808080
 
@@ -19,21 +21,21 @@
 	be,pt	%icc, 9f
 	 sethi	%hi(HI_MAGIC), %o4
 10:
-	ldub	[%o0], %o5
+	lduba	[%o0] ASI_S, %o5
 	brz,pn	%o5, 21f
 	 add	%o0, 1, %o0
 	andcc	%o0, 3, %g0
 	be,pn	%icc, 4f
 	 or	%o4, %lo(HI_MAGIC), %o3
 11:
-	ldub	[%o0], %o5
+	lduba	[%o0] ASI_S, %o5
 	brz,pn	%o5, 22f
 	 add	%o0, 1, %o0
 	andcc	%o0, 3, %g0
 	be,pt	%icc, 5f
 	 sethi	%hi(LO_MAGIC), %o4
 12:
-	ldub	[%o0], %o5
+	lduba	[%o0] ASI_S, %o5
 	brz,pn	%o5, 23f
 	 add	%o0, 1, %o0
 	ba,pt	%icc, 13f
@@ -45,7 +47,7 @@
 5:
 	or	%o4, %lo(LO_MAGIC), %o2
 13:
-	ld	[%o0], %o5
+	lda	[%o0] ASI_S, %o5
 2:
 	sub	%o5, %o2, %o4
 	andcc	%o4, %o3, %g0
@@ -68,7 +70,7 @@
 	andcc	%o5, 0xff, %g0
 	bne,a,pt %icc, 2b
 14:
-	 ld	[%o0], %o5
+	 lda	[%o0] ASI_S, %o5
 	add	%o4, 1, %o4
 1:
 	retl
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/lib/strncpy_from_user.S linux/arch/sparc64/lib/strncpy_from_user.S
--- v2.1.39/linux/arch/sparc64/lib/strncpy_from_user.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/strncpy_from_user.S	Sun May 18 17:10:37 1997
@@ -24,14 +24,14 @@
 	sub	%g0, %o2, %o3
 	add	%o0, %o2, %o0
 10:
-	ldub	[%o1 + %o3], %o4
+	lduba	[%o1 + %o3] ASI_S, %o4
 1:
 	brz,pn	%o4, 2f
 	 stb	%o4, [%o0 + %o3]
 	addcc	%o3, 1, %o3
 	bne,pt	%xcc, 1b
 11:
-	 ldub	[%o1 + %o3], %o4
+	 lduba	[%o1 + %o3] ASI_S, %o4
 	retl
 	 mov	%o2, %o0
 2:
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.1.39/linux/arch/sparc64/mm/fault.c	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/mm/fault.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.5 1997/05/15 21:14:31 davem Exp $
+/* $Id: fault.c,v 1.8 1997/05/18 04:16:52 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -134,8 +134,11 @@
 	return 0;
 }
 
+/* #define FAULT_TRACER */
+
 asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
-				 unsigned long address)
+				 unsigned long address, unsigned long tag,
+				 unsigned long sfsr)
 {
 	struct vm_area_struct *vma;
 	struct task_struct *tsk = current;
@@ -143,7 +146,19 @@
 	unsigned long fixup;
 	unsigned long g2;
 	int from_user = !(regs->tstate & TSTATE_PRIV);
-
+#ifdef FAULT_TRACER
+	static unsigned long last_addr = 0;
+	static int rcnt = 0;
+
+	printk("do_sparc64_fault(PC[%016lx],t[%d],w[%d],addr[%016lx]tag[%016lx]"
+	       "sfar[%016lx])\n", regs->tpc, text_fault, write, address, tag, sfsr);
+	if(address == last_addr && rcnt++ > 5) {
+		printk("Wheee lotsa bogus faults, something wrong, spinning\n");
+		while(1)
+			barrier();
+	}
+	last_addr = address;
+#endif
 	lock_kernel ();
 	down(&mm->mmap_sem);
 	vma = find_vma(mm, address);
diff -u --recursive --new-file v2.1.39/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.39/linux/arch/sparc64/mm/init.c	Tue May 13 22:41:04 1997
+++ linux/arch/sparc64/mm/init.c	Sun May 18 17:10:37 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.25 1997/04/28 14:57:11 davem Exp $
+/*  $Id: init.c,v 1.28 1997/05/18 04:16:53 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -457,16 +457,18 @@
 	pte_clear(ptep);
 }
 
-#ifdef DEBUG_MMU
 void sparc_ultra_dump_itlb(void)
 {
         int slot;
 
-        prom_printf ("Contents of itlb:\n");
-        for (slot = 0; slot < 64; slot+=2) {
-        	prom_printf ("%2x:%016lx,%016lx    %2x:%016lx,%016lx\n", 
+        printk ("Contents of itlb: ");
+	for (slot = 0; slot < 14; slot++) printk ("    ");
+	printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
+        for (slot = 1; slot < 64; slot+=3) {
+        	printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
         		slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
-        		slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1));
+        		slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
+        		slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
         }
 }
 
@@ -474,14 +476,16 @@
 {
         int slot;
 
-        prom_printf ("Contents of dtlb:\n");
-        for (slot = 0; slot < 64; slot+=2) {
-        	prom_printf ("%2x:%016lx,%016lx    %2x:%016lx,%016lx\n", 
+        printk ("Contents of dtlb: ");
+	for (slot = 0; slot < 14; slot++) printk ("    ");
+	printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+        for (slot = 1; slot < 64; slot+=3) {
+        	printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
         		slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
-        		slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1));
+        		slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
+        		slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
         }
 }
-#endif
 
 /* paging_init() sets up the page tables */
 
@@ -643,7 +647,7 @@
 	high_memory = (void *) end_mem;
 
 	start_mem = PAGE_ALIGN(start_mem);
-	num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT;
+	num_physpages = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
 
 	addr = PAGE_OFFSET;
 	while(addr < start_mem) {
@@ -707,9 +711,14 @@
 	
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-		free_page(addr);
+		unsigned long page = addr;
+
+		if(page < ((unsigned long)__va(phys_base)))
+			page += phys_base;
+
+		mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved);
+		atomic_set(&mem_map[MAP_NR(page)].count, 1);
+		free_page(page);
 	}
 }
 
diff -u --recursive --new-file v2.1.39/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.1.39/linux/drivers/block/Makefile	Sat Dec 21 04:24:02 1996
+++ linux/drivers/block/Makefile	Sun May 18 17:10:37 1997
@@ -30,6 +30,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_ATARI_ACSI),y)
+  LX_OBJS += acsi.o
+else
+  ifeq ($(CONFIG_ATARI_ACSI),m)
+  MX_OBJS += acsi.o
+  endif
+endif
+
+ifeq ($(CONFIG_ATARI_SLM),y)
+  L_OBJS += acsi_slm.o
+else
+  ifeq ($(CONFIG_ATARI_SLM),m)
+  M_OBJS += acsi_slm.o
+  endif
+endif
+
 ifeq ($(CONFIG_AMIGA_Z2RAM),y)
 L_OBJS += z2ram.o
 else
diff -u --recursive --new-file v2.1.39/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.39/linux/drivers/block/genhd.c	Tue May 13 22:41:04 1997
+++ linux/drivers/block/genhd.c	Sun May 18 17:10:37 1997
@@ -573,12 +573,12 @@
 	spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
 	for(i=0; i < 8; i++, p++) {
 		unsigned long st_sector;
+		int num_sectors;
 
-		/* We register all partitions, even if zero size, so that
-		 * the minor numbers end up ok as per SunOS interpretation.
-		 */
 		st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc;
-		add_partition(hd, current_minor, st_sector, be32_to_cpu(p->num_sectors));
+		num_sectors = be32_to_cpu(p->num_sectors);
+		if (num_sectors)
+			add_partition(hd, current_minor, st_sector, num_sectors);
 		current_minor++;
 	}
 	printk("\n");
@@ -592,10 +592,10 @@
 #include <asm/byteorder.h>
 #include <linux/affs_hardblocks.h>
 
-static __inline__ __u32
-checksum_block(__u32 *m, int size)
+static __inline__ u32
+checksum_block(u32 *m, int size)
 {
-	__u32 sum = 0;
+	u32 sum = 0;
 
 	while (size--)
 		sum += htonl(*m++);
diff -u --recursive --new-file v2.1.39/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v2.1.39/linux/drivers/cdrom/mcdx.c	Tue May 13 22:41:06 1997
+++ linux/drivers/cdrom/mcdx.c	Tue May 20 19:59:56 1997
@@ -359,6 +359,10 @@
             msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
             msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
 
+            stuffp->stop.dt.minute = msf.cdmsf_min1;
+            stuffp->stop.dt.second = msf.cdmsf_sec1;
+            stuffp->stop.dt.frame = msf.cdmsf_frame1;
+
             return mcdx_playmsf(stuffp, &msf);
         }
 
diff -u --recursive --new-file v2.1.39/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.39/linux/drivers/char/Makefile	Tue May 13 22:41:06 1997
+++ linux/drivers/char/Makefile	Wed May 21 09:57:45 1997
@@ -39,7 +39,10 @@
 
 ifndef CONFIG_SUN_KEYBOARD
 ifdef CONFIG_VT
-L_OBJS += keyboard.o defkeymap.o
+L_OBJS += keyboard.o
+endif
+ifneq ($(ARCH),m68k)
+L_OBJS += pc_keyb.o defkeymap.o
 endif
 endif
 
diff -u --recursive --new-file v2.1.39/linux/drivers/char/keyb_m68k.c linux/drivers/char/keyb_m68k.c
--- v2.1.39/linux/drivers/char/keyb_m68k.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/keyb_m68k.c	Wed Dec 31 16:00:00 1969
@@ -1,876 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Keyboard driver for Linux v0.99 using Latin-1.
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting,  Sept 1994
- * `Sticky' modifier keys, 951006.
- * 
- */
-
-/*
- * modified to provide 'generic' keyboard support by Hamish Macdonald
- */
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/machdep.h>
-
-#include "kbd_kern.h"
-#include "diacr.h"
-#include "vt_kern.h"
-
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
-#ifndef KBD_DEFMODE
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-#endif
-
-#ifndef KBD_DEFLEDS
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock
- * is on. This seems a good reason to start with NumLock off.
- */
-#define KBD_DEFLEDS 0
-#endif
-
-#ifndef KBD_DEFLOCK
-#define KBD_DEFLOCK 0
-#endif
-
-/*
- * The default IO slowdown is doing 'inb()'s from 0x61, which should be
- * safe. But as that is the keyboard controller chip address, we do our
- * slowdowns here by doing short jumps: the keyboard controller should
- * be able to keep up
- */
-#define REALLY_SLOW_IO
-#define SLOW_IO_BY_JUMPING
-#include <asm/io.h>
-#include <asm/system.h>
-
-extern void poke_blanked_console(void);
-extern void ctrl_alt_del(void);
-extern void reset_vc(unsigned int new_console);
-extern void scrollback(int);
-extern void scrollfront(int);
-extern int vc_cons_allocated(unsigned int);
-
-unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
-
-struct wait_queue * keypress_wait = NULL;
-
-void keyboard_wait_for_keypress(void)
-{
-	sleep_on(&keypress_wait);
-}
-
-/*
- * global state includes the following, and various static variables
- * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next.
- * (last_console is now a global variable)
- */
-
-/* shift state counters.. */
-static unsigned char k_down[NR_SHIFT] = {0, };
-/* keyboard key bitmap */
-#define BITS_PER_LONG (8*sizeof(unsigned long))
-static unsigned long key_down[256/BITS_PER_LONG] = { 0, };
-
-static int dead_key_next = 0;
-/* 
- * In order to retrieve the shift_state (for the mouse server), either
- * the variable must be global, or a new procedure must be created to 
- * return the value. I chose the former way.
- */
-/*static*/ int shift_state = 0;
-static int npadch = -1;			/* -1 or number assembled on pad */
-static unsigned char diacr = 0;
-static char rep = 0;			/* flag telling character repeat */
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-static struct tty_struct **ttytab;
-static struct kbd_struct *kbd = kbd_table;
-static struct tty_struct *tty = NULL;
-
-extern void compute_shiftstate(void);
-
-typedef void (*k_hand)(unsigned char value, char up_flag);
-typedef void (k_handfn)(unsigned char value, char up_flag);
-
-static k_handfn
-        do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
-	do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
-
-static k_hand key_handler[16] = {
-	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
-	do_meta, do_ascii, do_lock, do_lowercase, do_slock,
-	do_ignore, do_ignore, do_ignore
-};
-
-typedef void (*void_fnp)(void);
-typedef void (void_fn)(void);
-
-static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle,
-	num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose,
-	SAK, decr_console, incr_console, spawn_console, bare_num;
-
-static void_fnp spec_fn_table[] = {
-	do_null,	enter,		show_ptregs,	show_mem,
-	show_state,	send_intr,	lastcons,	caps_toggle,
-	num,		hold,		scroll_forw,	scroll_back,
-	boot_it,	caps_on,	compose,	SAK,
-	decr_console,	incr_console,	spawn_console,	bare_num
-};
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-	255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
-	NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
-	255, NR_ASCII - 1, NR_LOCK - 1, 255,
-	NR_LOCK - 1
-};
-
-const int NR_TYPES = SIZE(max_vals);
-
-static void put_queue(int);
-static unsigned char handle_diacr(unsigned char);
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-void to_utf8(ushort c) {
-    if (c < 0x80)
-	put_queue(c);			/*  0*******  */
-    else if (c < 0x800) {
-	put_queue(0xc0 | (c >> 6)); 	/*  110***** 10******  */
-	put_queue(0x80 | (c & 0x3f));
-    } else {
-	put_queue(0xe0 | (c >> 12)); 	/*  1110**** 10****** 10******  */
-	put_queue(0x80 | ((c >> 6) & 0x3f));
-	put_queue(0x80 | (c & 0x3f));
-    }
-    /* UTF-8 is defined for words of up to 31 bits,
-       but we need only 16 bits here */
-}
-
-void process_keycode (int keycode)
-{
-	char up_flag;		                 /* 0 or 0200 */
-	char raw_mode;
-
-	do_poke_blanked_console = 1;
-	mark_bh(KEYBOARD_BH);
-	add_keyboard_randomness(keycode);
-
-	tty = ttytab[fg_console];
- 	kbd = kbd_table + fg_console;
-	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
- 		put_queue(keycode);
-		/* we do not return yet, because we want to maintain
-		   the key_down array, so that we have the correct
-		   values when finishing RAW mode or when changing VT's */
- 	}
-
-	/*
-	 * At this point the variable `keycode' contains the keycode.
-	 * Note: the keycode must not be 0.
-	 * We keep track of the up/down status of the key, and
-	 * return the keycode if in MEDIUMRAW mode.
-	 */
-
-	up_flag = (keycode & 0200);
-        keycode &= 0x7f;
-	if (up_flag) {
-		rep = 0;
- 		if(!test_and_clear_bit(keycode, key_down)) {
-		    /* unexpected, but this can happen:
-		       maybe this was a key release for a FOCUS 9000
-		       PF key; if we want to see it, we have to clear
-		       up_flag */
-#ifndef __mc68000__
-		    if (keycode >= SC_LIM || keycode == 85)
-		      up_flag = 0;
-#endif
-		}
-	} else
- 		rep = test_and_set_bit(keycode, key_down);
-
-	if (raw_mode)
-	        return;
-
-	if (kbd->kbdmode == VC_MEDIUMRAW) {
-		/* soon keycodes will require more than one byte */
- 		put_queue(keycode + up_flag);
-		return;
-	}
-
- 	/*
-	 * Small change in philosophy: earlier we defined repetition by
-	 *	 rep = keycode == prev_keycode;
-	 *	 prev_keycode = keycode;
-	 * but now by the fact that the depressed key was down already.
-	 * Does this ever make a difference? Yes.
-	 */
-
-	/*
- 	 *  Repeat a key only if the input buffers are empty or the
- 	 *  characters get echoed locally. This makes key repeat usable
- 	 *  with slow applications and under heavy loads.
-	 */
-	if (!rep ||
-	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
-	     (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) {
-		u_short keysym;
-		u_char type;
-
-		/* the XOR below used to be an OR */
-		int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
-		ushort *key_map = key_maps[shift_final];
-
-		if (key_map != NULL) {
-			keysym = key_map[keycode];
-			type = KTYP(keysym);
-
-			if (type >= 0xf0) {
-			    type -= 0xf0;
-			    if (type == KT_LETTER) {
-				type = KT_LATIN;
-				if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-				    key_map = key_maps[shift_final ^ (1<<KG_SHIFT)];
-				    if (key_map)
-				      keysym = key_map[keycode];
-				}
-			    }
-			    (*key_handler[type])(keysym & 0xff, up_flag);
-			    if (type != KT_SLOCK)
-			      kbd->slockstate = 0;
-			} else {
-			    /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
-			    if (!up_flag)
-			      to_utf8(keysym);
-			}
-		} else {
-			/* maybe beep? */
-			/* we have at least to update shift_state */
-#if 1			/* how? two almost equivalent choices follow */
-			compute_shiftstate();
-#else
-			keysym = U(plain_map[keycode]);
-			type = KTYP(keysym);
-			if (type == KT_SHIFT)
-			  (*key_handler[type])(keysym & 0xff, up_flag);
-#endif
-		}
-        }
-}
-
-static void put_queue(int ch)
-{
-	wake_up(&keypress_wait);
-	if (tty) {
-		tty_insert_flip_char(tty, ch, 0);
-		tty_schedule_flip(tty);
-	}
-}
-
-static void puts_queue(char *cp)
-{
-	wake_up(&keypress_wait);
-	if (!tty)
-		return;
-
-	while (*cp) {
-		tty_insert_flip_char(tty, *cp, 0);
-		cp++;
-	}
-	tty_schedule_flip(tty);
-}
-
-static void applkey(int key, char mode)
-{
-	static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
-	buf[1] = (mode ? 'O' : '[');
-	buf[2] = key;
-	puts_queue(buf);
-}
-
-static void enter(void)
-{
-	put_queue(13);
-	if (vc_kbd_mode(kbd,VC_CRLF))
-		put_queue(10);
-}
-
-static void caps_toggle(void)
-{
-	if (rep)
-		return;
-	chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void caps_on(void)
-{
-	if (rep)
-		return;
-	set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-struct pt_regs *pt_regs;
-
-static void show_ptregs(void)
-{
-	if (pt_regs)
-		show_regs(pt_regs);
-	return;
-}
-
-static void hold(void)
-{
-	if (rep || !tty)
-		return;
-
-	/*
-	 * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
-	 * these routines are also activated by ^S/^Q.
-	 * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
-	 */
-	if (tty->stopped)
-		start_tty(tty);
-	else
-		stop_tty(tty);
-}
-
-static void num(void)
-{
-	if (vc_kbd_mode(kbd,VC_APPLIC))
-		applkey('P', 1);
-	else
-		bare_num();
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void bare_num(void)
-{
-	if (!rep)
-		chg_vc_kbd_led(kbd,VC_NUMLOCK);
-}
-
-static void lastcons(void)
-{
-	/* switch to the last used console, ChN */
-	set_console(last_console);
-}
-
-static void decr_console(void)
-{
-	int i;
- 
-	for (i = fg_console-1; i != fg_console; i--) {
-		if (i == -1)
-			i = MAX_NR_CONSOLES-1;
-		if (vc_cons_allocated(i))
-			break;
-	}
-	set_console(i);
-}
-
-static void incr_console(void)
-{
-	int i;
-
-	for (i = fg_console+1; i != fg_console; i++) {
-		if (i == MAX_NR_CONSOLES)
-			i = 0;
-		if (vc_cons_allocated(i))
-			break;
-	}
-	set_console(i);
-}
-
-static void send_intr(void)
-{
-	if (!tty)
-		return;
-	tty_insert_flip_char(tty, 0, TTY_BREAK);
-	tty_schedule_flip(tty);
-}
-
-static void scroll_forw(void)
-{
-	scrollfront(0);
-}
-
-static void scroll_back(void)
-{
-	scrollback(0);
-}
-
-static void boot_it(void)
-{
-	ctrl_alt_del();
-}
-
-static void compose(void)
-{
-	dead_key_next = 1;
-}
-
-int spawnpid, spawnsig;
-
-static void spawn_console(void)
-{
-        if (spawnpid)
-	   if(kill_proc(spawnpid, spawnsig, 1))
-	     spawnpid = 0;
-}
-
-static void SAK(void)
-{
-	do_SAK(tty);
-#if 0
-	/*
-	 * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and
-	 * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK
-	 * handling.
-	 * 
-	 * We should do this some day --- the whole point of a secure
-	 * attention key is that it should be guaranteed to always
-	 * work.
-	 */
-	reset_vc(fg_console);
-	do_unblank_screen();	/* not in interrupt routine? */
-#endif
-}
-
-static void do_ignore(unsigned char value, char up_flag)
-{
-}
-
-static void do_null()
-{
-	compute_shiftstate();
-}
-
-static void do_spec(unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-	if (value >= SIZE(spec_fn_table))
-		return;
-	spec_fn_table[value]();
-}
-
-static void do_lowercase(unsigned char value, char up_flag)
-{
-	printk("keyboard.c: do_lowercase was called - impossible\n");
-}
-
-static void do_self(unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return; 	/* no action, if this is a key release */
-
-	if (diacr)
-		value = handle_diacr(value);
-
-        if (dead_key_next) {
-                dead_key_next = 0;
-                diacr = value;
-                return;
-        }
-
-	put_queue(value);
-}
-
-#define A_GRAVE  '`'
-#define A_ACUTE  '\''
-#define A_CFLEX  '^'
-#define A_TILDE  '~'
-#define A_DIAER  '"'
-#define A_CEDIL  ','
-static unsigned char ret_diacr[NR_DEAD] =
-        {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
-
-/* If a dead key pressed twice, output a character corresponding to it, */
-/* otherwise just remember the dead key.				*/
-
-static void do_dead(unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-
-        value = ret_diacr[value];
-        if (diacr == value) {   /* pressed twice */
-                diacr = 0;
-                put_queue(value);
-                return;
-        }
-	diacr = value;
-}
-
-
-/* If space is pressed, return the character corresponding the pending	*/
-/* dead key, otherwise try to combine the two.				*/
-
-unsigned char handle_diacr(unsigned char ch)
-{
-        int d = diacr;
-        int i;
-
-        diacr = 0;
-        if (ch == ' ')
-                return d;
-
-	for (i = 0; i < accent_table_size; i++) {
-		if (accent_table[i].diacr == d && accent_table[i].base == ch)
-			return accent_table[i].result;
-	}
-
-        put_queue(d);
-        return ch;
-}
-
-static void do_cons(unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-	set_console(value);
-}
-
-static void do_fn(unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-	if (value < SIZE(func_table)) {
-		if (func_table[value])
-			puts_queue(func_table[value]);
-	} else
-	        printk("do_fn called with value=%d\n", value);
-}
-
-static void do_pad(unsigned char value, char up_flag)
-{
-	static const char *pad_chars = "0123456789+-*/\015,.?";
-	static const char *app_map = "pqrstuvwxylSRQMnn?";
-
-	if (up_flag)
-		return;		/* no action, if this is a key release */
-
-	/* kludge... shift forces cursor/number keys */
-	if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
-		applkey(app_map[value], 1);
-		return;
-	}
-
-	if (!vc_kbd_led(kbd,VC_NUMLOCK))
-		switch (value) {
-			case KVAL(K_PCOMMA):
-			case KVAL(K_PDOT):
-				do_fn(KVAL(K_REMOVE), 0);
-				return;
-			case KVAL(K_P0):
-				do_fn(KVAL(K_INSERT), 0);
-				return;
-			case KVAL(K_P1):
-				do_fn(KVAL(K_SELECT), 0);
-				return;
-			case KVAL(K_P2):
-				do_cur(KVAL(K_DOWN), 0);
-				return;
-			case KVAL(K_P3):
-				do_fn(KVAL(K_PGDN), 0);
-				return;
-			case KVAL(K_P4):
-				do_cur(KVAL(K_LEFT), 0);
-				return;
-			case KVAL(K_P6):
-				do_cur(KVAL(K_RIGHT), 0);
-				return;
-			case KVAL(K_P7):
-				do_fn(KVAL(K_FIND), 0);
-				return;
-			case KVAL(K_P8):
-				do_cur(KVAL(K_UP), 0);
-				return;
-			case KVAL(K_P9):
-				do_fn(KVAL(K_PGUP), 0);
-				return;
-			case KVAL(K_P5):
-				applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
-				return;
-		}
-
-	put_queue(pad_chars[value]);
-	if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
-		put_queue(10);
-}
-
-static void do_cur(unsigned char value, char up_flag)
-{
-	static const char *cur_chars = "BDCA";
-	if (up_flag)
-		return;
-
-	applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
-}
-
-static void do_shift(unsigned char value, char up_flag)
-{
-	int old_state = shift_state;
-
-	if (rep)
-		return;
-
-	/* Mimic typewriter:
-	   a CapsShift key acts like Shift but undoes CapsLock */
-	if (value == KVAL(K_CAPSSHIFT)) {
-		value = KVAL(K_SHIFT);
-		if (!up_flag)
-			clr_vc_kbd_led(kbd, VC_CAPSLOCK);
-	}
-
-	if (up_flag) {
-	        /* handle the case that two shift or control
-		   keys are depressed simultaneously */
-		if (k_down[value])
-			k_down[value]--;
-	} else
-		k_down[value]++;
-
-	if (k_down[value])
-		shift_state |= (1 << value);
-	else
-		shift_state &= ~ (1 << value);
-
-	/* kludge */
-	if (up_flag && shift_state != old_state && npadch != -1) {
-		if (kbd->kbdmode == VC_UNICODE)
-		  to_utf8(npadch & 0xffff);
-		else
-		  put_queue(npadch & 0xff);
-		npadch = -1;
-	}
-}
-
-/* called after returning from RAW mode or when changing consoles -
-   recompute k_down[] and shift_state from key_down[] */
-/* maybe called when keymap is undefined, so that shiftkey release is seen */
-void compute_shiftstate(void)
-{
-	int i, j, k, sym, val;
-
-	shift_state = 0;
-	for(i=0; i < SIZE(k_down); i++)
-	  k_down[i] = 0;
-
-	for(i=0; i < SIZE(key_down); i++)
-	  if(key_down[i]) {	/* skip this word if not a single bit on */
-	    k = i*BITS_PER_LONG;
-	    for(j=0; j<BITS_PER_LONG; j++,k++)
-	      if(test_bit(k, key_down)) {
-		sym = U(plain_map[k]);
-		if(KTYP(sym) == KT_SHIFT) {
-		  val = KVAL(sym);
-		  if (val == KVAL(K_CAPSSHIFT))
-		    val = KVAL(K_SHIFT);
-		  k_down[val]++;
-		  shift_state |= (1<<val);
-	        }
-	      }
-	  }
-}
-
-static void do_meta(unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-
-	if (vc_kbd_mode(kbd, VC_META)) {
-		put_queue('\033');
-		put_queue(value);
-	} else
-		put_queue(value | 0x80);
-}
-
-static void do_ascii(unsigned char value, char up_flag)
-{
-	int base;
-
-	if (up_flag)
-		return;
-
-	if (value < 10)    /* decimal input of code, while Alt depressed */
-	    base = 10;
-	else {       /* hexadecimal input of code, while AltGr depressed */
-	    value -= 10;
-	    base = 16;
-	}
-
-	if (npadch == -1)
-	        npadch = value;
-	else
-		npadch = npadch * base + value;
-}
-
-static void do_lock(unsigned char value, char up_flag)
-{
-	if (up_flag || rep)
-		return;
-	chg_vc_kbd_lock(kbd, value);
-}
-
-static void do_slock(unsigned char value, char up_flag)
-{
-	if (up_flag || rep)
-		return;
-	chg_vc_kbd_slock(kbd, value);
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-
-static unsigned char ledstate = 0xff; /* undefined */
-static unsigned char ledioctl;
-
-unsigned char getledstate(void) {
-    return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led) {
-    if (!(led & ~7)) {
-	ledioctl = led;
-	kbd->ledmode = LED_SHOW_IOCTL;
-    } else
-	kbd->ledmode = LED_SHOW_FLAGS;
-    set_leds();
-}
-
-static struct ledptr {
-    unsigned int *addr;
-    unsigned int mask;
-    unsigned char valid:1;
-} ledptrs[3];
-
-void register_leds(int console, unsigned int led,
-		   unsigned int *addr, unsigned int mask) {
-    struct kbd_struct *kbd = kbd_table + console;
-    if (led < 3) {
-	ledptrs[led].addr = addr;
-	ledptrs[led].mask = mask;
-	ledptrs[led].valid = 1;
-	kbd->ledmode = LED_SHOW_MEM;
-    } else
-	kbd->ledmode = LED_SHOW_FLAGS;
-}
-
-static inline unsigned char getleds(void){
-    struct kbd_struct *kbd = kbd_table + fg_console;
-    unsigned char leds;
-
-    if (kbd->ledmode == LED_SHOW_IOCTL)
-      return ledioctl;
-    leds = kbd->ledflagstate;
-    if (kbd->ledmode == LED_SHOW_MEM) {
-	if (ledptrs[0].valid) {
-	    if (*ledptrs[0].addr & ledptrs[0].mask)
-	      leds |= 1;
-	    else
-	      leds &= ~1;
-	}
-	if (ledptrs[1].valid) {
-	    if (*ledptrs[1].addr & ledptrs[1].mask)
-	      leds |= 2;
-	    else
-	      leds &= ~2;
-	}
-	if (ledptrs[2].valid) {
-	    if (*ledptrs[2].addr & ledptrs[2].mask)
-	      leds |= 4;
-	    else
-	      leds &= ~4;
-	}
-    }
-    return leds;
-}
-
-/*
- * This routine is the bottom half of the keyboard interrupt
- * routine, and runs with all interrupts enabled. It does
- * console changing, led setting and copy_to_cooked, which can
- * take a reasonably long time.
- *
- * Aside from timing (which isn't really that important for
- * keyboard interrupts as they happen often), using the software
- * interrupt routines for this thing allows us to easily mask
- * this when we don't want any of the above to happen. Not yet
- * used, but this allows for easy and efficient race-condition
- * prevention later on.
- */
-static void kbd_bh(void)
-{
-	unsigned char leds = getleds();
-
-	if (leds != ledstate) {
-		ledstate = leds;
-		if (mach_kbd_leds)
-			mach_kbd_leds(leds);
-	}
-}
-
-__initfunc(int kbd_init(void))
-{
-	int i;
-	struct kbd_struct kbd0;
-	extern struct tty_driver console_driver;
-
-	kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
-	kbd0.ledmode = LED_SHOW_FLAGS;
-	kbd0.lockstate = KBD_DEFLOCK;
-	kbd0.slockstate = 0;
-	kbd0.modeflags = KBD_DEFMODE;
-	kbd0.kbdmode = VC_XLATE;
- 
-	for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
-		kbd_table[i] = kbd0;
-
-	ttytab = console_driver.table;
-
-	init_bh(KEYBOARD_BH, kbd_bh);
-	mark_bh(KEYBOARD_BH);
-
-	mach_keyb_init ();
-
-	return 0;
-}
diff -u --recursive --new-file v2.1.39/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.1.39/linux/drivers/char/keyboard.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/keyboard.c	Wed May 21 09:57:45 1997
@@ -13,46 +13,29 @@
  * dynamic function/string keys, led setting,  Sept 1994
  * `Sticky' modifier keys, 951006.
  * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ * 
+ * Modified to provide 'generic' keyboard support by Hamish Macdonald
+ * Merge with the m68k keyboard driver and split-off of the PC low-level
+ * parts by Geert Uytterhoeven, May 1997
  */
 
-#define KEYBOARD_IRQ 1
-#define DISABLE_KBD_DURING_INTERRUPTS 0
-
 #include <linux/sched.h>
-#include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/mm.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
 #include <linux/string.h>
-#include <linux/ioport.h>
 #include <linux/random.h>
 #include <linux/init.h>
 
+#include <asm/keyboard.h>
 #include <asm/bitops.h>
 
 #include "kbd_kern.h"
 #include "diacr.h"
 #include "vt_kern.h"
 
-/*
- * On non-x86 hardware we do a full keyboard controller
- * initialization, in case the bootup software hasn't done
- * it. On a x86, the BIOS will already have initialized the
- * keyboard.
- */
-#ifndef __i386__
-#define INIT_KBD
-static int initialize_kbd(void);
-#endif
-
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
 #ifndef KBD_DEFMODE
 #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
 #endif
@@ -69,16 +52,11 @@
 #define KBD_DEFLOCK 0
 #endif
 
-#include <asm/io.h>
-#include <asm/system.h>
-
 extern void ctrl_alt_del(void);
 extern void reset_vc(unsigned int new_console);
 extern void scrollback(int);
 extern void scrollfront(int);
 
-unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
-
 struct wait_queue * keypress_wait = NULL;
 
 void keyboard_wait_for_keypress(void)
@@ -113,12 +91,7 @@
 static struct kbd_struct * kbd = kbd_table;
 static struct tty_struct * tty = NULL;
 
-/* used only by send_data - set by keyboard_interrupt */
-static volatile unsigned char reply_expected = 0;
-static volatile unsigned char acknowledge = 0;
-static volatile unsigned char resend = 0;
-
-extern void compute_shiftstate(void);
+void compute_shiftstate(void);
 
 typedef void (*k_hand)(unsigned char value, char up_flag);
 typedef void (k_handfn)(unsigned char value, char up_flag);
@@ -168,23 +141,7 @@
 static unsigned char handle_diacr(unsigned char);
 
 /* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-static struct pt_regs * pt_regs;
-
-static inline void kb_wait(void)
-{
-	int i;
-
-	for (i=0; i<0x100000; i++)
-		if ((inb_p(0x64) & 0x02) == 0)
-			return;
-	printk(KERN_WARNING "Keyboard timed out\n");
-}
-
-static inline void send_cmd(unsigned char c)
-{
-	kb_wait();
-	outb(c,0x64);
-}
+struct pt_regs * pt_regs;
 
 /*
  * Many other routines do put_queue, but I think either
@@ -209,178 +166,25 @@
 
 /*
  * Translation of escaped scancodes to keycodes.
- * This is now user-settable.
- * The keycodes 1-88,96-111,119 are fairly standard, and
- * should probably not be changed - changing might confuse X.
- * X also interprets scancode 0x5d (KEY_Begin).
- *
- * For 1-88 keycode equals scancode.
+ * This is now user-settable (for machines were it makes sense).
  */
 
-#define E0_KPENTER 96
-#define E0_RCTRL   97
-#define E0_KPSLASH 98
-#define E0_PRSCR   99
-#define E0_RALT    100
-#define E0_BREAK   101  /* (control-pause) */
-#define E0_HOME    102
-#define E0_UP      103
-#define E0_PGUP    104
-#define E0_LEFT    105
-#define E0_RIGHT   106
-#define E0_END     107
-#define E0_DOWN    108
-#define E0_PGDN    109
-#define E0_INS     110
-#define E0_DEL     111
-
-#define E1_PAUSE   119
-
-/*
- * The keycodes below are randomly located in 89-95,112-118,120-127.
- * They could be thrown away (and all occurrences below replaced by 0),
- * but that would force many users to use the `setkeycodes' utility, where
- * they needed not before. It does not matter that there are duplicates, as
- * long as no duplication occurs for any single keyboard.
- */
-#define SC_LIM 89
-
-#define FOCUS_PF1 85           /* actual code! */
-#define FOCUS_PF2 89
-#define FOCUS_PF3 90
-#define FOCUS_PF4 91
-#define FOCUS_PF5 92
-#define FOCUS_PF6 93
-#define FOCUS_PF7 94
-#define FOCUS_PF8 95
-#define FOCUS_PF9 120
-#define FOCUS_PF10 121
-#define FOCUS_PF11 122
-#define FOCUS_PF12 123
-
-#define JAP_86     124
-/* tfj@olivia.ping.dk:
- * The four keys are located over the numeric keypad, and are
- * labelled A1-A4. It's an rc930 keyboard, from
- * Regnecentralen/RC International, Now ICL.
- * Scancodes: 59, 5a, 5b, 5c.
- */
-#define RGN1 124
-#define RGN2 125
-#define RGN3 126
-#define RGN4 127
-
-static unsigned char high_keys[128 - SC_LIM] = {
-  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
-  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
-  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
-  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
-  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
-};
-
-/* BTC */
-#define E0_MACRO   112
-/* LK450 */
-#define E0_F13     113
-#define E0_F14     114
-#define E0_HELP    115
-#define E0_DO      116
-#define E0_F17     117
-#define E0_KPMINPLUS 118
-/*
- * My OmniKey generates e0 4c for  the "OMNI" key and the
- * right alt key does nada. [kkoller@nyx10.cs.du.edu]
- */
-#define E0_OK	124
-/*
- * New microsoft keyboard is rumoured to have
- * e0 5b (left window button), e0 5c (right window button),
- * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
- * [or: Windows_L, Windows_R, TaskMan]
- */
-#define E0_MSLW	125
-#define E0_MSRW	126
-#define E0_MSTM	127
-
-static unsigned char e0_keys[128] = {
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
-  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
-  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
-  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
-  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
-  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
-  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
-  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
-  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
-  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
-};
-
 int setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
-	  return -EINVAL;
-	if (scancode < 128)
-	  high_keys[scancode - SC_LIM] = keycode;
-	else
-	  e0_keys[scancode - 128] = keycode;
-	return 0;
+    return kbd_setkeycode(scancode, keycode);
 }
 
 int getkeycode(unsigned int scancode)
 {
-	return
-	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
-	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
-	    e0_keys[scancode - 128];
+    return kbd_getkeycode(scancode);
 }
 
-#if DISABLE_KBD_DURING_INTERRUPTS
-#define disable_keyboard()	do { send_cmd(0xAD); kb_wait(); } while (0)
-#define enable_keyboard()	send_cmd(0xAE)
-#else
-#define disable_keyboard()	/* nothing */
-#define enable_keyboard()	/* nothing */
-#endif
-
-static void handle_scancode(unsigned char scancode)
+void handle_scancode(unsigned char scancode)
 {
 	unsigned char keycode;
-	static unsigned int prev_scancode = 0;   /* remember E0, E1 */
 	char up_flag;				 /* 0 or 0200 */
 	char raw_mode;
 
-	if (reply_expected) {
-	  /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
-	  /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
-		reply_expected = 0;
-		if (scancode == 0xfa) {
-			acknowledge = 1;
-			return;
-		} else if (scancode == 0xfe) {
-			resend = 1;
-			return;
-		}
-		/* strange ... */
-		reply_expected = 1;
-#if 0
-		printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
-		       scancode);
-#endif
-	}
-	if (scancode == 0) {
-#ifdef KBD_REPORT_ERR
-		printk(KERN_INFO "keyboard buffer overflow\n");
-#endif
-		prev_scancode = 0;
-		return;
-	}
 	do_poke_blanked_console = 1;
 	mark_bh(CONSOLE_BH);
 	add_keyboard_randomness(scancode);
@@ -394,121 +198,28 @@
 		   values when finishing RAW mode or when changing VT's */
  	}
 
-	if (scancode == 0xff) {
-	        /* in scancode mode 1, my ESC key generates 0xff */
-		/* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
-		if (!raw_mode)
-		  printk(KERN_DEBUG "keyboard error\n");
-#endif
-#endif
-		prev_scancode = 0;
-		return;
-	}
-
-	if (scancode == 0xe0 || scancode == 0xe1) {
-		prev_scancode = scancode;
-		return;
- 	}
-
+	if (!kbd_pretranslate(scancode, raw_mode))
+	    return;
  	/*
-	 *  Convert scancode to keycode, using prev_scancode.
+	 *  Convert scancode to keycode
  	 */
 	up_flag = (scancode & 0200);
  	scancode &= 0x7f;
 
-	if (prev_scancode) {
-	  /*
-	   * usually it will be 0xe0, but a Pause key generates
-	   * e1 1d 45 e1 9d c5 when pressed, and nothing when released
-	   */
-	  if (prev_scancode != 0xe0) {
-	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
-		  prev_scancode = 0x100;
-		  return;
-	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
-		  keycode = E1_PAUSE;
-		  prev_scancode = 0;
-	      } else {
-#ifdef KBD_REPORT_UNKN
-		  if (!raw_mode)
-		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-#endif
-		  prev_scancode = 0;
-		  return;
-	      }
-	  } else {
-	      prev_scancode = 0;
-	      /*
-	       *  The keyboard maintains its own internal caps lock and
-	       *  num lock statuses. In caps lock mode E0 AA precedes make
-	       *  code and E0 2A follows break code. In num lock mode,
-	       *  E0 2A precedes make code and E0 AA follows break code.
-	       *  We do our own book-keeping, so we will just ignore these.
-	       */
-	      /*
-	       *  For my keyboard there is no caps lock mode, but there are
-	       *  both Shift-L and Shift-R modes. The former mode generates
-	       *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
-	       *  So, we should also ignore the latter. - aeb@cwi.nl
-	       */
-	      if (scancode == 0x2a || scancode == 0x36)
-		return;
-
-	      if (e0_keys[scancode])
-		keycode = e0_keys[scancode];
-	      else {
-#ifdef KBD_REPORT_UNKN
-		  if (!raw_mode)
-		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
-			   scancode);
-#endif
-		  return;
-	      }
-	  }
-	} else if (scancode >= SC_LIM) {
-	    /* This happens with the FOCUS 9000 keyboard
-	       Its keys PF1..PF12 are reported to generate
-	       55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
-	       Moreover, unless repeated, they do not generate
-	       key-down events, so we have to zero up_flag below */
-	    /* Also, Japanese 86/106 keyboards are reported to
-	       generate 0x73 and 0x7d for \ - and \ | respectively. */
-	    /* Also, some Brazilian keyboard is reported to produce
-	       0x73 and 0x7e for \ ? and KP-dot, respectively. */
-
-	  keycode = high_keys[scancode - SC_LIM];
-
-	  if (!keycode) {
-	      if (!raw_mode) {
-#ifdef KBD_REPORT_UNKN
-		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
-			 " - ignored\n", scancode);
-#endif
-	      }
-	      return;
-	  }
- 	} else
-	  keycode = scancode;
+	if (!kbd_translate(scancode, &keycode, raw_mode))
+	    return;
 
 	/*
 	 * At this point the variable `keycode' contains the keycode.
-	 * Note: the keycode must not be 0.
+	 * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid).
 	 * We keep track of the up/down status of the key, and
 	 * return the keycode if in MEDIUMRAW mode.
 	 */
 
 	if (up_flag) {
 		rep = 0;
-		if(!test_and_clear_bit(keycode, key_down)) {
-		    /* unexpected, but this can happen:
-		       maybe this was a key release for a FOCUS 9000
-		       PF key; if we want to see it, we have to clear
-		       up_flag */
-		    if (keycode >= SC_LIM || keycode == 85)
-		      up_flag = 0;
-		}
+ 		if(!test_and_clear_bit(keycode, key_down))
+		    up_flag = kbd_unexpected_up(keycode);
 	} else
  		rep = test_and_set_bit(keycode, key_down);
 
@@ -580,31 +291,6 @@
 	}
 }
 
-static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned char status;
-
-	pt_regs = regs;
-	disable_keyboard();
-
-	status = inb_p(0x64);
-	do {
-		unsigned char scancode;
-
-		/* mouse data? */
-		if (status & kbd_read_mask & 0x20)
-			break;
-
-		scancode = inb(0x60);
-		if (status & 0x01)
-			handle_scancode(scancode);
-
-		status = inb(0x64);
-	} while (status & 0x01);
-
-	mark_bh(KEYBOARD_BH);
-	enable_keyboard();
-}
 
 static void put_queue(int ch)
 {
@@ -894,8 +580,8 @@
 
 static void do_pad(unsigned char value, char up_flag)
 {
-	static const char *pad_chars = "0123456789+-*/\015,.?";
-	static const char *app_map = "pqrstuvwxylSRQMnn?";
+	static const char *pad_chars = "0123456789+-*/\015,.?()";
+	static const char *app_map = "pqrstuvwxylSRQMnn?PQ";
 
 	if (up_flag)
 		return;		/* no action, if this is a key release */
@@ -1071,35 +757,6 @@
 }
 
 /*
- * send_data sends a character to the keyboard and waits
- * for an acknowledge, possibly retrying if asked to. Returns
- * the success status.
- */
-static int send_data(unsigned char data)
-{
-	int retries = 3;
-	int i;
-
-	do {
-		kb_wait();
-		acknowledge = 0;
-		resend = 0;
-		reply_expected = 1;
-		outb_p(data, 0x60);
-		for(i=0; i<0x200000; i++) {
-			inb_p(0x64);		/* just as a delay */
-			if (acknowledge)
-				return 1;
-			if (resend)
-				break;
-		}
-		if (!resend)
-			return 0;
-	} while (retries-- > 0);
-	return 0;
-}
-
-/*
  * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
  * or (ii) whatever pattern of lights people want to show using KDSETLED,
  * or (iii) specified bits of specified words in kernel memory.
@@ -1188,8 +845,7 @@
 
 	if (leds != ledstate) {
 		ledstate = leds;
-		if (!send_data(0xed) || !send_data(leds))
-			send_data(0xf4);	/* re-enable kbd if any errors */
+		kbd_leds(leds);
 	}
 }
 
@@ -1211,194 +867,8 @@
 
 	ttytab = console_driver.table;
 
-	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
-	request_region(0x60,16,"keyboard");
-#ifdef INIT_KBD
-	initialize_kbd();
-#endif
+	kbd_init_hw();
 	init_bh(KEYBOARD_BH, kbd_bh);
 	mark_bh(KEYBOARD_BH);
 	return 0;
 }
-
-#ifdef INIT_KBD
-/*
- * keyboard controller registers
- */
-#define KBD_STATUS_REG      (unsigned int) 0x64
-#define KBD_CNTL_REG        (unsigned int) 0x64
-#define KBD_DATA_REG	    (unsigned int) 0x60
-/*
- * controller commands
- */
-#define KBD_READ_MODE	    (unsigned int) 0x20
-#define KBD_WRITE_MODE	    (unsigned int) 0x60
-#define KBD_SELF_TEST	    (unsigned int) 0xAA
-#define KBD_SELF_TEST2	    (unsigned int) 0xAB
-#define KBD_CNTL_ENABLE	    (unsigned int) 0xAE
-/*
- * keyboard commands
- */
-#define KBD_ENABLE	    (unsigned int) 0xF4
-#define KBD_DISABLE	    (unsigned int) 0xF5
-#define KBD_RESET	    (unsigned int) 0xFF
-/*
- * keyboard replies
- */
-#define KBD_ACK		    (unsigned int) 0xFA
-#define KBD_POR		    (unsigned int) 0xAA
-/*
- * status register bits
- */
-#define KBD_OBF		    (unsigned int) 0x01
-#define KBD_IBF		    (unsigned int) 0x02
-#define KBD_GTO		    (unsigned int) 0x40
-#define KBD_PERR	    (unsigned int) 0x80
-/*
- * keyboard controller mode register bits
- */
-#define KBD_EKI		    (unsigned int) 0x01
-#define KBD_SYS		    (unsigned int) 0x04
-#define KBD_DMS		    (unsigned int) 0x20
-#define KBD_KCC		    (unsigned int) 0x40
-
-#define TIMEOUT_CONST	500000
-
-static int kbd_wait_for_input(void)
-{
-        int     n;
-        int     status, data;
-
-        n = TIMEOUT_CONST;
-        do {
-                status = inb(KBD_STATUS_REG);
-                /*
-                 * Wait for input data to become available.  This bit will
-                 * then be cleared by the following read of the DATA
-                 * register.
-                 */
-
-                if (!(status & KBD_OBF))
-			continue;
-
-		data = inb(KBD_DATA_REG);
-
-                /*
-                 * Check to see if a timeout error has occurred.  This means
-                 * that transmission was started but did not complete in the
-                 * normal time cycle.  PERR is set when a parity error occurred
-                 * in the last transmission.
-                 */
-                if (status & (KBD_GTO | KBD_PERR)) {
-			continue;
-                }
-		return (data & 0xff);
-        } while (--n);
-        return (-1);	/* timed-out if fell through to here... */
-}
-
-static void kbd_write(int address, int data)
-{
-	int status;
-
-	do {
-		status = inb(KBD_STATUS_REG);  /* spin until input buffer empty*/
-	} while (status & KBD_IBF);
-	outb(data, address);               /* write out the data*/
-}
-
-__initfunc(static int initialize_kbd(void))
-{
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	/* Flush any pending input. */
-	while (kbd_wait_for_input() != -1)
-		continue;
-
-	/*
-	 * Test the keyboard interface.
-	 * This seems to be the only way to get it going.
-	 * If the test is successful a x55 is placed in the input buffer.
-	 */
-	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
-	if (kbd_wait_for_input() != 0x55) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "keyboard failed self test.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/*
-	 * Perform a keyboard interface test.  This causes the controller
-	 * to test the keyboard clock and data lines.  The results of the
-	 * test are placed in the input buffer.
-	 */
-	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
-	if (kbd_wait_for_input() != 0x00) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "keyboard failed self test 2.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/* Enable the keyboard by allowing the keyboard clock to run. */
-	kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
-
-	/*
-	 * Reset keyboard. If the read times out
-	 * then the assumption is that no keyboard is
-	 * plugged into the machine.
-	 * This defaults the keyboard to scan-code set 2.
-	 */
-	kbd_write(KBD_DATA_REG, KBD_RESET);
-	if (kbd_wait_for_input() != KBD_ACK) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "reset kbd failed, no ACK.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	if (kbd_wait_for_input() != KBD_POR) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "reset kbd failed, not POR.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/*
-	 * now do a DEFAULTS_DISABLE always
-	 */
-	kbd_write(KBD_DATA_REG, KBD_DISABLE);
-	if (kbd_wait_for_input() != KBD_ACK) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "disable kbd failed, no ACK.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/*
-	 * Enable keyboard interrupt, operate in "sys" mode,
-	 *  enable keyboard (by clearing the disable keyboard bit),
-	 *  disable mouse, do conversion of keycodes.
-	 */
-	kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
-	kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
-
-	/*
-	 * now ENABLE the keyboard to set it scanning...
-	 */
-	kbd_write(KBD_DATA_REG, KBD_ENABLE);
-	if (kbd_wait_for_input() != KBD_ACK) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "keyboard enable failed.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	restore_flags(flags);
-
-	return (1);
-}
-#endif /* INIT_KBD */
diff -u --recursive --new-file v2.1.39/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.39/linux/drivers/char/pc_keyb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/pc_keyb.c	Wed May 21 09:57:45 1997
@@ -0,0 +1,609 @@
+/*
+ * linux/drivers/char/pc_keyb.c
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting,  Sept 1994
+ * `Sticky' modifier keys, 951006.
+ * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ * 
+ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+
+/*
+ * On non-x86 hardware we do a full keyboard controller
+ * initialization, in case the bootup software hasn't done
+ * it. On a x86, the BIOS will already have initialized the
+ * keyboard.
+ */
+#ifdef INIT_KBD
+static int initialize_kbd(void);
+#endif
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
+
+/* used only by send_data - set by keyboard_interrupt */
+static volatile unsigned char reply_expected = 0;
+static volatile unsigned char acknowledge = 0;
+static volatile unsigned char resend = 0;
+
+/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+static inline void kb_wait(void)
+{
+	int i;
+
+	for (i=0; i<0x100000; i++)
+		if ((inb_p(0x64) & 0x02) == 0)
+			return;
+	printk(KERN_WARNING "Keyboard timed out\n");
+}
+
+extern struct pt_regs *pt_regs;
+
+extern void handle_scancode(unsigned char scancode);
+
+
+/*
+ * Translation of escaped scancodes to keycodes.
+ * This is now user-settable.
+ * The keycodes 1-88,96-111,119 are fairly standard, and
+ * should probably not be changed - changing might confuse X.
+ * X also interprets scancode 0x5d (KEY_Begin).
+ *
+ * For 1-88 keycode equals scancode.
+ */
+
+#define E0_KPENTER 96
+#define E0_RCTRL   97
+#define E0_KPSLASH 98
+#define E0_PRSCR   99
+#define E0_RALT    100
+#define E0_BREAK   101  /* (control-pause) */
+#define E0_HOME    102
+#define E0_UP      103
+#define E0_PGUP    104
+#define E0_LEFT    105
+#define E0_RIGHT   106
+#define E0_END     107
+#define E0_DOWN    108
+#define E0_PGDN    109
+#define E0_INS     110
+#define E0_DEL     111
+
+#define E1_PAUSE   119
+
+/*
+ * The keycodes below are randomly located in 89-95,112-118,120-127.
+ * They could be thrown away (and all occurrences below replaced by 0),
+ * but that would force many users to use the `setkeycodes' utility, where
+ * they needed not before. It does not matter that there are duplicates, as
+ * long as no duplication occurs for any single keyboard.
+ */
+#define SC_LIM 89
+
+#define FOCUS_PF1 85           /* actual code! */
+#define FOCUS_PF2 89
+#define FOCUS_PF3 90
+#define FOCUS_PF4 91
+#define FOCUS_PF5 92
+#define FOCUS_PF6 93
+#define FOCUS_PF7 94
+#define FOCUS_PF8 95
+#define FOCUS_PF9 120
+#define FOCUS_PF10 121
+#define FOCUS_PF11 122
+#define FOCUS_PF12 123
+
+#define JAP_86     124
+/* tfj@olivia.ping.dk:
+ * The four keys are located over the numeric keypad, and are
+ * labelled A1-A4. It's an rc930 keyboard, from
+ * Regnecentralen/RC International, Now ICL.
+ * Scancodes: 59, 5a, 5b, 5c.
+ */
+#define RGN1 124
+#define RGN2 125
+#define RGN3 126
+#define RGN4 127
+
+static unsigned char high_keys[128 - SC_LIM] = {
+  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
+  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
+  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
+  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
+  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
+};
+
+/* BTC */
+#define E0_MACRO   112
+/* LK450 */
+#define E0_F13     113
+#define E0_F14     114
+#define E0_HELP    115
+#define E0_DO      116
+#define E0_F17     117
+#define E0_KPMINPLUS 118
+/*
+ * My OmniKey generates e0 4c for  the "OMNI" key and the
+ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
+ */
+#define E0_OK	124
+/*
+ * New microsoft keyboard is rumoured to have
+ * e0 5b (left window button), e0 5c (right window button),
+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
+ * [or: Windows_L, Windows_R, TaskMan]
+ */
+#define E0_MSLW	125
+#define E0_MSRW	126
+#define E0_MSTM	127
+
+static unsigned char e0_keys[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
+  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
+  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
+  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
+  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
+  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
+  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
+  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
+  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
+  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
+};
+
+static unsigned int prev_scancode = 0;   /* remember E0, E1 */
+
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
+	  return -EINVAL;
+	if (scancode < 128)
+	  high_keys[scancode - SC_LIM] = keycode;
+	else
+	  e0_keys[scancode - 128] = keycode;
+	return 0;
+}
+
+int pckbd_getkeycode(unsigned int scancode)
+{
+	return
+	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
+	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
+	    e0_keys[scancode - 128];
+}
+
+#if DISABLE_KBD_DURING_INTERRUPTS
+static inline void send_cmd(unsigned char c)
+{
+	kb_wait();
+	outb(c,0x64);
+}
+
+#define disable_keyboard()	do { send_cmd(0xAD); kb_wait(); } while (0)
+#define enable_keyboard()	send_cmd(0xAE)
+#else
+#define disable_keyboard()	/* nothing */
+#define enable_keyboard()	/* nothing */
+#endif
+
+static int do_acknowledge(unsigned char scancode)
+{
+	if (reply_expected) {
+	  /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
+	  /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
+		reply_expected = 0;
+		if (scancode == 0xfa) {
+			acknowledge = 1;
+			return 0;
+		} else if (scancode == 0xfe) {
+			resend = 1;
+			return 0;
+		}
+		/* strange ... */
+		reply_expected = 1;
+#if 0
+		printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
+		       scancode);
+#endif
+	}
+	if (scancode == 0) {
+#ifdef KBD_REPORT_ERR
+		printk(KERN_INFO "keyboard buffer overflow\n");
+#endif
+		prev_scancode = 0;
+		return 0;
+	}
+	return 1;
+}
+
+int pckbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+	if (scancode == 0xff) {
+	        /* in scancode mode 1, my ESC key generates 0xff */
+		/* the calculator keys on a FOCUS 9000 generate 0xff */
+#ifndef KBD_IS_FOCUS_9000
+#ifdef KBD_REPORT_ERR
+		if (!raw_mode)
+		  printk(KERN_DEBUG "keyboard error\n");
+#endif
+#endif
+		prev_scancode = 0;
+		return 0;
+	}
+
+	if (scancode == 0xe0 || scancode == 0xe1) {
+		prev_scancode = scancode;
+		return 0;
+ 	}
+ 	return 1;
+}
+
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode)
+{
+	if (prev_scancode) {
+	  /*
+	   * usually it will be 0xe0, but a Pause key generates
+	   * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+	   */
+	  if (prev_scancode != 0xe0) {
+	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
+		  prev_scancode = 0x100;
+		  return 0;
+	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
+		  *keycode = E1_PAUSE;
+		  prev_scancode = 0;
+	      } else {
+#ifdef KBD_REPORT_UNKN
+		  if (!raw_mode)
+		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+#endif
+		  prev_scancode = 0;
+		  return 0;
+	      }
+	  } else {
+	      prev_scancode = 0;
+	      /*
+	       *  The keyboard maintains its own internal caps lock and
+	       *  num lock statuses. In caps lock mode E0 AA precedes make
+	       *  code and E0 2A follows break code. In num lock mode,
+	       *  E0 2A precedes make code and E0 AA follows break code.
+	       *  We do our own book-keeping, so we will just ignore these.
+	       */
+	      /*
+	       *  For my keyboard there is no caps lock mode, but there are
+	       *  both Shift-L and Shift-R modes. The former mode generates
+	       *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+	       *  So, we should also ignore the latter. - aeb@cwi.nl
+	       */
+	      if (scancode == 0x2a || scancode == 0x36)
+		return 0;
+
+	      if (e0_keys[scancode])
+		*keycode = e0_keys[scancode];
+	      else {
+#ifdef KBD_REPORT_UNKN
+		  if (!raw_mode)
+		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+			   scancode);
+#endif
+		  return 0;
+	      }
+	  }
+	} else if (scancode >= SC_LIM) {
+	    /* This happens with the FOCUS 9000 keyboard
+	       Its keys PF1..PF12 are reported to generate
+	       55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
+	       Moreover, unless repeated, they do not generate
+	       key-down events, so we have to zero up_flag below */
+	    /* Also, Japanese 86/106 keyboards are reported to
+	       generate 0x73 and 0x7d for \ - and \ | respectively. */
+	    /* Also, some Brazilian keyboard is reported to produce
+	       0x73 and 0x7e for \ ? and KP-dot, respectively. */
+
+	  *keycode = high_keys[scancode - SC_LIM];
+
+	  if (!*keycode) {
+	      if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
+		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+			 " - ignored\n", scancode);
+#endif
+	      }
+	      return 0;
+	  }
+ 	} else
+	  *keycode = scancode;
+ 	return 1;
+}
+
+char pckbd_unexpected_up(unsigned char keycode)
+{
+	/* unexpected, but this can happen: maybe this was a key release for a
+	   FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
+	if (keycode >= SC_LIM || keycode == 85)
+	    return 0;
+	else
+	    return 0200;
+}
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned char status;
+
+	pt_regs = regs;
+	disable_keyboard();
+
+	status = inb_p(0x64);
+	do {
+		unsigned char scancode;
+
+		/* mouse data? */
+		if (status & kbd_read_mask & 0x20)
+			break;
+
+		scancode = inb(0x60);
+		if ((status & 0x01) && do_acknowledge(scancode))
+			handle_scancode(scancode);
+
+		status = inb(0x64);
+	} while (status & 0x01);
+
+	mark_bh(KEYBOARD_BH);
+	enable_keyboard();
+}
+
+/*
+ * send_data sends a character to the keyboard and waits
+ * for an acknowledge, possibly retrying if asked to. Returns
+ * the success status.
+ */
+static int send_data(unsigned char data)
+{
+	int retries = 3;
+	int i;
+
+	do {
+		kb_wait();
+		acknowledge = 0;
+		resend = 0;
+		reply_expected = 1;
+		outb_p(data, 0x60);
+		for(i=0; i<0x200000; i++) {
+			inb_p(0x64);		/* just as a delay */
+			if (acknowledge)
+				return 1;
+			if (resend)
+				break;
+		}
+		if (!resend)
+			return 0;
+	} while (retries-- > 0);
+	return 0;
+}
+
+void pckbd_leds(unsigned char leds)
+{
+	if (!send_data(0xed) || !send_data(leds))
+	    send_data(0xf4);	/* re-enable kbd if any errors */
+}
+
+__initfunc(void pckbd_init_hw(void))
+{
+	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+	request_region(0x60,16,"keyboard");
+#ifdef INIT_KBD
+	initialize_kbd();
+#endif
+}
+
+#ifdef INIT_KBD
+/*
+ * keyboard controller registers
+ */
+#define KBD_STATUS_REG      (unsigned int) 0x64
+#define KBD_CNTL_REG        (unsigned int) 0x64
+#define KBD_DATA_REG	    (unsigned int) 0x60
+/*
+ * controller commands
+ */
+#define KBD_READ_MODE	    (unsigned int) 0x20
+#define KBD_WRITE_MODE	    (unsigned int) 0x60
+#define KBD_SELF_TEST	    (unsigned int) 0xAA
+#define KBD_SELF_TEST2	    (unsigned int) 0xAB
+#define KBD_CNTL_ENABLE	    (unsigned int) 0xAE
+/*
+ * keyboard commands
+ */
+#define KBD_ENABLE	    (unsigned int) 0xF4
+#define KBD_DISABLE	    (unsigned int) 0xF5
+#define KBD_RESET	    (unsigned int) 0xFF
+/*
+ * keyboard replies
+ */
+#define KBD_ACK		    (unsigned int) 0xFA
+#define KBD_POR		    (unsigned int) 0xAA
+/*
+ * status register bits
+ */
+#define KBD_OBF		    (unsigned int) 0x01
+#define KBD_IBF		    (unsigned int) 0x02
+#define KBD_GTO		    (unsigned int) 0x40
+#define KBD_PERR	    (unsigned int) 0x80
+/*
+ * keyboard controller mode register bits
+ */
+#define KBD_EKI		    (unsigned int) 0x01
+#define KBD_SYS		    (unsigned int) 0x04
+#define KBD_DMS		    (unsigned int) 0x20
+#define KBD_KCC		    (unsigned int) 0x40
+
+#define TIMEOUT_CONST	    500000
+
+static int kbd_wait_for_input(void)
+{
+        int     n;
+        int     status, data;
+
+        n = TIMEOUT_CONST;
+        do {
+                status = inb(KBD_STATUS_REG);
+                /*
+                 * Wait for input data to become available.  This bit will
+                 * then be cleared by the following read of the DATA
+                 * register.
+                 */
+
+                if (!(status & KBD_OBF))
+			continue;
+
+		data = inb(KBD_DATA_REG);
+
+                /*
+                 * Check to see if a timeout error has occurred.  This means
+                 * that transmission was started but did not complete in the
+                 * normal time cycle.  PERR is set when a parity error occurred
+                 * in the last transmission.
+                 */
+                if (status & (KBD_GTO | KBD_PERR)) {
+			continue;
+                }
+		return (data & 0xff);
+        } while (--n);
+        return (-1);	/* timed-out if fell through to here... */
+}
+
+static void kbd_write(int address, int data)
+{
+	int status;
+
+	do {
+		status = inb(KBD_STATUS_REG);  /* spin until input buffer empty*/
+	} while (status & KBD_IBF);
+	outb(data, address);               /* write out the data*/
+}
+
+__initfunc(static int initialize_kbd(void))
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	/* Flush any pending input. */
+	while (kbd_wait_for_input() != -1)
+		continue;
+
+	/*
+	 * Test the keyboard interface.
+	 * This seems to be the only way to get it going.
+	 * If the test is successful a x55 is placed in the input buffer.
+	 */
+	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
+	if (kbd_wait_for_input() != 0x55) {
+		printk(KERN_WARNING "initialize_kbd: "
+		       "keyboard failed self test.\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	/*
+	 * Perform a keyboard interface test.  This causes the controller
+	 * to test the keyboard clock and data lines.  The results of the
+	 * test are placed in the input buffer.
+	 */
+	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
+	if (kbd_wait_for_input() != 0x00) {
+		printk(KERN_WARNING "initialize_kbd: "
+		       "keyboard failed self test 2.\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	/* Enable the keyboard by allowing the keyboard clock to run. */
+	kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
+
+	/*
+	 * Reset keyboard. If the read times out
+	 * then the assumption is that no keyboard is
+	 * plugged into the machine.
+	 * This defaults the keyboard to scan-code set 2.
+	 */
+	kbd_write(KBD_DATA_REG, KBD_RESET);
+	if (kbd_wait_for_input() != KBD_ACK) {
+		printk(KERN_WARNING "initialize_kbd: "
+		       "reset kbd failed, no ACK.\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	if (kbd_wait_for_input() != KBD_POR) {
+		printk(KERN_WARNING "initialize_kbd: "
+		       "reset kbd failed, not POR.\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	/*
+	 * now do a DEFAULTS_DISABLE always
+	 */
+	kbd_write(KBD_DATA_REG, KBD_DISABLE);
+	if (kbd_wait_for_input() != KBD_ACK) {
+		printk(KERN_WARNING "initialize_kbd: "
+		       "disable kbd failed, no ACK.\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	/*
+	 * Enable keyboard interrupt, operate in "sys" mode,
+	 *  enable keyboard (by clearing the disable keyboard bit),
+	 *  disable mouse, do conversion of keycodes.
+	 */
+	kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
+	kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
+
+	/*
+	 * now ENABLE the keyboard to set it scanning...
+	 */
+	kbd_write(KBD_DATA_REG, KBD_ENABLE);
+	if (kbd_wait_for_input() != KBD_ACK) {
+		printk(KERN_WARNING "initialize_kbd: "
+		       "keyboard enable failed.\n");
+		restore_flags(flags);
+		return(-1);
+	}
+
+	restore_flags(flags);
+
+	return (1);
+}
+#endif /* INIT_KBD */
diff -u --recursive --new-file v2.1.39/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.1.39/linux/drivers/net/defxx.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/defxx.c	Sun May 18 16:38:34 1997
@@ -226,6 +226,11 @@
 
 #include "defxx.h"
 
+#define DYNAMIC_BUFFERS 1
+
+#define SKBUFF_RX_COPYBREAK 200
+#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX)
+
 /* Define global routines */
 
 int	dfx_probe(struct device *dev);
@@ -1083,7 +1088,9 @@
 	alloc_size = sizeof(PI_DESCR_BLOCK) +
 					PI_CMD_REQ_K_SIZE_MAX +
 					PI_CMD_RSP_K_SIZE_MAX +
+#ifndef DYNAMIC_BUFFERS
 					(bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
+#endif
 					sizeof(PI_CONSUMER_BLOCK) +
 					(PI_ALIGN_K_DESC_BLK - 1);
 	top_v = (char *) kmalloc(alloc_size, GFP_KERNEL);
@@ -1135,8 +1142,11 @@
 
 	bp->rcv_block_virt = curr_v;
 	bp->rcv_block_phys = curr_p;
+
+#ifndef DYNAMIC_BUFFERS
 	curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
 	curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX);
+#endif
 
 	/* Reserve space for the consumer block */
 
@@ -2926,6 +2936,22 @@
 	 *		driver initialization when we allocated memory for the receive buffers.
 	 */
 
+#ifdef DYNAMIC_BUFFERS
+	for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
+		for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+		{
+			struct sk_buff *newskb;
+			bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
+				((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
+			newskb = dev_alloc_skb(NEW_SKB_SIZE);
+			bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
+			/*
+			 * p_rcv_buff_va is only used inside the
+			 * kernel so we put the skb pointer here.
+			 */
+			bp->p_rcv_buff_va[i+j] = (char *) newskb;
+		}
+#else
 	for (i=0; i < (int)(bp->rcv_bufs_to_post); i++)
 		for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
 			{
@@ -2934,6 +2960,7 @@
 			bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX));
 			bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
 			}
+#endif
 
 	/* Update receive producer and Type 2 register */
 
@@ -2985,6 +3012,8 @@
 	u32					descr, pkt_len;		/* FMC descriptor field and packet length */
 	struct sk_buff		*skb;				/* pointer to a sk_buff to hold incoming packet data */
 
+	static int testing_dyn;
+
 	/* Service all consumed LLC receive frames */
 
 	p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
@@ -2992,7 +3021,14 @@
 		{
 		/* Process any errors */
 
-		p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp];
+		int entry;
+
+		entry = bp->rcv_xmt_reg.index.rcv_comp;
+#ifdef DYNAMIC_BUFFERS
+		p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data);
+#else
+		p_buff = (char *) bp->p_rcv_buff_va[entry];
+#endif
 		memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32));
 
 		if (descr & PI_FMC_DESCR_M_RCC_FLUSH)
@@ -3003,29 +3039,60 @@
 				bp->rcv_frame_status_errors++;
 			}
 		else
-			{
+		{
+			int rx_in_place = 0;
+
 			/* The frame was received without errors - verify packet length */
 
 			pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN);
 			pkt_len -= 4;				/* subtract 4 byte CRC */
 			if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
 				bp->rcv_length_errors++;
-			else
-				{
-				skb = dev_alloc_skb(pkt_len+3);	/* alloc new buffer to pass up, add room for PRH */
+			else{
+#ifdef DYNAMIC_BUFFERS
+				if (pkt_len > SKBUFF_RX_COPYBREAK) {
+					struct sk_buff *newskb;
+
+					newskb = dev_alloc_skb(NEW_SKB_SIZE);
+					if (newskb){
+						rx_in_place = 1;
+#define JES_TESTING
+#ifdef JES_TESTING
+						if(testing_dyn++ < 5)
+						  printk("Skipping a memcpy\n");
+						skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
+						skb->data += RCV_BUFF_K_PADDING;
+						bp->p_rcv_buff_va[entry] = (char *)newskb;
+						bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
+#else
+						memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+						skb = newskb;
+#endif
+					} else
+						skb = 0;
+				} else
+#endif
+					skb = dev_alloc_skb(pkt_len+3);	/* alloc new buffer to pass up, add room for PRH */
 				if (skb == NULL)
 					{
 					printk("%s: Could not allocate receive buffer.  Dropping packet.\n", bp->dev->name);
 					bp->rcv_discards++;
+					break;
 					}
-				else
+				else {
+#ifndef DYNAMIC_BUFFERS
+					if (! rx_in_place)
+#endif
 					{
-					/* Receive buffer allocated, pass receive packet up */
+						/* Receive buffer allocated, pass receive packet up */
+
+						memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+					}
 
-					memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
 					skb->data += 3;			/* adjust data field so that it points to FC byte */
 					skb->len = pkt_len;		/* pass up packet length, NOT including CRC */
 					skb->dev = bp->dev;		/* pass up device pointer */
+
 					skb->protocol = fddi_type_trans(skb, bp->dev);
 					netif_rx(skb);
 
@@ -3034,9 +3101,9 @@
 					bp->rcv_total_frames++;
 					if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
 						bp->rcv_multicast_frames++;
-					}
 				}
 			}
+			}
 
 		/*
 		 * Advance the producer (for recycling) and advance the completion
@@ -3140,6 +3207,7 @@
 			dev->name, skb->len);
 		bp->xmt_length_errors++;		/* bump error counter */
 		dev_tint(dev);				/* dequeue packets from xmt queue and send them */
+		dev_kfree_skb(skb, FREE_WRITE);
 		return(0);				/* return "success" */
 	}
 	/*
diff -u --recursive --new-file v2.1.39/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v2.1.39/linux/drivers/net/dummy.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/dummy.c	Sun May 18 16:38:34 1997
@@ -134,7 +134,7 @@
 {
 	/* Find a name for this unit */
 	int err=dev_alloc_name(&dev_dummy,"dummy%d");
-	if(err)
+	if(err<0)
 		return err;
 	if (register_netdev(&dev_dummy) != 0)
 		return -EIO;
diff -u --recursive --new-file v2.1.39/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.1.39/linux/drivers/net/hp100.c	Wed Apr 23 19:01:19 1997
+++ linux/drivers/net/hp100.c	Mon May 19 12:49:29 1997
@@ -1,89 +1,54 @@
 /*
- * hp100.c: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
- *
- * Author:  Jaroslav Kysela, <perex@pf.jcu.cz>
- *
- * Supports only the following Hewlett Packard cards:
- *
- *  	HP J2577	10/100 EISA card with REVA Cascade chip
- *	HP J2573	10/100 ISA card with REVA Cascade chip
- *	HP 27248B	10 only EISA card with Cascade chip
- *	HP J2577	10/100 EISA card with Cascade chip
- *	HP J2573	10/100 ISA card with Cascade chip
- *	HP J2585	10/100 PCI card
- *
- * Other ATT2MD01 Chip based boards might be supported in the future
- * (there are some minor changes needed).
- *
- * This driver is based on the 'hpfepkt' crynwr packet driver.
- *
- * This source/code is public free; you can distribute it and/or modify
- * it under terms of the GNU General Public License (published by the
- * Free Software Foundation) either version two of this License, or any
- * later version.
- * ----------------------------------------------------------------------------
- *
- * Note: Some routines (interrupt handling, transmit) assumes that
- *       there is the PERFORMANCE page selected...
- *
- * ----------------------------------------------------------------------------
- *
- * If you are going to use the module version of this driver, you may
- * change this values at the "insert time" :
- *
- *   Variable                   Description
- *
- *   hp100_rx_ratio		Range 1-99 - onboard memory used for RX
- *                              packets in %.
- *   hp100_priority_tx		If this variable is nonzero - all outgoing
- *                              packets will be transmitted as priority.
- *   hp100_port			Adapter port (for example 0x380).
- *
- * ----------------------------------------------------------------------------
- * MY BEST REGARDS GOING TO:
- *
- * IPEX s.r.o which lend me two HP J2573 cards and
- * the HP AdvanceStack 100VG Hub-15 for debugging.
- *
- * Russel Nellson <nelson@crynwr.com> for help with obtaining sources
- * of the 'hpfepkt' packet driver.
- *
- * Also thanks to Abacus Electric s.r.o which let me to use their
- * motherboard for my second computer.
- *
- * ----------------------------------------------------------------------------
- *
- * TO DO:
- * ======
- *       - ioctl handling - some runtime setup things
- *       - 100Mb/s Voice Grade AnyLAN network adapter/hub services support
- *		- 802.5 frames
- *		- promiscuous mode
- *		- bridge mode
- *		- cascaded repeater mode
- *		- 100Mbit MAC
- *
- * Revision history:
- * =================
- *
- *    Version   Date	    Description
- *
- *	0.1	14-May-95   Initial writing. ALPHA code was released.
- *                          Only HP J2573 on 10Mb/s (two machines) tested.
- *      0.11    14-Jun-95   Reset interface bug fixed?
- *			    Little bug in hp100_close function fixed.
- *                          100Mb/s connection debugged.
- *      0.12    14-Jul-95   Link down is now handled better.
- *      0.20    01-Aug-95   Added PCI support for HP J2585A card.
- *                          Statistics bug fixed.
- *      0.21    04-Aug-95   Memory mapped access support for PCI card.
- *                          Added priority transmit support for 100Mb/s
- *                          Voice Grade AnyLAN network.
- *
- */
+** hp100.c 
+** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
+**
+** $Id: hp100.c,v 1.52 1997/04/21 14:20:20 perex Exp perex $
+**
+** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
+** Extended for new busmaster capable chipsets by 
+** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
+**
+** Maintained by: Jaroslav Kysela <perex@jcu.cz>
+** 
+** This driver has only been tested with
+** -- HP J2585B 10/100 Mbit/s PCI Busmaster
+** -- HP J2585A 10/100 Mbit/s PCI 
+** -- HP J2970  10 Mbit/s PCI Combo 10base-T/BNC
+** -- HP J2973  10 Mbit/s PCI 10base-T
+** -- HP J2573  10/100 ISA
+** -- Compex ReadyLink ENET100-VG4  10/100 Mbit/s PCI / EISA
+** 
+** but it should also work with the other CASCADE based adapters.
+**
+** TODO:
+**       -  J2573 seems to hang sometimes when in shared memory mode.
+**       -  Mode for Priority TX
+**       -  Check PCI registers, performance might be improved?
+**       -  To reduce interrupt load in busmaster, one could switch off
+**          the interrupts that are used to refill the queues whenever the
+**          queues are filled up to more than a certain threshold.
+**
+**
+** This source/code is public free; you can distribute it and/or modify 
+** it under terms of the GNU General Public License (published by the
+** Free Software Foundation) either version two of this License, or any 
+** later version.
+**
+*/
+
+#define HP100_DEFAULT_PRIORITY_TX 0 
+
+#undef HP100_DEBUG
+#undef HP100_DEBUG_B           /* Trace  */
+#undef HP100_DEBUG_BM          /* Debug busmaster code (PDL stuff) */
+
+#undef HP100_DEBUG_TRAINING    /* Debug login-to-hub procedure */
+#undef HP100_DEBUG_TX   
+#undef HP100_DEBUG_IRQ 
+#undef HP100_DEBUG_RX 
 
+#include <linux/version.h>
 #include <linux/module.h>
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -102,7 +67,17 @@
 #include <linux/skbuff.h>
 
 #include <linux/types.h>
-#include <linux/config.h>	/* for CONFIG_PCI */
+#include <linux/config.h>  /* for CONFIG_PCI */
+#include <linux/delay.h>
+
+#if LINUX_VERSION_CODE < 0x020100
+#define ioremap vremap
+#define iounmap vfree
+typedef struct enet_statistics hp100_stats_t;
+#else
+#define LINUX_2_1
+typedef struct net_device_stats hp100_stats_t;
+#endif
 
 #include "hp100.h"
 
@@ -110,18 +85,28 @@
  *  defines
  */
 
-#define HP100_BUS_ISA		0
-#define HP100_BUS_EISA		1
-#define HP100_BUS_PCI		2
+#define HP100_BUS_ISA     0
+#define HP100_BUS_EISA    1
+#define HP100_BUS_PCI     2
 
-#define HP100_REGION_SIZE	0x20
+#ifndef PCI_DEVICE_ID_HP_J2585B
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
+#endif
+#ifndef PCI_VENDOR_ID_COMPEX
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#endif
+#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+#endif
+
+#define HP100_REGION_SIZE  0x20 /* for ioports */
 
-#define HP100_MAX_PACKET_SIZE	(1536+4)
-#define HP100_MIN_PACKET_SIZE	60
+#define HP100_MAX_PACKET_SIZE  (1536+4)
+#define HP100_MIN_PACKET_SIZE  60
 
 #ifndef HP100_DEFAULT_RX_RATIO
-/* default - 65% onboard memory on the card are used for RX packets */
-#define HP100_DEFAULT_RX_RATIO	65
+/* default - 75% onboard memory on the card are used for RX packets */
+#define HP100_DEFAULT_RX_RATIO  75
 #endif
 
 #ifndef HP100_DEFAULT_PRIORITY_TX
@@ -141,18 +126,37 @@
 
 struct hp100_private {
   struct hp100_eisa_id *id;
+  u_short chip;
   u_short soft_model;
-  u_int memory_size;
-  u_short rx_ratio;		    /* 1 - 99 */
-  u_short priority_tx;	            /* != 0 - priority tx */
-  short mem_mapped;		    /* memory mapped access */
-  u_char *mem_ptr_virt;		    /* virtual memory mapped area, maybe NULL */
-  u_char *mem_ptr_phys;		    /* physical memory mapped area */
-  short lan_type;		    /* 10Mb/s, 100Mb/s or -1 (error) */
-  int hub_status;		    /* login to hub was successful? */
+  u_int memory_size; 
+  u_short rx_ratio;       /* 1 - 99 */
+  u_short priority_tx;    /* != 0 - priority tx */
+  u_short mode;           /* PIO, Shared Mem or Busmaster */
+  u_char bus;
+  u_char pci_bus;
+  u_char pci_device_fn;
+  short mem_mapped;	  /* memory mapped access */
+  u_int *mem_ptr_virt;    /* virtual memory mapped area, maybe NULL */
+  u_int *mem_ptr_phys;	  /* physical memory mapped area */
+  short lan_type;	  /* 10Mb/s, 100Mb/s or -1 (error) */
+  int hub_status;	  /* was login to hub successful? */
   u_char mac1_mode;
   u_char mac2_mode;
-  struct net_device_stats stats;
+  hp100_stats_t stats;
+
+  /* Rings for busmaster mode: */
+  hp100_ring_t *rxrhead;  /* Head (oldest) index into rxring */
+  hp100_ring_t *rxrtail;  /* Tail (newest) index into rxring */
+  hp100_ring_t *txrhead;  /* Head (oldest) index into txring */
+  hp100_ring_t *txrtail;  /* Tail (newest) index into txring */
+
+  hp100_ring_t rxring[ MAX_RX_PDL ];
+  hp100_ring_t txring[ MAX_TX_PDL ];
+
+  u_int *page_vaddr;      /* Virtual address of allocated page */
+  u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */
+  int rxrcommit;          /* # Rx PDLs commited to adapter */
+  int txrcommit;          /* # Tx PDLs commited to adapter */
 };
 
 /*
@@ -161,78 +165,124 @@
 
 static struct hp100_eisa_id hp100_eisa_ids[] = {
 
-  /* 10/100 EISA card with REVA Cascade chip */
-  { 0x080F1F022, "HP J2577 rev A", HP100_BUS_EISA },
+  /* 10/100 EISA card with revision A Cascade chip */
+  { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA },
 
-  /* 10/100 ISA card with REVA Cascade chip */
-  { 0x050F1F022, "HP J2573 rev A", HP100_BUS_ISA },
+  /* 10/100 ISA card with revision A Cascade chip */
+  { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA },
 
   /* 10 only EISA card with Cascade chip */
-  { 0x02019F022, "HP 27248B",      HP100_BUS_EISA },
+  { 0x2019F022, "HP 27248B",      HP100_BUS_EISA },
 
   /* 10/100 EISA card with Cascade chip */
-  { 0x04019F022, "HP J2577",       HP100_BUS_EISA },
+  { 0x4019F022, "HP J2577",       HP100_BUS_EISA },
 
   /* 10/100 ISA card with Cascade chip */
-  { 0x05019F022, "HP J2573",       HP100_BUS_ISA },
+  { 0x5019F022, "HP J2573",       HP100_BUS_ISA },
+
+  /* 10/100 PCI card - old J2585A */
+  { 0x1030103c, "HP J2585A", 	    HP100_BUS_PCI },
+
+  /* 10/100 PCI card - new J2585B - master capable */
+  { 0x1041103c, "HP J2585B",      HP100_BUS_PCI },
+
+  /* 10 Mbit Combo Adapter */
+  { 0x1042103c, "HP J2970",       HP100_BUS_PCI },
 
-  /* 10/100 PCI card */
-  /* Note: ID for this card is same as PCI vendor/device numbers. */
-  { 0x01030103c, "HP J2585", 	   HP100_BUS_PCI },
+  /* 10 Mbit 10baseT Adapter */
+  { 0x1040103c, "HP J2973",       HP100_BUS_PCI },
+
+  /* 10/100 EISA card from Compex */
+  { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA },
+
+  /* 10/100 PCI card from Compex (J2585A compatible) */
+  { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI }
 };
 
 static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
 static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
+static int hp100_mode = 1;
+
+#ifdef LINUX_2_1
+MODULE_PARM( hp100_rx_ratio, "1i" );
+MODULE_PARM( hp100_priority_tx, "1i" );
+MODULE_PARM( hp100_mode, "1i" );
+#endif
 
 /*
  *  prototypes
  */
 
-static int hp100_probe1( struct device *dev, int ioaddr, int bus );
-static int hp100_open( struct device *dev );
-static int hp100_close( struct device *dev );
-static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int  hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn  );
+static int  hp100_open( struct device *dev );
+static int  hp100_close( struct device *dev );
+static int  hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int  hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev );
 static void hp100_rx( struct device *dev );
-static struct net_device_stats *hp100_get_stats( struct device *dev );
+static hp100_stats_t *hp100_get_stats( struct device *dev );
 static void hp100_update_stats( struct device *dev );
 static void hp100_clear_stats( int ioaddr );
 static void hp100_set_multicast_list( struct device *dev);
 static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs );
-
 static void hp100_start_interface( struct device *dev );
 static void hp100_stop_interface( struct device *dev );
 static void hp100_load_eeprom( struct device *dev );
-static int hp100_sense_lan( struct device *dev );
-static int hp100_login_to_vg_hub( struct device *dev );
-static int hp100_down_vg_link( struct device *dev );
+static int  hp100_sense_lan( struct device *dev );
+static int  hp100_login_to_vg_hub( struct device *dev, u_short force_relogin );
+static int  hp100_down_vg_link( struct device *dev );
+static void hp100_cascade_reset( struct device *dev, u_short enable );
+static void hp100_BM_shutdown( struct device *dev );
+static void hp100_mmuinit( struct device *dev );
+static void hp100_init_pdls( struct device *dev );
+static int  hp100_init_rxpdl( register hp100_ring_t *ringptr, register u_int *pdlptr);
+static int  hp100_init_txpdl( register hp100_ring_t *ringptr, register u_int *pdlptr);
+static void hp100_rxfill( struct device *dev );
+static void hp100_hwinit( struct device *dev );
+static void hp100_clean_txring( struct device *dev );
+#ifdef HP100_DEBUG
+static void hp100_RegisterDump( struct device *dev );
+#endif
+
+/* TODO: This function should not really be needed in a good design... */
+static void wait( void )
+{
+  udelay( 1000 );
+}
 
 /*
  *  probe functions
+ *  These functions should - if possible - avoid doing write operations
+ *  since this could cause problems when the card is not installed.
  */
 
 __initfunc(int hp100_probe( struct device *dev ))
 {
   int base_addr = dev ? dev -> base_addr : 0;
-  int ioaddr;
+  int ioaddr = 0;
 #ifdef CONFIG_PCI
   int pci_start_index = 0;
 #endif
 
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4200, TRACE );
+  printk( "hp100: probe\n" );
+#endif
+
   if ( base_addr > 0xff )	/* Check a single specified location. */
     {
       if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL;
       if ( base_addr < 0x400 )
-        return hp100_probe1( dev, base_addr, HP100_BUS_ISA );
-       else
-        return hp100_probe1( dev, base_addr, HP100_BUS_EISA );
+        return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 );
+      else
+        return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 );
     }
-   else
+  else
 #ifdef CONFIG_PCI
-  if ( base_addr > 0 && base_addr < 8 + 1 )
-    pci_start_index = 0x100 | ( base_addr - 1 );
-   else
+    if ( base_addr > 0 && base_addr < 8 + 1 )
+      pci_start_index = 0x100 | ( base_addr - 1 );
+    else
 #endif
-    if ( base_addr != 0 ) return -ENXIO;
+      if ( base_addr != 0 ) return -ENXIO;
 
   /* at first - scan PCI bus(es) */
 
@@ -249,65 +299,80 @@
           u_char pci_bus, pci_device_fn;
           u_short pci_command;
 
-          if ( pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
-          			    pci_index, &pci_bus,
-          			    &pci_device_fn ) != 0 ) break;
+          if ((pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
+                                    pci_index, &pci_bus,
+                                    &pci_device_fn ) != 0 ) && 
+              (pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B,
+                                    pci_index, &pci_bus,
+                                    &pci_device_fn ) != 0 ) &&
+              (pcibios_find_device( PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4,
+                                    pci_index, &pci_bus,
+                                    &pci_device_fn ) != 0 ) ) break; 
+
           pcibios_read_config_dword( pci_bus, pci_device_fn,
-              		             PCI_BASE_ADDRESS_0, &ioaddr );
+                                     PCI_BASE_ADDRESS_0, &ioaddr );
 
-          ioaddr &= ~3;		/* remove I/O space marker in bit 0. */
+          ioaddr &= ~3;    /* remove I/O space marker in bit 0. */
 
           if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
 
           pcibios_read_config_word( pci_bus, pci_device_fn,
-              			    PCI_COMMAND, &pci_command );
+                                    PCI_COMMAND, &pci_command );
           if ( !( pci_command & PCI_COMMAND_MASTER ) )
             {
-#ifdef HP100_DEBUG_PCI
+#ifdef HP100_DEBUG
               printk( "hp100: PCI Master Bit has not been set. Setting...\n" );
 #endif
               pci_command |= PCI_COMMAND_MASTER;
               pcibios_write_config_word( pci_bus, pci_device_fn,
-                  			 PCI_COMMAND, pci_command );
+                                         PCI_COMMAND, pci_command );
             }
-#ifdef HP100_DEBUG_PCI
+#ifdef HP100_DEBUG
           printk( "hp100: PCI adapter found at 0x%x\n", ioaddr );
 #endif
-       	  if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI ) == 0 ) return 0;
+	  if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 )
+	    return 0;
         }
     }
   if ( pci_start_index > 0 ) return -ENODEV;
 #endif /* CONFIG_PCI */
 
-  /* at second - probe all EISA possible port regions (if EISA bus present) */
-
+  /* Second: Probe all EISA possible port regions (if EISA bus present) */
   for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
     {
       if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
-      if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA ) == 0 ) return 0;
+      if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0;
     }
 
-  /* at third - probe all ISA possible port regions */
-
+  /* Third Probe all ISA possible port regions */
   for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
     {
       if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
-      if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA ) == 0 ) return 0;
+      if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0;
     }
 
   return -ENODEV;
 }
 
-__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus ))
+
+__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ))
 {
   int i;
+
   u_char uc, uc_1;
   u_int eisa_id;
+  u_int chip;
+  u_int memory_size = 0;
   short mem_mapped;
-  u_char *mem_ptr_phys, *mem_ptr_virt;
+  u_int *mem_ptr_phys, *mem_ptr_virt;
   struct hp100_private *lp;
   struct hp100_eisa_id *eid;
 
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4201, TRACE );
+  printk("hp100: probe1\n");
+#endif
+
   if ( dev == NULL )
     {
 #ifdef HP100_DEBUG
@@ -315,19 +380,27 @@
 #endif
       return EIO;
     }
+  
+  if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE ) 
+    {
+      return -ENODEV;
+    }
+  else
+    {
+      chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK;
+#ifdef HP100_DEBUG
+      if ( chip == HP100_CHIPID_SHASTA )
+        printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n");
+      else if ( chip == HP100_CHIPID_RAINIER )
+        printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n");
+      else if ( chip == HP100_CHIPID_LASSEN )
+        printk("hp100: Lassen Chip detected.\n");
+      else
+        printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n",chip);
+#endif 
+    }
 
-  if ( bus != HP100_BUS_PCI )		/* don't check PCI cards again */
-    if ( inb( ioaddr + 0 ) != HP100_HW_ID_0 ||
-         inb( ioaddr + 1 ) != HP100_HW_ID_1 ||
-         ( inb( ioaddr + 2 ) & 0xf0 ) != HP100_HW_ID_2_REVA ||
-         inb( ioaddr + 3 ) != HP100_HW_ID_3 )
-       return -ENODEV;
-
-  dev -> base_addr = ioaddr;
-
-#ifdef HP100_DEBUG_PROBE1
-  printk( "hp100_probe1: card found at port 0x%x\n", ioaddr );
-#endif
+  dev->base_addr = ioaddr;
 
   hp100_page( ID_MAC_ADDR );
   for ( i = uc = eisa_id = 0; i < 4; i++ )
@@ -339,17 +412,13 @@
     }
   uc += hp100_inb( BOARD_ID + 4 );
 
-#ifdef HP100_DEBUG_PROBE1
-  printk( "hp100_probe1: EISA ID = 0x%08x  checksum = 0x%02x\n", eisa_id, uc );
-#endif
-
-  if ( uc != 0xff )		/* bad checksum? */
+  if ( uc != 0xff )    /* bad checksum? */
     {
-      printk( "hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
+      printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
       return -ENODEV;
     }
 
-  for ( i = 0; i < sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ); i++ )
+  for ( i=0; i<sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id); i++)
     if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
       break;
   if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) )
@@ -358,10 +427,10 @@
       return -ENODEV;
     }
   eid = &hp100_eisa_ids[ i ];
-  if ( ( eid -> id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
+  if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
     {
       printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n",
-	eid -> name, ioaddr );
+	      eid->name, ioaddr );
       return -ENODEV;
     }
 
@@ -369,461 +438,1592 @@
     uc += hp100_inb( LAN_ADDR + i );
   if ( uc != 0xff )
     {
-      printk( "hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
-	eid -> name, ioaddr );
+      printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
+	     eid->name, ioaddr );
       return -EIO;
     }
 
-#ifndef HP100_IO_MAPPED
+  /* Determine driver operation mode
+   *
+   * Use the variable "hp100_mode" upon insmod or as kernel parameter to
+   * force driver modes:
+   * hp100_mode=1 -> default, use busmaster mode if configured.
+   * hp100_mode=2 -> enable shared memory mode 
+   * hp100_mode=3 -> force use of i/o mapped mode.
+   * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
+   */
+
+  if(hp100_mode==3)
+    {
+      hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW);
+      hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW);
+      hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+      printk("hp100: IO mapped mode forced.\n");
+    }
+  else	if(hp100_mode==2)
+    {
+      hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+      hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW);
+      hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+      printk("hp100: Shared memory mode requested.\n");
+    } 
+  else if(hp100_mode==4)
+    {
+      if(chip==HP100_CHIPID_LASSEN)
+	{
+	  hp100_outw(HP100_BM_WRITE|
+		     HP100_BM_READ | HP100_SET_HB, OPTION_LSW);
+	  hp100_outw(HP100_IO_EN   | 
+		     HP100_MEM_EN  | HP100_RESET_LB, OPTION_LSW);
+	  printk("hp100: Busmaster mode requested.\n");
+	}
+      hp100_mode=1;
+    }
+		
+  if(hp100_mode==1) /* default behaviour */
+    {
+      if( (hp100_inw(OPTION_LSW)&HP100_IO_EN) &&
+	  (~hp100_inw(OPTION_LSW)&HP100_MEM_EN) &&
+	  (~hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ))
+	  )
+	{
+#ifdef HP100_DEBUG
+	  printk("hp100: IO_EN bit is set on card.\n");
+#endif
+	  hp100_mode=3;
+	}
+      else if( ( chip==HP100_CHIPID_LASSEN ) 	&&
+	       (	(hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ) ) == 
+			(HP100_BM_WRITE|HP100_BM_READ) )  )	
+	{
+	  printk("hp100: Busmaster mode enabled.\n");
+	  hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW);
+	}
+      else
+	{
+#ifdef HP100_DEBUG
+	  printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n");
+#endif
+	  /* In this case, try shared memory mode */
+	  hp100_mode=2;
+	  hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+	  /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */
+	}
+    }
+
+  /* Check for shared memory on the card, eventually remap it */
   hp100_page( HW_MAP );
-  mem_mapped = ( hp100_inw( OPTION_LSW ) &
-                 ( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) ) != 0;
+  mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0);
   mem_ptr_phys = mem_ptr_virt = NULL;
-  if ( mem_mapped )
+  memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07));
+
+  /* For memory mapped or busmaster mode, we want the memory address */
+  if ( mem_mapped || (hp100_mode==1))
     {
-      mem_ptr_phys = (u_char *)( hp100_inw( MEM_MAP_LSW ) |
-                               ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
-      (u_int)mem_ptr_phys &= ~0x1fff;	/* 8k alignment */
+      mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) | 
+				( hp100_inw( MEM_MAP_MSW ) << 16 ) );
+      (u_int)mem_ptr_phys &= ~0x1fff;  /* 8k alignment */
+
       if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 )
         {
+	  printk("hp100: Can only use programmed i/o mode.\n");
           mem_ptr_phys = NULL;
           mem_mapped = 0;
+	  hp100_mode=3; /* Use programmed i/o */
         }
-      if ( mem_mapped && bus == HP100_BUS_PCI )
-        {
-          if ( ( mem_ptr_virt = ioremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL )
-            {
-              printk( "hp100: ioremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys );
-              mem_ptr_phys = NULL;
-              mem_mapped = 0;
-            }
-        }
-    }
-#else
-  mem_mapped = 0;
-  mem_ptr_phys = mem_ptr_virt = NULL;
+						
+      /* We do not need access to shared memory in busmaster mode */
+      /* However in slave mode we need to remap high (>1GB) card memory  */
+      if(hp100_mode!=1) /* = not busmaster */
+	{
+	  if ( bus == HP100_BUS_PCI )
+	    {
+	      /* We try with smaller memory sizes, if ioremap fails */
+	      for(; memory_size>16383; memory_size=memory_size/2)
+		{
+		  if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,memory_size))==NULL)
+		    {
+#ifdef HP100_DEBUG
+		      printk( "hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long)mem_ptr_phys );														
 #endif
+		    }	
+		  else
+		    {
+#ifdef HP100_DEBUG
+		      printk( "hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt);
+#endif
+		      break;
+		    }
+		}
+														
+	      if(mem_ptr_virt==NULL) /* all ioremap tries failed */
+		{
+		  printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n");
+		  hp100_mode=3;
+		  memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07) );
+		}
+	    }
+	}
+						
+    }
+
+  if(hp100_mode==3) /* io mapped forced */
+    {
+      mem_mapped = 0;
+      mem_ptr_phys = mem_ptr_virt = NULL;
+      printk("hp100: Using (slow) programmed i/o mode.\n");
+    }
 
-  if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL )
+  /* Initialise the "private" data structure for this card. */
+  if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL)
     return -ENOMEM;
-  memset( dev -> priv, 0, sizeof( struct hp100_private ) );
+  memset( dev->priv, 0, sizeof(struct hp100_private) );
 
-  lp = (struct hp100_private *)dev -> priv;
-  lp -> id = eid;
-  lp -> mem_mapped = mem_mapped;
-  lp -> mem_ptr_phys = mem_ptr_phys;
-  lp -> mem_ptr_virt = mem_ptr_virt;
+  lp = (struct hp100_private *)dev->priv;
+  lp->id = eid;
+  lp->chip = chip;
+  lp->mode = hp100_mode;
+  lp->pci_bus = pci_bus;
+  lp->bus = bus;
+  lp->pci_device_fn = pci_device_fn;
+  lp->priority_tx = hp100_priority_tx;
+  lp->rx_ratio = hp100_rx_ratio;
+  lp->mem_ptr_phys = mem_ptr_phys;
+  lp->mem_ptr_virt = mem_ptr_virt;
   hp100_page( ID_MAC_ADDR );
-  lp -> soft_model = hp100_inb( SOFT_MODEL );
-  lp -> mac1_mode = HP100_MAC1MODE3;
-  lp -> mac2_mode = HP100_MAC2MODE3;
+  lp->soft_model = hp100_inb( SOFT_MODEL );
+  lp->mac1_mode = HP100_MAC1MODE3;
+  lp->mac2_mode = HP100_MAC2MODE3;
+
+  dev->base_addr = ioaddr;
+
+  lp->memory_size = memory_size;
+  lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
+
+  /* memory region for programmed i/o */
+  request_region( dev->base_addr, HP100_REGION_SIZE, eid->name );
+
+  dev->open = hp100_open;
+  dev->stop = hp100_close;
+
+  if (lp->mode==1) /* busmaster */
+    dev->hard_start_xmit = hp100_start_xmit_bm;
+  else
+    dev->hard_start_xmit = hp100_start_xmit;
 
-  dev -> base_addr = ioaddr;
+  dev->get_stats = hp100_get_stats;
+  dev->set_multicast_list = &hp100_set_multicast_list;
+
+  /* Ask the card for which IRQ line it is configured */
   hp100_page( HW_MAP );
-  dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK;
-  if ( dev -> irq == 2 ) dev -> irq = 9;
-  lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 );
-  lp -> rx_ratio = hp100_rx_ratio;
-
-  dev -> open = hp100_open;
-  dev -> stop = hp100_close;
-  dev -> hard_start_xmit = hp100_start_xmit;
-  dev -> get_stats = hp100_get_stats;
-  dev -> set_multicast_list = &hp100_set_multicast_list;
+  dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK;
+  if ( dev->irq == 2 )
+    dev->irq = 9;
 
-  request_region( dev -> base_addr, HP100_REGION_SIZE, eid -> name );
+  if(lp->mode==1) /* busmaster */
+    dev->dma=4; 
 
+  /* Ask the card for its MAC address and store it for later use. */
   hp100_page( ID_MAC_ADDR );
   for ( i = uc = 0; i < 6; i++ )
-    dev -> dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+    dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
 
+  /* Reset statistics (counters) */
   hp100_clear_stats( ioaddr );
 
   ether_setup( dev );
 
-  lp -> lan_type = hp100_sense_lan( dev );
-
-  printk( "%s: %s at 0x%x, IRQ %d, ",
-    dev -> name, lp -> id -> name, ioaddr, dev -> irq );
+  /* If busmaster mode is wanted, a dma-capable memory area is needed for
+   * the rx and tx PDLs 
+   * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
+   * needed for the allocation of the memory area. 
+   */
+
+  /* TODO: We do not need this with old cards, where PDLs are stored
+   * in the cards shared memory area. But currently, busmaster has been
+   * implemented/tested only with the lassen chip anyway... */
+  if(lp->mode==1) /* busmaster */
+    {
+      /* Get physically continous memory for TX & RX PDLs    */
+      if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL)
+        return -ENOMEM;
+      lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f));
+      memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f);
+
+#ifdef HP100_DEBUG_BM
+      printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n",
+             (u_int)lp->page_vaddr_algn,
+             (u_int)lp->page_vaddr_algn+MAX_RINGSIZE);
+#endif
+      lp->rxrcommit  = lp->txrcommit = 0;
+      lp->rxrhead    = lp->rxrtail   = &(lp->rxring[0]);
+      lp->txrhead    = lp->txrtail   = &(lp->txring[0]); 
+    }
+
+  /* Initialise the card. */
+  /* (I'm not really sure if it's a good idea to do this during probing, but 
+   * like this it's assured that the lan connection type can be sensed
+   * correctly)
+   */
+  hp100_hwinit( dev );
+
+  /* Try to find out which kind of LAN the card is connected to. */
+  lp->lan_type = hp100_sense_lan( dev );
+     
+  /* Print out a message what about what we think we have probed. */
+  printk( "hp100: %s: %s at 0x%x, IRQ %d, ",
+          dev->name, lp->id->name, ioaddr, dev->irq );
   switch ( bus ) {
-    case HP100_BUS_EISA: printk( "EISA" ); break;
-    case HP100_BUS_PCI:  printk( "PCI" );  break;
-    default:		 printk( "ISA" );  break;
+  case HP100_BUS_EISA: printk( "EISA" ); break;
+  case HP100_BUS_PCI:  printk( "PCI" );  break;
+  default:     printk( "ISA" );  break;
   }
   printk( " bus, %dk SRAM (rx/tx %d%%).\n",
-    lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio );
-  if ( mem_mapped )
+          lp->memory_size >> 10, lp->rx_ratio );
+
+  if ( lp->mode==2 ) /* memory mapped */ 
     {
       printk( "%s: Memory area at 0x%lx-0x%lx",
-		dev -> name, (u_long)mem_ptr_phys, (u_long)mem_ptr_phys + 0x1fff );
+              dev->name,(u_long)mem_ptr_phys,(u_long)mem_ptr_phys+(u_long)lp->memory_size );
       if ( mem_ptr_virt )
-        printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
+	printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
       printk( ".\n" );
+
+      /* Set for info when doing ifconfig */
+      dev->mem_start = (u_long)mem_ptr_phys;
+      dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size;
     }
-  printk( "%s: ", dev -> name );
-  if ( lp -> lan_type != HP100_LAN_ERR )
+  printk( "%s: ", dev->name );
+  if ( lp->lan_type != HP100_LAN_ERR )
     printk( "Adapter is attached to " );
-  switch ( lp -> lan_type ) {
-    case HP100_LAN_100:
-      printk( "100Mb/s Voice Grade AnyLAN network.\n" );
-      break;
-    case HP100_LAN_10:
-      printk( "10Mb/s network.\n" );
-      break;
-    default:
-      printk( "Warning! Link down.\n" );
+  switch ( lp->lan_type ) {
+  case HP100_LAN_100:
+    printk( "100Mb/s Voice Grade AnyLAN network.\n" );
+    break;
+  case HP100_LAN_10:
+    printk( "10Mb/s network.\n" );
+    break;
+  default:
+    printk( "Warning! Link down.\n" );
   }
+  return 0;
+}
 
-  hp100_stop_interface( dev );
+
+/* This procedure puts the card into a stable init state */
+static void hp100_hwinit( struct device *dev )
+{
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
 
-  return 0;
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4202, TRACE );
+  printk("hp100: hwinit\n");
+#endif
+
+  /* Initialise the card. -------------------------------------------- */
+
+  /* Clear all pending Ints and disable Ints */
+  hp100_page( PERFORMANCE );
+  hp100_outw( 0xfefe, IRQ_MASK );    /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS );  /* clear all pending ints */
+
+  hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+  hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW );
+
+  if(lp->mode==1)
+    { 
+      hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */
+      wait();
+    }
+  else
+    {
+      hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+      hp100_cascade_reset( dev, TRUE );
+      hp100_page( MAC_CTRL );
+      hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1); 
+    }
+		
+  /* Initiate EEPROM reload */
+  hp100_load_eeprom( dev );
+		
+  wait();
+		
+  /* Go into reset again. */
+  hp100_cascade_reset( dev, TRUE );
+		
+  /* Set Option Registers to a safe state  */
+  hp100_outw( HP100_DEBUG_EN |
+              HP100_RX_HDR   |
+              HP100_EE_EN    |
+              HP100_BM_WRITE |
+              HP100_BM_READ  | HP100_RESET_HB |
+              HP100_FAKE_INT |
+              HP100_INT_EN   |
+	      HP100_MEM_EN   |
+              HP100_IO_EN    | HP100_RESET_LB, OPTION_LSW);
+		
+  hp100_outw( HP100_TRI_INT  |
+              HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+
+  hp100_outb( HP100_PRIORITY_TX |
+              HP100_ADV_NXT_PKT |
+              HP100_TX_CMD      | HP100_RESET_LB, OPTION_MSW );
+
+  /* TODO: Configure MMU for Ram Test. */
+  /* TODO: Ram Test. */
+
+  /* Re-check if adapter is still at same i/o location      */
+  /* (If the base i/o in eeprom has been changed but the    */
+  /* registers had not been changed, a reload of the eeprom */
+  /* would move the adapter to the address stored in eeprom */
+  
+  /* TODO: Code to implement. */
+		
+  /* Until here it was code from HWdiscover procedure. */
+  /* Next comes code from mmuinit procedure of SCO BM driver which is
+   * called from HWconfigure in the SCO driver.  */
+
+  /* Initialise MMU, eventually switch on Busmaster Mode, initialise 
+   * multicast filter...
+   */
+  hp100_mmuinit( dev );
+
+  /* We don't turn the interrupts on here - this is done by start_interface. */
+  wait(); /* TODO: Do we really need this? */
+
+  /* Enable Hardware (e.g. unreset) */
+  hp100_cascade_reset( dev, FALSE );
+
+  /* ------- initialisation complete ----------- */
+
+  /* Finally try to log in the Hub if there may be a VG connection. */
+  if( lp->lan_type != HP100_LAN_10 )
+    hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
 }
 
-/*
- *  open/close functions
+
+/* 
+ * mmuinit - Reinitialise Cascade MMU and MAC settings.
+ * Note: Must already be in reset and leaves card in reset. 
  */
-
-static int hp100_open( struct device *dev )
+static void hp100_mmuinit( struct device *dev )
 {
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
   int i;
-  int ioaddr = dev -> base_addr;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
 
-  if ( request_irq( dev -> irq, hp100_interrupt, SA_INTERRUPT, lp -> id -> name, NULL ) )
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4203, TRACE );
+  printk("hp100: mmuinit\n");
+#endif
+
+#ifdef HP100_DEBUG
+  if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) )
     {
-      printk( "%s: unable to get IRQ %d\n", dev -> name, dev -> irq );
-      return -EAGAIN;
+      printk("hp100: Not in reset when entering mmuinit. Fix me.\n");
+      return;
     }
-  irq2dev_map[ dev -> irq ] = dev;
+#endif
 
-  MOD_INC_USE_COUNT;
+  /* Make sure IRQs are masked off and ack'ed. */
+  hp100_page( PERFORMANCE );
+  hp100_outw( 0xfefe, IRQ_MASK );  /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS );  /* ack IRQ */
 
-  dev -> tbusy = 0;
-  dev -> trans_start = jiffies;
-  dev -> interrupt = 0;
-  dev -> start = 1;
-
-  lp -> lan_type = hp100_sense_lan( dev );
-  lp -> mac1_mode = HP100_MAC1MODE3;
-  lp -> mac2_mode = HP100_MAC2MODE3;
+  /*
+   * Enable Hardware 
+   * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
+   * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
+   * - Clear Priority, Advance Pkt and Xmit Cmd
+   */
+
+  hp100_outw( HP100_DEBUG_EN |
+              HP100_RX_HDR   |
+              HP100_EE_EN    | HP100_RESET_HB |
+              HP100_IO_EN    |
+              HP100_FAKE_INT |
+              HP100_INT_EN   | HP100_RESET_LB, OPTION_LSW );
+  	
+  hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
+		
+  if(lp->mode==1) /* busmaster */
+    {
+      hp100_outw( HP100_BM_WRITE | 
+		  HP100_BM_READ  |
+		  HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+    }
+  else if(lp->mode==2) /* memory mapped */
+    {
+      hp100_outw( HP100_BM_WRITE |
+		  HP100_BM_READ  | HP100_RESET_HB, OPTION_LSW );
+      hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
+      hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW );
+      hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+    }
+  else if( lp->mode==3 ) /* i/o mapped mode */
+    {
+      hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | 
+                  HP100_IO_EN    | HP100_SET_LB, OPTION_LSW );
+    }
 
-  hp100_page( MAC_CTRL );
-  hp100_orw( HP100_LINK_BEAT_DIS | HP100_RESET_LB, LAN_CFG_10 );
+  hp100_page( HW_MAP );
+  hp100_outb( 0, EARLYRXCFG );
+  hp100_outw( 0, EARLYTXCFG );
+  
+  /*
+   * Enable Bus Master mode
+   */
+  if(lp->mode==1) /* busmaster */
+    {
+      /* Experimental: Set some PCI configuration bits */
+      hp100_page( HW_MAP );
+      hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */
+      hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */
+
+      /* PCI Bus failures should result in a Misc. Interrupt */
+      hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2);
+					
+      hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW );
+      hp100_page( HW_MAP );					
+      /* Use Burst Mode and switch on PAGE_CK */
+      hp100_orb( HP100_BM_BURST_RD |
+                 HP100_BM_BURST_WR, BM);
+      if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+	hp100_orb( HP100_BM_PAGE_CK, BM );
+      hp100_orb( HP100_BM_MASTER, BM );		
+    }
+  else /* not busmaster */
+    {
+      hp100_page(HW_MAP);
+      hp100_andb(~HP100_BM_MASTER, BM );
+    }
+
+  /*
+   * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs
+   */  
+  hp100_page( MMU_CFG );
+  if(lp->mode==1) /* only needed for Busmaster */
+    {
+      int xmit_stop, recv_stop;
 
-  hp100_stop_interface( dev );
-  hp100_load_eeprom( dev );
+      if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+        {
+          int pdl_stop;
+          
+          /*
+           * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and
+           * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded
+           * to the next higher 1k boundary) bytes for the rx-pdl's
+	   * Note: For non-etr chips the transmit stop register must be
+	   * programmed on a 1k boundary, i.e. bits 9:0 must be zero. 
+	   */
+          pdl_stop  = lp->memory_size;
+          xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff);
+          recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff);
+          hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP );
+#ifdef HP100_DEBUG_BM
+          printk("hp100: PDL_STOP = 0x%x\n", pdl_stop);
+#endif
+        }
+      else /* ETR chip (Lassen) in busmaster mode */
+        {
+          xmit_stop = ( lp->memory_size ) - 1;
+          recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff);
+        }
 
-  hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
-              HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
-  hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB |
-              HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW );
-  hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB |
-                HP100_PRIORITY_TX | ( hp100_priority_tx ? HP100_SET_HB : HP100_RESET_HB ),
-              OPTION_MSW );
+      hp100_outw( xmit_stop>>4 , TX_MEM_STOP );
+      hp100_outw( recv_stop>>4 , RX_MEM_STOP );
+#ifdef HP100_DEBUG_BM
+      printk("hp100: TX_STOP  = 0x%x\n",xmit_stop>>4);
+      printk("hp100: RX_STOP  = 0x%x\n",recv_stop>>4);
+#endif
+    }  
+  else /* Slave modes (memory mapped and programmed io)  */
+    {
+      hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP );
+      hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP );  
+#ifdef HP100_DEBUG
+      printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP));
+      printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP));
+#endif
+    }
 
+  /* Write MAC address into page 1 */
   hp100_page( MAC_ADDRESS );
   for ( i = 0; i < 6; i++ )
-    hp100_outb( dev -> dev_addr[ i ], MAC_ADDR + i );
-  for ( i = 0; i < 8; i++ )		/* setup multicast filter to receive all */
-    hp100_outb( 0xff, HASH_BYTE0 + i );
+    hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i );
+  
+  /* Zero the multicast hash registers */
+  for ( i = 0; i < 8; i++ )
+    hp100_outb( 0x0, HASH_BYTE0 + i );  
+  
+  /* Set up MAC defaults */
+  hp100_page( MAC_CTRL );
+ 
+  /* Go to LAN Page and zero all filter bits */
+  /* Zero accept error, accept multicast, accept broadcast and accept */
+  /* all directed packet bits */
+  hp100_andb( ~(HP100_RX_EN|
+		HP100_TX_EN|
+		HP100_ACC_ERRORED|
+		HP100_ACC_MC|
+		HP100_ACC_BC|
+		HP100_ACC_PHY),   MAC_CFG_1 );
+
+  hp100_outb( 0x00, MAC_CFG_2 );
+
+  /* Zero the frame format bit. This works around a training bug in the */
+  /* new hubs. */
+  hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */	
+
+  if(lp->priority_tx)
+    hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW );
+  else
+    hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW );
+	
+  hp100_outb( HP100_ADV_NXT_PKT |
+	      HP100_TX_CMD      | HP100_RESET_LB, OPTION_MSW );
+	
+  /* If busmaster, initialize the PDLs */
+  if(lp->mode==1)
+    hp100_init_pdls( dev );
+
+  /* Go to performance page and initalize isr and imr registers */
   hp100_page( PERFORMANCE );
-  hp100_outw( 0xfefe, IRQ_MASK );	/* mask off all ints */
-  hp100_outw( 0xffff, IRQ_STATUS );	/* ack IRQ */
-  hp100_outw( (HP100_RX_PACKET | HP100_RX_ERROR | HP100_SET_HB) |
-              (HP100_TX_ERROR | HP100_SET_LB ), IRQ_MASK );
-              				/* and enable few */
-  hp100_reset_card();
-  hp100_page( MMU_CFG );
-  hp100_outw( ( lp -> memory_size * lp -> rx_ratio ) / 100, RX_MEM_STOP );
-  hp100_outw( lp -> memory_size - 1, TX_MEM_STOP );
-  hp100_unreset_card();
+  hp100_outw( 0xfefe, IRQ_MASK );  /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS );  /* ack IRQ */
+}
+
+
+/*
+ *  open/close functions
+ */
+
+static int hp100_open( struct device *dev )
+{
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+#ifdef HP100_DEBUG_B	
+  int ioaddr=dev->base_addr;
+#endif
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4204, TRACE );
+  printk("hp100: open\n");
+#endif
+		
+  /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
+  if((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA))
+    {
+      if(request_irq(dev->irq,hp100_interrupt,SA_SHIRQ,lp->id->name,dev))
+	{
+	  printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq );
+	  return -EAGAIN;
+	}
+    }
+  else
+    if(request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, NULL))
+      {
+	printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq );
+	return -EAGAIN;
+      }
+
+  irq2dev_map[ dev->irq ] = dev;
+		
+  MOD_INC_USE_COUNT;
+
+  dev->tbusy = 0;
+  dev->trans_start = jiffies;
+  dev->interrupt = 0;
+  dev->start = 1;
+
+  lp->lan_type = hp100_sense_lan( dev );
+  lp->mac1_mode = HP100_MAC1MODE3;
+  lp->mac2_mode = HP100_MAC2MODE3;
 
-  if ( lp -> lan_type == HP100_LAN_100 )
-    lp -> hub_status = hp100_login_to_vg_hub( dev );
+  hp100_stop_interface( dev );
+ 
+  hp100_hwinit( dev );
 
-  hp100_start_interface( dev );
+  hp100_start_interface( dev ); /* sets mac modes, enables interrupts */
 
   return 0;
 }
 
+
+/* The close function is called when the interface is to be brought down */
 static int hp100_close( struct device *dev )
 {
-  int ioaddr = dev -> base_addr;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4205, TRACE );
+  printk("hp100:close\n");
+#endif
 
   hp100_page( PERFORMANCE );
-  hp100_outw( 0xfefe, IRQ_MASK );		/* mask off all IRQs */
+  hp100_outw( 0xfefe, IRQ_MASK );    /* mask off all IRQs */
 
   hp100_stop_interface( dev );
 
-  if ( lp -> lan_type == HP100_LAN_100 )	/* relogin */
-    hp100_login_to_vg_hub( dev );
+  if ( lp->lan_type == HP100_LAN_100 ) 
+    lp->hub_status=hp100_login_to_vg_hub( dev, FALSE );
 
-  dev -> tbusy = 1;
-  dev -> start = 0;
+  dev->tbusy = 1;
+  dev->start = 0;
 
-  free_irq( dev -> irq, NULL );
-  irq2dev_map[ dev -> irq ] = NULL;
+  if ((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA))
+    free_irq( dev->irq, dev );
+  else
+    free_irq( dev->irq, NULL );
+  irq2dev_map[ dev->irq ] = NULL;
   MOD_DEC_USE_COUNT;
   return 0;
 }
 
+
+/*
+ * Configure the PDL Rx rings and LAN 
+ */
+static void hp100_init_pdls( struct device *dev )
+{
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  hp100_ring_t         *ringptr;
+  u_int                *pageptr;
+  int                  i;
+
+#ifdef HP100_DEBUG_B
+  int ioaddr = dev->base_addr;
+#endif
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4206, TRACE );
+  printk("hp100: init pdls\n");
+#endif
+
+  if(0==lp->page_vaddr_algn)
+    printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n");
+  else
+    {
+      /* pageptr shall point into the DMA accessible memory region  */
+      /* we use this pointer to status the upper limit of allocated */
+      /* memory in the allocated page. */
+      /* note: align the pointers to the pci cache line size */
+      memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero  Rx/Tx ring page */
+      pageptr=lp->page_vaddr_algn;
+						
+      lp->rxrcommit =0;
+      ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]);
+      
+      /* Initialise Rx Ring */
+      for (i=MAX_RX_PDL-1; i>=0; i--)
+        {
+          lp->rxring[i].next = ringptr;
+          ringptr=&(lp->rxring[i]);
+          pageptr+=hp100_init_rxpdl(ringptr, pageptr);
+        }
+      
+      /* Initialise Tx Ring */
+      lp->txrcommit = 0;
+      ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]);
+      for (i=MAX_TX_PDL-1; i>=0; i--)
+        {
+          lp->txring[i].next = ringptr;
+          ringptr=&(lp->txring[i]);
+          pageptr+=hp100_init_txpdl(ringptr, pageptr);
+        }
+    }
+}
+
+
+/* These functions "format" the entries in the pdl structure   */
+/* They return how much memory the fragments need.            */
+static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u32 *pdlptr )
+{
+  /* pdlptr is starting adress for this pdl */
+
+  if( 0!=( ((unsigned)pdlptr) & 0xf) )
+    printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n",(unsigned)pdlptr);
+
+  ringptr->pdl       = pdlptr+1; 
+  ringptr->pdl_paddr = virt_to_bus(pdlptr+1);
+  ringptr->skb       = (void *) NULL; 
+
+  /* 
+   * Write address and length of first PDL Fragment (which is used for
+   * storing the RX-Header
+   * We use the 4 bytes _before_ the PDH in the pdl memory area to 
+   * store this information. (PDH is at offset 0x04)
+   */
+  /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
+
+  *(pdlptr+2) =(u_int) virt_to_bus(pdlptr);  /* Address Frag 1 */ 
+  *(pdlptr+3) = 4;                           /* Length  Frag 1 */
+
+  return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 );
+}
+
+
+static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u32 *pdlptr )
+{
+  if( 0!=( ((unsigned)pdlptr) & 0xf) )
+    printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n",(unsigned) pdlptr);
+
+  ringptr->pdl       = pdlptr; /* +1; */  
+  ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */
+  ringptr->skb = (void *) NULL;
+  
+  return((((MAX_TX_FRAG*2+2)+3)/4)*4);
+}
+
+
 /*
- *  transmit
+ * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes 
+ * for possible odd word alignment rounding up to next dword and set PDL
+ * address for fragment#2 
+ * Returns: 0 if unable to allocate skb_buff
+ *          1 if successful
+ */
+int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev )
+{
+#ifdef HP100_DEBUG_B
+  int ioaddr = dev->base_addr;
+#endif
+#ifdef HP100_DEBUG_BM
+  u_int *p;
+#endif
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4207, TRACE );
+  printk("hp100: build rx pdl\n");
+#endif
+
+  /* Allocate skb buffer of maximum size */
+  /* Note: This depends on the alloc_skb functions allocating more 
+   * space than requested, i.e. aligning to 16bytes */
+
+  ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 );
+		
+  if(NULL!=ringptr->skb)
+    {
+      /* 
+       * Reserve 2 bytes at the head of the buffer to land the IP header
+       * on a long word boundary (According to the Network Driver section
+       * in the Linux KHG, this should help to increase performance.)
+       */
+      skb_reserve(ringptr->skb, 2);
+
+      ringptr->skb->dev=dev; 
+      ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE );
+						
+      /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
+      /* Note: 1st Fragment is used for the 4 byte packet status
+       * (receive header). Its PDL entries are set up by init_rxpdl. So 
+       * here we only have to set up the PDL fragment entries for the data
+       * part. Those 4 bytes will be stored in the DMA memory region 
+       * directly before the PDL. 
+       */
+#ifdef HP100_DEBUG_BM
+      printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
+	     (u_int) ringptr->pdl,
+	     ((MAX_ETHER_SIZE+2+3)/4)*4,
+	     (unsigned int) ringptr->skb->data);
+#endif
+
+      ringptr->pdl[0] = 0x00020000;                          /* Write PDH */
+      ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data)); 
+      ringptr->pdl[4] = MAX_ETHER_SIZE;                 /* Length of Data */
+						
+#ifdef HP100_DEBUG_BM
+      for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++)
+        printk("Adr 0x%.8x = 0x%.8x\n",(u_int) p,(u_int) *p );
+#endif
+      return(1);
+    }
+  /* else: */
+  /* alloc_skb failed (no memory) -> still can receive the header
+   * fragment into PDL memory. make PDL safe by clearing msgptr and
+   * making the PDL only 1 fragment (i.e. the 4 byte packet status)
+   */
+#ifdef HP100_DEBUG_BM
+  printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n",
+	 (u_int) ringptr->pdl);
+#endif
+
+  ringptr->pdl[0]=0x00010000;   /* PDH: Count=1 Fragment */
+
+  return(0);
+}
+
+
+/*
+ *  hp100_rxfill - attempt to fill the Rx Ring will empty skb's
+ *
+ * Makes assumption that skb's are always contiguous memory areas and
+ * therefore PDLs contain only 2 physical fragments.
+ * -  While the number of Rx PDLs with buffers is less than maximum
+ *      a.  Get a maximum packet size skb
+ *      b.  Put the physical address of the buffer into the PDL.
+ *      c.  Output physical address of PDL to adapter.
+ */
+static void hp100_rxfill( struct device *dev )
+{
+  int ioaddr=dev->base_addr; 
+
+  struct hp100_private  *lp      = (struct hp100_private *)dev->priv;
+  hp100_ring_t    *ringptr;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4208, TRACE );
+  printk("hp100: rxfill\n");
+#endif
+		
+  hp100_page( PERFORMANCE );
+
+  while (lp->rxrcommit < MAX_RX_PDL)
+    {
+      /*
+      ** Attempt to get a buffer and build a Rx PDL.
+      */
+      ringptr = lp->rxrtail;
+      if (0 == hp100_build_rx_pdl( ringptr, dev ))
+        {
+          return;      /* None available, return */
+        }
+      
+      /* Hand this PDL over to the card */
+      /* Note: This needs performance page selected! */
+#ifdef HP100_DEBUG_BM
+      printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",
+             lp->rxrcommit,
+             (u_int)ringptr->pdl,
+             (u_int)ringptr->pdl_paddr,
+             (u_int)ringptr->pdl[3]);
+#endif
+
+      hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA); 
+      
+      lp->rxrcommit += 1;
+      lp->rxrtail = ringptr->next;
+    }
+}
+
+
+/*
+ * BM_shutdown - shutdown bus mastering and leave chip in reset state
+ */
+
+static void hp100_BM_shutdown( struct device *dev )
+{
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  unsigned long time;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4209, TRACE );
+  printk("hp100: bm shutdown\n");
+#endif
+
+  hp100_page( PERFORMANCE );
+  hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */
+
+  /* Ensure Interrupts are off */
+  hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW );
+
+  /* Disable all MAC activity */
+  hp100_page( MAC_CTRL );
+  hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );  /* stop rx/tx */
+
+  /* If cascade MMU is not already in reset */
+  if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) )
+    {
+      /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so
+       * MMU pointers will not be reset out from underneath
+       */
+      hp100_page( MAC_CTRL );
+      for(time=0; time<5000; time++)
+        {
+          if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))==
+              (HP100_TX_IDLE|HP100_RX_IDLE) ) break;
+        }
+      
+      /* Shutdown algorithm depends on the generation of Cascade */
+      if( lp->chip==HP100_CHIPID_LASSEN )
+        { /* ETR shutdown/reset */
+          /* Disable Busmaster mode and wait for bit to go to zero. */
+          hp100_page(HW_MAP);
+          hp100_andb( ~HP100_BM_MASTER, BM );
+          /* 100 ms timeout */
+          for(time=0; time<32000; time++)
+            {
+              if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break;
+            }
+        }
+      else
+        { /* Shasta or Rainier Shutdown/Reset */
+          /* To ensure all bus master inloading activity has ceased,
+           * wait for no Rx PDAs or no Rx packets on card. 
+           */
+          hp100_page( PERFORMANCE );
+          /* 100 ms timeout */
+          for(time=0; time<10000; time++)
+            {
+              /* RX_PDL: PDLs not executed. */
+              /* RX_PKT_CNT: RX'd packets on card. */
+              if ( (hp100_inb( RX_PDL ) == 0) &&
+                   (hp100_inb( RX_PKT_CNT ) == 0) ) break;
+            }
+          
+          if(time>=10000)
+            printk("hp100: BM shutdown error.\n");
+          
+          /* To ensure all bus master outloading activity has ceased,
+           * wait until the Tx PDA count goes to zero or no more Tx space
+           * available in the Tx region of the card. 
+           */
+          /* 100 ms timeout */
+          for(time=0; time<10000; time++) {
+            if ( (0 == hp100_inb( TX_PKT_CNT )) &&
+                 (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break;
+          } 
+          
+          /* Disable Busmaster mode */
+          hp100_page(HW_MAP);
+          hp100_andb( ~HP100_BM_MASTER, BM );
+        } /* end of shutdown procedure for non-etr parts */  
+						
+      hp100_cascade_reset( dev, TRUE );
+    }
+  hp100_page( PERFORMANCE );
+  hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW );
+  /* Busmaster mode should be shut down now. */
+}
+
+
+
+/* 
+ *  transmit functions
  */
 
+/* tx function for busmaster mode */
+static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev )
+{
+  int i, ok_flag;
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  hp100_ring_t *ringptr;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4210, TRACE );
+  printk("hp100: start_xmit_bm\n");
+#endif
+
+  if ( skb==NULL )
+    {
+      dev_tint( dev );
+      return 0;
+    }
+	
+  if ( skb->len <= 0 ) return 0;
+	
+  /* Get Tx ring tail pointer */
+  if( lp->txrtail->next==lp->txrhead )
+    {
+      /* No memory. */
+#ifdef HP100_DEBUG
+      printk("hp100: start_xmit_bm: No TX PDL available.\n");
+#endif
+      /* not waited long enough since last tx? */
+      if ( jiffies - dev->trans_start < HZ/10 ) return -EAGAIN;
+
+      if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
+	{
+	  hp100_stop_interface( dev );
+	  if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
+	    {
+	      printk( "%s: no connection found - check wire\n", dev->name );
+	      hp100_start_interface( dev );  /* 10Mb/s RX pkts maybe handled */
+	      return -EIO;
+	    }
+	  if ( lp->lan_type == HP100_LAN_100 )
+	    lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
+	  hp100_start_interface( dev );
+	}
+				
+      if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+	/* we have a 100Mb/s adapter but it isn't connected to hub */
+	{
+	  printk( "%s: login to 100Mb/s hub retry\n", dev->name );
+	  hp100_stop_interface( dev );
+	  lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+	  hp100_start_interface( dev );
+	}
+      else
+	{
+	  hp100_ints_off();
+	  i = hp100_sense_lan( dev );
+	  hp100_page( PERFORMANCE );
+	  hp100_ints_on();
+	  if ( i == HP100_LAN_ERR )
+	    printk( "%s: link down detected\n", dev->name );
+	  else
+	    if ( lp->lan_type != i ) /* cable change! */
+	      {
+		/* it's very hard - all network setting must be changed!!! */
+		printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+		lp->lan_type = i;
+		hp100_stop_interface( dev );
+		if ( lp->lan_type == HP100_LAN_100 )
+		  lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+		hp100_start_interface( dev );
+	      }
+	    else
+	      {
+		printk( "%s: interface reset\n", dev->name );
+		hp100_stop_interface( dev );
+		hp100_start_interface( dev );
+	      }
+	}
+
+      dev->trans_start = jiffies;
+      return -EAGAIN;
+    }
+	
+  /*
+   * we have to turn int's off before modifying this, otherwise
+   * a tx_pdl_cleanup could occur at the same time
+   */
+  cli();
+  ringptr=lp->txrtail;
+  lp->txrtail=ringptr->next;
+	
+  /* Check whether packet has minimal packet size */
+  ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+  i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+					
+  ringptr->skb=skb;
+  ringptr->pdl[0]=((1<<16) | i);                /* PDH: 1 Fragment & length */
+  ringptr->pdl[1]=(u32)virt_to_bus(skb->data);  /* 1st Frag: Adr. of data */
+  if(lp->chip==HP100_CHIPID_SHASTA)
+    {
+      /* TODO:Could someone who has the EISA card please check if this works? */
+      ringptr->pdl[2]=i;
+    }
+  else /* Lassen */
+    {
+      /* In the PDL, don't use the padded size but the real packet size: */
+      ringptr->pdl[2]=skb->len;              /* 1st Frag: Length of frag */
+    }
+
+  /* Hand this PDL to the card. */
+  hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */
+	
+  lp->txrcommit++;
+  sti();
+	
+  /* Update statistics */	
+  lp->stats.tx_packets++;
+#ifdef LINUX_2_1
+  lp->stats.tx_bytes += skb->len;
+#endif
+  dev->trans_start = jiffies;
+	
+  return 0;
+}
+
+
+/* clean_txring checks if packets have been sent by the card by reading
+ * the TX_PDL register from the performance page and comparing it to the
+ * number of commited packets. It then frees the skb's of the packets that
+ * obviously have been sent to the network.
+ *
+ * Needs the PERFORMANCE page selected. 
+ */
+static void hp100_clean_txring( struct device *dev )
+{
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  int    ioaddr = dev->base_addr;
+  int    donecount;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4211, TRACE );
+  printk("hp100: clean txring\n");
+#endif
+
+  /* How many PDLs have been transmitted? */
+  donecount=(lp->txrcommit)-hp100_inb(TX_PDL);
+
+#ifdef HP100_DEBUG
+  if(donecount>MAX_TX_PDL)
+    printk("hp100: Warning: More PDLs transmitted than commited to card???\n");
+#endif
+
+  for( ; 0!=donecount; donecount-- )
+    {
+#ifdef HP100_DEBUG_BM
+      printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",
+	     (u_int) lp->txrhead->skb->data,
+	     lp->txrcommit,
+	     hp100_inb(TX_PDL),
+	     donecount);
+#endif
+      dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+      lp->txrhead->skb=(void *)NULL;
+      lp->txrhead=lp->txrhead->next;
+      lp->txrcommit--;
+    }
+}
+
+
+/* tx function for slave modes */
 static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
 {
   int i, ok_flag;
-  int ioaddr = dev -> base_addr;
+  int ioaddr = dev->base_addr;
   u_short val;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4212, TRACE );
+  printk("hp100: start_xmit\n");
+#endif
 
-  if ( lp -> lan_type < 0 )
+  if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
     {
       hp100_stop_interface( dev );
-      if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) < 0 )
+      if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
         {
-          printk( "%s: no connection found - check wire\n", dev -> name );
-          hp100_start_interface( dev );	/* 10Mb/s RX packets maybe handled */
+          printk( "%s: no connection found - check wire\n", dev->name );
+          hp100_start_interface( dev );  /* 10Mb/s RX packets maybe handled */
           return -EIO;
         }
-      if ( lp -> lan_type == HP100_LAN_100 )
-        lp -> hub_status = hp100_login_to_vg_hub( dev );
+      if ( lp->lan_type == HP100_LAN_100 )
+        lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
       hp100_start_interface( dev );
     }
 
-  if ( ( i = ( hp100_inl( TX_MEM_FREE ) & ~0x7fffffff ) ) < skb -> len + 16 )
+  /* If there is not enough free memory on the card... */
+  i=hp100_inl(TX_MEM_FREE)&0x7fffffff;
+  if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) )
     {
 #ifdef HP100_DEBUG
-      printk( "hp100_start_xmit: rx free mem = 0x%x\n", i );
+      printk( "hp100_start_xmit: tx free mem = 0x%x\n", i );
+#endif
+      /* not waited long enough since last failed tx try? */
+      if ( jiffies - dev->trans_start < HZ/2 ) 
+	{
+#ifdef HP100_DEBUG
+	  printk("hp100: trans_start timing problem\n");
 #endif
-      if ( jiffies - dev -> trans_start < 2 * HZ ) return -EAGAIN;
-      if ( lp -> lan_type == HP100_LAN_100 && lp -> hub_status < 0 )
- 				/* 100Mb/s adapter isn't connected to hub */
+	  return -EAGAIN;
+	}
+      if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+	/* we have a 100Mb/s adapter but it isn't connected to hub */
         {
-          printk( "%s: login to 100Mb/s hub retry\n", dev -> name );
+          printk( "%s: login to 100Mb/s hub retry\n", dev->name );
           hp100_stop_interface( dev );
-          lp -> hub_status = hp100_login_to_vg_hub( dev );
+          lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
           hp100_start_interface( dev );
         }
-       else
+      else
         {
           hp100_ints_off();
           i = hp100_sense_lan( dev );
           hp100_page( PERFORMANCE );
           hp100_ints_on();
           if ( i == HP100_LAN_ERR )
-            printk( "%s: link down detected\n", dev -> name );
-           else
-          if ( lp -> lan_type != i )
-            {
-              /* it's very heavy - all network setting must be changed!!! */
-              printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev -> name );
-              lp -> lan_type = i;
-              hp100_stop_interface( dev );
-              if ( lp -> lan_type == HP100_LAN_100 )
-                lp -> hub_status = hp100_login_to_vg_hub( dev );
-              hp100_start_interface( dev );
-            }
-           else
-            {
-              printk( "%s: interface reset\n", dev -> name );
-              hp100_stop_interface( dev );
-              hp100_start_interface( dev );
-            }
+            printk( "%s: link down detected\n", dev->name );
+	  else
+	    if ( lp->lan_type != i ) /* cable change! */
+	      {
+		/* it's very hard - all network setting must be changed!!! */
+		printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+		lp->lan_type = i;
+		hp100_stop_interface( dev );
+		if ( lp->lan_type == HP100_LAN_100 )
+		  lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+		hp100_start_interface( dev );
+	      }
+	    else
+	      {
+		printk( "%s: interface reset\n", dev->name );
+		hp100_stop_interface( dev );
+		hp100_start_interface( dev );
+		udelay(1000);
+	      }
         }
-      dev -> trans_start = jiffies;
+      dev->trans_start = jiffies;
       return -EAGAIN;
     }
 
-  for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
+  for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ )
     {
 #ifdef HP100_DEBUG_TX
       printk( "hp100_start_xmit: busy\n" );
 #endif
     }
-
+	
   hp100_ints_off();
   val = hp100_inw( IRQ_STATUS );
-  hp100_outw( val & HP100_TX_COMPLETE, IRQ_STATUS );
+  /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set
+   * when the current packet being transmitted on the wire is completed. */
+  hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS ); 
 #ifdef HP100_DEBUG_TX
-  printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len );
+  printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",val,hp100_inw(IRQ_MASK),(int)skb->len );
 #endif
-  ok_flag = skb -> len >= HP100_MIN_PACKET_SIZE;
-  i = ok_flag ? skb -> len : HP100_MIN_PACKET_SIZE;
-  hp100_outw( i, DATA32 );		/* length to memory manager */
-  hp100_outw( i, FRAGMENT_LEN );
-  if ( lp -> mem_mapped )
-    {
-      if ( lp -> mem_ptr_virt )
-        {
-          memcpy( lp -> mem_ptr_virt, skb -> data, skb -> len );
-          if ( !ok_flag )
-            memset( lp -> mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb -> len );
-        }
-       else
-        {
-          memcpy_toio( lp -> mem_ptr_phys, skb -> data, skb -> len );
-          if ( !ok_flag )
-            memset_io( lp -> mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb -> len );
-        }
+
+  ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+  i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+  hp100_outw( i, DATA32 );       /* tell card the total packet length */
+  hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length    */
+	
+  if ( lp->mode==2 ) /* memory mapped */
+    {
+      if ( lp->mem_ptr_virt ) /* high pci memory was remapped */
+	{
+	  /* Note: The J2585B needs alignment to 32bits here!  */
+	  memcpy( lp->mem_ptr_virt, skb->data, ( skb->len +3 ) & ~3 );
+	  if ( !ok_flag )
+	    memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len );
+	}
+      else
+	{
+	  memcpy_toio( lp->mem_ptr_phys, skb->data, skb->len );
+	  if ( !ok_flag )
+	    memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len );
+	}
     }
-   else
+  else /* programmed i/o */
     {
-      outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
+      outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 );
       if ( !ok_flag )
-        for ( i = ( skb -> len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
-          hp100_outl( 0, DATA32 );
+	for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
+	  hp100_outl( 0, DATA32 );
     }
-  hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
-  lp -> stats.tx_packets++;
-  dev -> trans_start = jiffies;
+	
+  hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+	
+  lp->stats.tx_packets++;
+#ifdef LINUX_2_1
+  lp->stats.tx_bytes += skb->len;
+#endif
+  dev->trans_start=jiffies;
   hp100_ints_on();
-
+	
   dev_kfree_skb( skb, FREE_WRITE );
-
+	
 #ifdef HP100_DEBUG_TX
   printk( "hp100_start_xmit: end\n" );
 #endif
-
+	
   return 0;
 }
 
+
 /*
- *  receive - called from interrupt handler
+ * Receive Function (Non-Busmaster mode)
+ * Called when an "Receive Packet" interrupt occurs, i.e. the receive 
+ * packet counter is non-zero.
+ * For non-busmaster, this function does the whole work of transfering
+ * the packet to the host memory and then up to higher layers via skb
+ * and netif_rx. 
  */
 
 static void hp100_rx( struct device *dev )
 {
   int packets, pkt_len;
-  int ioaddr = dev -> base_addr;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
   u_int header;
   struct sk_buff *skb;
 
-#if 0
-  if ( lp -> lan_type < 0 )
-    {
-      if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) == HP100_LAN_100 )
-        lp -> hub_status = hp100_login_to_vg_hub( dev );
-      hp100_page( PERFORMANCE );
-    }
+#ifdef DEBUG_B
+  hp100_outw( 0x4213, TRACE );
+  printk("hp100: rx\n");
 #endif
 
+  /* First get indication of received lan packet */
+  /* RX_PKT_CND indicates the number of packets which have been fully */
+  /* received onto the card but have not been fully transfered of the card */
   packets = hp100_inb( RX_PKT_CNT );
-#ifdef HP100_DEBUG
+#ifdef HP100_DEBUG_RX
   if ( packets > 1 )
     printk( "hp100_rx: waiting packets = %d\n", packets );
 #endif
+
   while ( packets-- > 0 )
     {
-      for ( pkt_len = 0; pkt_len < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_ADV_NXT_PKT ); pkt_len++ )
+      /* If ADV_NXT_PKT is still set, we have to wait until the card has */
+      /* really advanced to the next packet. */
+      for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT);
+	   pkt_len++ )
         {
-#ifdef HP100_DEBUG_TX
+#ifdef HP100_DEBUG_RX
           printk( "hp100_rx: busy, remaining packets = %d\n", packets );
-#endif
+#endif    
         }
-      if ( lp -> mem_mapped )
+
+      /* First we get the header, which contains information about the */
+      /* actual length of the received packet. */
+      if( lp->mode==2 ) /* memory mapped mode */
         {
-          if ( lp -> mem_ptr_virt )
-            header = *(__u32 *)lp -> mem_ptr_virt;
-           else
-            header = readl( lp -> mem_ptr_phys );
+          if ( lp->mem_ptr_virt )    /* if memory was remapped */
+            header = *(__u32 *)lp->mem_ptr_virt;
+          else
+            header = readl( lp->mem_ptr_phys );
         }
-       else
+      else /* programmed i/o */
         header = hp100_inl( DATA32 );
+      
       pkt_len = header & HP100_PKT_LEN_MASK;
+
 #ifdef HP100_DEBUG_RX
-      printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n",
-      	header & HP100_PKT_LEN_MASK, ( header >> 16 ) & 0xfff8, ( header >> 16 ) & 7 );
-#endif
-      /*
-       * NOTE! This (and the skb_put() below) depends on the skb-functions
+      printk( "hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
+              header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8,
+              (header>>16)&7);
+#endif
+    
+      /* Now we allocate the skb and transfer the data into it. */  
+      /* NOTE! This (and the skb_put() below) depends on the skb-functions
        * allocating more than asked (notably, aligning the request up to
        * the next 16-byte length).
        */
       skb = dev_alloc_skb( pkt_len );
-      if ( skb == NULL )
-        {
+      if ( skb == NULL ) /* Not enough memory->drop packet */
+	{
 #ifdef HP100_DEBUG
-          printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
+	  printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
 #endif
-          lp -> stats.rx_dropped++;
-        }
-       else
-        {
-          u_char *ptr;
-
-          skb -> dev = dev;
-          ptr = (u_char *)skb_put( skb, pkt_len );
-          if ( lp -> mem_mapped )
+	  lp->stats.rx_dropped++;
+	}
+      else /* skb successfully allocated */
+	{
+	  u_char *ptr;
+      
+	  skb->dev = dev;
+      
+	  /* ptr to start of the sk_buff data area */
+	  ptr = (u_char *)skb_put( skb, pkt_len );
+      
+	  /* Now transfer the data from the card into that area */
+	  if ( lp->mode==2 )
             {
-              if ( lp -> mem_ptr_virt )
-                memcpy( ptr, lp -> mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
-               else
-                memcpy_fromio( ptr, lp -> mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
+              if ( lp->mem_ptr_virt )
+                memcpy( ptr, lp->mem_ptr_virt, ( pkt_len + 3 ) & ~3 );
+              /* Note alignment to 32bit transfers */
+              else
+                memcpy_fromio( ptr, lp->mem_ptr_phys, ( pkt_len + 3 ) & ~3 );
             }
-           else
-            insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
-          skb -> protocol = eth_type_trans( skb, dev );
-          netif_rx( skb );
-          lp -> stats.rx_packets++;
-#ifdef HP100_DEBUG_RX
-          printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-		ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
-		ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
+	  else /* io mapped */
+	    insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 );
+      
+	  skb->protocol = eth_type_trans( skb, dev );
+
+	  netif_rx( skb );
+	  lp->stats.rx_packets++;
+#ifdef LINUX_2_1
+	  lp->stats.rx_bytes += skb->len;
 #endif
-        }
-      hp100_outw( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+      
+#ifdef HP100_DEBUG_RX
+	  printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		  ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
+		  ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
+#endif
+	}
+  
+      /* Indicate the card that we have got the packet */
+      hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+
       switch ( header & 0x00070000 ) {
-        case (HP100_MULTI_ADDR_HASH<<16):
-        case (HP100_MULTI_ADDR_NO_HASH<<16):
-          lp -> stats.multicast++; break;
+      case (HP100_MULTI_ADDR_HASH<<16):
+      case (HP100_MULTI_ADDR_NO_HASH<<16):
+	lp->stats.multicast++; break;
       }
-    }
+    } /* end of while(there are packets) loop */
 #ifdef HP100_DEBUG_RX
-   printk( "hp100_rx: end\n" );
+  printk( "hp100_rx: end\n" );
+#endif
+}
+
+
+/* 
+ * Receive Function for Busmaster Mode
+ */
+static void hp100_rx_bm( struct device *dev )
+{
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  hp100_ring_t *ptr;
+  u_int header;
+  int pkt_len;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4214, TRACE );
+  printk("hp100: rx_bm\n");
+#endif
+
+#ifdef HP100_DEBUG
+  if(0==lp->rxrcommit)
+    {
+      printk("hp100: rx_bm called although no PDLs were committed to adapter?\n"); 
+      return;
+    }
+  else
+
+    /* RX_PKT_CNT states how many PDLs are currently formatted and available to 
+     * the cards BM engine */
+    if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit)
+      {
+	printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit);
+	return;
+      }
+#endif
+
+  while( (lp->rxrcommit > hp100_inb(RX_PDL)) )
+    {
+      /*
+       * The packet was received into the pdl pointed to by lp->rxrhead (
+       * the oldest pdl in the ring 
+       */
+						
+      /* First we get the header, which contains information about the */
+      /* actual length of the received packet. */
+      
+      ptr=lp->rxrhead;
+      
+      header = *(ptr->pdl-1);
+      pkt_len = (header & HP100_PKT_LEN_MASK);
+
+#ifdef HP100_DEBUG_BM
+      printk( "hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
+              (u_int) (ptr->pdl-1),(u_int) header,
+              pkt_len, 
+              (header>>16)&0xfff8,
+              (header>>16)&7);
+      printk( "hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n",
+	      hp100_inb( RX_PDL ),
+	      hp100_inb( TX_PDL ),
+	      hp100_inb( RX_PKT_CNT ),
+	      (u_int) *(ptr->pdl),
+	      (u_int) *(ptr->pdl+3),
+	      (u_int) *(ptr->pdl+4));
+#endif
+      
+      if( (pkt_len>=MIN_ETHER_SIZE) &&
+          (pkt_len<=MAX_ETHER_SIZE) )  
+        {
+	  if(ptr->skb==NULL)
+	    {
+	      printk("hp100: rx_bm: skb null\n");
+	      /* can happen if we only allocated room for the pdh due to memory shortage. */
+	      lp->stats.rx_dropped++;
+	    }
+	  else
+	    {
+	      skb_trim( ptr->skb, pkt_len );     /* Shorten it */
+	      ptr->skb->protocol = eth_type_trans( ptr->skb, dev );
+														
+	      netif_rx( ptr->skb );              /* Up and away... */
+
+	      lp->stats.rx_packets++;
+#ifdef LINUX_2_1
+	      lp->stats.rx_bytes += ptr->skb->len;
+#endif
+	    }
+
+          switch ( header & 0x00070000 ) {
+          case (HP100_MULTI_ADDR_HASH<<16):
+          case (HP100_MULTI_ADDR_NO_HASH<<16):
+            lp->stats.multicast++; break;
+          }
+        }
+      else
+        {
+#ifdef HP100_DEBUG
+          printk("hp100: rx_bm: Received bad packet (length=%d)\n",pkt_len);
 #endif
+	  if(ptr->skb!=NULL)
+	    dev_kfree_skb( ptr->skb, FREE_READ );					
+          lp->stats.rx_errors++;
+        }
+						
+      lp->rxrhead=lp->rxrhead->next;
+
+      /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */
+      if (0 == hp100_build_rx_pdl( lp->rxrtail, dev ))
+        {
+	  /* No space for skb, header can still be received. */
+#ifdef HP100_DEBUG
+          printk("hp100: rx_bm: No space for new PDL.\n");
+#endif
+	  return;
+        } 
+      else
+        { /* successfully allocated new PDL - put it in ringlist at tail. */
+	  hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA);
+          lp->rxrtail=lp->rxrtail->next;
+	}
+						
+    }
 }
 
+
+
 /*
  *  statistics
  */
-
-static struct net_device_stats *hp100_get_stats( struct device *dev )
+static hp100_stats_t *hp100_get_stats( struct device *dev )
 {
-  int ioaddr = dev -> base_addr;
+  int ioaddr = dev->base_addr;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4215, TRACE );
+#endif
 
   hp100_ints_off();
   hp100_update_stats( dev );
   hp100_ints_on();
-  return &((struct hp100_private *)dev -> priv) -> stats;
+  return &((struct hp100_private *)dev->priv)->stats;
 }
 
 static void hp100_update_stats( struct device *dev )
 {
-  int ioaddr = dev -> base_addr;
+  int ioaddr = dev->base_addr;
   u_short val;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4216, TRACE );
+  printk("hp100: update-stats\n");
+#endif
 
-  hp100_page( MAC_CTRL );		/* get all statistics bytes */
+  /* Note: Statistics counters clear when read. */
+  hp100_page( MAC_CTRL ); 
   val = hp100_inw( DROPPED ) & 0x0fff;
-  lp -> stats.rx_errors += val;
-  lp -> stats.rx_over_errors += val;
+  lp->stats.rx_errors += val;
+  lp->stats.rx_over_errors += val;
   val = hp100_inb( CRC );
-  lp -> stats.rx_errors += val;
-  lp -> stats.rx_crc_errors += val;
+  lp->stats.rx_errors += val;
+  lp->stats.rx_crc_errors += val;
   val = hp100_inb( ABORT );
-  lp -> stats.tx_errors += val;
-  lp -> stats.tx_aborted_errors += val;
+  lp->stats.tx_errors += val;
+  lp->stats.tx_aborted_errors += val;
   hp100_page( PERFORMANCE );
 }
 
 static void hp100_clear_stats( int ioaddr )
 {
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4217, TRACE );
+  printk("hp100: clear_stats\n");
+#endif
+
   cli();
-  hp100_page( MAC_CTRL );		/* get all statistics bytes */
+  hp100_page( MAC_CTRL );    /* get all statistics bytes */
   hp100_inw( DROPPED );
   hp100_inb( CRC );
   hp100_inb( ABORT );
@@ -831,54 +2031,73 @@
   sti();
 }
 
+
 /*
  *  multicast setup
  */
 
 /*
  *  Set or clear the multicast filter for this adapter.
+ *  TODO: Currently when in multicast mode, card accepts all multicast packets
+ *        for all MC addresses. Should better use the list on the card.
  */
-
+                                                          
 static void hp100_set_multicast_list( struct device *dev)
 {
-  int ioaddr = dev -> base_addr;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
 
-#ifdef HP100_DEBUG_MULTI
-  printk( "hp100_set_multicast_list: num_addrs = %d\n", dev->mc_count);
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4218, TRACE );
+  printk("hp100: set_mc_list\n");
 #endif
+
   cli();
   hp100_ints_off();
   hp100_page( MAC_CTRL );
-  hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );	/* stop rx/tx */
+  hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );  /* stop rx/tx */
 
-  if ( dev->flags&IFF_PROMISC)
+  if ( dev->flags & IFF_PROMISC )
     {
-      lp -> mac2_mode = HP100_MAC2MODE6;  /* promiscuous mode, all good */
-      lp -> mac1_mode = HP100_MAC1MODE6;  /* packets on the net */
+      lp->mac2_mode = HP100_MAC2MODE6;  /* promiscuous mode = get all good */
+      lp->mac1_mode = HP100_MAC1MODE6;  /* packets on the net */
     }
-   else
-  if ( dev->mc_count || dev->flags&IFF_ALLMULTI )
+  else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) )
     {
-      lp -> mac2_mode = HP100_MAC2MODE5;  /* multicast mode, packets for me */
-      lp -> mac1_mode = HP100_MAC1MODE5;  /* broadcasts and all multicasts */
+      lp->mac2_mode = HP100_MAC2MODE5;  /* multicast mode = get packets for */
+      lp->mac1_mode = HP100_MAC1MODE5;  /* me, broadcasts and all multicasts */
     }
-   else
+  else
     {
-      lp -> mac2_mode = HP100_MAC2MODE3;  /* normal mode, packets for me */
-      lp -> mac1_mode = HP100_MAC1MODE3;  /* and broadcasts */
+      lp->mac2_mode = HP100_MAC2MODE3;  /* normal mode = get packets for me */
+      lp->mac1_mode = HP100_MAC1MODE3;  /* and broadcasts */
     }
 
-  hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
-  hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
-  hp100_orb( lp -> mac1_mode |
-  	     HP100_RX_EN | HP100_RX_IDLE |		/* enable rx */
-  	     HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );	/* enable tx */
+  if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) ||
+        ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) {
+    hp100_outb( lp->mac2_mode, MAC_CFG_2 );
+    hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */
+    hp100_orb( lp->mac1_mode, MAC_CFG_1 );       /* and set the new mode */
+
+    if(lp->lan_type==HP100_LAN_100)
+      {
+#ifdef HP100_DEBUG
+	printk("hp100: 100VG MAC settings have changed - relogin.\n");
+#endif
+	lp->hub_status=hp100_login_to_vg_hub( dev, TRUE );  /* force a relogin to the hub */
+      }
+  }
+
+  hp100_page( MAC_CTRL );
+  hp100_orb( HP100_RX_EN | HP100_RX_IDLE |              /* enable rx */
+	     HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );  /* enable tx */
+
   hp100_page( PERFORMANCE );
   hp100_ints_on();
   sti();
 }
 
+
 /*
  *  hardware interrupt handling
  */
@@ -886,249 +2105,747 @@
 static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs )
 {
   struct device *dev = (struct device *)irq2dev_map[ irq ];
-  struct hp100_private *lp;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
   int ioaddr;
-  u_short val;
+  u_int val;
 
   if ( dev == NULL ) return;
-  ioaddr = dev -> base_addr;
-  if ( dev -> interrupt )
-    printk( "%s: re-entering the interrupt handler\n", dev -> name );
+  ioaddr = dev->base_addr;
+
+  if ( dev->interrupt )
+    printk( "%s: re-entering the interrupt handler\n", dev->name );
   hp100_ints_off();
-  dev -> interrupt = 1;
-  hp100_page( PERFORMANCE );
+  dev->interrupt = 1;          /* mark that we are inside the handler */
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4219, TRACE );
+#endif
+
+  /*  hp100_page( PERFORMANCE ); */
   val = hp100_inw( IRQ_STATUS );
 #ifdef HP100_DEBUG_IRQ
-  printk( "hp100_interrupt: irq_status = 0x%x\n", val );
+  printk( "hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n",
+          lp->mode,
+	  (u_int)val,
+          hp100_inb( RX_PKT_CNT ),
+          hp100_inb( RX_PDL ),
+	  hp100_inb( TX_PKT_CNT ),
+	  hp100_inb( TX_PDL )
+	  );
 #endif
-  if ( val & HP100_RX_PACKET )
-    {
-      hp100_rx( dev );
-      hp100_outw( HP100_RX_PACKET, IRQ_STATUS );
-    }
-  if ( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE) )
+
+  if(val==0) /* might be a shared interrupt */ 
     {
-      hp100_outw( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE), IRQ_STATUS );
+      dev->interrupt=0;
+      hp100_ints_on();
+      return;
     }
+  /* We're only interested in those interrupts we really enabled. */
+  /* val &= hp100_inw( IRQ_MASK ); */
+
+  /* 
+   * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL 
+   * is considered executed whenever the RX_PDL data structure is no longer 
+   * needed.
+   */
+  if ( val & HP100_RX_PDL_FILL_COMPL )
+    {
+      if(lp->mode==1)
+	hp100_rx_bm( dev );
+      else
+	printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n");
+    }
+		
+  /* 
+   * The RX_PACKET interrupt is set, when the receive packet counter is
+   * non zero. We use this interrupt for receiving in slave mode. In
+   * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
+   * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then
+   * we somehow have missed a rx_pdl_fill_compl interrupt.
+   */
+
+  if ( val & HP100_RX_PACKET  ) /* Receive Packet Counter is non zero */
+    {
+      if(lp->mode!=1) /* non busmaster */
+        hp100_rx( dev );
+      else if ( !(val & HP100_RX_PDL_FILL_COMPL ))
+	{
+	  /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt?  */
+	  hp100_rx_bm( dev );
+	}
+    }
+
+  /*
+   * Ack. that we have noticed the interrupt and thereby allow next one.
+   * Note that this is now done after the slave rx function, since first
+   * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt
+   * on the J2573.
+   */
+  hp100_outw( val, IRQ_STATUS );
+
+  /*
+   * RX_ERROR is set when a packet is dropped due to no memory resources on 
+   * the card or when a RCV_ERR occurs. 
+   * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists  
+   * only in the 802.3 MAC and happens when 16 collisions occur during a TX 
+   */
   if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
     {
-      lp = (struct hp100_private *)dev -> priv;
-      hp100_update_stats( dev );
-      hp100_outw( val & (HP100_TX_ERROR | HP100_RX_ERROR), IRQ_STATUS );
-    }
 #ifdef HP100_DEBUG_IRQ
-  printk( "hp100_interrupt: end\n" );
+      printk("hp100: TX/RX Error IRQ\n");
 #endif
-  dev -> interrupt = 0;
+      hp100_update_stats( dev );
+      if(lp->mode==1)
+	{
+	  hp100_rxfill( dev );
+	  hp100_clean_txring( dev );
+	}
+    }
+				
+  /* 
+   * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. 
+   */
+  if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) )
+    hp100_rxfill( dev );
+		
+  /* 
+   * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire 
+   * is completed 
+   */
+  if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) )
+    hp100_clean_txring( dev );
+
+  /* 
+   * MISC_ERROR is set when either the LAN link goes down or a detected
+   * bus error occurs.
+   */
+  if ( val & HP100_MISC_ERROR ) /* New for J2585B */
+    {
+      printk("hp100: Misc. Error Interrupt - Check cabling.\n");
+      if(lp->mode==1)
+	{
+	  hp100_clean_txring( dev );
+	  hp100_rxfill( dev );
+	}
+    }
+	
+  dev->interrupt = 0;
   hp100_ints_on();
 }
 
+
 /*
  *  some misc functions
  */
 
 static void hp100_start_interface( struct device *dev )
 {
-  int ioaddr = dev -> base_addr;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4220, TRACE );
+  printk("hp100: hp100_start_interface %s\n",dev->name);
+#endif
 
   cli();
-  hp100_unreset_card();
-  hp100_page( MAC_CTRL );
-  hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
-  hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
-  hp100_orb( lp -> mac1_mode |
-             HP100_RX_EN | HP100_RX_IDLE |
-             HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );
+
+  /* Ensure the adapter does not want to request an interrupt when */
+  /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */
   hp100_page( PERFORMANCE );
-  hp100_outw( HP100_INT_EN | HP100_SET_LB, OPTION_LSW );
-  hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
-  if ( lp -> mem_mapped )
+  hp100_outw( 0xfefe, IRQ_MASK );  /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS );  /* ack all IRQs */
+  hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW);
+  /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */
+  hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW ); 
+
+  if(lp->mode==1)
+    {
+      /* Make sure BM bit is set... */
+      hp100_page(HW_MAP);
+      hp100_orb( HP100_BM_MASTER, BM );
+      hp100_rxfill( dev );
+    }
+  else if(lp->mode==2)
     {
-      /* enable memory mapping */
+      /* Enable memory mapping. Note: Don't do this when busmaster. */
       hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
     }
-  sti();
+
+  hp100_page(PERFORMANCE);
+  hp100_outw( 0xfefe, IRQ_MASK );  /* mask off all ints */
+  hp100_outw( 0xffff, IRQ_STATUS );  /* ack IRQ */
+
+  /* enable a few interrupts: */
+  if(lp->mode==1) /* busmaster mode */
+    {
+      hp100_outw( HP100_RX_PDL_FILL_COMPL |
+		  HP100_RX_PDA_ZERO  |  
+		  HP100_RX_ERROR     |  
+		  /* HP100_RX_PACKET    | */    
+		  /* HP100_RX_EARLY_INT |  */     HP100_SET_HB  |  
+		  /* HP100_TX_PDA_ZERO  |  */
+		  HP100_TX_COMPLETE  |  
+		  /* HP100_MISC_ERROR   |  */
+		  HP100_TX_ERROR     | HP100_SET_LB, IRQ_MASK );
+    } 
+  else
+    {  
+      hp100_outw( HP100_RX_PACKET  |
+		  HP100_RX_ERROR   | HP100_SET_HB |
+                  HP100_TX_ERROR   | HP100_SET_LB , IRQ_MASK );
+    }
+	
+  /* Enable MAC Tx and RX, set MAC modes, ... */
+  /* Note: This function also turns on the interrupts. */
+  hp100_set_multicast_list( dev );
 }
 
+
 static void hp100_stop_interface( struct device *dev )
 {
-  int ioaddr = dev -> base_addr;
-  u_short val;
-
-  hp100_outw( HP100_INT_EN | HP100_RESET_LB |
-              HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
-  val = hp100_inw( OPTION_LSW );
-  hp100_page( HW_MAP );
-  hp100_andb( HP100_BM_SLAVE, BM );
-  hp100_page( MAC_CTRL );
-  hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
-  if ( !(val & HP100_HW_RST) ) return;
-  for ( val = 0; val < 6000; val++ )
-    if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
-                                    (HP100_TX_IDLE | HP100_RX_IDLE) )
-      return;
-  printk( "%s: hp100_stop_interface - timeout\n", dev -> name );
+  struct hp100_private *lp = (struct hp100_private *)dev->priv; 
+  int ioaddr = dev->base_addr;
+  u_int val;
+
+#ifdef HP100_DEBUG_B
+  printk("hp100: hp100_stop_interface %s\n",dev->name);
+  hp100_outw( 0x4221, TRACE );
+#endif
+
+  if (lp->mode==1) 
+    hp100_BM_shutdown( dev );
+  else
+    {
+      /* Note: MMAP_DIS will be reenabled by start_interface */
+      hp100_outw( HP100_INT_EN | HP100_RESET_LB | 
+                  HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+      val = hp100_inw( OPTION_LSW );
+   
+      hp100_page( MAC_CTRL );
+      hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
+
+      if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */
+      /* ... else: busy wait until idle */
+      for ( val = 0; val < 6000; val++ )
+	if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
+	     (HP100_TX_IDLE | HP100_RX_IDLE) )
+	  {
+	    hp100_page(PERFORMANCE);
+	    return;
+	  }
+      printk( "%s: hp100_stop_interface - timeout\n", dev->name );
+      hp100_page(PERFORMANCE);
+    }
 }
 
+
 static void hp100_load_eeprom( struct device *dev )
 {
   int i;
-  int ioaddr = dev -> base_addr;
+  int ioaddr = dev->base_addr;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4222, TRACE );
+#endif
 
   hp100_page( EEPROM_CTRL );
   hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL );
   hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL );
-  for ( i = 0; i < 6000; i++ )
-    if ( !( hp100_inw( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
-  printk( "%s: hp100_load_eeprom - timeout\n", dev -> name );
+  for ( i = 0; i < 10000; i++ )
+    if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
+  printk( "%s: hp100_load_eeprom - timeout\n", dev->name );
 }
 
-/* return values: LAN_10, LAN_100 or LAN_ERR (not connected or hub is down)... */
-
+
+/*  Sense connection status.
+ *  return values: LAN_10  - Connected to 10Mbit/s network
+ *                 LAN_100 - Connected to 100Mbit/s network
+ *                 LAN_ERR - not connected or 100Mbit/s Hub down
+ */
 static int hp100_sense_lan( struct device *dev )
 {
-  int i;
-  int ioaddr = dev -> base_addr;
+  int ioaddr = dev->base_addr;
   u_short val_VG, val_10;
-  struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4223, TRACE );
+#endif
 
   hp100_page( MAC_CTRL );
-  hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
-  val_10 = hp100_inw( LAN_CFG_10 );
-  val_VG = hp100_inw( LAN_CFG_VG );
-#ifdef HP100_DEBUG_SENSE
+  /* Enable Auto Selection */
+  /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */
+  /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */
+  /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */
+  /* Now we have to wait a while... */
+  /* for(i=0; i<5000; i++) */
+  /* { */
+  val_10 = hp100_inb( 10_LAN_CFG_1 );
+  val_VG = hp100_inb( VG_LAN_CFG_1 );
+  /* } */
+#ifdef HP100_DEBUG
   printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 );
 #endif
   if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10;
-  if ( lp -> id -> id == 0x02019F022 ) /* HP J27248B doesn't have 100Mb/s interface */
-    return HP100_LAN_ERR;
-  for ( i = 0; i < 2500; i++ )
-    {
-      val_VG = hp100_inw( LAN_CFG_VG );
-      if ( val_VG & HP100_LINK_CABLE_ST ) return HP100_LAN_100;
-    }
+  if ( (lp->id->id == 0x02019F022) || 
+       (lp->id->id == 0x01042103c) ||
+       (lp->id->id == 0x01040103c) )
+    { 
+      hp100_page(PERFORMANCE);
+      return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */
+    }
+  /* for ( i = 0; i < 2500; i++ ) */
+  /*     { */
+  val_VG = hp100_inb( VG_LAN_CFG_1 );
+  hp100_page(PERFORMANCE);
+
+  if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */ 
+    return HP100_LAN_100;
+  /*   } */
   return HP100_LAN_ERR;
 }
 
+
+
 static int hp100_down_vg_link( struct device *dev )
 {
-  int ioaddr = dev -> base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  int ioaddr = dev->base_addr;
   unsigned long time;
-  int i;
+  long savelan, newlan;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4224, TRACE );
+  printk("hp100: down_vg_link\n");
+#endif
 
   hp100_page( MAC_CTRL );
-  for ( i = 2500; i > 0; i-- )
-    if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
-  if ( i <= 0 )				/* not signal - not logout */
+  time=jiffies+(HZ/4);
+  do{
+    if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+  } while (time>jiffies);
+
+  if ( jiffies >= time )       /* no signal->no logout */
     return 0;
-  hp100_andw( ~HP100_LINK_CMD, LAN_CFG_VG );
-  time = jiffies + 10*HZ/100;
-  while ( time > jiffies )
-    if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST |
-                                        HP100_LINK_CABLE_ST |
-                                        HP100_LINK_GOOD_ST ) ) )
-      return 0;
+
+  /* Drop the VG Link by clearing the link up cmd and load addr.*/
+
+  hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1); 
+  hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1); 
+
+  /* Conditionally stall for >250ms on Link-Up Status (to go down) */
+  time=jiffies+(HZ/2);
+  do{
+    if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break;
+  } while(time>jiffies);
+
 #ifdef HP100_DEBUG
-  printk( "hp100_down_vg_link: timeout\n" );
+  if (jiffies>=time)
+    printk("hp100_down_vg_link: Link does not go down?\n");
 #endif
-  return -EIO;
-}
 
-static int hp100_login_to_vg_hub( struct device *dev )
-{
-  int i;
-  int ioaddr = dev -> base_addr;
-  u_short val;
-  unsigned long time;
+  /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */
+  /* logout under traffic (even though all the status bits are cleared),  */
+  /* do this workaround to get the Rev 1 MAC in its idle state */
+  if ( lp->chip==HP100_CHIPID_LASSEN )
+    {
+      /* Reset VG MAC to insure it leaves the logoff state even if */
+      /* the Hub is still emitting tones */
+      hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1);
+      udelay(1500); /* wait for >1ms */
+      hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */
+      udelay(1500);
+    }
+
+  /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */
+  /* to get the VG mac to full reset. This is not req.d with later chips */
+  /* Note: It will take the between 1 and 2 seconds for the VG mac to be */
+  /* selected again! This will be left to the connect hub function to */
+  /* perform if desired.  */
+  if (lp->chip==HP100_CHIPID_LASSEN)
+    {
+      /* Have to write to 10 and 100VG control registers simultaneously */
+      savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */
+      newlan &= ~(HP100_VG_SEL<<16);
+      newlan |= (HP100_DOT3_MAC)<<8;
+      hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */
+      hp100_outl(newlan, 10_LAN_CFG_1);
+
+      /* Conditionally stall for 5sec on VG selected. */
+      time=jiffies+(HZ*5);
+      do{
+        if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break;
+      } while(time>jiffies);
 
-  hp100_page( MAC_CTRL );
-  hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
-  time = jiffies + ( HZ / 2 );
+      hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
+      hp100_outl(savelan, 10_LAN_CFG_1);
+    }
+
+  time=jiffies+(3*HZ); /* Timeout 3s */
   do {
-    if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
-  } while ( time > jiffies );
-  if ( time <= jiffies )
+    if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break;
+  } while (time>jiffies);
+  
+  if(time<=jiffies)
     {
 #ifdef HP100_DEBUG
-      printk( "hp100_login_to_vg_hub: timeout for link\n" );
+      printk( "hp100_down_vg_link: timeout\n" );
 #endif
       return -EIO;
     }
+  
+  time=jiffies+(2*HZ); /* This seems to take a while.... */
+  do {} while (time>jiffies);
+  
+  return 0;
+}
 
-  if ( hp100_down_vg_link( dev ) < 0 )	/* if fail, try reset VG link */
-    {
-      hp100_andw( ~HP100_VG_RESET, LAN_CFG_VG );
-      hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
-    }
-  /* bring up link */
-  hp100_orw( HP100_LOAD_ADDR | HP100_LINK_CMD, LAN_CFG_VG );
-  for ( i = 2500; i > 0; i-- )
-    if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
-  if ( i <= 0 )
+
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
+{
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  u_short val=0;
+  unsigned long time;
+  int startst;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4225, TRACE );
+  printk("hp100: login_to_vg_hub\n");
+#endif
+
+  /* Initiate a login sequence iff VG MAC is enabled and either Load Address
+   * bit is zero or the force relogin flag is set (e.g. due to MAC address or
+   * promiscuous mode change)
+   */
+  hp100_page( MAC_CTRL );
+  startst=hp100_inb( VG_LAN_CFG_1 );
+  if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST))
     {
-#ifdef HP100_DEBUG
-      printk( "hp100_login_to_vg_hub: timeout for link (bring up)\n" );
+#ifdef HP100_DEBUG_TRAINING
+      printk("hp100: Start training\n");
 #endif
-      goto down_link;
-    }
 
-  time = jiffies + ( HZ / 2 );
-  do {
-    val = hp100_inw( LAN_CFG_VG );
-    if ( ( val & ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) ==
-                 ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) )
-      return 0;	/* success */
-  } while ( time > jiffies );
-  if ( val & HP100_LINK_GOOD_ST )
-    printk( "%s: 100Mb cable training failed, check cable.\n", dev -> name );
-   else
-    printk( "%s: 100Mb node not accepted by hub, check frame type or security.\n", dev -> name );
+      /* Ensure VG Reset bit is 1 (i.e., do not reset)*/
+      hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 );
+
+      /* If Lassen AND auto-select-mode AND VG tones were sensed on */
+      /* entry then temporarily put them into force 100Mbit mode */
+      if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) )
+        hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 );
+						
+      /* Drop the VG link by zeroing Link Up Command and Load Address  */
+      hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1);
+
+#ifdef HP100_DEBUG_TRAINING
+      printk("hp100: Bring down the link\n");
+#endif
+
+      /* Wait for link to drop */
+      time = jiffies + (HZ/10); 
+      do {
+        if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break;
+      } while (time>jiffies);
+
+      /* Start an addressed training and optionally request promiscuous port */
+      if ( (dev->flags) & IFF_PROMISC )
+	{
+	  hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2);
+	  if(lp->chip==HP100_CHIPID_LASSEN)
+	    hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+	}
+      else
+	{
+	  hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2);
+	  /* For ETR parts we need to reset the prom. bit in the training
+	   * register, otherwise promiscious mode won't be disabled.
+	   */
+	  if(lp->chip==HP100_CHIPID_LASSEN)
+	    {
+	      hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+	    }
+	}
+
+      /* With ETR parts, frame format request bits can be set. */
+      if(lp->chip==HP100_CHIPID_LASSEN)
+        hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST);
+
+      hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1);
+
+      /* Note: Next wait could be omitted for Hood and earlier chips under */
+      /* certain circumstances */
+      /* TODO: check if hood/earlier and skip wait. */
+
+      /* Wait for either short timeout for VG tones or long for login    */
+      /* Wait for the card hardware to signalise link cable status ok... */
+      hp100_page( MAC_CTRL );
+      time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */
+      do {
+        if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+      } while ( jiffies < time );
+      
+      if ( jiffies >= time )
+	{
+#ifdef HP100_DEBUG_TRAINING
+	  printk( "hp100: Link cable status not ok? Training aborted.\n" );
+#endif  
+	}
+      else
+	{
+#ifdef HP100_DEBUG_TRAINING
+	  printk( "hp100: HUB tones detected. Trying to train.\n");
+#endif
+
+	  time = jiffies + ( 2*HZ ); /* again a timeout */
+	  do {
+	    val = hp100_inb( VG_LAN_CFG_1 );
+	    if ( (val & ( HP100_LINK_UP_ST )) )
+	      {
+#ifdef HP100_DEBUG_TRAINING
+		printk( "hp100: Passed training.\n");
+#endif
+		break;
+	      }
+	  } while ( time > jiffies );
+	}
+      
+      /* If LINK_UP_ST is set, then we are logged into the hub. */
+      if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) )
+        {
+#ifdef HP100_DEBUG_TRAINING
+          printk( "hp100: Successfully logged into the HUB.\n");
+          if(lp->chip==HP100_CHIPID_LASSEN)
+            {
+	      val = hp100_inw(TRAIN_ALLOW);
+              printk( "hp100: Card supports 100VG MAC Version \"%s\" ",
+                      (hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre");
+	      printk( "Driver will use MAC Version \"%s\"\n",
+                      ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" ); 
+              printk( "hp100: Frame format is %s.\n",(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3");
+            }
+#endif
+        }
+      else
+        {
+          /* If LINK_UP_ST is not set, login was not successful */
+          printk("hp100/%s: Problem logging into the HUB.\n",dev->name);
+          if(lp->chip==HP100_CHIPID_LASSEN)
+            {
+              /* Check allowed Register to find out why there is a problem. */
+              val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */
+#ifdef HP100_DEBUG_TRAINING
+              printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val);
+#endif
+              if ( val & HP100_MALLOW_ACCDENIED )
+                printk("hp100: HUB access denied.\n");
+              if ( val & HP100_MALLOW_CONFIGURE )
+                printk("hp100: MAC Configuration is incompatible with the Network.\n");
+              if ( val & HP100_MALLOW_DUPADDR )
+                printk("hp100: Duplicate MAC Address on the Network.\n");
+            }
+        }
+      
+      /* If we have put the chip into forced 100 Mbit mode earlier, go back */
+      /* to auto-select mode */
+      
+      if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) )
+        {
+          hp100_page( MAC_CTRL );
+          hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 );
+        }
+     
+      val=hp100_inb(VG_LAN_CFG_1);
 
-down_link:
-  hp100_down_vg_link( dev );
-  hp100_page( MAC_CTRL );
-  hp100_andw( ~( HP100_LOAD_ADDR | HP100_PROM_MODE ), LAN_CFG_VG );
-  hp100_orw( HP100_LINK_CMD, LAN_CFG_VG );
+      /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */
+      hp100_page(PERFORMANCE);
+      hp100_outw( HP100_MISC_ERROR, IRQ_STATUS);
+					
+      if (val&HP100_LINK_UP_ST)
+        return(0); /* login was ok */
+      else
+        {
+          printk("hp100: Training failed.\n");
+          hp100_down_vg_link( dev );
+          return -EIO;
+        }
+    }
+  /* no forced relogin & already link there->no training. */
   return -EIO;
 }
 
+
+static void hp100_cascade_reset( struct device *dev, u_short enable )
+{
+  int ioaddr = dev->base_addr;
+  struct hp100_private *lp = (struct hp100_private *)dev->priv;
+  int i;
+
+#ifdef HP100_DEBUG_B
+  hp100_outw( 0x4226, TRACE );
+  printk("hp100: cascade_reset\n");
+#endif
+
+  if (enable==TRUE) 
+    {
+      hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW );
+      if(lp->chip==HP100_CHIPID_LASSEN)
+	{
+	  /* Lassen requires a PCI transmit fifo reset */
+	  hp100_page( HW_MAP );
+	  hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+	  hp100_orb( HP100_PCI_RESET, PCICTRL2 );
+	  /* Wait for min. 300 ns */
+	  /* we cant use jiffies here, because it may be */
+	  /* that we have disabled the timer... */
+	  for (i=0; i<0xffff; i++);
+	  hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+	  hp100_page( PERFORMANCE );
+	}	
+    }
+  else
+    { /* bring out of reset */
+      hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW);
+      for (i=0; i<0xffff; i++ );
+      hp100_page(PERFORMANCE);
+    }
+}
+
+#ifdef HP100_DEBUG		
+void hp100_RegisterDump( struct device *dev )
+{
+  int ioaddr=dev->base_addr;
+  int Page;
+  int Register;
+
+  /* Dump common registers */
+  printk("hp100: Cascade Register Dump\n");
+  printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID));
+  printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING));
+  printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW));
+  printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW));
+
+  /* Dump paged registers */
+  for (Page = 0; Page < 8; Page++) 
+    {
+      /* Dump registers */
+      printk("page: 0x%.2x\n",Page);
+      outw( Page, ioaddr+0x02);
+      for (Register = 0x8; Register < 0x22; Register += 2)
+	{
+	  /* Display Register contents except data port */
+	  if (((Register != 0x10) && (Register != 0x12)) || (Page > 0))
+	    {
+	      printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register));
+	    }
+	}
+    }
+  hp100_page(PERFORMANCE);
+}
+#endif
+
+
+
 /*
  *  module section
  */
-
+ 
 #ifdef MODULE
 
-static int hp100_port = -1;
-MODULE_PARM(hp100_port, "i");
+/* Parameters set by insmod */
+int hp100_port[5] = { 0, -1, -1, -1, -1 };
+#ifdef LINUX_2_1
+MODULE_PARM(hp100_port, "1-5i");
+#endif
 
-static char devicename[9] = { 0, };
-static struct device dev_hp100 = {
-	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-	0, 0, 0, 0,
-	0, 0,
-	0, 0, 0, NULL, hp100_probe
-};
+#ifdef LINUX_2_1
+char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
+MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ));
+#else
+static char devname[5][IFNAMSIZ] = { "", "", "", "", "" };
+static char *hp100_name[5] = { devname[0], devname[1],
+                               devname[2], devname[3],
+                               devname[4] };
+#endif
+
+/* List of devices */
+static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL };
+
+/*
+ * Note: if you have more than five 100vg cards in your pc, feel free to
+ * increase this value 
+ */
+
+/*
+ * Note: to register three eisa or pci devices, use:
+ * option hp100 hp100_port=0,0,0
+ *        to register one card at io 0x280 as eth239, use:
+ * option hp100 hp100_port=0x280 hp100_name=eth239
+ */
 
 int init_module( void )
 {
-  if (hp100_port == 0 && !EISA_bus)
+  int	i;
+  int	ret = 0;
+
+  if (hp100_port == 0 && !EISA_bus && !pcibios_present())
     printk("HP100: You should not use auto-probing with insmod!\n");
-  if ( hp100_port > 0 )
-    dev_hp100.base_addr = hp100_port;
-  if ( register_netdev( &dev_hp100 ) != 0 )
-    return -EIO;
-  return 0;
+
+  /* Loop on all possible base addresses */
+  i = -1;
+  while((hp100_port[++i] != -1) && (i < 5))
+    {
+      /* Create device and set basics args */
+      hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL);
+      memset(hp100_devlist[i], 0x00, sizeof(struct device));
+      hp100_devlist[i]->name = hp100_name[i];
+      hp100_devlist[i]->base_addr = hp100_port[i];
+      hp100_devlist[i]->init = &hp100_probe;
+
+      /* Try to create the device */
+      if(register_netdev(hp100_devlist[i]) != 0)
+	{
+	  /* DeAllocate everything */
+	  /* Note: if dev->priv is mallocated, there is no way to fail */
+	  kfree_s(hp100_devlist[i], sizeof(struct device));
+	  hp100_devlist[i] = (struct device *) NULL;
+	  ret = -EIO;
+	}
+    }			/* Loop over all devices */
+
+  return ret;
 }
 
 void cleanup_module( void )
 {
-  unregister_netdev( &dev_hp100 );
-  release_region( dev_hp100.base_addr, HP100_REGION_SIZE );
-  if ( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt )
-    iounmap( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt );
-  kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
-  dev_hp100.priv = NULL;
+  int		i;
+
+  /* TODO: Check if all skb's are released/freed. */
+  for(i = 0; i < 5; i++)
+    if(hp100_devlist[i] != (struct device *) NULL)
+      {
+	unregister_netdev( hp100_devlist[i] );
+	release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE );
+	if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */
+	  kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f); 
+	if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt )
+	  iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt );
+	kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) );
+	hp100_devlist[i]->priv = NULL;
+	kfree_s(hp100_devlist[i], sizeof(struct device));
+	hp100_devlist[i] = (struct device *) NULL;
+      }
 }
 
-#endif
+#endif		/* MODULE */
+
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c"
+ *  c-indent-level: 2
+ *  tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.39/linux/drivers/net/hp100.h linux/drivers/net/hp100.h
--- v2.1.39/linux/drivers/net/hp100.h	Mon May  6 02:26:08 1996
+++ linux/drivers/net/hp100.h	Mon May 19 12:49:29 1997
@@ -1,9 +1,10 @@
 /*
  * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
  *
- * Author:  Jaroslav Kysela, <perex@pf.jcu.cz>
+ * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $
  *
- * Header file...
+ * Authors:  Jaroslav Kysela, <perex@pf.jcu.cz>
+ *           Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de>
  *
  * This driver is based on the 'hpfepkt' crynwr packet driver.
  *
@@ -16,9 +17,10 @@
 /****************************************************************************
  *  Hardware Constants
  ****************************************************************************/
- 
-/*
- *  ATT2MD01 Register Page Constants
+
+/* 
+ * Page Identifiers
+ * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
  */
 
 #define HP100_PAGE_PERFORMANCE	0x0	/* Page 0 */
@@ -30,11 +32,8 @@
 #define HP100_PAGE_ID_MAC_ADDR	0x6	/* Page 6 */
 #define HP100_PAGE_MMU_POINTER	0x7	/* Page 7 */
 
-/*
- *  ATT2MD01 Register Addresses
- */
 
-/*  Present on all pages  */
+/* Registers that are present on all pages  */
 
 #define HP100_REG_HW_ID		0x00	/* R:  (16) Unique card ID           */
 #define HP100_REG_TRACE		0x00	/* W:  (16) Used for debug output    */
@@ -47,14 +46,29 @@
 
 #define HP100_REG_IRQ_STATUS	0x08	/* RW: (16) Which ints are pending   */
 #define HP100_REG_IRQ_MASK	0x0a	/* RW: (16) Select ints to allow     */
-#define HP100_REG_FRAGMENT_LEN	0x0c	/* RW: (16)12:0 Current fragment len */
+#define HP100_REG_FRAGMENT_LEN	0x0c	/* W: (16)12:0 Current fragment len */
+/* Note: For 32 bit systems, fragment len and offset registers are available */
+/*       at offset 0x28 and 0x2c, where they can be written as 32bit values. */
 #define HP100_REG_OFFSET	0x0e	/* RW: (16)12:0 Offset to start read */
 #define HP100_REG_DATA32	0x10	/* RW: (32) I/O mode data port       */
 #define HP100_REG_DATA16	0x12	/* RW: WORDs must be read from here  */
 #define HP100_REG_TX_MEM_FREE	0x14	/* RD: (32) Amount of free Tx mem    */
+#define HP100_REG_TX_PDA_L      0x14    /* W: (32) BM: Ptr to PDL, Low Pri  */
+#define HP100_REG_TX_PDA_H      0x1c    /* W: (32) BM: Ptr to PDL, High Pri */
 #define HP100_REG_RX_PKT_CNT	0x18	/* RD: (8) Rx count of pkts on card  */
 #define HP100_REG_TX_PKT_CNT	0x19	/* RD: (8) Tx count of pkts on card  */
-                                        
+#define HP100_REG_RX_PDL        0x1a    /* R: (8) BM: # rx pdl not executed */
+#define HP100_REG_TX_PDL        0x1b    /* R: (8) BM: # tx pdl not executed */
+#define HP100_REG_RX_PDA        0x18    /* W: (32) BM: Up to 31 addresses */
+                                        /*             which point to a PDL */
+#define HP100_REG_SL_EARLY      0x1c    /*    (32) Enhanced Slave Early Rx */
+#define HP100_REG_STAT_DROPPED  0x20    /* R (12) Dropped Packet Counter */
+#define HP100_REG_STAT_ERRORED  0x22    /* R (8) Errored Packet Counter */
+#define HP100_REG_STAT_ABORT    0x23    /* R (8) Abort Counter/OW Coll. Flag */
+#define HP100_REG_RX_RING       0x24    /* W (32) Slave: RX Ring Pointers */
+#define HP100_REG_32_FRAGMENT_LEN 0x28  /* W (13) Slave: Fragment Length Reg */
+#define HP100_REG_32_OFFSET     0x2c    /* W (16) Slave: Offset Register */
+
 /*  Page 1 - MAC Address/Hash Table  */
 
 #define HP100_REG_MAC_ADDR	0x08	/* RW: (8) Cards MAC address	     */
@@ -68,27 +82,46 @@
 #define HP100_REG_IRQ_CHANNEL	0x0d	/* RW: (8) IRQ and edge/level int    */
 #define HP100_REG_SRAM		0x0e	/* RW: (8) How much RAM on card      */
 #define HP100_REG_BM		0x0f	/* RW: (8) Controls BM functions     */
+
+/* New on Page 2 for ETR chips: */
+#define HP100_REG_MODECTRL1     0x10    /* RW: (8) Mode Control 1 */
+#define HP100_REG_MODECTRL2     0x11    /* RW: (8) Mode Control 2 */
+#define HP100_REG_PCICTRL1      0x12    /* RW: (8) PCI Cfg 1 */
+#define HP100_REG_PCICTRL2      0x13    /* RW: (8) PCI Cfg 2 */
+#define HP100_REG_PCIBUSMLAT    0x15    /* RW: (8) PCI Bus Master Latency */
+#define HP100_REG_EARLYTXCFG    0x16    /* RW: (16) Early TX Cfg/Cntrl Reg */
+#define HP100_REG_EARLYRXCFG    0x18    /* RW: (8) Early RX Cfg/Cntrl Reg */
+#define HP100_REG_ISAPNPCFG1    0x1a    /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */
+#define HP100_REG_ISAPNPCFG2    0x1b    /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */
                                         
 /*  Page 3 - EEPROM/Boot ROM  */
 
 #define HP100_REG_EEPROM_CTRL	0x08	/* RW: (16) Used to load EEPROM      */
+#define HP100_REG_BOOTROM_CTRL  0x0a
                                         
-/*  Page 4 - LAN Configuration  */
+/*  Page 4 - LAN Configuration  (MAC_CTRL) */
 
-#define HP100_REG_LAN_CFG_10	0x08	/* RW: (16) Set 10M XCVR functions   */
-#define HP100_REG_LAN_CFG_VG	0x0a	/* RW: (16) Set 100M XCVR functions  */
+#define HP100_REG_10_LAN_CFG_1	0x08	/* RW: (8) Set 10M XCVR functions   */
+#define HP100_REG_10_LAN_CFG_2  0x09    /* RW: (8)     10M XCVR functions   */
+#define HP100_REG_VG_LAN_CFG_1	0x0a	/* RW: (8) Set 100M XCVR functions  */
+#define HP100_REG_VG_LAN_CFG_2  0x0b    /* RW: (8) 100M LAN Training cfgregs */
 #define HP100_REG_MAC_CFG_1	0x0c	/* RW: (8) Types of pkts to accept   */
 #define HP100_REG_MAC_CFG_2	0x0d	/* RW: (8) Misc MAC functions        */
-/* The follow clear when read: */
+#define HP100_REG_MAC_CFG_3     0x0e    /* RW: (8) Misc MAC functions */
+#define HP100_REG_MAC_CFG_4     0x0f    /* R:  (8) Misc MAC states */
 #define HP100_REG_DROPPED	0x10	/* R:  (16),11:0 Pkts cant fit in mem*/
 #define HP100_REG_CRC		0x12	/* R:  (8) Pkts with CRC             */
 #define HP100_REG_ABORT		0x13	/* R:  (8) Aborted Tx pkts           */
-                                        
+#define HP100_REG_TRAIN_REQUEST 0x14    /* RW: (16) Endnode MAC register.*/
+#define HP100_REG_TRAIN_ALLOW   0x16    /* R:  (16) Hub allowed register */
+                    
 /*  Page 5 - MMU  */
 
 #define HP100_REG_RX_MEM_STOP	0x0c	/* RW: (16) End of Rx ring addr      */
 #define HP100_REG_TX_MEM_STOP	0x0e	/* RW: (16) End of Tx ring addr      */
-                                        
+#define HP100_REG_PDL_MEM_STOP  0x10    /* Not used by 802.12 devices */
+#define HP100_REG_ECB_MEM_STOP  0x14    /* I've no idea what this is */
+          
 /*  Page 6 - Card ID/Physical LAN Address  */
 
 #define HP100_REG_BOARD_ID	0x08	/* R:  (8) EISA/ISA card ID          */
@@ -99,32 +132,46 @@
                                         
 /*  Page 7 - MMU Current Pointers  */
 
-#define HP100_REG_RX_MEM_BR	0x08	/* R:  (16) Current begin of Rx ring */
-#define HP100_REG_RX_MEM_ER	0x0a	/* R:  (16) Current end of Rx ring   */
-#define HP100_REG_TX_MEM_BR	0x0c	/* R:  (16) Current begin of Tx ring */
-#define HP100_REG_TX_MEM_ER	0x0e	/* R:  (16) Current end of Rx ring   */
-#define HP100_REG_MEM_DEBUG	0x1a	/* RW: (16) Used for memory tests    */
-                                                
-/*
- *  HardwareIDReg bits/masks
- */
-
-#define HP100_HW_ID_0		0x50	/* Hardware ID bytes.                */
-#define HP100_HW_ID_1		0x48
-#define HP100_HW_ID_2_REVA	0x50	/* Rev. A ID. NOTE: lower nibble not used */
-#define HP100_HW_ID_3		0x53
-
-/*
- *  OptionLSWReg bits/masks
- */
-
-#define HP100_DEBUG_EN		0x8000	/* 0:Disable, 1:Enable Debug Dump Pointer */
-#define HP100_RX_HDR		0x4000	/* 0:Disable, 1:Enable putting pkt into */
-                                        /*   system memory before Rx interrupt */
-#define HP100_MMAP_DIS		0x2000	/* 0:Enable, 1:Disable memory mapping. */
-                                        /*   MMAP_DIS must be 0 and MEM_EN must */
-                                        /*   be 1 for memory-mapped mode to be */
-                                        /*   enabled */
+#define HP100_REG_PTR_RXSTART	0x08	/* R:  (16) Current begin of Rx ring */
+#define HP100_REG_PTR_RXEND	0x0a	/* R:  (16) Current end of Rx ring   */
+#define HP100_REG_PTR_TXSTART	0x0c	/* R:  (16) Current begin of Tx ring */
+#define HP100_REG_PTR_TXEND	0x0e	/* R:  (16) Current end of Rx ring   */
+#define HP100_REG_PTR_RPDLSTART 0x10
+#define HP100_REG_PTR_RPDLEND   0x12
+#define HP100_REG_PTR_RINGPTRS  0x14
+#define HP100_REG_PTR_MEMDEBUG  0x1a
+/* ------------------------------------------------------------------------ */
+
+
+/* 
+ * Hardware ID Register I (Always available, HW_ID, Offset 0x00)
+ */
+#define HP100_HW_ID_CASCADE     0x4850  /* Identifies Cascade Chip */
+
+/* 
+ * Hardware ID Register 2 & Paging Register
+ * (Always available, PAGING, Offset 0x02)
+ * Bits 15:4 are for the Chip ID 
+ */
+#define HP100_CHIPID_MASK        0xFFF0
+#define HP100_CHIPID_SHASTA      0x5350  /* Not 802.12 compliant */
+                                         /* EISA BM/SL, MCA16/32 SL, ISA SL */
+#define HP100_CHIPID_RAINIER     0x5360  /* Not 802.12 compliant EISA BM,*/
+                                         /* PCI SL, MCA16/32 SL, ISA SL */
+#define HP100_CHIPID_LASSEN      0x5370  /* 802.12 compliant PCI BM, PCI SL */
+                                         /* LRF supported */
+
+/*
+ *  Option Registers I and II 
+ * (Always available, OPTION_LSW, Offset 0x04-0x05)
+ */
+#define HP100_DEBUG_EN		0x8000	/* 0:Dis., 1:Enable Debug Dump Ptr. */
+#define HP100_RX_HDR		0x4000	/* 0:Dis., 1:Enable putting pkt into */
+                                        /*   system mem. before Rx interrupt */
+#define HP100_MMAP_DIS		0x2000	/* 0:Enable, 1:Disable mem.mapping. */
+                                        /*   MMAP_DIS must be 0 and MEM_EN */
+                                        /*   must be 1 for memory-mapped */
+                                        /*   mode to be enabled */
 #define HP100_EE_EN		0x1000	/* 0:Disable,1:Enable EEPROM writing */
 #define HP100_BM_WRITE		0x0800	/* 0:Slave, 1:Bus Master for Tx data */
 #define HP100_BM_READ		0x0400	/* 0:Slave, 1:Bus Master for Rx data */
@@ -132,121 +179,236 @@
 #define HP100_MEM_EN		0x0040	/* Config program set this to */
                                         /*   0:Disable, 1:Enable mem map. */
                                         /*   See MMAP_DIS. */
-#define HP100_IO_EN		0x0020	/* 0:Disable, 1:Enable I/O transfers */
-#define HP100_BOOT_EN		0x0010	/* 0:Disable, 1:Enable boot ROM access */
-#define HP100_FAKE_INT		0x0008	/* 0:No int, 1:int */
-#define HP100_INT_EN		0x0004	/* 0:Disable, 1:Enable ints from card */
+#define HP100_IO_EN		0x0020	/* 1:Enable I/O transfers */
+#define HP100_BOOT_EN		0x0010	/* 1:Enable boot ROM access */
+#define HP100_FAKE_INT		0x0008	/* 1:int */
+#define HP100_INT_EN		0x0004	/* 1:Enable ints from card */
 #define HP100_HW_RST		0x0002	/* 0:Reset, 1:Out of reset */
+                                        /* NIC reset on 0 to 1 transition */
 
 /*
- *  OptionMSWReg bits/masks
+ *  Option Register III 
+ * (Always available, OPTION_MSW, Offset 0x06)
  */
-#define HP100_PRIORITY_TX	0x0080	/* 0:Don't, 1:Do all Tx pkts as priority */
+#define HP100_PRIORITY_TX	0x0080	/* 1:Do all Tx pkts as priority */
 #define HP100_EE_LOAD		0x0040	/* 1:EEPROM loading, 0 when done */
-#define HP100_ADV_NXT_PKT	0x0004	/* 1:Advance to next pkt in Rx queue, */
+#define HP100_ADV_NXT_PKT	0x0004	/* 1:Advance to next pkt in Rx queue */
                                         /*   h/w will set to 0 when done */
-#define HP100_TX_CMD		0x0002	/* 1:Tell h/w download done, h/w will set */
-                                        /*   to 0 when done */
+#define HP100_TX_CMD		0x0002	/* 1:Tell h/w download done, h/w */
+                                        /*   will set to 0 when done */
 
 /*
- *  InterruptStatusReg/InterruptMaskReg bits/masks.  These bits will 0 when a 1 
- *  is written to them.
- */
+ * Interrupt Status Registers I and II
+ * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09)
+ * Note: With old chips, these Registers will clear when 1 is written to them
+ *       with new chips this depends on setting of CLR_ISMODE
+ */
+#define HP100_RX_EARLY_INT      0x2000
+#define HP100_RX_PDA_ZERO       0x1000
+#define HP100_RX_PDL_FILL_COMPL 0x0800
 #define HP100_RX_PACKET		0x0400	/* 0:No, 1:Yes pkt has been Rx */
 #define HP100_RX_ERROR		0x0200	/* 0:No, 1:Yes Rx pkt had error */
+#define HP100_TX_PDA_ZERO       0x0020  /* 1 when PDA count goes to zero */
 #define HP100_TX_SPACE_AVAIL	0x0010	/* 0:<8192, 1:>=8192 Tx free bytes */
 #define HP100_TX_COMPLETE	0x0008	/* 0:No, 1:Yes a Tx has completed */
+#define HP100_MISC_ERROR        0x0004  /* 0:No, 1:Lan Link down or bus error*/
 #define HP100_TX_ERROR		0x0002	/* 0:No, 1:Yes Tx pkt had error */
-                                        
+
 /*
- *  TxMemoryFreeCountReg bits/masks.
+ * Xmit Memory Free Count
+ * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit)
  */
-#define HP100_AUTO_COMPARE	0x8000	/* Says at least 8k is available for Tx. */
-                                        /*   NOTE: This mask is for the upper */
-                                        /*   word of the register. */
+#define HP100_AUTO_COMPARE	0x80000000	/* Tx Space avail & pkts<255 */
+#define HP100_FREE_SPACE	0x7fffffe0	/* Tx free memory */
 
 /*
- *  IRQChannelReg bits/masks.
+ *  IRQ Channel
+ * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d)
  */
 #define HP100_ZERO_WAIT_EN	0x80	/* 0:No, 1:Yes asserts NOWS signal */
+#define HP100_IRQ_SCRAMBLE      0x40
+#define HP100_BOND_HP           0x20
 #define HP100_LEVEL_IRQ		0x10	/* 0:Edge, 1:Level type interrupts. */
-                                        /*   Only valid on EISA cards. */
-#define HP100_IRQ_MASK		0x0F	/* Isolate the IRQ bits */
+                                        /* (Only valid on EISA cards) */
+#define HP100_IRQMASK		0x0F	/* Isolate the IRQ bits */
 
 /*
- *  SRAMReg bits/masks.
+ * SRAM Parameters
+ * (Page HW_MAP, SRAM, Offset 0x0e)
  */
 #define HP100_RAM_SIZE_MASK	0xe0	/* AND to get SRAM size index */
-#define HP100_RAM_SIZE_SHIFT	0x05	/* Shift count to put index in lower bits */
+#define HP100_RAM_SIZE_SHIFT	0x05	/* Shift count(put index in lwr bits)*/
+
+/*
+ * Bus Master Register
+ * (Page HW_MAP, BM, Offset 0x0f)
+ */
+#define HP100_BM_BURST_RD       0x01    /* EISA only: 1=Use burst trans. fm system */
+                                        /* memory to chip (tx) */
+#define HP100_BM_BURST_WR       0x02    /* EISA only: 1=Use burst trans. fm system */
+                                        /* memory to chip (rx) */
+#define HP100_BM_MASTER		0x04	/* 0:Slave, 1:BM mode */
+#define HP100_BM_PAGE_CK        0x08    /* This bit should be set whenever in*/
+                                        /* an EISA system */
+#define HP100_BM_PCI_8CLK       0x40    /* ... cycles 8 clocks apart */
+
+
+/* 
+ * Mode Control Register I
+ * (Page HW_MAP, MODECTRL1, Offset0x10)
+ */
+#define HP100_TX_DUALQ          0x10
+   /* If set and BM -> dual tx pda queues*/
+#define HP100_ISR_CLRMODE       0x02   /* If set ISR will clear all pending */
+                                       /* interrupts on read (etr only?) */
+#define HP100_EE_NOLOAD         0x04   /* Status whether res will be loaded */
+                                       /* from the eeprom */
+#define HP100_TX_CNT_FLG        0x08   /* Controls Early TX Reg Cnt Field */
+#define HP100_PDL_USE3          0x10   /* If set BM engine will read only */
+                                       /* first three data elements of a PDL */
+                                       /* on the first access. */
+#define HP100_BUSTYPE_MASK      0xe0   /* Three bit bus type info */
+
+/*
+ * Mode Control Register II
+ * (Page HW_MAP, MODECTRL2, Offset0x11)
+ */
+#define HP100_EE_MASK           0x0f   /* Tell EEPROM circuit not to load */ 
+                                       /* certain resources */
+#define HP100_DIS_CANCEL        0x20   /* For tx dualq mode operation */
+#define HP100_EN_PDL_WB         0x40   /* 1: Status of PDL completion may be */
+                                       /* written back to system mem */
+#define HP100_EN_BUS_FAIL       0x80   /* Enables bus-fail portion of misc */
+                                       /* interrupt */
+
+/* 
+ * PCI Configuration and Control Register I
+ * (Page HW_MAP, PCICTRL1, Offset 0x12)
+ */
+#define HP100_LO_MEM            0x01   /* 1: Mapped Mem requested below 1MB */
+#define HP100_NO_MEM            0x02   /* 1: Disables Req for sysmem to PCI */ 
+                                       /* bios */
+#define HP100_USE_ISA           0x04   /* 1: isa type decodes will occur */
+                                       /* simultaneously with PCI decodes */
+#define HP100_IRQ_HI_MASK       0xf0   /* pgmed by pci bios */
+#define HP100_PCI_IRQ_HI_MASK   0x78    /* Isolate 4 bits for PCI IRQ  */
+ 
+/*
+ * PCI Configuration and Control Register II
+ * (Page HW_MAP, PCICTRL2, Offset 0x13)
+ */
+#define HP100_RD_LINE_PDL       0x01   /* 1: PCI command Memory Read Line en */
+#define HP100_RD_TX_DATA_MASK   0x06   /* choose PCI memread cmds for TX */ 
+#define HP100_MWI               0x08   /* 1: en. PCI memory write invalidate */
+#define HP100_ARB_MODE          0x10   /* Select PCI arbitor type */
+#define HP100_STOP_EN           0x20   /* Enables PCI state machine to issue */
+                                       /* pci stop if cascade not ready */
+#define HP100_IGNORE_PAR        0x40   /* 1: PCI state machine ignores parity*/
+#define HP100_PCI_RESET         0x80   /* 0->1: Reset PCI block */
+
+/*
+ * Early TX Configuration and Control Register
+ * (Page HW_MAP, EARLYTXCFG, Offset 0x16)
+ */
+#define HP100_EN_EARLY_TX       0x8000  /* 1=Enable Early TX */
+#define HP100_EN_ADAPTIVE       0x4000  /* 1=Enable adaptive mode */
+#define HP100_EN_TX_UR_IRQ      0x2000  /* reserved, must be 0 */
+#define HP100_EN_LOW_TX         0x1000  /* reserved, must be 0 */
+#define HP100_ET_CNT_MASK       0x0fff  /* bits 11..0: ET counters */
 
 /*
- *  BMReg bits/masks.
+ * Early RX Configuration and Control Register
+ * (Page HW_MAP, EARLYRXCFG, Offset 0x18)
  */
-#define HP100_BM_SLAVE		0x04	/* 0:Slave, 1:BM mode */
+#define HP100_EN_EARLY_RX       0x80     /* 1=Enable Early RX */
+#define HP100_EN_LOW_RX         0x40     /* reserved, must be 0 */
+#define HP100_RX_TRIP_MASK      0x1f     /* bits 4..0: threshold at which the
+					  * early rx circuit will start the
+					  * dma of received packet into system
+					  * memory for BM */
 
 /*
- *  EEPROMControlReg bits/masks.
+ *  Serial Devices Control Register
+ * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08)
  */
-#define HP100_EEPROM_LOAD	0x0001	/* 0->1 loads the EEPROM into registers. */
-                                        /*   When it goes back to 0, load is  */
-                                        /*   complete.  This should take ~600us. */
+#define HP100_EEPROM_LOAD	0x0001	/* 0->1 loads EEPROM into registers. */
+                                        /* When it goes back to 0, load is   */
+                                        /* complete. This should take ~600us.*/
 
 /*
- *  LANCntrCfg10Reg bits/masks.
+ * 10MB LAN Control and Configuration Register I
+ * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08)
  */
-#define HP100_SQU_ST		0x0100	/* 0:No, 1:Yes collision signal sent */
-                                        /*   after Tx.  Only used for AUI. */
-#define HP100_MAC10_SEL		0x00c0	/* Get bits to indicate MAC */
-#define HP100_AUI_SEL		0x0020	/* Status of AUI selection */
-#define HP100_LOW_TH		0x0010	/* 0:No, 1:Yes allow better cabling */
-#define HP100_LINK_BEAT_DIS	0x0008	/* 0:Enable, 1:Disable link beat */
-#define HP100_LINK_BEAT_ST	0x0004	/* 0:No, 1:Yes link beat being Rx */
-#define HP100_R_ROL_ST		0x0002	/* 0:No, 1:Yes Rx twisted pair has been */
-                                        /*   reversed */
-#define HP100_AUI_ST		0x0001	/* 0:No, 1:Yes use AUI on TP card */
+#define HP100_MAC10_SEL		0xc0	/* Get bits to indicate MAC */
+#define HP100_AUI_SEL		0x20	/* Status of AUI selection */
+#define HP100_LOW_TH		0x10	/* 0:No, 1:Yes allow better cabling */
+#define HP100_LINK_BEAT_DIS	0x08	/* 0:Enable, 1:Disable link beat */
+#define HP100_LINK_BEAT_ST	0x04	/* 0:No, 1:Yes link beat being Rx */
+#define HP100_R_ROL_ST		0x02	/* 0:No, 1:Yes Rx twisted pair has */
+                                        /*             been reversed */
+#define HP100_AUI_ST		0x01	/* 0:No, 1:Yes use AUI on TP card */
 
-/* MAC Selection, use with MAC10_SEL bits */
+/*
+ * 10 MB LAN Control and Configuration Register II
+ * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09)
+ */
+#define HP100_SQU_ST		0x01	/* 0:No, 1:Yes collision signal sent */
+                                        /*       after Tx.Only used for AUI. */
+#define HP100_FULLDUP           0x02    /* 1: LXT901 XCVR fullduplx enabled */
+#define HP100_DOT3_MAC          0x04    /* 1: DOT 3 Mac sel. unless Autosel */
+
+/*
+ * MAC Selection, use with MAC10_SEL bits
+ */
 #define HP100_AUTO_SEL_10	0x0	/* Auto select */
 #define HP100_XCVR_LXT901_10	0x1	/* LXT901 10BaseT transceiver */
 #define HP100_XCVR_7213		0x2	/* 7213 transceiver */
 #define HP100_XCVR_82503	0x3	/* 82503 transceiver */
 
-
 /*
- *  LANCntrCfgVGReg bits/masks.
+ *  100MB LAN Training Register
+ * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12)
  */
-#define HP100_FRAME_FORMAT	0x0800	/* 0:802.3, 1:802.5 frames */
-#define HP100_BRIDGE		0x0400	/* 0:No, 1:Yes tell hub it's a bridge */
-#define HP100_PROM_MODE		0x0200	/* 0:No, 1:Yes tell hub card is */
-                                        /*   promiscuous */
-#define HP100_REPEATER		0x0100	/* 0:No, 1:Yes tell hub MAC wants to be */
-                                        /*   a cascaded repeater */
-#define HP100_MAC100_SEL	0x0080	/* 0:No, 1:Yes use 100 Mbit MAC */
-#define HP100_LINK_UP_ST	0x0040	/* 0:No, 1:Yes endnode logged in */
-#define HP100_LINK_CABLE_ST	0x0020	/* 0:No, 1:Yes cable can hear tones from */
-                                        /*   hub */
-#define HP100_LOAD_ADDR		0x0010	/* 0->1 card addr will be sent to hub. */
-                                        /*   100ms later the link status bits are */
-                                        /*   valid */
-#define HP100_LINK_CMD		0x0008	/* 0->1 link will attempt to log in. */
-                                        /*   100ms later the link status bits are */
-                                        /*   valid */
-#define HP100_LINK_GOOD_ST	0x0002	/* 0:No, 1:Yes cable passed training */
-#define HP100_VG_RESET		0x0001	/* 0:Yes, 1:No reset the 100VG MAC */
+#define HP100_FRAME_FORMAT	0x08	/* 0:802.3, 1:802.5 frames */
+#define HP100_BRIDGE		0x04	/* 0:No, 1:Yes tell hub i am a bridge */
+#define HP100_PROM_MODE		0x02	/* 0:No, 1:Yes tell hub card is */
+                                        /*         promiscuous */
+#define HP100_REPEATER		0x01	/* 0:No, 1:Yes tell hub MAC wants to */
+                                        /*         be a cascaded repeater */
+
+/*
+ * 100MB LAN Control and Configuration Register
+ * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a) 
+ */
+#define HP100_VG_SEL	        0x80	/* 0:No, 1:Yes use 100 Mbit MAC */
+#define HP100_LINK_UP_ST	0x40	/* 0:No, 1:Yes endnode logged in */
+#define HP100_LINK_CABLE_ST	0x20	/* 0:No, 1:Yes cable can hear tones */
+                                        /*         from  hub */
+#define HP100_LOAD_ADDR		0x10	/* 0->1 card addr will be sent  */
+                                        /* 100ms later the link status  */
+                                        /* bits are valid */
+#define HP100_LINK_CMD		0x08	/* 0->1 link will attempt to log in. */
+                                        /* 100ms later the link status */
+                                        /* bits are valid */
+#define HP100_TRN_DONE          0x04    /* NEW ETR-Chips only: Will be reset */
+                                        /* after LinkUp Cmd is given and set */
+                                        /* when training has completed. */
+#define HP100_LINK_GOOD_ST	0x02	/* 0:No, 1:Yes cable passed training */
+#define HP100_VG_RESET		0x01	/* 0:Yes, 1:No reset the 100VG MAC */
 
 
 /*
- *  MACConfiguration1Reg bits/masks.
+ *  MAC Configuration Register I
+ * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c)
  */
 #define HP100_RX_IDLE		0x80	/* 0:Yes, 1:No currently receiving pkts */
 #define HP100_TX_IDLE		0x40	/* 0:Yes, 1:No currently Txing pkts */
-#define HP100_RX_EN		0x20	/* 0:No, 1:Yes allow receiving of pkts */
-#define HP100_TX_EN		0x10	/* 0:No, 1:Yes allow transmitting of pkts */
+#define HP100_RX_EN		0x20	/* 1: allow receiving of pkts */
+#define HP100_TX_EN		0x10	/* 1: allow transmitting of pkts */
 #define HP100_ACC_ERRORED	0x08	/* 0:No, 1:Yes allow Rx of errored pkts */
 #define HP100_ACC_MC		0x04	/* 0:No, 1:Yes allow Rx of multicast pkts */
 #define HP100_ACC_BC		0x02	/* 0:No, 1:Yes allow Rx of broadcast pkts */
-#define HP100_ACC_PHY		0x01	/* 0:No, 1:Yes allow Rx of ALL physical pkts */
-
+#define HP100_ACC_PHY		0x01	/* 0:No, 1:Yes allow Rx of ALL phys. pkts */
 #define HP100_MAC1MODEMASK	0xf0	/* Hide ACC bits */
 #define HP100_MAC1MODE1		0x00	/* Receive nothing, must also disable RX */
 #define HP100_MAC1MODE2		0x00
@@ -254,15 +416,14 @@
 #define HP100_MAC1MODE4		HP100_MAC1MODE3 | HP100_ACC_MC
 #define HP100_MAC1MODE5		HP100_MAC1MODE4 /* set mc hash to all ones also */
 #define HP100_MAC1MODE6		HP100_MAC1MODE5 | HP100_ACC_PHY	/* Promiscuous */
-
 /* Note MODE6 will receive all GOOD packets on the LAN. This really needs
    a mode 7 defined to be LAN Analyzer mode, which will receive errored and
    runt packets, and keep the CRC bytes. */
-
-#define HP100_MAC1MODE7		MAC1MODE6 OR ACC_ERRORED
+#define HP100_MAC1MODE7		HP100_MAC1MODE6 | HP100_ACC_ERRORED
 
 /*
- *  MACConfiguration2Reg bits/masks.
+ *  MAC Configuration Register II 
+ * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
  */
 #define HP100_TR_MODE		0x80	/* 0:No, 1:Yes support Token Ring formats */
 #define HP100_TX_SAME		0x40	/* 0:No, 1:Yes Tx same packet continuous */
@@ -270,9 +431,12 @@
                                         /*   transceiver */
 #define HP100_LBK_MAC		0x10	/* 0:No, 1:Yes loopback through MAC */
 #define HP100_CRC_I		0x08	/* 0:No, 1:Yes inhibit CRC on Tx packets */
+#define HP100_ACCNA             0x04    /* 1: For 802.5: Accept only token ring
+					 * group addr that maches NA mask */
 #define HP100_KEEP_CRC		0x02	/* 0:No, 1:Yes keep CRC on Rx packets. */
                                         /*   The length will reflect this. */
-
+#define HP100_ACCFA             0x01    /* 1: For 802.5: Accept only functional
+					 * addrs that match FA mask (page1) */
 #define HP100_MAC2MODEMASK	0x02
 #define HP100_MAC2MODE1		0x00
 #define HP100_MAC2MODE2		0x00
@@ -283,6 +447,65 @@
 #define HP100_MAC2MODE7		KEEP_CRC
 
 /*
+ * MAC Configuration Register III 
+ * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e) 
+ */
+#define HP100_PACKET_PACE       0x03     /* Packet Pacing:
+					  * 00: No packet pacing
+                                          * 01: 8 to 16 uS delay
+                                          * 10: 16 to 32 uS delay
+                                          * 11: 32 to 64 uS delay
+					  */
+#define HP100_LRF_EN            0x04     /* 1: External LAN Rcv Filter and
+					  * TCP/IP Checksumming enabled. */
+#define HP100_AUTO_MODE         0x10     /* 1: AutoSelect between 10/100 */
+
+/*
+ * MAC Configuration Register IV 
+ * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
+ */
+#define HP100_MAC_SEL_ST        0x01      /* (R): Status of external VGSEL
+					   * Signal, 1=100VG, 0=10Mbit sel. */
+#define HP100_LINK_FAIL_ST      0x02      /* (R): Status of Link Fail portion
+                                           * of the Misc. Interrupt */
+
+/* 
+ *  100 MB LAN Training Request/Allowed Registers 
+ * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
+ */
+#define HP100_MACRQ_REPEATER         0x0001  /* 1: MAC tells HUB it wants to be 
+				              *    a cascaded repeater
+					      * 0: ... wants to be a DTE */
+#define HP100_MACRQ_PROMSC           0x0006  /* 2 bits: Promiscious mode
+					      * 00: Rcv only unicast packets
+					      *     specifically addr to this
+					      *     endnode
+					      * 10: Rcv all pckts fwded by 
+					      *     the local repeater */
+#define HP100_MACRQ_FRAMEFMT_EITHER  0x0018  /* 11: either format allowed */
+#define HP100_MACRQ_FRAMEFMT_802_3   0x0000  /* 00: 802.3 is requested */
+#define HP100_MACRQ_FRAMEFMT_802_5   0x0010  /* 10: 802.5 format is requested */
+#define HP100_CARD_MACVER            0xe000  /* R: 3 bit Cards 100VG MAC version */
+#define HP100_MALLOW_REPEATER        0x0001  /* If reset, requested access as an
+					      * end node is allowed */
+#define HP100_MALLOW_PROMSC          0x0004  /* 2 bits: Promiscious mode
+					      * 00: Rcv only unicast packets
+					      *     specifically addr to this
+					      *     endnode
+					      * 10: Rcv all pckts fwded by 
+					      *     the local repeater */
+#define HP100_MALLOW_FRAMEFMT        0x00e0  /* 2 bits: Frame Format
+					      * 00: 802.3 format will be used
+					      * 10: 802.5 format will be used */
+#define HP100_MALLOW_ACCDENIED       0x0400  /* N bit */
+#define HP100_MALLOW_CONFIGURE       0x0f00  /* C bit */
+#define HP100_MALLOW_DUPADDR         0x1000  /* D bit */
+#define HP100_HUB_MACVER             0xe000  /* R: 3 bit 802.12 MAC/RMAC training */
+                                             /*    protocol of repeater */
+
+/* ****************************************************************************** */
+
+/*
  *  Set/Reset bits
  */
 #define HP100_SET_HB		0x0100	/* 0:Set fields to 0 whose mask is 1 */
@@ -297,20 +520,45 @@
 #define HP100_LAN_10		10	/* lan_type value for 10BaseT */
 #define HP100_LAN_ERR		(-1)	/* lan_type value for link down */
 
-/*
- *  Receive Header Definition.
+#define TRUE 1
+#define FALSE 0
+
+
+/* 
+ * Bus Master Data Structures  ----------------------------------------------
  */
 
-struct hp100_rx_header {
-  u_short rx_length;			/* Pkt length is bits 12:0 */
-  u_short rx_status;			/* status of the packet */
-};
+#define MAX_RX_PDL              30   /* Card limit = 31 */
+#define MAX_RX_FRAG             2    /* Dont need more... */
+#define MAX_TX_PDL              29
+#define MAX_TX_FRAG             2   /* Limit = 31 */
+
+/* Define total PDL area size in bytes (should be 4096) */
+/* This is the size of kernel (dma) memory that will be allocated. */
+#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16
+
+/* Ethernet Packet Sizes */
+#define MIN_ETHER_SIZE          60
+#define MAX_ETHER_SIZE          1514    /* Needed for preallocation of */
+                                        /* skb buffer when busmastering */
+
+/* Tx or Rx Ring Entry */
+typedef struct hp100_ring {
+  u_int                     *pdl;       /* Address of PDLs PDH, dword before
+					 * this address is used for rx hdr */
+  u_int                     pdl_paddr;  /* Physical address of PDL */
+  struct sk_buff            *skb;
+  struct hp100_ring         *next;      
+} hp100_ring_t;
+
+
+
+/* Mask for Header Descriptor */
+#define HP100_PKT_LEN_MASK	0x1FFF	/* AND with RxLength to get length */
 
-#define HP100_PKT_LEN_MASK	0x1FFF	/* AND with RxLength to get length bits */
 
 /* Receive Packet Status.  Note, the error bits are only valid if ACC_ERRORED 
    bit in the MAC Configuration Register 1 is set. */
-   
 #define HP100_RX_PRI		0x8000	/* 0:No, 1:Yes packet is priority */
 #define HP100_SDF_ERR		0x4000	/* 0:No, 1:Yes start of frame error */
 #define HP100_SKEW_ERR		0x2000	/* 0:No, 1:Yes skew out of range */
@@ -368,7 +616,11 @@
 	outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
 #define hp100_mem_map_disable() \
 	outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_reset_card() \
-	outw( HP100_HW_RST | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_unreset_card() \
-	outw( HP100_HW_RST | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 2
+ *  tab-width: 8
+ * End:
+*/
diff -u --recursive --new-file v2.1.39/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.39/linux/drivers/net/ibmtr.c	Tue May 13 22:41:09 1997
+++ linux/drivers/net/ibmtr.c	Sun May 18 16:38:34 1997
@@ -84,7 +84,7 @@
 /* version and credits */
 static char *version =
 "ibmtr.c: v1.3.57  8/ 7/94 Peter De Schrijver and Mark Swanson\n"
-"         v2.1.29  3/15/97 Paul Norton <pnorton@cts.com>\n";
+"         v2.1.35  5/ 1/97 Paul Norton <pnorton@cts.com>\n";
 
 static char pcchannelid[] = {
 	0x05, 0x00, 0x04, 0x09,
@@ -1013,14 +1013,15 @@
 			} /* ARB response */
 
 			if (status & SSB_RESP_INT) { /* SSB response */
-
+				unsigned char retcode;
 				switch (readb(ti->ssb)) { /* SSB command check */
-
+				      
 				      case XMIT_DIR_FRAME:
 				      case XMIT_UI_FRAME:
-					if (readb(ti->ssb+2)) /* checks ret_code */
+					retcode = readb(ti->ssb+2);
+					if (retcode && (retcode != 0x22)) /* checks ret_code */
 						DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
-							(int)readb(ti->ssb+2), (int)readb(ti->ssb+6));
+							(int)retcode, (int)readb(ti->ssb+6));
 					else ti->tr_stats.tx_packets++;
 					break;
 
@@ -1321,12 +1322,12 @@
 	__u32 rbuffer, rbufdata;
 	__u32 llc;
 	unsigned char *data;
-	unsigned int rbuffer_len, lan_hdr_len, hdr_len;
-	unsigned int arb_frame_len;
+	unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length;
 	struct sk_buff *skb;
 	unsigned int skb_size = 0;
 	int	is8022 = 0;
 	unsigned int chksum = 0;
+	struct iphdr *iph;
 
 	rbuffer=(ti->sram
 		 +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2;
@@ -1400,8 +1401,8 @@
        	}
 #endif
 
-       	arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
-       	skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr);
+       	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
+       	skb_size = length-lan_hdr_len+sizeof(struct trh_hdr);
        	if (is8022) {
        		skb_size += sizeof(struct trllc);
        	}
@@ -1429,30 +1430,42 @@
 	rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)))-lan_hdr_len;
 
 	if (is8022) {
-		/* create whitewashed LLC header in skb buffer (why not the real one?) */
+		/* create whitewashed LLC header in sk buffer */
 		struct trllc	*local_llc = (struct trllc *)data;
 		memset(local_llc, 0, sizeof(*local_llc));
 		local_llc->ethertype = htons(ETH_P_TR_802_2);
 		hdr_len = sizeof(struct trllc);
+		/* copy the real LLC header to the sk buffer */
+		data += hdr_len;
+		memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len);
 	} else {
                 /* Copy the LLC header and the IPv4 header */
 		hdr_len = sizeof(struct trllc) + sizeof(struct iphdr);
 		memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len);
+
+		/* Watch for padded packets and bogons */
+		iph=(struct iphdr*)(data+sizeof(struct trllc));
+		ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr);
+		length -= lan_hdr_len + hdr_len;
+		if ((ip_len <= length) && (ip_len > 7))
+			length = ip_len;
         }
 	data        += hdr_len;
-       	lan_hdr_len += hdr_len;
 	rbuffer_len -= hdr_len;
-	rbufdata     = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len;
+	rbufdata     = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len + hdr_len;
 
 	/* Copy the payload... */
 	for (;;) {
 		if (is8022)
 			memcpy_fromio(data, rbufdata, rbuffer_len);
 		else
-			chksum = csum_partial_copy(bus_to_virt(rbufdata), data, rbuffer_len, chksum);
+			chksum = csum_partial_copy(bus_to_virt(rbufdata), data,
+						   length < rbuffer_len ? length : rbuffer_len,
+						   chksum);
 		rbuffer = ntohs(readw(rbuffer));
 		if (!rbuffer)
 			break;
+		length -= rbuffer_len;
 		data += rbuffer_len;
 		rbuffer += ti->sram;
 		rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
diff -u --recursive --new-file v2.1.39/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.39/linux/drivers/pci/pci.c	Tue May 13 22:41:12 1997
+++ linux/drivers/pci/pci.c	Sun May 18 16:38:34 1997
@@ -150,6 +150,7 @@
 	DEVICE( CMD,		CMD_646,	"646"),
 	DEVICE( VISION,		VISION_QD8500,	"QD-8500"),
 	DEVICE( VISION,		VISION_QD8580,	"QD-8580"),
+	DEVICE( BROOKTREE,	BT848,		"Brooktree 848"),
 	DEVICE( SIERRA,		SIERRA_STB,	"STB Horizon 64"),
 	DEVICE( ACC,		ACC_2056,	"2056"),
 	DEVICE( WINBOND,	WINBOND_83769,	"W83769F"),
@@ -264,6 +265,7 @@
 	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II"),
 	DEVICE( INTEL,		INTEL_82371AB,	"82371AB 430TX PIIX4"),
 	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
+ 	DEVICE( INTEL,		INTEL_P6_2,	"82450GX Orion P6"),
 	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
 	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850"),
 	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855"),
@@ -518,6 +520,7 @@
 	      case PCI_VENDOR_ID_OLICOM:	return "Olicom";
 	      case PCI_VENDOR_ID_CMD:		return "CMD";
 	      case PCI_VENDOR_ID_VISION:	return "Vision";
+	      case PCI_VENDOR_ID_BROOKTREE:	return "Brooktree";
 	      case PCI_VENDOR_ID_SIERRA:	return "Sierra";
 	      case PCI_VENDOR_ID_ACC:		return "ACC MICROELECTRONICS";
 	      case PCI_VENDOR_ID_WINBOND:	return "Winbond";
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.1.39/linux/drivers/scsi/53c7xx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/53c7xx.c	Sun May 18 17:10:37 1997
@@ -0,0 +1,6107 @@
+/*
+ * 53c710 driver.  Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ * Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
+ * relevant machine specific file (eg. mvme166.[ch], amiga7xx.[ch]).
+ * There are also currently some defines at the top of 53c7xx.scr.
+ * The chip type is #defined in script_asm.pl, as well as the Makefile.
+ * Host scsi ID expected to be 7 - see NCR53c7x0_init().
+ *
+ * I have removed the PCI code and some of the 53c8xx specific code - 
+ * simply to make this file smaller and easier to manage.
+ *
+ * MVME166 issues:
+ *   Problems trying to read any chip registers in NCR53c7x0_init(), as they
+ *   may never have been set by 166Bug (eg. If kernel has come in over tftp).
+ */
+
+/*
+ * Adapted for Linux/m68k Amiga platforms for the A4000T/A4091 and
+ * WarpEngine SCSI controllers.
+ * By Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * Thanks to Richard Hirst for making it possible with the MVME additions
+ */
+
+/*
+ * 53c710 rev 0 doesn't support add with carry.  Rev 1 and 2 does.  To
+ * overcome this problem you can define FORCE_DSA_ALIGNMENT, which ensures
+ * that the DSA address is always xxxxxx00.  If disconnection is not allowed,
+ * then the script only ever tries to add small (< 256) positive offsets to
+ * DSA, so lack of carry isn't a problem.  FORCE_DSA_ALIGNMENT can, of course,
+ * be defined for all chip revisions at a small cost in memory usage.
+ */
+
+#define FORCE_DSA_ALIGNMENT
+
+/*
+ * Selection timer does not always work on the 53c710, depending on the
+ * timing at the last disconnect, if this is a problem for you, try
+ * using validids as detailed below.
+ *
+ * Options for the NCR7xx driver
+ *
+ * nosync:0		-	disables synchronous negotiation
+ * nodisconnect:0	-	disables disconnection
+ * validids:0x??	-	Bitmask field that disallows certain ID's.
+ *			-	e.g.	0x03	allows ID 0,1
+ *			-		0x1F	allows ID 0,1,2,3,4
+ */
+
+/*
+ * PERM_OPTIONS are driver options which will be enabled for all NCR boards
+ * in the system at driver initialization time.
+ *
+ * Don't THINK about touching these in PERM_OPTIONS : 
+ *   OPTION_MEMORY_MAPPED 
+ * 	680x0 doesn't have an IO map!
+ *
+ *   OPTION_DEBUG_TEST1
+ *	Test 1 does bus mastering and interrupt tests, which will help weed 
+ *	out brain damaged main boards.
+ *
+ * Other PERM_OPTIONS settings are listed below.  Note the actual options
+ * required are set in the relevant file (mvme166.c, amiga7xx.c, etc):
+ *
+ *   OPTION_NO_ASYNC
+ *	Don't negotiate for asynchronous transfers on the first command 
+ *	when OPTION_ALWAYS_SYNCHRONOUS is set.  Useful for dain bramaged
+ *	devices which do something bad rather than sending a MESSAGE 
+ *	REJECT back to us like they should if they can't cope.
+ *
+ *   OPTION_SYNCHRONOUS
+ *	Enable support for synchronous transfers.  Target negotiated 
+ *	synchronous transfers will be responded to.  To initiate 
+ *	a synchronous transfer request,  call 
+ *
+ *	    request_synchronous (hostno, target) 
+ *
+ *	from within KGDB.
+ *
+ *   OPTION_ALWAYS_SYNCHRONOUS
+ *	Negotiate for synchronous transfers with every target after
+ *	driver initialization or a SCSI bus reset.  This is a bit dangerous, 
+ *	since there are some dain bramaged SCSI devices which will accept
+ *	SDTR messages but keep talking asynchronously.
+ *
+ *   OPTION_DISCONNECT
+ *	Enable support for disconnect/reconnect.  To change the 
+ *	default setting on a given host adapter, call
+ *
+ *	    request_disconnect (hostno, allow)
+ *
+ *	where allow is non-zero to allow, 0 to disallow.
+ * 
+ *  If you really want to run 10MHz FAST SCSI-II transfers, you should 
+ *  know that the NCR driver currently ignores parity information.  Most
+ *  systems do 5MHz SCSI fine.  I've seen a lot that have problems faster
+ *  than 8MHz.  To play it safe, we only request 5MHz transfers.
+ *
+ *  If you'd rather get 10MHz transfers, edit sdtr_message and change 
+ *  the fourth byte from 50 to 25.
+ */
+
+#include <linux/config.h>
+
+/*
+ * Sponsored by 
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@PoohSticks.ORG
+ *	+1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ * 
+ * For more information, please consult 
+ *
+ * NCR53C810 
+ * SCSI I/O Processor
+ * Programmer's Guide
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810/53C820
+ * PCI-SCSI I/O Processor Design In Guide
+ *
+ * For literature on Symbios Logic Inc. formerly NCR, SCSI, 
+ * and Communication products please call (800) 334-5454 or
+ * (719) 536-3300. 
+ * 
+ * PCI BIOS Specification Revision
+ * PCI Local Bus Specification
+ * PCI System Design Guide
+ *
+ * PCI Special Interest Group
+ * M/S HF3-15A
+ * 5200 N.E. Elam Young Parkway
+ * Hillsboro, Oregon 97124-6497
+ * +1 (503) 696-2000 
+ * +1 (800) 433-5177
+ */
+
+/*
+ * Design issues : 
+ * The cumulative latency needed to propagate a read/write request 
+ * through the file system, buffer cache, driver stacks, SCSI host, and 
+ * SCSI device is ultimately the limiting factor in throughput once we 
+ * have a sufficiently fast host adapter.
+ *  
+ * So, to maximize performance we want to keep the ratio of latency to data 
+ * transfer time to a minimum by
+ * 1.  Minimizing the total number of commands sent (typical command latency
+ *	including drive and bus mastering host overhead is as high as 4.5ms)
+ *	to transfer a given amount of data.  
+ *
+ *      This is accomplished by placing no arbitrary limit on the number
+ *	of scatter/gather buffers supported, since we can transfer 1K
+ *	per scatter/gather buffer without Eric's cluster patches, 
+ *	4K with.  
+ *
+ * 2.  Minimizing the number of fatal interrupts serviced, since
+ * 	fatal interrupts halt the SCSI I/O processor.  Basically,
+ *	this means offloading the practical maximum amount of processing 
+ *	to the SCSI chip.
+ * 
+ *	On the NCR53c810/820/720,  this is accomplished by using 
+ *		interrupt-on-the-fly signals when commands complete, 
+ *		and only handling fatal errors and SDTR / WDTR 	messages 
+ *		in the host code.
+ *
+ *	On the NCR53c710, interrupts are generated as on the NCR53c8x0,
+ *		only the lack of a interrupt-on-the-fly facility complicates
+ *		things.   Also, SCSI ID registers and commands are 
+ *		bit fielded rather than binary encoded.
+ *		
+ * 	On the NCR53c700 and NCR53c700-66, operations that are done via 
+ *		indirect, table mode on the more advanced chips must be
+ *	        replaced by calls through a jump table which 
+ *		acts as a surrogate for the DSA.  Unfortunately, this 
+ * 		will mean that we must service an interrupt for each 
+ *		disconnect/reconnect.
+ * 
+ * 3.  Eliminating latency by pipelining operations at the different levels.
+ * 	
+ *	This driver allows a configurable number of commands to be enqueued
+ *	for each target/lun combination (experimentally, I have discovered
+ *	that two seems to work best) and will ultimately allow for 
+ *	SCSI-II tagged queuing.
+ * 	
+ *
+ * Architecture : 
+ * This driver is built around a Linux queue of commands waiting to 
+ * be executed, and a shared Linux/NCR array of commands to start.  Commands
+ * are transfered to the array  by the run_process_issue_queue() function 
+ * which is called whenever a command completes.
+ *
+ * As commands are completed, the interrupt routine is triggered,
+ * looks for commands in the linked list of completed commands with
+ * valid status, removes these commands from a list of running commands, 
+ * calls the done routine, and flags their target/luns as not busy.
+ *
+ * Due to limitations in the intelligence of the NCR chips, certain
+ * concessions are made.  In many cases, it is easier to dynamically 
+ * generate/fix-up code rather than calculate on the NCR at run time.  
+ * So, code is generated or fixed up for
+ *
+ * - Handling data transfers, using a variable number of MOVE instructions
+ *	interspersed with CALL MSG_IN, WHEN MSGIN instructions.
+ *
+ * 	The DATAIN and DATAOUT routines	are separate, so that an incorrect
+ *	direction can be trapped, and space isn't wasted. 
+ *
+ *	It may turn out that we're better off using some sort 
+ *	of table indirect instruction in a loop with a variable
+ *	sized table on the NCR53c710 and newer chips.
+ *
+ * - Checking for reselection (NCR53c710 and better)
+ *
+ * - Handling the details of SCSI context switches (NCR53c710 and better),
+ *	such as reprogramming appropriate synchronous parameters, 
+ *	removing the dsa structure from the NCR's queue of outstanding
+ *	commands, etc.
+ *
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/config.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/blk.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/pgtable.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#ifdef CONFIG_MVME166
+#include <asm/mvme166hw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+#include <linux/stddef.h>
+
+#ifdef NO_IO_SPACE
+/*
+ * The following make the definitions in 53c7xx.h (write8, etc) smaller,
+ * we don't have seperate i/o space anyway.
+ */
+#undef inb
+#undef outb
+#define inb(x)          1
+#define inw(x)          1
+#define inl(x)          1
+#define outb(x,y)       1
+#define outw(x,y)       1
+#define outl(x,y)       1
+#endif
+
+static int check_address (unsigned long addr, int size);
+static void dump_events (struct Scsi_Host *host, int count);
+static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host, 
+    int free, int issue);
+static void hard_reset (struct Scsi_Host *host);
+static void ncr_scsi_reset (struct Scsi_Host *host);
+static void print_lots (struct Scsi_Host *host);
+static void set_synchronous (struct Scsi_Host *host, int target, int sxfer, 
+    int scntl3, int now_connected);
+static int datapath_residual (struct Scsi_Host *host);
+static const char * sbcl_to_phase (int sbcl);
+static void print_progress (Scsi_Cmnd *cmd);
+static void print_queues (struct Scsi_Host *host);
+static void process_issue_queue (unsigned long flags);
+static int shutdown (struct Scsi_Host *host);
+static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
+static int disable (struct Scsi_Host *host);
+static int NCR53c7xx_run_tests (struct Scsi_Host *host);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static int ncr_halt (struct Scsi_Host *host);
+static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
+    *cmd);
+static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+static void print_dsa (struct Scsi_Host *host, u32 *dsa,
+    const char *prefix);
+static int print_insn (struct Scsi_Host *host, const u32 *insn,
+    const char *prefix, int kernel);
+
+static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_init_fixup (struct Scsi_Host *host);
+static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct 
+    NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
+
+/* Size of event list (per host adapter) */
+static int track_events = 0;
+static struct Scsi_Host *first_host = NULL;	/* Head of list of NCR boards */
+static Scsi_Host_Template *the_template = NULL;	
+
+/* NCR53c710 script handling code */
+
+#include "53c7xx_d.h"
+#ifdef A_int_debug_sync
+#define DEBUG_SYNC_INTR A_int_debug_sync
+#endif
+int NCR53c7xx_script_len = sizeof (SCRIPT);
+int NCR53c7xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
+#ifdef FORCE_DSA_ALIGNMENT
+int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
+#endif
+int flushsize;
+
+static char *setup_strings[] =
+	{"","","","","","","",""};
+
+#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_STRINGS];
+
+void ncr53c7xx_setup (char *str, int *ints)
+{
+   int i;
+   char *p1, *p2;
+
+   p1 = setup_buffer;
+   *p1 = '\0';
+   if (str)
+      strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+   setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+   p1 = setup_buffer;
+   i = 0;
+   while (*p1 && (i < MAX_SETUP_STRINGS)) {
+      p2 = strchr(p1, ',');
+      if (p2) {
+         *p2 = '\0';
+         if (p1 != p2)
+            setup_strings[i] = p1;
+         p1 = p2 + 1;
+         i++;
+         }
+      else {
+         setup_strings[i] = p1;
+         break;
+         }
+      }
+   for (i=0; i<MAX_SETUP_STRINGS; i++)
+      setup_used[i] = 0;
+}
+
+
+/* check_setup_strings() returns index if key found, 0 if not
+ */
+
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
+{
+int x;
+char *cp;
+
+   for  (x=0; x<MAX_SETUP_STRINGS; x++) {
+      if (setup_used[x])
+         continue;
+      if (!strncmp(setup_strings[x], key, strlen(key)))
+         break;
+      if (!strncmp(setup_strings[x], "next", strlen("next")))
+         return 0;
+      }
+   if (x == MAX_SETUP_STRINGS)
+      return 0;
+   setup_used[x] = 1;
+   cp = setup_strings[x] + strlen(key);
+   *val = -1;
+   if (*cp != ':')
+      return ++x;
+   cp++;
+   if ((*cp >= '0') && (*cp <= '9')) {
+      *val = simple_strtoul(cp,NULL,0);
+      }
+   return ++x;
+}
+
+
+
+/*
+ * KNOWN BUGS :
+ * - There is some sort of conflict when the PPP driver is compiled with 
+ * 	support for 16 channels?
+ * 
+ * - On systems which predate the 1.3.x initialization order change,
+ *      the NCR driver will cause Cannot get free page messages to appear.  
+ *      These are harmless, but I don't know of an easy way to avoid them.
+ *
+ * - With OPTION_DISCONNECT, on two systems under unknown circumstances,
+ *	we get a PHASE MISMATCH with DSA set to zero (suggests that we 
+ *	are occurring somewhere in the reselection code) where 
+ *	DSP=some value DCMD|DBC=same value.  
+ * 	
+ *	Closer inspection suggests that we may be trying to execute
+ *	some portion of the DSA?
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : no current command : unexpected phase MSGIN.
+ *         DSP=0x1c46cc, DCMD|DBC=0x1c46ac, DSA=0x0
+ *         DSPS=0x0, TEMP=0x1c3e70, DMODE=0x80
+ * scsi0 : DSP->
+ * 001c46cc : 0x001c46cc 0x00000000
+ * 001c46d4 : 0x001c5ea0 0x000011f8
+ *
+ *	Changed the print code in the phase_mismatch handler so
+ *	that we call print_lots to try to diagnose this.
+ *
+ */
+
+/* 
+ * Possible future direction of architecture for max performance :
+ *
+ * We're using a single start array for the NCR chip.  This is 
+ * sub-optimal, because we cannot add a command which would conflict with 
+ * an executing command to this start queue, and therefore must insert the 
+ * next command for a given I/T/L combination after the first has completed;
+ * incurring our interrupt latency between SCSI commands.
+ *
+ * To allow further pipelining of the NCR and host CPU operation, we want 
+ * to set things up so that immediately on termination of a command destined 
+ * for a given LUN, we get that LUN busy again.  
+ * 
+ * To do this, we need to add a 32 bit pointer to which is jumped to 
+ * on completion of a command.  If no new command is available, this 
+ * would point to the usual DSA issue queue select routine.
+ *
+ * If one were, it would point to a per-NCR53c7x0_cmd select routine 
+ * which starts execution immediately, inserting the command at the head 
+ * of the start queue if the NCR chip is selected or reselected.
+ *
+ * We would change so that we keep a list of outstanding commands 
+ * for each unit, rather than a single running_list.  We'd insert 
+ * a new command into the right running list; if the NCR didn't 
+ * have something running for that yet, we'd put it in the 
+ * start queue as well.  Some magic needs to happen to handle the 
+ * race condition between the first command terminating before the 
+ * new one is written.
+ *
+ * Potential for profiling : 
+ * Call do_gettimeofday(struct timeval *tv) to get 800ns resolution.
+ */
+
+
+/*
+ * TODO : 
+ * 1.  To support WIDE transfers, not much needs to happen.  We
+ *	should do CHMOVE instructions instead of MOVEs when
+ *	we have scatter/gather segments of uneven length.  When
+ * 	we do this, we need to handle the case where we disconnect
+ *	between segments.
+ * 
+ * 2.  Currently, when Icky things happen we do a FATAL().  Instead,
+ *     we want to do an integrity check on the parts of the NCR hostdata
+ *     structure which were initialized at boot time; FATAL() if that 
+ *     fails, and otherwise try to recover.  Keep track of how many
+ *     times this has happened within a single SCSI command; if it 
+ *     gets excessive, then FATAL().
+ *
+ * 3.  Parity checking is currently disabled, and a few things should 
+ *     happen here now that we support synchronous SCSI transfers :
+ *     1.  On soft-reset, we shoould set the EPC (Enable Parity Checking)
+ *	   and AAP (Assert SATN/ on parity error) bits in SCNTL0.
+ *	
+ *     2.  We should enable the parity interrupt in the SIEN0 register.
+ * 
+ *     3.  intr_phase_mismatch() needs to believe that message out is 
+ *	   always an "acceptable" phase to have a mismatch in.  If 
+ *	   the old phase was MSG_IN, we should send a MESSAGE PARITY 
+ *	   error.  If the old phase was something else, we should send
+ *	   a INITIATOR_DETECTED_ERROR message.  Note that this could
+ *	   cause a RESTORE POINTERS message; so we should handle that 
+ *	   correctly first.  Instead, we should probably do an 
+ *	   initiator_abort.
+ *
+ * 4.  MPEE bit of CTEST4 should be set so we get interrupted if 
+ *     we detect an error.
+ *
+ *  
+ * 5.  The initial code has been tested on the NCR53c810.  I don't 
+ *     have access to NCR53c700, 700-66 (Forex boards), NCR53c710
+ *     (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to 
+ *     finish development on those platforms.
+ *
+ *     NCR53c820/825/720 - need to add wide transfer support, including WDTR 
+ *     		negotiation, programming of wide transfer capabilities
+ *		on reselection and table indirect selection.
+ *
+ *     NCR53c710 - need to add fatal interrupt or GEN code for 
+ *		command completion signaling.   Need to modify all 
+ *		SDID, SCID, etc. registers, and table indirect select code 
+ *		since these use bit fielded (ie 1<<target) instead of 
+ *		binary encoded target ids.  Need to accommodate
+ *		different register mappings, probably scan through
+ *		the SCRIPT code and change the non SFBR register operand
+ *		of all MOVE instructions.
+ *
+ *		It is rather worse than this actually, the 710 corrupts
+ *		both TEMP and DSA when you do a MOVE MEMORY.  This
+ *		screws you up all over the place.  MOVE MEMORY 4 with a
+ *		destination of DSA seems to work OK, which helps some.
+ *		Richard Hirst  richard@sleepie.demon.co.uk
+ * 
+ *     NCR53c700/700-66 - need to add code to refix addresses on 
+ *		every nexus change, eliminate all table indirect code,
+ *		very messy.
+ *
+ * 6.  The NCR53c7x0 series is very popular on other platforms that 
+ *     could be running Linux - ie, some high performance AMIGA SCSI 
+ *     boards use it.  
+ *	
+ *     So, I should include #ifdef'd code so that it is 
+ *     compatible with these systems.
+ *	
+ *     Specifically, the little Endian assumptions I made in my 
+ *     bit fields need to change, and if the NCR doesn't see memory
+ *     the right way, we need to provide options to reverse words
+ *     when the scripts are relocated.
+ *
+ * 7.  Use vremap() to access memory mapped boards.  
+ */
+
+/* 
+ * Allow for simultaneous existence of multiple SCSI scripts so we 
+ * can have a single driver binary for all of the family.
+ *
+ * - one for NCR53c700 and NCR53c700-66 chips	(not yet supported)
+ * - one for rest (only the NCR53c810, 815, 820, and 825 are currently 
+ *	supported)
+ * 
+ * So that we only need two SCSI scripts, we need to modify things so
+ * that we fixup register accesses in READ/WRITE instructions, and 
+ * we'll also have to accommodate the bit vs. binary encoding of IDs
+ * with the 7xx chips.
+ */
+
+#define ROUNDUP(adr,type)	\
+  ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))
+
+
+/*
+ * Function: issue_to_cmd
+ *
+ * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd
+ *	structure pointer.  
+ *
+ * Inputs; issue - pointer to start of NOP or JUMP instruction
+ *	in issue array.
+ *
+ * Returns: pointer to command on success; 0 if opcode is NOP.
+ */
+
+static inline struct NCR53c7x0_cmd *
+issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+    u32 *issue)
+{
+    return (issue[0] != hostdata->NOP_insn) ? 
+    /* 
+     * If the IF TRUE bit is set, it's a JUMP instruction.  The
+     * operand is a bus pointer to the dsa_begin routine for this DSA.  The
+     * dsa field of the NCR53c7x0_cmd structure starts with the 
+     * DSA code template.  By converting to a virtual address,
+     * subtracting the code template size, and offset of the 
+     * dsa field, we end up with a pointer to the start of the 
+     * structure (alternatively, we could use the 
+     * dsa_cmnd field, an anachronism from when we weren't
+     * sure what the relationship between the NCR structures
+     * and host structures were going to be.
+     */
+	(struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) - 
+	    (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
+	    offsetof(struct NCR53c7x0_cmd, dsa)) 
+    /* If the IF TRUE bit is not set, it's a NOP */
+	: NULL;
+}
+
+
+/* 
+ * FIXME: we should junk these, in favor of synchronous_want and 
+ * wide_want in the NCR53c7x0_hostdata structure.
+ */
+
+/* Template for "preferred" synchronous transfer parameters. */
+
+static const unsigned char sdtr_message[] = {
+#ifdef CONFIG_SCSI_NCR53C7xx_FAST
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */
+#else
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */ 
+#endif
+};
+
+/* Template to request asynchronous transfers */
+
+static const unsigned char async_message[] = {
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */
+};
+
+/* Template for "preferred" WIDE transfer parameters */
+
+static const unsigned char wdtr_message[] = {
+    EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
+};
+
+/*
+ * Function : struct Scsi_Host *find_host (int host)
+ * 
+ * Purpose : KGDB support function which translates a host number 
+ * 	to a host structure. 
+ *
+ * Inputs : host - number of SCSI host
+ *
+ * Returns : NULL on failure, pointer to host structure on success.
+ */
+
+static struct Scsi_Host *
+find_host (int host) {
+    struct Scsi_Host *h;
+    for (h = first_host; h && h->host_no != host; h = h->next);
+    if (!h) {
+	printk (KERN_ALERT "scsi%d not found\n", host);
+	return NULL;
+    } else if (h->hostt != the_template) {
+	printk (KERN_ALERT "scsi%d is not a NCR board\n", host);
+	return NULL;
+    }
+    return h;
+}
+
+/*
+ * Function : request_synchronous (int host, int target)
+ * 
+ * Purpose : KGDB interface which will allow us to negotiate for 
+ * 	synchronous transfers.  This ill be replaced with a more 
+ * 	integrated function; perhaps a new entry in the scsi_host 
+ *	structure, accessible via an ioctl() or perhaps /proc/scsi.
+ *
+ * Inputs : host - number of SCSI host; target - number of target.
+ *
+ * Returns : 0 when negotiation has been setup for next SCSI command,
+ *	-1 on failure.
+ */
+
+static int
+request_synchronous (int host, int target) {
+    struct Scsi_Host *h;
+    struct NCR53c7x0_hostdata *hostdata;
+    unsigned long flags;
+    if (target < 0) {
+	printk (KERN_ALERT "target %d is bogus\n", target);
+	return -1;
+    }
+    if (!(h = find_host (host)))
+	return -1;
+    else if (h->this_id == target) {
+	printk (KERN_ALERT "target %d is host ID\n", target);
+	return -1;
+    } 
+    else if (target > h->max_id) {
+	printk (KERN_ALERT "target %d exceeds maximum of %d\n", target,
+	    h->max_id);
+	return -1;
+    }
+    hostdata = (struct NCR53c7x0_hostdata *)h->hostdata;
+
+    save_flags(flags);
+    cli();
+    if (hostdata->initiate_sdtr & (1 << target)) {
+	restore_flags(flags);
+	printk (KERN_ALERT "target %d already doing SDTR\n", target);
+	return -1;
+    } 
+    hostdata->initiate_sdtr |= (1 << target);
+    restore_flags(flags);
+    return 0;
+}
+
+/*
+ * Function : request_disconnect (int host, int on_or_off)
+ * 
+ * Purpose : KGDB support function, tells us to allow or disallow 
+ *	disconnections.
+ *
+ * Inputs : host - number of SCSI host; on_or_off - non-zero to allow,
+ *	zero to disallow.
+ *
+ * Returns : 0 on success, *	-1 on failure.
+ */
+
+static int 
+request_disconnect (int host, int on_or_off) {
+    struct Scsi_Host *h;
+    struct NCR53c7x0_hostdata *hostdata;
+    if (!(h = find_host (host)))
+	return -1;
+    hostdata = (struct NCR53c7x0_hostdata *) h->hostdata;
+    if (on_or_off) 
+	hostdata->options |= OPTION_DISCONNECT;
+    else
+	hostdata->options &= ~OPTION_DISCONNECT;
+    return 0;
+}
+
+/*
+ * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
+ *
+ * Purpose : Initialize internal structures, as required on startup, or 
+ *	after a SCSI bus reset.
+ * 
+ * Inputs : host - pointer to this host adapter's structure
+ */
+
+static void 
+NCR53c7x0_driver_init (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    int i, j;
+    u32 *ncrcurrent;
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    for (i = 0; i < 16; ++i) {
+	hostdata->request_sense[i] = 0;
+    	for (j = 0; j < 8; ++j) 
+	    hostdata->busy[i][j] = 0;
+	set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0);
+    }
+    hostdata->issue_queue = NULL;
+    hostdata->running_list = hostdata->finished_queue = 
+	hostdata->ncrcurrent = NULL;
+    for (i = 0, ncrcurrent = (u32 *) hostdata->schedule; 
+	i < host->can_queue; ++i, ncrcurrent += 2) {
+	ncrcurrent[0] = hostdata->NOP_insn;
+	ncrcurrent[1] = 0xdeadbeef;
+    }
+    ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+    ncrcurrent[1] = (u32) virt_to_bus (hostdata->script) +
+	hostdata->E_wait_reselect;
+    hostdata->reconnect_dsa_head = 0;
+    hostdata->addr_reconnect_dsa_head = (u32) 
+	virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+    hostdata->expecting_iid = 0;
+    hostdata->expecting_sto = 0;
+    if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS) 
+	hostdata->initiate_sdtr = 0xffff; 
+    else
+    	hostdata->initiate_sdtr = 0;
+    hostdata->talked_to = 0;
+    hostdata->idle = 1;
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/* 
+ * Function : static int clock_to_ccf_710 (int clock)
+ *
+ * Purpose :  Return the clock conversion factor for a given SCSI clock.
+ *
+ * Inputs : clock - SCSI clock expressed in Hz.
+ *
+ * Returns : ccf on success, -1 on failure.
+ */
+
+static int 
+clock_to_ccf_710 (int clock) {
+    if (clock <= 16666666)
+	return -1;
+    if (clock <= 25000000)
+	return 2; 	/* Divide by 1.0 */
+    else if (clock <= 37500000)
+	return 1; 	/* Divide by 1.5 */
+    else if (clock <= 50000000)
+	return 0;	/* Divide by 2.0 */
+    else if (clock <= 66000000)
+	return 3;	/* Divide by 3.0 */
+    else 
+	return -1;
+}
+    
+/* 
+ * Function : static int NCR53c7x0_init (struct Scsi_Host *host)
+ *
+ * Purpose :  initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : when this function is called, the chip_type 
+ * 	field of the hostdata structure MUST have been set.
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int 
+NCR53c7x0_init (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    int i, ccf;
+    unsigned char revision;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    struct Scsi_Host *search;
+    /* 
+     * There are some things which we need to know about in order to provide
+     * a semblance of support.  Print 'em if they aren't what we expect, 
+     * otherwise don't add to the noise.
+     * 
+     * -1 means we don't know what to expect.
+     */
+    int val, flags;
+    char buf[32];
+    int expected_id = -1;
+    int expected_clock = -1;
+    int uninitialized = 0;
+#ifdef NO_IO_SPACE
+    int expected_mapping = OPTION_MEMORY_MAPPED;
+#else
+    int expected_mapping = OPTION_IO_MAPPED;
+#endif
+    for (i=0;i<7;i++)
+	hostdata->valid_ids[i] = 1;	/* Default all ID's to scan */
+
+    /* Parse commandline flags */
+    if (check_setup_strings("nosync",&flags,&val,buf))
+    {
+	hostdata->options |= OPTION_NO_ASYNC;
+	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+    }
+
+    if (check_setup_strings("nodisconnect",&flags,&val,buf))
+	hostdata->options &= ~OPTION_DISCONNECT;
+
+    if (check_setup_strings("validids",&flags,&val,buf))
+    {
+	for (i=0;i<7;i++) 
+		hostdata->valid_ids[i] = val & (1<<i);
+    }
+ 
+    if  ((i = check_setup_strings("next",&flags,&val,buf)))
+    {
+	while (i)
+		setup_used[--i] = 1;
+    }
+
+
+    NCR53c7x0_local_setup(host);
+
+    switch (hostdata->chip) {
+    case 710:
+    	hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
+    	hostdata->init_save_regs = NULL;
+    	hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
+    	hostdata->init_fixup = NCR53c7x0_init_fixup;
+    	hostdata->soft_reset = NCR53c7x0_soft_reset;
+	hostdata->run_tests = NCR53c7xx_run_tests;
+	expected_clock = hostdata->scsi_clock = 50000000;
+	expected_id = 7;
+    	break;
+    default:
+	printk ("scsi%d : chip type of %d is not supported yet, detaching.\n",
+	    host->host_no, hostdata->chip);
+	scsi_unregister (host);
+	return -1;
+    }
+
+    /* Assign constants accessed by NCR */
+    hostdata->NCR53c7xx_zero = 0;			
+    hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
+    hostdata->NCR53c7xx_msg_abort = ABORT;
+    hostdata->NCR53c7xx_msg_nop = NOP;
+    hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+
+    if (expected_mapping == -1 || 
+	(hostdata->options & (OPTION_MEMORY_MAPPED)) != 
+	(expected_mapping & OPTION_MEMORY_MAPPED))
+	printk ("scsi%d : using %s mapped access\n", host->host_no, 
+	    (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" : 
+	    "io");
+
+    hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ? 
+	DMODE_REG_00 : DMODE_REG_10;
+    hostdata->istat = ((hostdata->chip / 100) == 8) ? 
+    	ISTAT_REG_800 : ISTAT_REG_700;
+
+/* Only the ISTAT register is readable when the NCR is running, so make 
+   sure it's halted. */
+    ncr_halt(host);
+
+/* 
+ * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
+ *	as does the 710 with one bit per SCSI ID.  Conversely, the NCR
+ * 	uses a normal, 3 bit binary representation of these values.
+ *
+ * Get the rest of the NCR documentation, and FIND OUT where the change
+ * was.
+ */
+
+#if 0
+	/* May not be able to do this - chip my not have been set up yet */
+	tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG);
+	for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);
+#else
+	host->this_id = 7;
+#endif
+
+/*
+ * Note : we should never encounter a board setup for ID0.  So,
+ * 	if we see ID0, assume that it was uninitialized and set it
+ * 	to the industry standard 7.
+ */
+    if (!host->this_id) {
+	printk("scsi%d : initiator ID was %d, changing to 7\n",
+	    host->host_no, host->this_id);
+	host->this_id = 7;
+	hostdata->this_id_mask = 1 << 7;
+	uninitialized = 1;
+    };
+
+    if (expected_id == -1 || host->this_id != expected_id)
+    	printk("scsi%d : using initiator ID %d\n", host->host_no,
+    	    host->this_id);
+
+    /*
+     * Save important registers to allow a soft reset.
+     */
+
+    /*
+     * CTEST7 controls cache snooping, burst mode, and support for 
+     * external differential drivers.  This isn't currently used - the
+     * default value may not be optimal anyway.
+     * Even worse, it may never have been set up since reset.
+     */
+	hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
+	revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
+	switch (revision) {
+		case 1:
+			revision = 0;
+			break;
+		case 2:
+			revision = 1;
+			break;
+		case 4: 
+			revision = 2;
+			break;
+		case 8:
+			revision = 3;
+			break;
+		default:
+			revision = 255;
+			break;
+	}
+	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+    /*
+     * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
+     * on 800 series chips, it allows for a totem-pole IRQ driver.
+     * NOTE saved_dcntl currently overwritten in init function.
+     * The value read here may be garbage anyway, MVME166 board at least
+     * does not initialise chip if kernel arrived via tftp.
+     */
+
+    hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
+
+    /*
+     * DMODE controls DMA burst length, and on 700 series chips,
+     * 286 mode and bus width  
+     * NOTE:  On MVME166, chip may have been reset, so this could be a
+     * power-on/reset default value.
+     */
+    hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
+
+    /* 
+     * Now that burst length and enabled/disabled status is known, 
+     * clue the user in on it.  
+     */
+   
+    ccf = clock_to_ccf_710 (expected_clock);
+
+    for (i = 0; i < 16; ++i) 
+	hostdata->cmd_allocated[i] = 0;
+
+    if (hostdata->init_save_regs)
+    	hostdata->init_save_regs (host);
+    if (hostdata->init_fixup)
+    	hostdata->init_fixup (host);
+
+    if (!the_template) {
+	the_template = host->hostt;
+	first_host = host;
+    }
+
+    /* 
+     * Linux SCSI drivers have always been plagued with initialization 
+     * problems - some didn't work with the BIOS disabled since they expected
+     * initialization from it, some didn't work when the networking code
+     * was enabled and registers got scrambled, etc.
+     *
+     * To avoid problems like this, in the future, we will do a soft 
+     * reset on the SCSI chip, taking it back to a sane state.
+     */
+
+    hostdata->soft_reset (host);
+
+#if 1
+    hostdata->debug_count_limit = -1;
+#else
+    hostdata->debug_count_limit = 1;
+#endif
+    hostdata->intrs = -1;
+    hostdata->resets = -1;
+    memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message, 
+	sizeof (hostdata->synchronous_want));
+
+    NCR53c7x0_driver_init (host);
+
+    /*
+     * Set up an interrupt handler if we aren't already sharing an IRQ
+     * with another board.
+     */
+
+#ifdef CONFIG_MVME166
+    if (request_irq(IRQ_MVME166_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+	panic ("Couldn't get SCSI IRQ");
+#ifdef MVME166_INTFLY
+    else if (request_irq(IRQ_MVME166_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+	panic ("Couldn't get INT_FLY IRQ");
+#endif
+#else
+    for (search = first_host; search && !(search->hostt == the_template &&
+	search->irq == host->irq && search != host); search=search->next);
+
+    if (!search) {
+#ifdef CONFIG_AMIGA
+	if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
+#else
+	if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
+#endif
+	    printk("scsi%d : IRQ%d not free, detaching\n"
+	           "         You have either a configuration problem, or a\n"
+                   "         broken BIOS.  You may wish to manually assign\n"
+	           "         an interrupt to the NCR board rather than using\n"
+                   "         an automatic setting.\n", 
+		host->host_no, host->irq);
+	    scsi_unregister (host);
+	    return -1;
+	} 
+    } else {
+	printk("scsi%d : using interrupt handler previously installed for scsi%d\n",
+	    host->host_no, search->host_no);
+    }
+#endif
+
+    if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
+        (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
+    	/* XXX Should disable interrupts, etc. here */
+	scsi_unregister (host);
+    	return -1;
+    } else {
+	if (host->io_port)  {
+	    host->n_io_port = 128;
+	    request_region (host->io_port, host->n_io_port, "ncr53c7xx");
+	}
+    }
+    
+    if (NCR53c7x0_read8 (SBCL_REG) & SBCL_BSY) {
+	printk ("scsi%d : bus wedge, doing SCSI reset\n", host->host_no);
+	hard_reset (host);
+    }
+    return 0;
+}
+
+/* 
+ * Function : static int normal_init(Scsi_Host_Template *tpnt, int board, 
+ *	int chip, u32 base, int io_port, int irq, int dma, int pcivalid,
+ *	unsigned char pci_bus, unsigned char pci_device_fn,
+ *	long long options);
+ *
+ * Purpose : initializes a NCR53c7,8x0 based on base addresses,
+ *	IRQ, and DMA channel.	
+ *	
+ *	Useful where a new NCR chip is backwards compatible with
+ *	a supported chip, but the DEVICE ID has changed so it 
+ *	doesn't show up when the autoprobe does a pcibios_find_device.
+ *
+ * Inputs : tpnt - Template for this SCSI adapter, board - board level
+ *	product, chip - 710
+ * 
+ * Returns : 0 on success, -1 on failure.
+ *
+ */
+
+int 
+ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, 
+    u32 base, int io_port, int irq, int dma, long long options, int clock)
+{
+    struct Scsi_Host *instance;
+    struct NCR53c7x0_hostdata *hostdata;
+    char chip_str[80];
+    int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
+	schedule_size = 0, ok = 0;
+    void *tmp;
+
+    switch (chip) {
+    case 710:
+	schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
+	script_len = NCR53c7xx_script_len;
+    	dsa_len = NCR53c7xx_dsa_len;
+    	options |= OPTION_INTFLY;
+    	sprintf (chip_str, "NCR53c%d", chip);
+    	break;
+    default:
+    	printk("scsi-ncr53c7xx : unsupported SCSI chip %d\n", chip);
+    	return -1;
+    }
+
+    printk("scsi-ncr53c7xx : %s at memory 0x%x, io 0x%x, irq %d",
+    	chip_str, (unsigned) base, io_port, irq);
+    if (dma == DMA_NONE)
+    	printk("\n");
+    else 
+    	printk(", dma %d\n", dma);
+
+    if (options & OPTION_DEBUG_PROBE_ONLY) {
+    	printk ("scsi-ncr53c7xx : probe only enabled, aborting initialization\n");
+    	return -1;
+    }
+
+    max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
+    	/* Size of dynamic part of command structure : */
+	2 * /* Worst case : we don't know if we need DATA IN or DATA out */
+		( 2 * /* Current instructions per scatter/gather segment */ 
+        	  tpnt->sg_tablesize + 
+                  3 /* Current startup / termination required per phase */
+		) *
+	8 /* Each instruction is eight bytes */;
+
+    /* Allocate fixed part of hostdata, dynamic part to hold appropriate
+       SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
+
+       We need a NCR53c7x0_cmd structure for scan_scsis() when we are 
+       not loaded as a module, and when we're loaded as a module, we 
+       can't use a non-dynamically allocated structure because modules
+       are vmalloc()'d, which can allow structures to cross page 
+       boundaries and breaks our physical/virtual address assumptions
+       for DMA.
+
+       So, we stick it past the end of our hostdata structure.
+
+       ASSUMPTION : 
+       	 Regardless of how many simultaneous SCSI commands we allow,
+	 the probe code only executes a _single_ instruction at a time,
+	 so we only need one here, and don't need to allocate NCR53c7x0_cmd
+	 structures for each target until we are no longer in scan_scsis
+	 and kmalloc() has become functional (memory_init() happens 
+	 after all device driver initialization).
+    */
+
+    size = sizeof(struct NCR53c7x0_hostdata) + script_len + 
+    /* Note that alignment will be guaranteed, since we put the command
+       allocated at probe time after the fixed-up SCSI script, which 
+       consists of 32 bit words, aligned on a 32 bit boundary.  But
+       on a 64bit machine we need 8 byte alignment for hostdata->free, so
+       we add in another 4 bytes to take care of potential misalignment
+       */
+	(sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
+
+#ifdef FORCE_DSA_ALIGNMENT
+    /*
+     * 53c710 rev.0 doesn't have an add-with-carry instruction.
+     * Ensure we allocate enough memory to force DSA alignment.
+    */
+    size += 256;
+#endif
+	flushsize = size;
+    instance = scsi_register (tpnt, size);
+    if (!instance)
+	return -1;
+
+    /* FIXME : if we ever support an ISA NCR53c7xx based board, we
+       need to check if the chip is running in a 16 bit mode, and if so 
+       unregister it if it is past the 16M (0x1000000) mark */
+   	
+    hostdata = (struct NCR53c7x0_hostdata *) 
+    	instance->hostdata;
+    hostdata->size = size;
+    hostdata->script_count = script_len / sizeof(u32);
+    hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
+    hostdata->board = board;
+    hostdata->chip = chip;
+
+    /*
+     * Being memory mapped is more desirable, since 
+     *
+     * - Memory accesses may be faster.
+     *
+     * - The destination and source address spaces are the same for 
+     *	 all instructions, meaning we don't have to twiddle dmode or 
+     *	 any other registers.
+     *
+     * So, we try for memory mapped, and if we don't get it,
+     * we go for port mapped, and that failing we tell the user
+     * it can't work.
+     */
+
+    if (base) {
+	instance->base = (unsigned char *) (unsigned long) base;
+	/* Check for forced I/O mapping */
+    	if (!(options & OPTION_IO_MAPPED)) {
+	    options |= OPTION_MEMORY_MAPPED;
+	    ok = 1;
+	}
+    } else {
+	options &= ~OPTION_MEMORY_MAPPED;
+    }
+
+    if (io_port) {
+	instance->io_port = io_port;
+	options |= OPTION_IO_MAPPED;
+	ok = 1;
+    } else {
+	options &= ~OPTION_IO_MAPPED;
+    }
+
+    if (!ok) {
+	printk ("scsi%d : not initializing, no I/O or memory mapping known \n",
+	    instance->host_no);
+	scsi_unregister (instance);
+	return -1;
+    }
+    instance->irq = irq;
+    instance->dma_channel = dma;
+
+    hostdata->options = options;
+    hostdata->dsa_len = dsa_len;
+    hostdata->max_cmd_size = max_cmd_size;
+    hostdata->num_cmds = 1;
+    /* Initialize single command */
+    tmp = (hostdata->script + hostdata->script_count);
+#ifdef FORCE_DSA_ALIGNMENT
+    {
+	void *t = ROUNDUP(tmp, void *);
+	if (((u32)t & 0xff) > CmdPageStart)
+	    t = (void *)((u32)t + 255);
+	t = (void *)(((u32)t & ~0xff) + CmdPageStart);
+        hostdata->free = t;
+	printk ("scsi: Registered size increased by 256 to %d\n", size);
+	printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
+	printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
+			(u32)tmp, (u32)t);
+    }
+#else
+    hostdata->free = ROUNDUP(tmp, void *);
+#endif
+    hostdata->free->real = tmp;
+    hostdata->free->size = max_cmd_size;
+    hostdata->free->free = NULL;
+    hostdata->free->next = NULL;
+    hostdata->extra_allocate = 0;
+
+    /* Allocate command start code space */
+    hostdata->schedule = (chip == 700 || chip == 70066) ?
+	NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);
+
+/* 
+ * For diagnostic purposes, we don't really care how fast things blaze.
+ * For profiling, we want to access the 800ns resolution system clock,
+ * using a 'C' call on the host processor.
+ *
+ * Therefore, there's no need for the NCR chip to directly manipulate
+ * this data, and we should put it wherever is most convenient for 
+ * Linux.
+ */
+    if (track_events) 
+	hostdata->events = (struct NCR53c7x0_event *) (track_events ? 
+	    vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL);
+    else
+	hostdata->events = NULL;
+
+    if (hostdata->events) {
+	memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) *
+	    track_events);	
+	hostdata->event_size = track_events;
+	hostdata->event_index = 0;
+    } else 
+	hostdata->event_size = 0;
+
+    return NCR53c7x0_init(instance);
+}
+
+
+/* 
+ * Function : static void NCR53c7x0_init_fixup (struct Scsi_Host *host)
+ *
+ * Purpose :  copy and fixup the SCSI SCRIPTS(tm) code for this device.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ */
+
+static void 
+NCR53c7x0_init_fixup (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    unsigned char tmp;
+    int i, ncr_to_memory, memory_to_ncr;
+    u32 base;
+    NCR53c7x0_local_setup(host);
+
+
+    /* XXX - NOTE : this code MUST be made endian aware */
+    /*  Copy code into buffer that was allocated at detection time.  */
+    memcpy ((void *) hostdata->script, (void *) SCRIPT, 
+	sizeof(SCRIPT));
+    /* Fixup labels */
+    for (i = 0; i < PATCHES; ++i) 
+	hostdata->script[LABELPATCHES[i]] += 
+    	    virt_to_bus(hostdata->script);
+    /* Fixup addresses of constants that used to be EXTERNAL */
+
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_msg_abort)));
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_msg_reject)));
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_zero)));
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_sink)));
+    patch_abs_32 (hostdata->script, 0, NOP_insn,
+	virt_to_bus(&(hostdata->NOP_insn)));
+    patch_abs_32 (hostdata->script, 0, schedule,
+	virt_to_bus((void *) hostdata->schedule));
+
+    /* Fixup references to external variables: */
+    for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
+       hostdata->script[EXTERNAL_PATCHES[i].offset] +=
+         virt_to_bus(EXTERNAL_PATCHES[i].address);
+
+    /* 
+     * Fixup absolutes set at boot-time.
+     * 
+     * All non-code absolute variables suffixed with "dsa_" and "int_"
+     * are constants, and need no fixup provided the assembler has done 
+     * it for us (I don't know what the "real" NCR assembler does in 
+     * this case, my assembler does the right magic).
+     */
+
+    patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer, 
+    	Ent_dsa_code_save_data_pointer - Ent_dsa_zero);
+    patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers,
+    	Ent_dsa_code_restore_pointers - Ent_dsa_zero);
+    patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
+    	Ent_dsa_code_check_reselect - Ent_dsa_zero);
+
+    /*
+     * Just for the hell of it, preserve the settings of 
+     * Burst Length and Enable Read Line bits from the DMODE 
+     * register.  Make sure SCRIPTS start automagically.
+     */
+
+#if defined(CONFIG_MVME166)
+    /* We know better what we want than 166Bug does! */
+    tmp = DMODE_10_BL_8 | DMODE_10_FC2;
+#else
+    tmp = NCR53c7x0_read8(DMODE_REG_10);
+    tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD |
+								DMODE_710_UO);
+#endif
+
+    if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
+    	base = (u32) host->io_port;
+    	memory_to_ncr = tmp|DMODE_800_DIOM;
+    	ncr_to_memory = tmp|DMODE_800_SIOM;
+    } else {
+    	base = virt_to_bus(host->base);
+	memory_to_ncr = ncr_to_memory = tmp;
+    }
+
+    /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */
+    patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
+    patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
+    patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_REG);
+
+    /*
+     * I needed some variables in the script to be accessible to 
+     * both the NCR chip and the host processor. For these variables,
+     * I made the arbitrary decision to store them directly in the 
+     * hostdata structure rather than in the RELATIVE area of the 
+     * SCRIPTS.
+     */
+    
+
+    patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp);
+    patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr);
+    patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
+
+    patch_abs_32 (hostdata->script, 0, msg_buf, 
+	virt_to_bus((void *)&(hostdata->msg_buf)));
+    patch_abs_32 (hostdata->script, 0, reconnect_dsa_head, 
+    	virt_to_bus((void *)&(hostdata->reconnect_dsa_head)));
+    patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head, 
+	virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head)));
+    patch_abs_32 (hostdata->script, 0, reselected_identify, 
+    	virt_to_bus((void *)&(hostdata->reselected_identify)));
+/* reselected_tag is currently unused */
+#if 0
+    patch_abs_32 (hostdata->script, 0, reselected_tag, 
+    	virt_to_bus((void *)&(hostdata->reselected_tag)));
+#endif
+
+    patch_abs_32 (hostdata->script, 0, test_dest, 
+	virt_to_bus((void*)&hostdata->test_dest));
+    patch_abs_32 (hostdata->script, 0, test_src, 
+	virt_to_bus(&hostdata->test_source));
+    patch_abs_32 (hostdata->script, 0, saved_dsa,
+	virt_to_bus(&hostdata->saved2_dsa));
+    patch_abs_32 (hostdata->script, 0, emulfly,
+	virt_to_bus(&hostdata->emulated_intfly));
+
+    patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, 
+	(unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
+
+/* These are for event logging; the ncr_event enum contains the 
+   actual interrupt numbers. */
+#ifdef A_int_EVENT_SELECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);
+#endif
+#ifdef A_int_EVENT_DISCONNECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);
+#endif
+#ifdef A_int_EVENT_RESELECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);
+#endif
+#ifdef A_int_EVENT_COMPLETE
+   patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);
+#endif
+#ifdef A_int_EVENT_IDLE
+   patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);
+#endif
+#ifdef A_int_EVENT_SELECT_FAILED
+   patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED, 
+	(u32) EVENT_SELECT_FAILED);
+#endif
+#ifdef A_int_EVENT_BEFORE_SELECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT,
+	(u32) EVENT_BEFORE_SELECT);
+#endif
+#ifdef A_int_EVENT_RESELECT_FAILED
+   patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED, 
+	(u32) EVENT_RESELECT_FAILED);
+#endif
+
+    /*
+     * Make sure the NCR and Linux code agree on the location of 
+     * certain fields.
+     */
+
+    hostdata->E_accept_message = Ent_accept_message;
+    hostdata->E_command_complete = Ent_command_complete;		
+    hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout;
+    hostdata->E_data_transfer = Ent_data_transfer;
+    hostdata->E_debug_break = Ent_debug_break;	
+    hostdata->E_dsa_code_template = Ent_dsa_code_template;
+    hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end;
+    hostdata->E_end_data_transfer = Ent_end_data_transfer;
+    hostdata->E_initiator_abort = Ent_initiator_abort;
+    hostdata->E_msg_in = Ent_msg_in;
+    hostdata->E_other_transfer = Ent_other_transfer;
+    hostdata->E_other_in = Ent_other_in;
+    hostdata->E_other_out = Ent_other_out;
+    hostdata->E_reject_message = Ent_reject_message;
+    hostdata->E_respond_message = Ent_respond_message;
+    hostdata->E_select = Ent_select;
+    hostdata->E_select_msgout = Ent_select_msgout;
+    hostdata->E_target_abort = Ent_target_abort;
+#ifdef Ent_test_0
+    hostdata->E_test_0 = Ent_test_0;
+#endif
+    hostdata->E_test_1 = Ent_test_1;
+    hostdata->E_test_2 = Ent_test_2;
+#ifdef Ent_test_3
+    hostdata->E_test_3 = Ent_test_3;
+#endif
+    hostdata->E_wait_reselect = Ent_wait_reselect;
+    hostdata->E_dsa_code_begin = Ent_dsa_code_begin;
+
+    hostdata->dsa_cmdout = A_dsa_cmdout;
+    hostdata->dsa_cmnd = A_dsa_cmnd;
+    hostdata->dsa_datain = A_dsa_datain;
+    hostdata->dsa_dataout = A_dsa_dataout;
+    hostdata->dsa_end = A_dsa_end;			
+    hostdata->dsa_msgin = A_dsa_msgin;
+    hostdata->dsa_msgout = A_dsa_msgout;
+    hostdata->dsa_msgout_other = A_dsa_msgout_other;
+    hostdata->dsa_next = A_dsa_next;
+    hostdata->dsa_select = A_dsa_select;
+    hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero;
+    hostdata->dsa_status = A_dsa_status;
+    hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero + 
+	8 /* destination operand */;
+
+    /* sanity check */
+    if (A_dsa_fields_start != Ent_dsa_code_template_end - 
+    	Ent_dsa_zero) 
+    	printk("scsi%d : NCR dsa_fields start is %d not %d\n",
+    	    host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - 
+    	    Ent_dsa_zero);
+
+    printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
+	virt_to_bus(hostdata->script), hostdata->script);
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static int NCR53c7xx_run_tests (struct Scsi_Host *host)
+ *
+ * Purpose : run various verification tests on the NCR chip, 
+ *	including interrupt generation, and proper bus mastering
+ * 	operation.
+ * 
+ * Inputs : host - a properly initialized Scsi_Host structure
+ *
+ * Preconditions : the NCR chip must be in a halted state.
+ *
+ * Returns : 0 if all tests were successful, -1 on error.
+ * 
+ */
+
+static int 
+NCR53c7xx_run_tests (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    unsigned long timeout;
+    u32 start;
+    int failed, i;
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+
+    /* The NCR chip _must_ be idle to run the test scripts */
+
+    save_flags(flags);
+    cli();
+    if (!hostdata->idle) {
+	printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+	restore_flags(flags);
+	return -1;
+    }
+
+    /* 
+     * Check for functional interrupts, this could work as an
+     * autoprobe routine.
+     */
+
+    if ((hostdata->options & OPTION_DEBUG_TEST1) && 
+	    hostdata->state != STATE_DISABLED) {
+	hostdata->idle = 0;
+	hostdata->test_running = 1;
+	hostdata->test_completed = -1;
+	hostdata->test_dest = 0;
+	hostdata->test_source = 0xdeadbeef;
+	start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
+    	hostdata->state = STATE_RUNNING;
+	printk ("scsi%d : test 1", host->host_no);
+	flush_cache_all();
+	cache_push(virt_to_bus(hostdata->script), flushsize);
+	cache_clear(virt_to_bus(hostdata->script), flushsize);
+	NCR53c7x0_write32 (DSP_REG, start);
+	if (hostdata->options & OPTION_DEBUG_TRACE)
+	    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
+						DCNTL_STD);
+	printk (" started\n");
+	sti();
+
+	/* 
+	 * This is currently a .5 second timeout, since (in theory) no slow 
+	 * board will take that long.  In practice, we've seen one 
+	 * pentium which occassionally fails with this, but works with 
+	 * 10 times as much?
+	 */
+
+	timeout = jiffies + 5 * HZ / 10;
+	while ((hostdata->test_completed == -1) && jiffies < timeout)
+		barrier();
+
+	failed = 1;
+	if (hostdata->test_completed == -1)
+	    printk ("scsi%d : driver test 1 timed out%s\n",host->host_no ,
+		(hostdata->test_dest == 0xdeadbeef) ? 
+		    " due to lost interrupt.\n"
+		    "         Please verify that the correct IRQ is being used for your board,\n"
+		    : "");
+	else if (hostdata->test_completed != 1) 
+	    printk ("scsi%d : test 1 bad interrupt value (%d)\n", 
+		host->host_no, hostdata->test_completed);
+	else 
+	    failed = (hostdata->test_dest != 0xdeadbeef);
+
+	if (hostdata->test_dest != 0xdeadbeef) {
+	    printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
+                    "         probable cache invalidation problem.  Please configure caching\n"
+		    "         as write-through or disabled\n",
+		host->host_no, hostdata->test_dest);
+	}
+
+	if (failed) {
+	    printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n",
+		host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)),
+		hostdata->script, start);
+	    printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
+		NCR53c7x0_read32(DSPS_REG));
+	    restore_flags(flags);
+	    return -1;
+	}
+    	hostdata->test_running = 0;
+    }
+
+    if ((hostdata->options & OPTION_DEBUG_TEST2) && 
+	hostdata->state != STATE_DISABLED) {
+	u32 dsa[48];
+    	unsigned char identify = IDENTIFY(0, 0);
+	unsigned char cmd[6];
+	unsigned char data[36];
+    	unsigned char status = 0xff;
+    	unsigned char msg = 0xff;
+
+    	cmd[0] = INQUIRY;
+    	cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
+    	cmd[4] = sizeof(data); 
+
+    	dsa[2] = 1;
+    	dsa[3] = virt_to_bus(&identify);
+    	dsa[4] = 6;
+    	dsa[5] = virt_to_bus(&cmd);
+    	dsa[6] = sizeof(data);
+    	dsa[7] = virt_to_bus(&data);
+    	dsa[8] = 1;
+    	dsa[9] = virt_to_bus(&status);
+    	dsa[10] = 1;
+    	dsa[11] = virt_to_bus(&msg);
+
+	for (i = 0; i < 6; ++i) {
+#ifdef VALID_IDS
+	    if (!hostdata->valid_ids[i])
+		continue;
+#endif
+	    cli();
+	    if (!hostdata->idle) {
+		printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+		restore_flags(flags);
+		return -1;
+	    }
+
+	    /* 710: bit mapped scsi ID, async   */
+            dsa[0] = (1 << i) << 16;
+	    hostdata->idle = 0;
+	    hostdata->test_running = 2;
+	    hostdata->test_completed = -1;
+	    start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
+	    hostdata->state = STATE_RUNNING;
+	    flush_cache_all();
+	    cache_clear(virt_to_bus(hostdata->script), flushsize);
+	    NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
+	    NCR53c7x0_write32 (DSP_REG, start);
+	    if (hostdata->options & OPTION_DEBUG_TRACE)
+	        NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+				DCNTL_SSM | DCNTL_STD);
+	    sti();
+
+	    timeout = jiffies + 5 * HZ;	/* arbitrary */
+	    while ((hostdata->test_completed == -1) && jiffies < timeout)
+	    	barrier();
+
+	    NCR53c7x0_write32 (DSA_REG, 0);
+
+	    if (hostdata->test_completed == 2) {
+		data[35] = 0;
+		printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
+		    host->host_no, i, data + 8);
+		printk ("scsi%d : status ", host->host_no);
+		print_status (status);
+		printk ("\nscsi%d : message ", host->host_no);
+		print_msg (&msg);
+		printk ("\n");
+	    } else if (hostdata->test_completed == 3) {
+		printk("scsi%d : test 2 no connection with target %d\n",
+		    host->host_no, i);
+		if (!hostdata->idle) {
+		    printk("scsi%d : not idle\n", host->host_no);
+		    restore_flags(flags);
+		    return -1;
+		}
+	    } else if (hostdata->test_completed == -1) {
+		printk ("scsi%d : test 2 timed out\n", host->host_no);
+		restore_flags(flags);
+		return -1;
+	    } 
+	    hostdata->test_running = 0;
+	}
+    }
+
+    restore_flags(flags);
+    return 0;
+}
+
+/*
+ * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer,
+ * 	performing all necessary relocation.
+ *
+ * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large
+ *	enough to hold the NCR53c8xx dsa.
+ */
+
+static void 
+NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
+    Scsi_Cmnd *c = cmd->cmd;
+    struct Scsi_Host *host = c->host;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+    	host->hostdata;
+    int i;
+
+    memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
+    	hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+
+    /* 
+     * Note : within the NCR 'C' code, dsa points to the _start_
+     * of the DSA structure, and _not_ the offset of dsa_zero within
+     * that structure used to facilitate shorter signed offsets
+     * for the 8 bit ALU.
+     * 
+     * The implications of this are that 
+     * 
+     * - 32 bit A_dsa_* absolute values require an additional 
+     * 	 dsa_zero added to their value to be correct, since they are 
+     *   relative to dsa_zero which is in essentially a separate
+     *   space from the code symbols.
+     *
+     * - All other symbols require no special treatment.
+     */
+
+    patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_lun, c->lun);
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+	dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
+	Ent_dsa_code_template + A_dsa_next);
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), 
+    	dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), 
+    	dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710));
+    patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	    dsa_temp_target, 1 << c->target);
+    /* XXX - new pointer stuff */
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_addr_residual, virt_to_bus(&cmd->residual));
+
+    /*  XXX - new start stuff */
+
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+	dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/* 
+ * Function : run_process_issue_queue (void)
+ * 
+ * Purpose : insure that the coroutine is running and will process our 
+ * 	request.  process_issue_queue_running is checked/set here (in an 
+ *	inline function) rather than in process_issue_queue itself to reduce 
+ * 	the chances of stack overflow.
+ *
+ */
+
+static volatile int process_issue_queue_running = 0;
+
+static __inline__ void 
+run_process_issue_queue(void) {
+    unsigned long flags;
+    save_flags (flags);
+    cli();
+    if (!process_issue_queue_running) {
+	process_issue_queue_running = 1;
+        process_issue_queue(flags);
+	/* 
+         * process_issue_queue_running is cleared in process_issue_queue 
+	 * once it can't do more work, and process_issue_queue exits with 
+	 * interrupts disabled.
+	 */
+    }
+    restore_flags (flags);
+}
+
+/*
+ * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int
+ *	result)
+ *
+ * Purpose : mark SCSI command as finished, OR'ing the host portion 
+ *	of the result word into the result field of the corresponding
+ *	Scsi_Cmnd structure, and removing it from the internal queues.
+ *
+ * Inputs : cmd - command, result - entire result field
+ *
+ * Preconditions : the 	NCR chip should be in a halted state when 
+ *	abnormal_finished is run, since it modifies structures which
+ *	the NCR expects to have exclusive access to.
+ */
+
+static void 
+abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
+    Scsi_Cmnd *c = cmd->cmd;
+    struct Scsi_Host *host = c->host;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+    	host->hostdata;
+    unsigned long flags;
+    int left, found;
+    volatile struct NCR53c7x0_cmd * linux_search;
+    volatile struct NCR53c7x0_cmd * volatile *linux_prev;
+    volatile u32 *ncr_prev, *ncrcurrent, ncr_search;
+
+#if 0
+    printk ("scsi%d: abnormal finished\n", host->host_no);
+#endif
+
+    save_flags(flags);
+    cli();
+    found = 0;
+    /* 
+     * Traverse the NCR issue array until we find a match or run out 
+     * of instructions.  Instructions in the NCR issue array are 
+     * either JUMP or NOP instructions, which are 2 words in length.
+     */
+
+
+    for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule; 
+	left > 0; --left, ncrcurrent += 2)
+    {
+	if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd) 
+	{
+	    ncrcurrent[0] = hostdata->NOP_insn;
+	    ncrcurrent[1] = 0xdeadbeef;
+	    ++found;
+	    break;
+	}
+    }
+	
+    /* 
+     * Traverse the NCR reconnect list of DSA structures until we find 
+     * a pointer to this dsa or have found too many command structures.  
+     * We let prev point at the next field of the previous element or 
+     * head of the list, so we don't do anything different for removing 
+     * the head element.  
+     */
+
+    for (left = host->can_queue,
+	    ncr_search = hostdata->reconnect_dsa_head, 
+	    ncr_prev = &hostdata->reconnect_dsa_head;
+	left >= 0 && ncr_search && 
+	    ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start) 
+		!= (char *) cmd->dsa;
+	ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) + 
+	    hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+
+    if (left < 0) 
+	printk("scsi%d: loop detected in ncr reconncect list\n",
+	    host->host_no);
+    else if (ncr_search) 
+	if (found)
+	    printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
+		host->host_no, c->pid);
+	else {
+	    volatile u32 * next = (u32 *) 
+	    	((char *)bus_to_virt(ncr_search) + hostdata->dsa_next);
+	    *ncr_prev = *next;
+/* If we're at the tail end of the issue queue, update that pointer too. */
+	    found = 1;
+	}
+
+    /*
+     * Traverse the host running list until we find this command or discover
+     * we have too many elements, pointing linux_prev at the next field of the 
+     * linux_previous element or head of the list, search at this element.
+     */
+
+    for (left = host->can_queue, linux_search = hostdata->running_list, 
+	    linux_prev = &hostdata->running_list;
+	left >= 0 && linux_search && linux_search != cmd;
+	linux_prev = &(linux_search->next), 
+	    linux_search = linux_search->next, --left);
+    
+    if (left < 0) 
+	printk ("scsi%d: loop detected in host running list for scsi pid %ld\n",
+	    host->host_no, c->pid);
+    else if (linux_search) {
+	*linux_prev = linux_search->next;
+	--hostdata->busy[c->target][c->lun];
+    }
+
+    /* Return the NCR command structure to the free list */
+    cmd->next = hostdata->free;
+    hostdata->free = cmd;
+    c->host_scribble = NULL;
+
+    /* And return */
+    c->result = result;
+    c->scsi_done(c);
+
+    restore_flags(flags);
+    run_process_issue_queue();
+}
+
+/* 
+ * Function : static void intr_break (struct Scsi_Host *host,
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose :  Handler for breakpoint interrupts from a SCSI script
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * 	cmd - pointer to the command (if any) dsa was pointing 
+ * 	to.
+ *
+ */
+
+static void 
+intr_break (struct Scsi_Host *host, struct 
+    NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_break *bp;
+#if 0
+    Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+#endif
+    u32 *dsp;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;		
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+
+    /*
+     * Find the break point corresponding to this address, and 
+     * dump the appropriate debugging information to standard 
+     * output.  
+     */
+    save_flags(flags);
+    cli();
+    flush_cache_all();
+    cache_push(virt_to_bus(hostdata->script), flushsize);
+    dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+    for (bp = hostdata->breakpoints; bp && bp->address != dsp; 
+    	bp = bp->next);
+    if (!bp) 
+    	panic("scsi%d : break point interrupt from %p with no breakpoint!",
+    	    host->host_no, dsp);
+
+    /*
+     * Configure the NCR chip for manual start mode, so that we can 
+     * point the DSP register at the instruction that follows the 
+     * INT int_debug_break instruction.
+     */
+
+    NCR53c7x0_write8 (hostdata->dmode, 
+	NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
+
+    /*
+     * And update the DSP register, using the size of the old 
+     * instruction in bytes.
+     */
+
+    restore_flags(flags);
+}
+/*
+ * Function : static void print_synchronous (const char *prefix, 
+ *	const unsigned char *msg)
+ * 
+ * Purpose : print a pretty, user and machine parsable representation
+ *	of a SDTR message, including the "real" parameters, data
+ *	clock so we can tell transfer rate at a glance.
+ *
+ * Inputs ; prefix - text to prepend, msg - SDTR message (5 bytes)
+ */
+
+static void
+print_synchronous (const char *prefix, const unsigned char *msg) {
+    if (msg[4]) {
+	int Hz = 1000000000 / (msg[3] * 4);
+	int integer = Hz / 1000000;
+	int fraction = (Hz - (integer * 1000000)) / 10000;
+	printk ("%speriod %dns offset %d %d.%02dMHz %s SCSI%s\n",
+	    prefix, (int) msg[3] * 4, (int) msg[4], integer, fraction,
+	    (((msg[3] * 4) < 200) ? "FAST" : "synchronous"),
+	    (((msg[3] * 4) < 200) ? "-II" : ""));
+    } else 
+	printk ("%sasynchronous SCSI\n", prefix);
+}
+
+/*
+ * Function : static void set_synchronous (struct Scsi_Host *host, 
+ *	 	int target, int sxfer, int scntl3, int now_connected)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and 
+ *	target with the given register values; in the indirect
+ *	select operand, reselection script, and chip registers.
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ *	sxfer and scntl3 - NCR registers. now_connected - if non-zero, 
+ *	we should reprogram the registers now too.
+ *
+ *      NOTE:  For 53c710, scntl3 is actually used for SCF bits from
+ *	SBCL, as we don't have a SCNTL3.
+ */
+
+static void
+set_synchronous (struct Scsi_Host *host, int target, int sxfer, int scntl3,
+    int now_connected) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) 
+	host->hostdata;
+    u32 *script;
+    NCR53c7x0_local_setup(host);
+
+    /* These are eight bit registers */
+    sxfer &= 0xff;
+    scntl3 &= 0xff;
+
+    hostdata->sync[target].sxfer_sanity = sxfer;
+    hostdata->sync[target].scntl3_sanity = scntl3;
+
+/* 
+ * HARD CODED : synchronous script is EIGHT words long.  This 
+ * must agree with 53c7.8xx.h
+ */
+
+    if ((hostdata->chip != 700) && (hostdata->chip != 70066)) {
+	hostdata->sync[target].select_indirect = (1 << target) << 16 |
+		(sxfer << 8);
+	hostdata->sync[target].sscf_710 = scntl3;
+
+	script = (u32 *) hostdata->sync[target].script;
+
+	/* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
+	script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+		DCMD_RWRI_OP_MOVE) << 24) |
+		(SBCL_REG << 16) | (scntl3 << 8);
+	script[1] = 0;
+	script += 2;
+
+	script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+	    DCMD_RWRI_OP_MOVE) << 24) |
+		(SXFER_REG << 16) | (sxfer << 8);
+	script[1] = 0;
+	script += 2;
+
+#ifdef DEBUG_SYNC_INTR
+	if (hostdata->options & OPTION_DEBUG_DISCONNECT) {
+	    script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_INT) << 24) | DBC_TCI_TRUE;
+	    script[1] = DEBUG_SYNC_INTR;
+	    script += 2;
+	}
+#endif
+
+	script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_RETURN) << 24) | DBC_TCI_TRUE;
+	script[1] = 0;
+	script += 2;
+    }
+
+    if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) 
+	printk ("scsi%d : target %d sync parameters are sxfer=0x%x, scntl3=0x%x\n",
+	host->host_no, target, sxfer, scntl3);
+
+    if (now_connected) {
+	NCR53c7x0_write8(SBCL_REG, scntl3);
+	NCR53c7x0_write8(SXFER_REG, sxfer);
+    }
+}
+
+
+/*
+ * Function : static int asynchronous (struct Scsi_Host *host, int target)
+ *
+ * Purpose : reprogram between the selected SCSI Host adapter and target 
+ *      (assumed to be currently connected) for asynchronous transfers.
+ *
+ * Inputs : host - SCSI host structure, target - numeric target ID.
+ *
+ * Preconditions : the NCR chip should be in one of the halted states
+ */
+    
+static void
+asynchronous (struct Scsi_Host *host, int target) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    NCR53c7x0_local_setup(host);
+    set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
+	1);
+    printk ("scsi%d : setting target %d to asynchronous SCSI\n",
+	host->host_no, target);
+}
+
+/* 
+ * XXX - do we want to go out of our way (ie, add extra code to selection
+ * 	in the NCR53c710/NCR53c720 script) to reprogram the synchronous
+ * 	conversion bits, or can we be content in just setting the 
+ * 	sxfer bits?  I chose to do so [richard@sleepie.demon.co.uk]
+ */
+
+/* Table for NCR53c8xx synchronous values */
+
+/* This table is also correct for 710, allowing that scf=4 is equivalent
+ * of SSCF=0 (ie use DCNTL, divide by 3) for a 50.01-66.00MHz clock.
+ * For any other clock values, we cannot use entries with SCF values of
+ * 4.  I guess that for a 66MHz clock, the slowest it will set is 2MHz,
+ * and for a 50MHz clock, the slowest will be 2.27Mhz.  Should check
+ * that a device doesn't try and negotiate sync below these limits!
+ */
+ 
+static const struct {
+    int div;		/* Total clock divisor * 10 */
+    unsigned char scf;	/* */
+    unsigned char tp;	/* 4 + tp = xferp divisor */
+} syncs[] = {
+/*	div	scf	tp	div	scf	tp	div	scf	tp */
+    {	40,	1,	0}, {	50,	1,	1}, {	60,	1,	2}, 
+    {	70,	1,	3}, {	75,	2,	1}, {	80,	1,	4},
+    {	90,	1,	5}, {	100,	1,	6}, {	105,	2,	3},
+    {	110,	1,	7}, {	120,	2,	4}, {	135,	2,	5},
+    {	140,	3,	3}, {	150,	2,	6}, {	160,	3,	4},
+    {	165,	2,	7}, {	180,	3,	5}, {	200,	3,	6},
+    {	210,	4,	3}, {	220,	3,	7}, {	240,	4,	4},
+    {	270,	4,	5}, {	300,	4,	6}, {	330,	4,	7}
+};
+
+/*
+ * Function : static void synchronous (struct Scsi_Host *host, int target, 
+ *	char *msg)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and 
+ *	target for synchronous SCSI transfers such that the synchronous 
+ *	offset is less than that requested and period at least as long 
+ *	as that requested.  Also modify *msg such that it contains 
+ *	an appropriate response. 
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ *	msg - synchronous transfer request.
+ */
+
+
+static void 
+synchronous (struct Scsi_Host *host, int target, char *msg) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    int desire, divisor, i, limit;
+    unsigned char scntl3, sxfer;
+/* The diagnostic message fits on one line, even with max. width integers */
+    char buf[80];	
+   
+/* Desired transfer clock in Hz */
+    desire = 1000000000L / (msg[3] * 4);
+/* Scale the available SCSI clock by 10 so we get tenths */
+    divisor = (hostdata->scsi_clock * 10) / desire;
+
+/* NCR chips can handle at most an offset of 8 */
+    if (msg[4] > 8)
+	msg[4] = 8;
+
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk("scsi%d : optimal synchronous divisor of %d.%01d\n", 
+	    host->host_no, divisor / 10, divisor % 10);
+
+    limit = (sizeof(syncs) / sizeof(syncs[0]) -1);
+    for (i = 0; (i < limit) && (divisor > syncs[i].div); ++i);
+
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk("scsi%d : selected synchronous divisor of %d.%01d\n", 
+	    host->host_no, syncs[i].div / 10, syncs[i].div % 10);
+
+    msg[3] = ((1000000000L / hostdata->scsi_clock) * syncs[i].div / 10 / 4);
+
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk("scsi%d : selected synchronous period of %dns\n", host->host_no,
+	    msg[3] * 4);
+
+    scntl3 = syncs[i].scf;
+    sxfer = (msg[4] << SXFER_MO_SHIFT) | (syncs[i].tp << 4);
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk ("scsi%d : sxfer=0x%x scntl3=0x%x\n", 
+	    host->host_no, (int) sxfer, (int) scntl3);
+    set_synchronous (host, target, sxfer, scntl3, 1);
+    sprintf (buf, "scsi%d : setting target %d to ", host->host_no, target);
+    print_synchronous (buf, msg);
+}
+
+/* 
+ * Function : static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host,
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose :  Handler for INT generated instructions for the 
+ * 	NCR53c810/820 SCSI SCRIPT
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * 	cmd - pointer to the command (if any) dsa was pointing 
+ * 	to.
+ *
+ */
+
+static int 
+NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct 
+    NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    int print;
+    Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;		
+    u32 dsps,*dsp;	/* Argument of the INT instruction */
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    NCR53c7x0_local_setup(host);
+    dsps = NCR53c7x0_read32(DSPS_REG);
+    dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+    if (hostdata->options & OPTION_DEBUG_INTR) 
+	printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
+
+    switch (dsps) {
+    case A_int_msg_1:
+	print = 1;
+	switch (hostdata->msg_buf[0]) {
+	/* 
+	 * Unless we've initiated synchronous negotiation, I don't
+	 * think that this should happen.
+	 */
+	case MESSAGE_REJECT:
+	    hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	    if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
+		printk ("scsi%d : target %d rejected SDTR\n", host->host_no, 
+		    c->target);
+		cmd->flags &= ~CMD_FLAG_SDTR;
+		asynchronous (host, c->target);
+		print = 0;
+	    } 
+	    break;
+	case INITIATE_RECOVERY:
+	    printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
+		host->host_no);
+	    /* Fall through to default */
+	    hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	    break;
+	default:
+	    printk ("scsi%d : unsupported message, rejecting\n",
+		host->host_no);
+	    hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	}
+	if (print) {
+	    printk ("scsi%d : received message", host->host_no);
+	    if (c) 
+	    	printk (" from target %d lun %d ", c->target, c->lun);
+	    print_msg ((unsigned char *) hostdata->msg_buf);
+	    printk("\n");
+	}
+	
+	return SPECIFIC_INT_NOTHING;
+
+
+    case A_int_msg_sdtr:
+/*
+ * At this point, hostdata->msg_buf contains
+ * 0 EXTENDED MESSAGE
+ * 1 length 
+ * 2 SDTR
+ * 3 period * 4ns
+ * 4 offset
+ */
+
+	if (cmd) {
+	    char buf[80];
+	    sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->target,
+		(cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
+	    print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
+
+	/* 
+	 * Initiator initiated, won't happen unless synchronous 
+	 * 	transfers are enabled.  If we get a SDTR message in
+	 * 	response to our SDTR, we should program our parameters
+	 * 	such that 
+	 *		offset <= requested offset
+	 *		period >= requested period		 	
+   	 */
+	    if (cmd->flags & CMD_FLAG_SDTR) {
+		cmd->flags &= ~CMD_FLAG_SDTR; 
+		if (hostdata->msg_buf[4]) 
+		    synchronous (host, c->target, (unsigned char *) 
+		    	hostdata->msg_buf);
+		else 
+		    asynchronous (host, c->target);
+		hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+		    sizeof(u32);
+		hostdata->dsp_changed = 1;
+		return SPECIFIC_INT_NOTHING;
+	    } else {
+		if (hostdata->options & OPTION_SYNCHRONOUS)  {
+		    cmd->flags |= CMD_FLAG_DID_SDTR;
+		    synchronous (host, c->target, (unsigned char *) 
+			hostdata->msg_buf);
+		} else {
+		    hostdata->msg_buf[4] = 0;		/* 0 offset = async */
+		    asynchronous (host, c->target);
+		}
+		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32) 
+		    virt_to_bus ((void *)&hostdata->msg_buf));
+		hostdata->dsp = hostdata->script + 
+		    hostdata->E_respond_message / sizeof(u32);
+		hostdata->dsp_changed = 1;
+	    }
+	    return SPECIFIC_INT_NOTHING;
+	}
+	/* Fall through to abort if we couldn't find a cmd, and 
+	   therefore a dsa structure to twiddle */
+    case A_int_msg_wdtr:
+	hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+    case A_int_err_unexpected_phase:
+	if (hostdata->options & OPTION_DEBUG_INTR) 
+	    printk ("scsi%d : unexpected phase\n", host->host_no);
+	return SPECIFIC_INT_ABORT;
+    case A_int_err_selected:
+	if ((hostdata->chip / 100) == 8)
+	    printk ("scsi%d : selected by target %d\n", host->host_no,
+	        (int) NCR53c7x0_read8(SDID_REG_800) &7);
+	else
+            printk ("scsi%d : selected by target LCRC=0x%02x\n", host->host_no,
+                (int) NCR53c7x0_read8(LCRC_REG_10));
+	hostdata->dsp = hostdata->script + hostdata->E_target_abort / 
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+    case A_int_err_unexpected_reselect:
+	if ((hostdata->chip / 100) == 8)
+	    printk ("scsi%d : unexpected reselect by target %d lun %d\n", 
+	        host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & 7,
+	        hostdata->reselected_identify & 7);
+	else
+            printk ("scsi%d : unexpected reselect LCRC=0x%02x\n", host->host_no,
+                (int) NCR53c7x0_read8(LCRC_REG_10));
+	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+/*
+ * Since contingent allegiance conditions are cleared by the next 
+ * command issued to a target, we must issue a REQUEST SENSE 
+ * command after receiving a CHECK CONDITION status, before
+ * another command is issued.
+ * 
+ * Since this NCR53c7x0_cmd will be freed after use, we don't 
+ * care if we step on the various fields, so modify a few things.
+ */
+    case A_int_err_check_condition: 
+#if 0
+	if (hostdata->options & OPTION_DEBUG_INTR) 
+#endif
+	    printk ("scsi%d : CHECK CONDITION\n", host->host_no);
+	if (!c) {
+	    printk("scsi%d : CHECK CONDITION with no SCSI command\n",
+		host->host_no);
+	    return SPECIFIC_INT_PANIC;
+	}
+
+	/* 
+	 * FIXME : this uses the normal one-byte selection message.
+	 * 	We may want to renegotiate for synchronous & WIDE transfers
+	 * 	since these could be the crux of our problem.
+	 *
+	 hostdata->NOP_insn* FIXME : once SCSI-II tagged queuing is implemented, we'll
+	 * 	have to set this up so that the rest of the DSA
+	 *	agrees with this being an untagged queue'd command.
+	 */
+
+    	patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+
+    	/* 
+    	 * Modify the table indirect for COMMAND OUT phase, since 
+    	 * Request Sense is a six byte command.
+    	 */
+
+    	patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+
+	c->cmnd[0] = REQUEST_SENSE;
+	c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
+	c->cmnd[2] = 0;
+	c->cmnd[3] = 0;
+	c->cmnd[4] = sizeof(c->sense_buffer);
+	c->cmnd[5] = 0; 
+
+	/*
+	 * Disable dataout phase, and program datain to transfer to the 
+	 * sense buffer, and add a jump to other_transfer after the 
+    	 * command so overflow/underrun conditions are detected.
+	 */
+
+    	patch_dsa_32 (cmd->dsa, dsa_dataout, 0, 
+	    virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+    	patch_dsa_32 (cmd->dsa, dsa_datain, 0, 
+	    virt_to_bus(cmd->data_transfer_start));
+    	cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
+    	    DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
+    	cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+
+	cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
+    	    << 24) | DBC_TCI_TRUE;
+	cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) + 
+	    hostdata->E_other_transfer;
+
+    	/*
+    	 * Currently, this command is flagged as completed, ie 
+    	 * it has valid status and message data.  Reflag it as
+    	 * incomplete.  Q - need to do something so that original
+	 * status, etc are used.
+    	 */
+
+	cmd->cmd->result = 0xffff;		
+
+	/* 
+	 * Restart command as a REQUEST SENSE.
+	 */
+	hostdata->dsp = (u32 *) hostdata->script + hostdata->E_select /
+	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+    case A_int_debug_break:
+	return SPECIFIC_INT_BREAK;
+    case A_int_norm_aborted:
+	hostdata->dsp = (u32 *) hostdata->schedule;
+	hostdata->dsp_changed = 1;
+	if (cmd)
+	    abnormal_finished (cmd, DID_ERROR << 16);
+	return SPECIFIC_INT_NOTHING;
+    case A_int_norm_emulateintfly:
+	/* I'm not sure this is the right ! thing to do, but it works
+	 * with the A4000T when copyback is disabled, and also the
+	 * WarpEngine with copyback enabled, so it looks as though
+	 * it does work to some extent.
+	 *
+	 * RGH:  I don't really like it - You get an interrupt which
+	 * calls NCR53c7x0_intr(), which calls this function (via
+	 * intr_dma()), which calls NCR53c7x0_intr().....
+	 * Anyway lets see how it goes for now.
+	 */
+	hostdata->emulated_intfly = 1;
+	NCR53c7x0_intr(host->irq, NULL, NULL);
+	return SPECIFIC_INT_NOTHING;
+    case A_int_test_1:
+    case A_int_test_2:
+	hostdata->idle = 1;
+	hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
+	if (hostdata->options & OPTION_DEBUG_INTR)
+	    printk("scsi%d : test%d complete\n", host->host_no,
+		hostdata->test_completed);
+	return SPECIFIC_INT_NOTHING;
+#ifdef A_int_debug_reselected_ok
+    case A_int_debug_reselected_ok:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    	OPTION_DEBUG_DISCONNECT)) {
+	    /* 
+	     * Note - this dsa is not based on location relative to 
+	     * the command structure, but to location relative to the 
+	     * DSA register 
+	     */	
+	    u32 *dsa;
+	    dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+	    printk("scsi%d : reselected_ok (DSA = 0x%x (virt 0x%p)\n", 
+		host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
+	    printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+		    host->host_no, cmd->saved_data_pointer,
+		    bus_to_virt(cmd->saved_data_pointer));
+	    print_insn (host, hostdata->script + Ent_reselected_ok / 
+    	    	    sizeof(u32), "", 1);
+	    if ((hostdata->chip / 100) == 8)
+    	        printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+		    host->host_no, NCR53c7x0_read8(SXFER_REG),
+		    NCR53c7x0_read8(SCNTL3_REG_800));
+	    else
+    	        printk ("scsi%d : sxfer=0x%x, cannot read SBCL\n",
+		    host->host_no, NCR53c7x0_read8(SXFER_REG));
+	    if (c) {
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->target].script, "", 1);
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->target].script + 2, "", 1);
+	    }
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_reselect_check
+    case A_int_debug_reselect_check:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    u32 *dsa;
+#if 0
+	    u32 *code;
+#endif
+	    /* 
+	     * Note - this dsa is not based on location relative to 
+	     * the command structure, but to location relative to the 
+	     * DSA register 
+	     */	
+	    dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+	    printk("scsi%d : reselected_check_next (DSA = 0x%lx (virt 0x%p))\n",
+		host->host_no, virt_to_bus(dsa), dsa);
+	    if (dsa) {
+		printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+		    host->host_no, cmd->saved_data_pointer,
+		    bus_to_virt (cmd->saved_data_pointer));
+#if 0
+		printk("scsi%d : template code :\n", host->host_no);
+		for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero) 
+		    / sizeof(u32); code < (dsa + Ent_dsa_zero / sizeof(u32)); 
+		    code += print_insn (host, code, "", 1));
+#endif
+	    }
+	    print_insn (host, hostdata->script + Ent_reselected_ok / 
+    	    	    sizeof(u32), "", 1);
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_schedule
+    case A_int_debug_dsa_schedule:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    u32 *dsa;
+	    /* 
+	     * Note - this dsa is not based on location relative to 
+	     * the command structure, but to location relative to the 
+	     * DSA register 
+	     */	
+	    dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+	    printk("scsi%d : dsa_schedule (old DSA = 0x%lx (virt 0x%p))\n", 
+		host->host_no, virt_to_bus(dsa), dsa);
+	    if (dsa) 
+		printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
+		       "         (temp was 0x%x (virt 0x%p))\n",
+		    host->host_no, cmd->saved_data_pointer,
+		    bus_to_virt (cmd->saved_data_pointer),
+		    NCR53c7x0_read32 (TEMP_REG),
+		    bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_scheduled
+    case A_int_debug_scheduled:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : new I/O 0x%x (virt 0x%p) scheduled\n", 
+		host->host_no, NCR53c7x0_read32(DSA_REG),
+	    	bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_idle
+    case A_int_debug_idle:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : idle\n", host->host_no);
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_cmd
+    case A_int_debug_cmd:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : command sent\n");
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_loaded
+    case A_int_debug_dsa_loaded:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : DSA loaded with 0x%x (virt 0x%p)\n", host->host_no,
+		NCR53c7x0_read32(DSA_REG), 
+		bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+	}
+	return SPECIFIC_INT_RESTART; 
+#endif
+#ifdef A_int_debug_reselected
+    case A_int_debug_reselected:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+	    OPTION_DEBUG_DISCONNECT)) {
+	    if ((hostdata->chip / 100) == 8)
+		printk("scsi%d : reselected by target %d lun %d\n",
+		    host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & ~0x80, 
+		    (int) hostdata->reselected_identify & 7);
+	    else
+		printk("scsi%d : reselected by LCRC=0x%02x lun %d\n",
+                    host->host_no, (int) NCR53c7x0_read8(LCRC_REG_10),
+                    (int) hostdata->reselected_identify & 7);
+	    print_queues(host);
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnect_msg
+    case A_int_debug_disconnect_msg:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    if (c)
+		printk("scsi%d : target %d lun %d disconnecting\n", 
+		    host->host_no, c->target, c->lun);
+	    else
+		printk("scsi%d : unknown target disconnecting\n",
+		    host->host_no);
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnected
+    case A_int_debug_disconnected:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+		OPTION_DEBUG_DISCONNECT)) {
+	    printk ("scsi%d : disconnected, new queues are\n", 
+		host->host_no);
+	    print_queues(host);
+#if 0
+	    /* Not valid on ncr53c710! */
+    	    printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+		host->host_no, NCR53c7x0_read8(SXFER_REG),
+		NCR53c7x0_read8(SCNTL3_REG_800));
+#endif
+	    if (c) {
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->target].script, "", 1);
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->target].script + 2, "", 1);
+	    }
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_panic
+    case A_int_debug_panic:
+	printk("scsi%d : int_debug_panic received\n", host->host_no);
+	print_lots (host);
+	return SPECIFIC_INT_PANIC;
+#endif
+#ifdef A_int_debug_saved
+    case A_int_debug_saved:
+    	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    OPTION_DEBUG_DISCONNECT)) {
+    	    printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
+    	    	host->host_no, cmd->saved_data_pointer,
+		bus_to_virt (cmd->saved_data_pointer));
+    	    print_progress (c);
+    	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_restored
+    case A_int_debug_restored:
+    	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    OPTION_DEBUG_DISCONNECT)) {
+    	    if (cmd) {
+		int size;
+    	    	printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
+    	    	    host->host_no, cmd->saved_data_pointer, bus_to_virt (
+		    cmd->saved_data_pointer));
+		size = print_insn (host, (u32 *) 
+		    bus_to_virt(cmd->saved_data_pointer), "", 1);
+		size = print_insn (host, (u32 *) 
+		    bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+    	    	print_progress (c);
+	    }
+#if 0
+	    printk ("scsi%d : datapath residual %d\n",
+		host->host_no, datapath_residual (host)) ;
+#endif
+    	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_sync
+    case A_int_debug_sync:
+    	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+	    unsigned char sxfer = NCR53c7x0_read8 (SXFER_REG), scntl3;
+	    if ((hostdata->chip / 100) == 8) {
+		scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
+		if (c) {
+		  if (sxfer != hostdata->sync[c->target].sxfer_sanity ||
+		    scntl3 != hostdata->sync[c->target].scntl3_sanity) {
+		   	printk ("scsi%d :  sync sanity check failed sxfer=0x%x, scntl3=0x%x",
+			    host->host_no, sxfer, scntl3);
+			NCR53c7x0_write8 (SXFER_REG, sxfer);
+			NCR53c7x0_write8 (SCNTL3_REG_800, scntl3);
+		    }
+		} else 
+    	    	  printk ("scsi%d : unknown command sxfer=0x%x, scntl3=0x%x\n",
+		    host->host_no, (int) sxfer, (int) scntl3);
+	    } else {
+		if (c) {
+		  if (sxfer != hostdata->sync[c->target].sxfer_sanity) {
+		   	printk ("scsi%d :  sync sanity check failed sxfer=0x%x",
+			    host->host_no, sxfer);
+			NCR53c7x0_write8 (SXFER_REG, sxfer);
+			NCR53c7x0_write8 (SBCL_REG,
+				hostdata->sync[c->target].sscf_710);
+		    }
+		} else 
+    	    	  printk ("scsi%d : unknown command sxfer=0x%x\n",
+		    host->host_no, (int) sxfer);
+	    }
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_datain
+	case A_int_debug_datain:
+	    if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+		OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+		int size;
+		if ((hostdata->chip / 100) == 8)
+		  printk ("scsi%d : In do_datain (%s) sxfer=0x%x, scntl3=0x%x\n"
+			"         datapath residual=%d\n",
+		    host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+		    (int) NCR53c7x0_read8(SXFER_REG), 
+		    (int) NCR53c7x0_read8(SCNTL3_REG_800),
+		    datapath_residual (host)) ;
+		else
+		  printk ("scsi%d : In do_datain (%s) sxfer=0x%x\n"
+			"         datapath residual=%d\n",
+		    host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+		    (int) NCR53c7x0_read8(SXFER_REG), 
+		    datapath_residual (host)) ;
+		print_insn (host, dsp, "", 1);
+		size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
+		print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+	   } 
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_check_dsa
+	case A_int_debug_check_dsa:
+	    if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+		int sdid;
+		int tmp;
+		char *where;
+		if (hostdata->chip / 100 == 8)
+		    sdid = NCR53c7x0_read8 (SDID_REG_800) & 15;
+		else {
+		    tmp = NCR53c7x0_read8 (SDID_REG_700);
+		    if (!tmp)
+			panic ("SDID_REG_700 = 0");
+		    tmp >>= 1;
+		    sdid = 0;
+		    while (tmp) {
+			tmp >>= 1;
+			sdid++;
+		    }
+		}
+		where = dsp - NCR53c7x0_insn_size(NCR53c7x0_read8 
+			(DCMD_REG)) == hostdata->script + 
+		    	Ent_select_check_dsa / sizeof(u32) ?
+		    "selection" : "reselection";
+		if (c && sdid != c->target) {
+		    printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
+			host->host_no, sdid, c->target, where);
+		    print_lots(host);
+		    dump_events (host, 20);
+		    return SPECIFIC_INT_PANIC;
+		}
+	    }
+	    return SPECIFIC_INT_RESTART;
+#endif
+    default:
+	if ((dsps & 0xff000000) == 0x03000000) {
+	     printk ("scsi%d : misc debug interrupt 0x%x\n",
+		host->host_no, dsps);
+	    return SPECIFIC_INT_RESTART;
+	} else if ((dsps & 0xff000000) == 0x05000000) {
+	    if (hostdata->events) {
+		struct NCR53c7x0_event *event;
+		++hostdata->event_index;
+		if (hostdata->event_index >= hostdata->event_size)
+		    hostdata->event_index = 0;
+		event = (struct NCR53c7x0_event *) hostdata->events + 
+		    hostdata->event_index;
+		event->event = (enum ncr_event) dsps;
+		event->dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+		if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+		    if (hostdata->chip / 100 == 8)
+			event->target = NCR53c7x0_read8(SSID_REG_800);
+		    else {
+			unsigned char tmp, sdid;
+		        tmp = NCR53c7x0_read8 (SDID_REG_700);
+		        if (!tmp)
+			    panic ("SDID_REG_700 = 0");
+		        tmp >>= 1;
+		        sdid = 0;
+		        while (tmp) {
+			    tmp >>= 1;
+			    sdid++;
+		        }
+			event->target = sdid;
+		    }
+		}
+		else 
+			event->target = 255;
+
+		if (event->event == EVENT_RESELECT)
+		    event->lun = hostdata->reselected_identify & 0xf;
+		else if (c)
+		    event->lun = c->lun;
+		else
+		    event->lun = 255;
+		do_gettimeofday(&(event->time));
+		if (c) {
+		    event->pid = c->pid;
+		    memcpy ((void *) event->cmnd, (void *) c->cmnd, 
+			sizeof (event->cmnd));
+		} else {
+		    event->pid = -1;
+		}
+	    }
+	    return SPECIFIC_INT_RESTART;
+	}
+
+	printk ("scsi%d : unknown user interrupt 0x%x\n", 
+	    host->host_no, (unsigned) dsps);
+	return SPECIFIC_INT_PANIC;
+    }
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+}
+
+/* 
+ * XXX - the stock NCR assembler won't output the scriptu.h file,
+ * which undefine's all #define'd CPP symbols from the script.h
+ * file, which will create problems if you use multiple scripts
+ * with the same  symbol names.
+ *
+ * If you insist on using NCR's assembler, you could generate
+ * scriptu.h from script.h using something like 
+ *
+ * grep #define script.h | \
+ * sed 's/#define[ 	][ 	]*\([_a-zA-Z][_a-zA-Z0-9]*\).*$/#undefine \1/' \
+ * > scriptu.h
+ */
+
+#include "53c7xx_u.h"
+
+/* XXX - add alternate script handling code here */
+
+
+/* 
+ * Function : static void NCR537xx_soft_reset (struct Scsi_Host *host)
+ *
+ * Purpose :  perform a soft reset of the NCR53c7xx chip
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : NCR53c7x0_init must have been called for this 
+ *      host.
+ * 
+ */
+
+static void 
+NCR53c7x0_soft_reset (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+#ifdef CONFIG_MVME166
+    volatile unsigned long v;
+#endif
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    NCR53c7x0_local_setup(host);
+
+    save_flags(flags);
+    cli();
+
+    /* Disable scsi chip and s/w level 7 ints */
+
+#ifdef CONFIG_MVME166
+    v = *(volatile unsigned long *)0xfff4006c;
+    v &= ~0x8000;
+    *(volatile unsigned long *)0xfff4006c = v;
+    v = *(volatile unsigned long *)0xfff4202c;
+    v &= ~0x10;
+    *(volatile unsigned long *)0xfff4202c = v;
+#else
+    /* Anything specific for your hardware? */
+#endif
+
+    /*
+     * Do a soft reset of the chip so that everything is 
+     * reinitialized to the power-on state.
+     *
+     * Basically follow the procedure outlined in the NCR53c700
+     * data manual under Chapter Six, How to Use, Steps Necessary to
+     * Start SCRIPTS, with the exception of actually starting the 
+     * script and setting up the synchronous transfer gunk.
+     */
+
+    /* Should we reset the scsi bus here??????????????????? */
+
+    NCR53c7x0_write8(ISTAT_REG_700, ISTAT_10_SRST);
+    NCR53c7x0_write8(ISTAT_REG_700, 0);
+
+    /*
+     * saved_dcntl is set up in NCR53c7x0_init() before it is overwritten
+     * here.  We should have some better way of working out the CF bit
+     * setting..
+     */
+
+    hostdata->saved_dcntl = DCNTL_10_EA|DCNTL_10_COM;
+    if (hostdata->scsi_clock > 50000000)
+	hostdata->saved_dcntl |= DCNTL_700_CF_3;
+    else
+    if (hostdata->scsi_clock > 37500000)
+        hostdata->saved_dcntl |= DCNTL_700_CF_2;
+#if 0
+    else
+	/* Any clocks less than 37.5MHz? */
+#endif
+
+    if (hostdata->options & OPTION_DEBUG_TRACE)
+    	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
+    else
+    	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
+#if 0
+    /* Following disables snooping - run with caches disabled at first */
+    NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
+#else
+    /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating
+     * cache lines. */
+    NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0);
+#endif
+    /* Actually burst of eight, according to my 53c710 databook */
+    NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
+    NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
+    NCR53c7x0_write8(SBCL_REG, 0);
+    NCR53c7x0_write8(SCNTL1_REG, SCNTL1_ESR_700);
+    NCR53c7x0_write8(SCNTL0_REG, ((hostdata->options & OPTION_PARITY) ? 
+            SCNTL0_EPC : 0) | SCNTL0_EPG_700 | SCNTL0_ARB1 | SCNTL0_ARB2);
+
+    /*
+     * Enable all interrupts, except parity which we only want when
+     * the user requests it.
+     */
+
+    NCR53c7x0_write8(DIEN_REG, DIEN_700_BF |
+		DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
+
+    NCR53c7x0_write8(SIEN_REG_700, ((hostdata->options & OPTION_PARITY) ?
+	    SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
+		SIEN_SGE | SIEN_MA);
+
+#ifdef CONFIG_MVME166
+    /* Enable scsi chip and s/w level 7 ints */
+
+    v = *(volatile unsigned long *)0xfff40080;
+    v = (v & ~(0xf << 28)) | (4 << 28);
+    *(volatile unsigned long *)0xfff40080 = v;
+    v = *(volatile unsigned long *)0xfff4006c;
+    v |= 0x8000;
+    *(volatile unsigned long *)0xfff4006c = v;
+    v = *(volatile unsigned long *)0xfff4202c;
+    v = (v & ~0xff) | 0x10 | 4;
+    *(volatile unsigned long *)0xfff4202c = v;
+#else
+    /* Anything needed for your hardware */
+#endif
+    restore_flags(flags);
+}
+
+
+/*
+ * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : Return the first free NCR53c7x0_cmd structure (which are 
+ * 	reused in a LIFO manner to minimize cache thrashing).
+ *
+ * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
+ *	structures for this device, do so.  Attempt to complete all scheduled
+ *	allocations using kmalloc(), putting NCR53c7x0_cmd structures on
+ *	the free list.  Teach programmers not to drink and hack.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure allocated on behalf of cmd;
+ *	NULL on failure.
+ */
+
+static struct NCR53c7x0_cmd *
+allocate_cmd (Scsi_Cmnd *cmd) {
+    struct Scsi_Host *host = cmd->host;
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata;
+    void *real;			/* Real address */
+    int size;			/* Size of *tmp */
+    struct NCR53c7x0_cmd *tmp;
+    unsigned long flags;
+
+    if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+	printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
+		"         target = %d, lun = %d, %s\n",
+	    host->host_no, hostdata->num_cmds, host->can_queue,
+	    cmd->target, cmd->lun, (hostdata->cmd_allocated[cmd->target] &
+		(1 << cmd->lun)) ? "already allocated" : "not allocated");
+
+/*
+ * If we have not yet reserved commands for this I_T_L nexus, and
+ * the device exists (as indicated by permanent Scsi_Cmnd structures
+ * being allocated under 1.3.x, or being outside of scan_scsis in
+ * 1.2.x), do so now.
+ */
+    if (!(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun)) &&
+				cmd->device && cmd->device->has_cmdblocks) {
+      if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
+          hostdata->extra_allocate += host->cmd_per_lun;
+      hostdata->cmd_allocated[cmd->target] |= (1 << cmd->lun);
+    }
+
+    for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate, 
+    	++hostdata->num_cmds) {
+    /* historically, kmalloc has returned unaligned addresses; pad so we
+       have enough room to ROUNDUP */
+	size = hostdata->max_cmd_size + sizeof (void *);
+#ifdef FORCE_DSA_ALIGNMENT
+	/*
+	 * 53c710 rev.0 doesn't have an add-with-carry instruction.
+	 * Ensure we allocate enough memory to force alignment.
+	 */
+	size += 256;
+#endif
+/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
+	real = kmalloc (size, GFP_ATOMIC);
+	if (!real) {
+	    if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+		printk ("scsi%d : kmalloc(%d) failed\n",
+		    host->host_no, size);
+	    break;
+	}
+	tmp = ROUNDUP(real, void *);
+#ifdef FORCE_DSA_ALIGNMENT
+	{
+	    if (((u32)tmp & 0xff) > CmdPageStart)
+		tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
+	    tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
+#ifdef DEBUG
+	    printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
+			size, (u32)real, (u32)tmp);
+#endif
+	}
+#endif
+	tmp->real = real;
+	tmp->size = size;			
+	tmp->free = ((void (*)(void *, int)) kfree);
+	save_flags (flags);
+	cli();
+	tmp->next = hostdata->free;
+	hostdata->free = tmp;
+	restore_flags (flags);
+    }
+    save_flags(flags);
+    cli();
+    tmp = (struct NCR53c7x0_cmd *) hostdata->free;
+    if (tmp) {
+	hostdata->free = tmp->next;
+    }
+    restore_flags(flags);
+    if (!tmp)
+	printk ("scsi%d : can't allocate command for target %d lun %d\n",
+	    host->host_no, cmd->target, cmd->lun);
+    return tmp;
+}
+
+/*
+ * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) 
+ *
+ *
+ * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the 
+ * 	Scsi_Cmnd structure passed in cmd, including dsa and Linux field 
+ * 	initialization, and dsa code relocation.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure corresponding to cmd,
+ *	NULL on failure.
+ */
+static struct NCR53c7x0_cmd *
+create_cmd (Scsi_Cmnd *cmd) {
+    NCR53c7x0_local_declare();
+    struct Scsi_Host *host = cmd->host;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+        host->hostdata;	
+    struct NCR53c7x0_cmd *tmp; 	/* NCR53c7x0_cmd structure for this command */
+    int datain,  		/* Number of instructions per phase */
+	dataout;
+    int data_transfer_instructions, /* Count of dynamic instructions */
+    	i;			/* Counter */
+    u32 *cmd_datain,		/* Address of datain/dataout code */
+	*cmd_dataout;		/* Incremented as we assemble */
+#ifdef notyet
+    unsigned char *msgptr;	/* Current byte in select message */
+    int msglen;			/* Length of whole select message */
+#endif
+    unsigned long flags;
+    u32 exp_select_indirect;	/* Used in sanity check */
+    NCR53c7x0_local_setup(cmd->host);
+
+    if (!(tmp = allocate_cmd (cmd)))
+	return NULL;
+
+
+    /*
+     * Decide whether we need to generate commands for DATA IN,
+     * DATA OUT, neither, or both based on the SCSI command 
+     */
+
+    switch (cmd->cmnd[0]) {
+    /* These commands do DATA IN */
+    case INQUIRY:
+    case MODE_SENSE:
+    case READ_6:
+    case READ_10:
+    case READ_CAPACITY:
+    case REQUEST_SENSE:
+	datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+    	dataout = 0;
+	break;
+    /* These commands do DATA OUT */
+    case MODE_SELECT: 
+    case WRITE_6:
+    case WRITE_10:
+    case START_STOP: /* also SCAN, which may do DATA OUT */
+#if 0
+	printk("scsi%d : command is ", host->host_no);
+	print_command(cmd->cmnd);
+#endif
+#if 0
+	printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
+	    cmd->use_sg);
+#endif
+    	datain = 0;
+	dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+#if 0
+	hostdata->options |= OPTION_DEBUG_INTR;
+#endif
+	break;
+    /* 
+     * These commands do no data transfer, we should force an
+     * interrupt if a data phase is attempted on them.
+     */
+    case TEST_UNIT_READY:
+    	datain = dataout = 0;
+	break;
+    /*
+     * We don't know about these commands, so generate code to handle
+     * both DATA IN and DATA OUT phases.
+     */
+    default:
+	datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+    }
+
+    /*
+     * New code : so that active pointers work correctly regardless
+     * 	of where the saved data pointer is at, we want to immediately
+     * 	enter the dynamic code after selection, and on a non-data
+     * 	phase perform a CALL to the non-data phase handler, with
+     * 	returns back to this address.
+     *
+     * 	If a phase mismatch is encountered in the middle of a 
+     * 	Block MOVE instruction, we want to _leave_ that instruction
+     *	unchanged as the current case is, modify a temporary buffer,
+     *	and point the active pointer (TEMP) at that.
+     *
+     * 	Furthermore, we want to implement a saved data pointer, 
+     * 	set by the SAVE_DATA_POINTERs message.
+     *
+     * 	So, the data transfer segments will change to 
+     *		CALL data_transfer, WHEN NOT data phase
+     *		MOVE x, x, WHEN data phase
+     *		( repeat )
+     *		JUMP other_transfer
+     */
+
+    data_transfer_instructions = datain + dataout;
+
+    /*
+     * When we perform a request sense, we overwrite various things,
+     * including the data transfer code.  Make sure we have enough
+     * space to do that.
+     */
+
+    if (data_transfer_instructions < 2)
+    	data_transfer_instructions = 2;
+
+
+    /*
+     * The saved data pointer is set up so that a RESTORE POINTERS message 
+     * will start the data transfer over at the begining.
+     */
+
+    tmp->saved_data_pointer = virt_to_bus (hostdata->script) + 
+	hostdata->E_data_transfer;
+
+    /*
+     * Initialize Linux specific fields.
+     */
+
+    tmp->cmd = cmd;
+    tmp->next = NULL;
+    tmp->flags = 0;
+    tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next - 
+	hostdata->dsa_start;
+    tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+
+    /* 
+     * Calculate addresses of dynamic code to fill in DSA
+     */
+
+    tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end - 
+    	hostdata->dsa_start) / sizeof(u32);
+    tmp->data_transfer_end = tmp->data_transfer_start + 
+    	2 * data_transfer_instructions;
+
+    cmd_datain = datain ? tmp->data_transfer_start : NULL;
+    cmd_dataout = dataout ? (datain ? cmd_datain + 2 * datain : tmp->
+    	data_transfer_start) : NULL;
+
+    /*
+     * Fill in the NCR53c7x0_cmd structure as follows
+     * dsa, with fixed up DSA code
+     * datain code
+     * dataout code
+     */
+
+    /* Copy template code into dsa and perform all necessary fixups */
+    if (hostdata->dsa_fixup)
+    	hostdata->dsa_fixup(tmp);
+
+    patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
+
+	exp_select_indirect = ((1 << cmd->target) << 16) |
+			(hostdata->sync[cmd->target].sxfer_sanity << 8);
+
+	if (hostdata->sync[cmd->target].select_indirect != 
+				exp_select_indirect) {
+	    printk ("scsi%d :  sanity check failed select_indirect=0x%x\n",
+		host->host_no, hostdata->sync[cmd->target].select_indirect);
+	    FATAL(host);
+
+	}
+    }
+
+    patch_dsa_32(tmp->dsa, dsa_select, 0,
+		hostdata->sync[cmd->target].select_indirect);
+
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    /*
+     * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
+     * different commands; although it should be trivial to do them
+     * both at the same time.
+     */
+    if (hostdata->initiate_wdtr & (1 << cmd->target)) {
+	memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
+	    sizeof(wdtr_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+	save_flags(flags);
+	cli();
+	hostdata->initiate_wdtr &= ~(1 << cmd->target);
+	restore_flags(flags);
+    } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
+	memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, 
+	    sizeof(sdtr_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+	tmp->flags |= CMD_FLAG_SDTR;
+	save_flags(flags);
+	cli();
+	hostdata->initiate_sdtr &= ~(1 << cmd->target);
+	restore_flags(flags);
+    
+    }
+#if 1
+    else if (!(hostdata->talked_to & (1 << cmd->target)) && 
+		!(hostdata->options & OPTION_NO_ASYNC)) {
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+	memcpy ((void *) (tmp->select + 1), (void *) async_message, 
+	    sizeof(async_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+	tmp->flags |= CMD_FLAG_SDTR;
+    } 
+#endif
+    else 
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    hostdata->talked_to |= (1 << cmd->target);
+    tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ? 
+	IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
+    patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
+    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
+    	    virt_to_bus (cmd_dataout)
+	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+    patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ? 
+    	    virt_to_bus (cmd_datain) 
+	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+    /* 
+     * XXX - need to make endian aware, should use separate variables
+     * for both status and message bytes.
+     */
+    patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+/* 
+ * FIXME : these only works for little endian.  We probably want to 
+ * 	provide message and status fields in the NCR53c7x0_cmd 
+ *	structure, and assign them to cmd->result when we're done.
+ */
+#ifdef BIG_ENDIAN
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 2);
+    patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result) + 3);
+#else
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
+    patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
+#endif
+    patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
+	virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+    
+    /*
+     * Generate code for zero or more of the DATA IN, DATA OUT phases 
+     * in the format 
+     *
+     * CALL data_transfer, WHEN NOT phase
+     * MOVE first buffer length, first buffer address, WHEN phase
+     * ...
+     * MOVE last buffer length, last buffer address, WHEN phase
+     * JUMP other_transfer
+     */
+
+/* 
+ * See if we're getting to data transfer by generating an unconditional 
+ * interrupt.
+ */
+#if 0
+    if (datain) {
+	cmd_datain[0] = 0x98080000;
+	cmd_datain[1] = 0x03ffd00d;
+	cmd_datain += 2;
+    }
+#endif
+
+/* 
+ * XXX - I'm undecided whether all of this nonsense is faster
+ * in the long run, or whether I should just go and implement a loop
+ * on the NCR chip using table indirect mode?
+ *
+ * In any case, this is how it _must_ be done for 53c700/700-66 chips,
+ * so this stays even when we come up with something better.
+ *
+ * When we're limited to 1 simultaneous command, no overlapping processing,
+ * we're seeing 630K/sec, with 7% CPU usage on a slow Syquest 45M
+ * drive.
+ *
+ * Not bad, not good. We'll see.
+ */
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+
+    for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, 
+	cmd_dataout += 4, ++i) {
+	u32 buf = cmd->use_sg ? 
+	    virt_to_bus(((struct scatterlist *)cmd->buffer)[i].address) :
+	    virt_to_bus(cmd->request_buffer);
+	u32 count = cmd->use_sg ?
+	    ((struct scatterlist *)cmd->buffer)[i].length :
+	    cmd->request_bufflen;
+
+	if (datain) {
+	    /* CALL other_in, WHEN NOT DATA_IN */  
+	    cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
+		DCMD_TCI_IO) << 24) | 
+		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+	    cmd_datain[1] = virt_to_bus (hostdata->script) + 
+		hostdata->E_other_in;
+	    /* MOVE count, buf, WHEN DATA_IN */
+	    cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
+    	    	<< 24) | count;
+	    cmd_datain[3] = buf;
+#if 0
+	    print_insn (host, cmd_datain, "dynamic ", 1);
+	    print_insn (host, cmd_datain + 2, "dynamic ", 1);
+#endif
+	}
+	if (dataout) {
+	    /* CALL other_out, WHEN NOT DATA_OUT */
+	    cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
+		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+	    cmd_dataout[1] = virt_to_bus(hostdata->script) + 
+    	    	hostdata->E_other_out;
+	    /* MOVE count, buf, WHEN DATA+OUT */
+	    cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
+		| count;
+	    cmd_dataout[3] = buf;
+#if 0
+	    print_insn (host, cmd_dataout, "dynamic ", 1);
+	    print_insn (host, cmd_dataout + 2, "dynamic ", 1);
+#endif
+	}
+    }
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+
+    /*
+     * Install JUMP instructions after the data transfer routines to return
+     * control to the do_other_transfer routines.
+     */
+  
+    
+    if (datain) {
+	cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+    	    DBC_TCI_TRUE;
+	cmd_datain[1] = virt_to_bus(hostdata->script) + 
+    	    hostdata->E_other_transfer;
+#if 0
+	print_insn (host, cmd_datain, "dynamic jump ", 1);
+#endif
+	cmd_datain += 2; 
+    }
+#if 0
+    if (datain) {
+	cmd_datain[0] = 0x98080000;
+	cmd_datain[1] = 0x03ffdeed;
+	cmd_datain += 2;
+    }
+#endif
+    if (dataout) {
+	cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+    	    DBC_TCI_TRUE;
+	cmd_dataout[1] = virt_to_bus(hostdata->script) + 
+    	    hostdata->E_other_transfer;
+#if 0
+	print_insn (host, cmd_dataout, "dynamic jump ", 1);
+#endif
+	cmd_dataout += 2;
+    }
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    return tmp;
+}
+
+/*
+ * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
+ *      void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *      a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ *      cmd is added to the per instance driver issue_queue, with major
+ *      twiddling done to the host specific fields of cmd.  If the
+ *      process_issue_queue coroutine isn't running, it is restarted.
+ * 
+ * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to 
+ *	hold our own data, and pervert the ptr field of the SCp field
+ *	to create a linked list.
+ */
+
+int
+NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
+    struct Scsi_Host *host = cmd->host;
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata;
+    unsigned long flags;
+    Scsi_Cmnd *tmp;
+
+    cmd->scsi_done = done;
+    cmd->host_scribble = NULL;
+    cmd->SCp.ptr = NULL;
+    cmd->SCp.buffer = NULL;
+
+#ifdef VALID_IDS
+    /* Ignore commands on invalid IDs */
+    if (!hostdata->valid_ids[cmd->target]) {
+        printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
+            cmd->target, cmd->lun);
+        cmd->result = (DID_BAD_TARGET << 16);
+        done(cmd);
+        return 0;
+    }
+#endif
+
+    save_flags(flags);
+    cli();
+    if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY)) 
+	|| ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+	    !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun))) 
+#ifdef LINUX_1_2
+	|| cmd->target > 7
+#else
+	|| cmd->target > host->max_id
+#endif
+	|| cmd->target == host->this_id
+	|| hostdata->state == STATE_DISABLED) {
+	printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
+	    cmd->target, cmd->lun);
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	restore_flags (flags);
+	return 0;
+    }
+
+    if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
+	(hostdata->debug_count_limit == 0)) {
+	printk("scsi%d : maximum commands exceeded\n", host->host_no);
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	restore_flags (flags);
+	return 0;
+    }
+
+    if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	    printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
+		host->host_no);
+	    cmd->result = (DID_BAD_TARGET << 16);
+	    done(cmd);
+	    restore_flags (flags);
+	    return 0;
+	}
+    }
+
+    if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+	    hostdata->debug_count_limit != -1) 
+	--hostdata->debug_count_limit;
+
+    cmd->result = 0xffff;	/* The NCR will overwrite message
+				       and status with valid data */
+    cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
+
+    /*
+     * REQUEST SENSE commands are inserted at the head of the queue 
+     * so that we do not clear the contingent allegiance condition
+     * they may be looking at.
+     */
+
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr; 
+		tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
+	tmp->SCp.ptr = (unsigned char *) cmd;
+    }
+    restore_flags (flags);
+    run_process_issue_queue();
+    return 0;
+}
+
+/*
+ * Function : void to_schedule_list (struct Scsi_Host *host,
+ * 	struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : takes a SCSI command which was just removed from the 
+ *	issue queue, and deals with it by inserting it in the first
+ *	free slot in the schedule list or by terminating it immediately.
+ *
+ * Inputs : 
+ *	host - SCSI host adapter; hostdata - hostdata structure for 
+ *	this adapter; cmd - a pointer to the command; should have 
+ *	the host_scribble field initialized to point to a valid 
+ *	
+ * Side effects : 
+ *      cmd is added to the per instance schedule list, with minor 
+ *      twiddling done to the host specific fields of cmd.
+ *
+ */
+
+static __inline__ void
+to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+    struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    Scsi_Cmnd *tmp = cmd->cmd;
+    unsigned long flags;
+    /* dsa start is negative, so subtraction is used */
+    volatile u32 *ncrcurrent;
+
+    int i;
+    NCR53c7x0_local_setup(host);
+#if 0
+    printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no, 
+	virt_to_bus(hostdata->dsa), hostdata->dsa);
+#endif
+
+    save_flags(flags);
+    cli();
+    
+    /* 
+     * Work around race condition : if an interrupt fired and we 
+     * got disabled forget about this command.
+     */
+
+    if (hostdata->state == STATE_DISABLED) {
+	printk("scsi%d : driver disabled\n", host->host_no);
+	tmp->result = (DID_BAD_TARGET << 16);
+	cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+	hostdata->free = cmd;
+	tmp->scsi_done(tmp);
+	restore_flags (flags);
+	return;
+    }
+
+    for (i = host->can_queue, ncrcurrent = hostdata->schedule; 
+	i > 0  && ncrcurrent[0] != hostdata->NOP_insn;
+	--i, ncrcurrent += 2 /* JUMP instructions are two words */);
+
+
+flush_cache_all();
+cache_push(virt_to_bus(hostdata->script), flushsize);
+cache_clear(virt_to_bus(hostdata->script), flushsize);
+
+    if (i > 0) {
+	++hostdata->busy[tmp->target][tmp->lun];
+	cmd->next = hostdata->running_list;
+	hostdata->running_list = cmd;
+
+	/* Restore this instruction to a NOP once the command starts */
+	cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / 
+	    sizeof(u32)] = (u32) virt_to_bus ((void *)ncrcurrent);
+	/* Replace the current jump operand.  */
+	ncrcurrent[1] =
+	    virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+	    hostdata->E_dsa_code_template;
+	/* Replace the NOP instruction with a JUMP */
+	ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+	    DBC_TCI_TRUE;
+    }  else {
+	printk ("scsi%d: no free slot\n", host->host_no);
+	disable(host);
+	tmp->result = (DID_ERROR << 16);
+	cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+	hostdata->free = cmd;
+	tmp->scsi_done(tmp);
+	restore_flags (flags);
+	return;
+    }
+
+    cache_push(virt_to_bus(cmd->dsa), hostdata->dsa_len);
+    cache_push(virt_to_bus(ncrcurrent), sizeof(ncrcurrent));
+
+    /* 
+     * If the NCR chip is in an idle state, start it running the scheduler
+     * immediately.  Otherwise, signal the chip to jump to schedule as 
+     * soon as it is idle.
+     */
+
+    if (hostdata->idle) {
+	hostdata->idle = 0;
+	hostdata->state = STATE_RUNNING;
+	NCR53c7x0_write32 (DSP_REG,  virt_to_bus ((void *)hostdata->schedule));
+	if (hostdata->options & OPTION_DEBUG_TRACE)
+	    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+				DCNTL_SSM | DCNTL_STD);
+    } else {
+	NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
+    }
+
+    restore_flags(flags);
+}
+
+/*
+ * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata 
+ *	*hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : decide if we can pass the given SCSI command on to the 
+ *	device in question or not.
+ *  
+ * Returns : non-zero when we're busy, 0 when we aren't.
+ */
+
+static __inline__ int
+busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, 
+    Scsi_Cmnd *cmd) {
+    /* FIXME : in the future, this needs to accommodate SCSI-II tagged
+       queuing, and we may be able to play with fairness here a bit.
+     */
+    return hostdata->busy[cmd->target][cmd->lun];
+}
+
+/*
+ * Function : process_issue_queue (void)
+ *
+ * Purpose : transfer commands from the issue queue to NCR start queue 
+ *	of each NCR53c7/8xx in the system, avoiding kernel stack 
+ *	overflows when the scsi_done() function is invoked recursively.
+ * 
+ * NOTE : process_issue_queue exits with interrupts *disabled*, so the 
+ *	caller must reenable them if it desires.
+ * 
+ * NOTE : process_issue_queue should be called from both 
+ *	NCR53c7x0_queue_command() and from the interrupt handler 
+ *	after command completion in case NCR53c7x0_queue_command()
+ * 	isn't invoked again but we've freed up resources that are
+ *	needed.
+ */
+
+static void 
+process_issue_queue (unsigned long flags) {
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *host;
+    struct NCR53c7x0_hostdata *hostdata;
+    int done;
+
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set process_issue_queue_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     */
+
+    do {
+	cli(); /* Freeze request queues */
+	done = 1;
+	for (host = first_host; host && host->hostt == the_template;
+	    host = host->next) {
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+	    cli();
+	    if (hostdata->issue_queue) {
+	    	if (hostdata->state == STATE_DISABLED) {
+		    tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+		    hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+		    tmp->result = (DID_BAD_TARGET << 16);
+		    if (tmp->host_scribble) {
+			((struct NCR53c7x0_cmd *)tmp->host_scribble)->next = 
+			    hostdata->free;
+			hostdata->free = 
+			    (struct NCR53c7x0_cmd *)tmp->host_scribble;
+			tmp->host_scribble = NULL;
+		    }
+		    tmp->scsi_done (tmp);
+		    done = 0;
+		} else 
+		    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+			prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) 
+			tmp->SCp.ptr) 
+			if (!tmp->host_scribble || 
+			    !busyp (host, hostdata, tmp)) {
+				if (prev)
+				    prev->SCp.ptr = tmp->SCp.ptr;
+				else
+				    hostdata->issue_queue = (Scsi_Cmnd *) 
+					tmp->SCp.ptr;
+			    tmp->SCp.ptr = NULL;
+			    if (tmp->host_scribble) {
+				if (hostdata->options & OPTION_DEBUG_QUEUES) 
+				    printk ("scsi%d : moving command for target %d lun %d to start list\n",
+					host->host_no, tmp->target, tmp->lun);
+		
+
+			    	to_schedule_list (host, hostdata, 
+				    (struct NCR53c7x0_cmd *)
+				    tmp->host_scribble);
+			    } else {
+				if (((tmp->result & 0xff) == 0xff) ||
+			    	    ((tmp->result & 0xff00) == 0xff00)) {
+				    printk ("scsi%d : danger Will Robinson!\n",
+					host->host_no);
+				    tmp->result = DID_ERROR << 16;
+				    disable (host);
+				}
+				tmp->scsi_done(tmp);
+			    }
+			    done = 0;
+			} /* if target/lun is not busy */
+	    } /* if hostdata->issue_queue */
+	    if (!done)
+		restore_flags (flags);
+    	} /* for host */
+    } while (!done);
+    process_issue_queue_running = 0;
+}
+
+/*
+ * Function : static void intr_scsi (struct Scsi_Host *host, 
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all SCSI interrupts, indicated by the setting 
+ * 	of the SIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ */
+
+static void 
+intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = 
+    	(struct NCR53c7x0_hostdata *) host->hostdata;
+    unsigned char sstat0_sist0, sist1, 		/* Registers */
+	    fatal; 				/* Did a fatal interrupt 
+						   occur ? */
+   
+    NCR53c7x0_local_setup(host);
+
+    fatal = 0;
+
+    sstat0_sist0 = NCR53c7x0_read8(SSTAT0_REG);
+    sist1 = 0;
+
+    if (hostdata->options & OPTION_DEBUG_INTR) 
+	printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
+	    sstat0_sist0, sist1);
+
+    /* 250ms selection timeout */
+    if (sstat0_sist0 & SSTAT0_700_STO) {
+	fatal = 1;
+	if (hostdata->options & OPTION_DEBUG_INTR) {
+	    printk ("scsi%d : Selection Timeout\n", host->host_no);
+    	    if (cmd) {
+    	    	printk("scsi%d : target %d, lun %d, command ",
+    	    	    host->host_no, cmd->cmd->target, cmd->cmd->lun);
+    	    	print_command (cmd->cmd->cmnd);
+		printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
+		    NCR53c7x0_read32(DSP_REG),
+		    bus_to_virt(NCR53c7x0_read32(DSP_REG)));
+    	    } else {
+    	    	printk("scsi%d : no command\n", host->host_no);
+    	    }
+    	}
+/*
+ * XXX - question : how do we want to handle the Illegal Instruction
+ * 	interrupt, which may occur before or after the Selection Timeout
+ * 	interrupt?
+ */
+
+	if (1) {
+	    hostdata->idle = 1;
+	    hostdata->expecting_sto = 0;
+
+	    if (hostdata->test_running) {
+		hostdata->test_running = 0;
+		hostdata->test_completed = 3;
+	    } else if (cmd) {
+		abnormal_finished(cmd, DID_BAD_TARGET << 16);
+	    }
+#if 0	    
+	    hostdata->intrs = 0;
+#endif
+	}
+    } 
+
+/*
+ * FIXME : in theory, we can also get a UDC when a STO occurs.
+ */
+    if (sstat0_sist0 & SSTAT0_UDC) {
+	fatal = 1;
+	if (cmd) {
+	    printk("scsi%d : target %d lun %d unexpected disconnect\n",
+		host->host_no, cmd->cmd->target, cmd->cmd->lun);
+	    print_lots (host);
+	    abnormal_finished(cmd, DID_ERROR << 16);
+	} else 
+	     printk("scsi%d : unexpected disconnect (no command)\n",
+		host->host_no);
+
+	hostdata->dsp = (u32 *) hostdata->schedule;
+	hostdata->dsp_changed = 1;
+    }
+
+    /* SCSI PARITY error */
+    if (sstat0_sist0 & SSTAT0_PAR) {
+	fatal = 1;
+	if (cmd && cmd->cmd) {
+	    printk("scsi%d : target %d lun %d parity error.\n",
+		host->host_no, cmd->cmd->target, cmd->cmd->lun);
+	    abnormal_finished (cmd, DID_PARITY << 16); 
+	} else
+	    printk("scsi%d : parity error\n", host->host_no);
+	/* Should send message out, parity error */
+
+	/* XXX - Reduce synchronous transfer rate! */
+	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1; 
+    /* SCSI GROSS error */
+    } 
+
+    if (sstat0_sist0 & SSTAT0_SGE) {
+	fatal = 1;
+	printk("scsi%d : gross error, saved2_dsa = 0x%x\n", host->host_no,
+					(unsigned int)hostdata->saved2_dsa);
+	print_lots (host);
+	
+	/* 
+         * A SCSI gross error may occur when we have 
+	 *
+	 * - A synchronous offset which causes the SCSI FIFO to be overwritten.
+	 *
+	 * - A REQ which causes the maximum synchronous offset programmed in 
+	 * 	the SXFER register to be exceeded.
+	 *
+	 * - A phase change with an outstanding synchronous offset.
+	 *
+	 * - Residual data in the synchronous data FIFO, with a transfer
+	 *	other than a synchronous receive is started.$#
+	 */
+		
+
+	/* XXX Should deduce synchronous transfer rate! */
+	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+    /* Phase mismatch */
+    } 
+
+    if (sstat0_sist0 & SSTAT0_MA) {
+	fatal = 1;
+	if (hostdata->options & OPTION_DEBUG_INTR)
+	    printk ("scsi%d : SSTAT0_MA\n", host->host_no);
+	intr_phase_mismatch (host, cmd);
+    }
+
+#if 0
+    if (sstat0_sist0 & SIST0_800_RSL) 
+	printk ("scsi%d : Oh no Mr. Bill!\n", host->host_no);
+#endif
+    
+/*
+ * If a fatal SCSI interrupt occurs, we must insure that the DMA and
+ * SCSI FIFOs were flushed.
+ */
+
+    if (fatal) {
+	if (!hostdata->dstat_valid) {
+	    hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	    hostdata->dstat_valid = 1;
+	}
+
+	if (!(hostdata->dstat & DSTAT_DFE)) {
+	  printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+	  /*
+	   * Really need to check this code for 710  RGH.
+	   * Havn't seen any problems, but maybe we should FLUSH before
+	   * clearing sometimes.
+	   */
+          NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+          while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
+		;
+	  hostdata->dstat |= DSTAT_DFE;
+    	}
+    }
+}
+
+#ifdef CYCLIC_TRACE
+
+/*
+ * The following implements a cyclic log of instructions executed, if you turn
+ * TRACE on.  It will also print the log for you.  Very useful when debugging
+ * 53c710 support, possibly not really needed any more.
+ */
+
+u32 insn_log[4096];
+u32 insn_log_index = 0;
+
+void log1 (u32 i)
+{
+	insn_log[insn_log_index++] = i;
+	if (insn_log_index == 4096)
+		insn_log_index = 0;
+}
+
+void log_insn (u32 *ip)
+{
+	log1 ((u32)ip);
+	log1 (*ip);
+	log1 (*(ip+1));
+	if (((*ip >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
+		log1 (*(ip+2));
+}
+
+void dump_log(void)
+{
+	int cnt = 0;
+	int i = insn_log_index;
+	int size;
+	struct Scsi_Host *host = first_host;
+
+	while (cnt < 4096) {
+		printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4);
+		if (++i == 4096)
+			i = 0;
+		cnt++;
+		if (((insn_log[i]  >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) 
+			size = 3;
+		else
+			size = 2;
+		while (size--) {
+			printk ("%08x ", insn_log[i]);
+			if (++i == 4096)
+				i = 0;
+			cnt++;
+		}
+		printk ("\n");
+	}
+}
+#endif
+
+/*
+ * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+ *
+ * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
+ *	the same IRQ line.  
+ * 
+ * Inputs : Since we're using the SA_INTERRUPT interrupt handler
+ *	semantics, irq indicates the interrupt which invoked 
+ *	this handler.  
+ *
+ * On the 710 we simualte an INTFLY with a script interrupt, and the
+ * script interrupt handler will call back to this function.
+ */
+
+void 
+NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
+    NCR53c7x0_local_declare();
+    struct Scsi_Host *host;			/* Host we are looking at */
+    unsigned char istat; 			/* Values of interrupt regs */
+    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata */
+    struct NCR53c7x0_cmd *cmd,			/* command which halted */
+	**cmd_prev_ptr;
+    u32 *dsa;					/* DSA */
+    int done = 1;				/* Indicates when handler 
+						   should terminate */
+    int interrupted = 0;			/* This HA generated 
+						   an interrupt */
+    int have_intfly;				/* Don't print warning 
+						   messages when we stack
+						   INTFLYs */
+    unsigned long flags;				
+
+#ifdef NCR_DEBUG
+    char buf[80];				/* Debugging sprintf buffer */
+    size_t buflen;				/* Length of same */
+#endif
+
+#if defined(CONFIG_AMIGA)
+    custom.intena = IF_PORTS;
+#endif
+
+    do {
+	done = 1;
+	for (host = first_host; host; host = host->next) 
+	    if (host->hostt == the_template
+#if defined(MVME166_INTFLY)
+			/* We have two different interrupts pointing
+			 * at this routine, so remove this check */
+#else
+				&& host->irq == irq
+#endif
+							) {
+    	    NCR53c7x0_local_setup(host);
+
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+	    hostdata->dsp_changed = 0;
+	    interrupted = 0;
+	    have_intfly = 0;
+
+	    do {
+		hostdata->dstat_valid = 0;
+		interrupted = 0;
+		/*
+		 * Only read istat once, since reading it again will unstack
+		 * interrupts?
+		 */
+		istat = NCR53c7x0_read8(hostdata->istat);
+
+		if ((hostdata->options & OPTION_INTFLY) && 
+#ifdef MVME166_INTFLY
+                    /* the bit is set which indicates an on-the-fly int */
+                        (*(volatile unsigned long *)0xfff40068 & 0x8000))
+#else
+		    (hostdata->emulated_intfly != 0))
+#endif
+		{
+		    char search_found = 0;	/* Got at least one ? */
+		    done = 0;
+		    interrupted = 1;
+
+#ifdef MVME166_INTFLY
+                    /* clear the INTFLY bit */
+                    *(volatile unsigned long *)0xfff40074 = 0x8000;
+#endif
+
+		    if (hostdata->options & OPTION_DEBUG_INTR)
+			printk ("scsi%d : INTFLY\n", host->host_no); 
+
+		    /*
+		     * Traverse our list of running commands, and look
+		     * for those with valid (non-0xff ff) status and message
+		     * bytes encoded in the result which signify command
+		     * completion.
+		     */
+
+
+		    save_flags(flags);
+		    cli();
+restart:
+		    for (cmd_prev_ptr = (struct NCR53c7x0_cmd **) 
+			 &(hostdata->running_list), cmd = 
+			 (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+			 cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next), 
+    	    	    	 cmd = (struct NCR53c7x0_cmd *) cmd->next) {
+			Scsi_Cmnd *tmp;
+
+			if (!cmd) {
+			    printk("scsi%d : very weird.\n", host->host_no);
+			    break;
+			}
+
+			if (!(tmp = cmd->cmd)) {
+			    printk("scsi%d : weird.  NCR53c7x0_cmd has no Scsi_Cmnd\n",
+				host->host_no);
+				continue;
+			}
+#if 0
+			printk ("scsi%d : looking at result of 0x%x\n",
+			    host->host_no, cmd->cmd->result);
+#endif
+		
+			if (((tmp->result & 0xff) == 0xff) ||
+			    ((tmp->result & 0xff00) == 0xff00))
+			    continue;
+
+			search_found = 1;
+
+			/* Important - remove from list _before_ done is called */
+			if (cmd_prev_ptr)
+			    *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
+
+			--hostdata->busy[tmp->target][tmp->lun];
+    	    	    	cmd->next = hostdata->free;
+    	    	    	hostdata->free = cmd;
+
+    	    	    	tmp->host_scribble = NULL;
+
+			if (hostdata->options & OPTION_DEBUG_INTR) {
+			    printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", 
+				host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result);
+			    print_command (tmp->cmnd);
+			}
+
+#if 0
+			hostdata->options &= ~OPTION_DEBUG_INTR;
+#endif
+			tmp->scsi_done(tmp);
+			goto restart;
+
+		    }
+		    restore_flags(flags);
+		   
+		    if (!search_found && !have_intfly)  {
+			printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
+			    host->host_no);
+		    } else if (!have_intfly)  {
+			have_intfly = 1; 
+    		    	run_process_issue_queue();
+		    }
+		}
+
+		if (hostdata->emulated_intfly)
+		{
+			hostdata->emulated_intfly = 0;
+			return;
+		}
+
+		if (istat & (ISTAT_SIP|ISTAT_DIP)) {
+		    done = 0;
+		    interrupted = 1;
+    	    	    hostdata->state = STATE_HALTED;
+
+		    if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) 
+			printk ("scsi%d : SCSI FIFO not empty\n", 
+			    host->host_no);
+
+		    /*
+		     * NCR53c700 and NCR53c700-66 change the current SCSI
+		     * process, hostdata->ncrcurrent, in the Linux driver so
+		     * cmd = hostdata->ncrcurrent.
+		     *
+		     * With other chips, we must look through the commands
+		     * executing and find the command structure which 
+		     * corresponds to the DSA register.
+		     */
+
+		    if (hostdata->options & OPTION_700) {
+			cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent;
+		    } else {
+			dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+			for (cmd = (struct NCR53c7x0_cmd *) 
+			    hostdata->running_list; cmd &&
+    	    	    	    (dsa + (hostdata->dsa_start / sizeof(u32))) != 
+    	    	    	    	cmd->dsa;
+			    cmd = (struct NCR53c7x0_cmd *)(cmd->next));
+		    }
+		    if (hostdata->options & OPTION_DEBUG_INTR) {
+			if (cmd) {
+			    printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", 
+				host->host_no, cmd->cmd->pid, (int) cmd->cmd->target,
+				(int) cmd->cmd->lun);
+			    print_command (cmd->cmd->cmnd);
+			} else {
+			    printk("scsi%d : no active command\n", host->host_no);
+			}
+		    }
+
+		    if (istat & ISTAT_SIP) {
+			if (hostdata->options & OPTION_DEBUG_INTR) 
+			    printk ("scsi%d : ISTAT_SIP\n", host->host_no);
+			intr_scsi (host, cmd);
+		    }
+		
+		    if (istat & ISTAT_DIP) {
+			if (hostdata->options & OPTION_DEBUG_INTR) 
+			    printk ("scsi%d : ISTAT_DIP\n", host->host_no);
+			intr_dma (host, cmd);
+		    }
+
+		    if (!hostdata->dstat_valid) {
+			hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+			hostdata->dstat_valid = 1;
+		    }
+
+		    if (!(hostdata->dstat & DSTAT_DFE)) {
+		      printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+		      /* Really need to check this out for 710 RGH */
+                      NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+                      while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+		      hostdata->dstat |= DSTAT_DFE;
+		    }
+		}
+	    } while (interrupted);
+
+
+
+	    if (hostdata->intrs != -1)
+		hostdata->intrs++;
+#if 0
+	    if (hostdata->intrs > 40) {
+		printk("scsi%d : too many interrupts, halting", host->host_no);
+		disable(host);
+	    }
+#endif
+
+	    if (!hostdata->idle && hostdata->state == STATE_HALTED) {
+		if (!hostdata->dsp_changed) {
+		    hostdata->dsp = (u32 *) 
+			bus_to_virt(NCR53c7x0_read32(DSP_REG));
+		}
+			
+#if 0
+		printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n",
+		    host->host_no,  virt_to_bus(hostdata->dsp), hostdata->dsp);
+#endif
+		
+		hostdata->state = STATE_RUNNING;
+		NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
+		if (hostdata->options & OPTION_DEBUG_TRACE) {
+#ifdef CYCLIC_TRACE
+		    log_insn (hostdata->dsp);
+#else
+	    	    print_insn (host, hostdata->dsp, "t ", 1);
+#endif
+		    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+				DCNTL_SSM | DCNTL_STD);
+		}
+	    }
+	}
+    } while (!done);
+#ifdef CONFIG_AMIGA
+	custom.intena = IF_SETCLR | IF_PORTS;
+#endif
+}
+
+
+/* 
+ * Function : static int abort_connected (struct Scsi_Host *host)
+ *
+ * Purpose : Assuming that the NCR SCSI processor is currently 
+ * 	halted, break the currently established nexus.  Clean
+ *	up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
+ *	be done on receipt of the abort interrupt.
+ *
+ * Inputs : host - SCSI host
+ *
+ */
+
+static int 
+abort_connected (struct Scsi_Host *host) {
+#ifdef NEW_ABORT
+    NCR53c7x0_local_declare();
+#endif
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+/* FIXME : this probably should change for production kernels; at the 
+   least, counter should move to a per-host structure. */
+    static int counter = 5;
+#ifdef NEW_ABORT
+    int sstat, phase, offset;
+    u32 *script;
+    NCR53c7x0_local_setup(host);
+#endif
+
+    if (--counter <= 0) {
+	disable(host);
+	return 0;
+    }
+
+    printk ("scsi%d : DANGER : abort_connected() called \n",
+	host->host_no);
+
+#ifdef NEW_ABORT
+
+/*
+ * New strategy : Rather than using a generic abort routine,
+ * we'll specifically try to source or sink the appropriate
+ * amount of data for the phase we're currently in (taking into 
+ * account the current synchronous offset) 
+ */
+
+    sstat = (NCR53c8x0_read8 (SSTAT2_REG);
+    offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+    phase = sstat & SSTAT2_PHASE_MASK;
+
+/*
+ * SET ATN
+ * MOVE source_or_sink, WHEN CURRENT PHASE 
+ * < repeat for each outstanding byte >
+ * JUMP send_abort_message
+ */
+
+    script = hostdata->abort_script = kmalloc (
+	8  /* instruction size */ * (
+	    1 /* set ATN */ +
+	    (!offset ? 1 : offset) /* One transfer per outstanding byte */ +
+	    1 /* send abort message */),
+	GFP_ATOMIC);
+
+
+#else /* def NEW_ABORT */
+    hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+	    sizeof(u32);
+#endif /* def NEW_ABORT */
+    hostdata->dsp_changed = 1;
+
+/* XXX - need to flag the command as aborted after the abort_connected
+ 	 code runs 
+ */
+    return 0;
+}
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.
+ *
+ * Inputs : host - SCSI host
+ */
+
+static int
+datapath_residual (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    int count, synchronous, sstat;
+    unsigned int ddir;
+
+    NCR53c7x0_local_setup(host);
+    /* COMPAT : the 700 and 700-66 need to use DFIFO_00_BO_MASK */
+    count = ((NCR53c7x0_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
+	(NCR53c7x0_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
+    synchronous = NCR53c7x0_read8 (SXFER_REG) & SXFER_MO_MASK;
+    /* COMPAT : DDIR is elsewhere on non-'8xx chips. */
+    ddir = NCR53c7x0_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
+
+    if (ddir) {
+    /* Receive */
+	if (synchronous) 
+	    count += (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+	else
+	    if (NCR53c7x0_read8 (SSTAT1_REG) & SSTAT1_ILF)
+		++count;
+    } else {
+    /* Send */
+	sstat = NCR53c7x0_read8 (SSTAT1_REG);
+	if (sstat & SSTAT1_OLF)
+	    ++count;
+	if (synchronous && (sstat & SSTAT1_ORF))
+	    ++count;
+    }
+    return count;
+}
+
+/* 
+ * Function : static const char * sbcl_to_phase (int sbcl)_
+ *
+ * Purpose : Convert SBCL register to user-parsable phase representation
+ *
+ * Inputs : sbcl - value of sbcl register
+ */
+
+
+static const char *
+sbcl_to_phase (int sbcl) {
+    switch (sbcl & SBCL_PHASE_MASK) {
+    case SBCL_PHASE_DATAIN:
+	return "DATAIN";
+    case SBCL_PHASE_DATAOUT:
+	return "DATAOUT";
+    case SBCL_PHASE_MSGIN:
+	return "MSGIN";
+    case SBCL_PHASE_MSGOUT:
+	return "MSGOUT";
+    case SBCL_PHASE_CMDOUT:
+	return "CMDOUT";
+    case SBCL_PHASE_STATIN:
+	return "STATUSIN";
+    default:
+	return "unknown";
+    }
+}
+
+/* 
+ * Function : static const char * sstat2_to_phase (int sstat)_
+ *
+ * Purpose : Convert SSTAT2 register to user-parsable phase representation
+ *
+ * Inputs : sstat - value of sstat register
+ */
+
+
+static const char *
+sstat2_to_phase (int sstat) {
+    switch (sstat & SSTAT2_PHASE_MASK) {
+    case SSTAT2_PHASE_DATAIN:
+	return "DATAIN";
+    case SSTAT2_PHASE_DATAOUT:
+	return "DATAOUT";
+    case SSTAT2_PHASE_MSGIN:
+	return "MSGIN";
+    case SSTAT2_PHASE_MSGOUT:
+	return "MSGOUT";
+    case SSTAT2_PHASE_CMDOUT:
+	return "CMDOUT";
+    case SSTAT2_PHASE_STATIN:
+	return "STATUSIN";
+    default:
+	return "unknown";
+    }
+}
+
+/* 
+ * Function : static void intr_phase_mismatch (struct Scsi_Host *host, 
+ *	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handle phase mismatch interrupts
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ *
+ * Side effects : The abort_connected() routine is called or the NCR chip 
+ *	is restarted, jumping to the command_complete entry point, or 
+ *	patching the address and transfer count of the current instruction 
+ *	and calling the msg_in entry point as appropriate.
+ */
+
+static void 
+intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    u32 dbc_dcmd, *dsp, *dsp_next;
+    unsigned char dcmd, sbcl;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+    	host->hostdata;
+    int residual;
+    enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action = 
+	ACTION_ABORT_PRINT;
+    const char *where = NULL;
+
+    NCR53c7x0_local_setup(host);
+
+    /*
+     * Corrective action is based on where in the SCSI SCRIPT(tm) the error 
+     * occurred, as well as which SCSI phase we are currently in.
+     */
+    dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+    /* 
+     * Fetch the current instruction, and remove the operands for easier 
+     * interpretation.
+     */
+    dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+    dcmd = (dbc_dcmd & 0xff000000) >> 24;
+    /*
+     * Like other processors, the NCR adjusts the instruction pointer before
+     * instruction decode.  Set the DSP address back to what it should
+     * be for this instruction based on its size (2 or 3 32 bit words).
+     */
+    dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+
+
+    /*
+     * Read new SCSI phase from the SBCL lines.  Since all of our code uses 
+     * a WHEN conditional instead of an IF conditional, we don't need to 
+     * wait for a new REQ.
+     */
+    sbcl = NCR53c7x0_read8(SBCL_REG) & SBCL_PHASE_MASK;
+
+    if (!cmd) {
+	action = ACTION_ABORT_PRINT;
+	where = "no current command";
+    /*
+     * The way my SCSI SCRIPTS(tm) are architected, recoverable phase
+     * mismatches should only occur where we're doing a multi-byte  
+     * BMI instruction.  Specifically, this means 
+     *
+     *  - select messages (a SCSI-I target may ignore additional messages
+     * 		after the IDENTIFY; any target may reject a SDTR or WDTR)
+     *
+     *  - command out (targets may send a message to signal an error 
+     * 		condition, or go into STATUSIN after they've decided 
+     *		they don't like the command.
+     *
+     *	- reply_message (targets may reject a multi-byte message in the 
+     *		middle)
+     *
+     * 	- data transfer routines (command completion with buffer space
+     *		left, disconnect message, or error message)
+     */
+    } else if (((dsp >= cmd->data_transfer_start && 
+	dsp < cmd->data_transfer_end)) || dsp == (cmd->residual + 2)) {
+	if ((dcmd & (DCMD_TYPE_MASK|DCMD_BMI_OP_MASK|DCMD_BMI_INDIRECT|
+		DCMD_BMI_MSG|DCMD_BMI_CD)) == (DCMD_TYPE_BMI|
+		DCMD_BMI_OP_MOVE_I)) {
+	    residual = datapath_residual (host);
+	    if (hostdata->options & OPTION_DEBUG_DISCONNECT)
+	    	printk ("scsi%d : handling residual transfer (+ %d bytes from DMA FIFO)\n", 
+		    host->host_no, residual);
+
+	    /*
+	     * The first instruction is a CALL to the alternate handler for 
+	     * this data transfer phase, so we can do calls to 
+	     * munge_msg_restart as we would if control were passed 
+	     * from normal dynamic code.
+	     */
+	    if (dsp != cmd->residual + 2) {
+		cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+			((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) | 
+		    DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+		cmd->residual[1] = virt_to_bus(hostdata->script)
+		    + ((dcmd & DCMD_BMI_IO)
+		       ? hostdata->E_other_in : hostdata->E_other_out);
+	    }
+
+	    /*
+	     * The second instruction is the a data transfer block
+	     * move instruction, reflecting the pointer and count at the 
+	     * time of the phase mismatch.
+	     */
+	    cmd->residual[2] = dbc_dcmd + residual;
+	    cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+
+	    /*
+	     * The third and final instruction is a jump to the instruction
+	     * which follows the instruction which had to be 'split'
+	     */
+	    if (dsp != cmd->residual + 2) {
+		cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) 
+		    << 24) | DBC_TCI_TRUE;
+		cmd->residual[5] = virt_to_bus(dsp_next);
+	    }
+
+	    /*
+	     * For the sake of simplicity, transfer control to the 
+	     * conditional CALL at the start of the residual buffer.
+	     */
+	    hostdata->dsp = cmd->residual;
+	    hostdata->dsp_changed = 1;
+	    action = ACTION_CONTINUE;
+	} else {
+	    where = "non-BMI dynamic DSA code";
+	    action = ACTION_ABORT_PRINT;
+	}
+    } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4)) {
+	/* Release ATN */
+	NCR53c7x0_write8 (SOCL_REG, 0);
+	switch (sbcl) {
+    /* 
+     * Some devices (SQ555 come to mind) grab the IDENTIFY message
+     * sent on selection, and decide to go into COMMAND OUT phase
+     * rather than accepting the rest of the messages or rejecting
+     * them.  Handle these devices gracefully.
+     */
+	case SBCL_PHASE_CMDOUT:
+	    hostdata->dsp = dsp + 2 /* two _words_ */;
+	    hostdata->dsp_changed = 1;
+	    printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n", 
+		host->host_no, cmd->cmd->target);
+	    cmd->flags &= ~CMD_FLAG_SDTR;
+	    action = ACTION_CONTINUE;
+	    break;
+	case SBCL_PHASE_MSGIN:
+	    hostdata->dsp = hostdata->script + hostdata->E_msg_in / 
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	    action = ACTION_CONTINUE;
+	    break;
+	default:
+	    where="select message out";
+	    action = ACTION_ABORT_PRINT;
+	}
+    /*
+     * Some SCSI devices will interpret a command as they read the bytes
+     * off the SCSI bus, and may decide that the command is Bogus before 
+     * they've read the entire command off the bus.
+     */
+    } else if (dsp == hostdata->script + hostdata->E_cmdout_cmdout / sizeof 
+	(u32)) {
+	hostdata->dsp = hostdata->script + hostdata->E_data_transfer /
+	    sizeof (u32);
+	hostdata->dsp_changed = 1;
+	action = ACTION_CONTINUE;
+    /* FIXME : we need to handle message reject, etc. within msg_respond. */
+#ifdef notyet
+    } else if (dsp == hostdata->script + hostdata->E_reply_message) {
+	switch (sbcl) {
+    /* Any other phase mismatches abort the currently executing command.  */
+#endif
+    } else {
+	where = "unknown location";
+	action = ACTION_ABORT_PRINT;
+    }
+
+    /* Flush DMA FIFO */
+    if (!hostdata->dstat_valid) {
+	hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	hostdata->dstat_valid = 1;
+    }
+    if (!(hostdata->dstat & DSTAT_DFE)) {
+      /* Really need to check this out for 710 RGH */
+      NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+      while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+      hostdata->dstat |= DSTAT_DFE;
+    }
+
+    switch (action) {
+    case ACTION_ABORT_PRINT:
+	printk("scsi%d : %s : unexpected phase %s.\n",
+	     host->host_no, where ? where : "unknown location", 
+	     sbcl_to_phase(sbcl));
+	print_lots (host);
+    /* Fall through to ACTION_ABORT */
+    case ACTION_ABORT:
+	abort_connected (host);
+	break;
+    case ACTION_CONTINUE:
+	break;
+    }
+
+#if 0
+    if (hostdata->dsp_changed) {
+	printk("scsi%d: new dsp 0x%p\n", host->host_no, hostdata->dsp);
+	print_insn (host, hostdata->dsp, "", 1);
+    }
+#endif
+    
+    cache_push(virt_to_bus(hostdata->script), flushsize);
+}
+
+/*
+ * Function : static void intr_bf (struct Scsi_Host *host, 
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle BUS FAULT interrupts 
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ */
+
+static void
+intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    u32 *dsp,
+	*next_dsp,		/* Current dsp */
+    	*dsa,
+	dbc_dcmd;		/* DCMD (high eight bits) + DBC */
+    char *reason = NULL;
+    /* Default behavior is for a silent error, with a retry until we've
+       exhausted retries. */
+    enum {MAYBE, ALWAYS, NEVER} retry = MAYBE;
+    int report = 0;
+    NCR53c7x0_local_setup(host);
+
+    dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+    next_dsp = bus_to_virt (NCR53c7x0_read32(DSP_REG));
+    dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* FIXME - check chip type  */
+    dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+    /*
+     * Bus faults can be caused by either a Bad Address or 
+     * Target Abort. We should check the Received Target Abort
+     * bit of the PCI status register and Master Abort Bit.
+     *
+     * 	- Master Abort bit indicates that no device claimed
+     *		the address with DEVSEL within five clocks
+     *
+     *	- Target Abort bit indicates that a target claimed it,
+     *		but changed its mind once it saw the byte enables.
+     *
+     */
+
+    /* 53c710, not PCI system */
+    report = 1;
+    reason = "Unknown";
+
+#ifndef notyet
+    report = 1;
+#endif
+    if (report && reason)
+    {
+	printk(KERN_ALERT "scsi%d : BUS FAULT reason = %s\n",
+	     host->host_no, reason ? reason : "unknown");
+	print_lots (host);
+    }
+
+#ifndef notyet
+    retry = NEVER;
+#endif
+
+    /* 
+     * TODO : we should attempt to recover from any spurious bus 
+     * faults.  After X retries, we should figure that things are 
+     * sufficiently wedged, and call NCR53c7xx_reset.
+     *
+     * This code should only get executed once we've decided that we 
+     * cannot retry.
+     */
+
+    if (retry == NEVER) {
+    	printk(KERN_ALERT "          mail drew@PoohSticks.ORG\n");
+    	FATAL (host);
+    }
+}
+
+/*
+ * Function : static void intr_dma (struct Scsi_Host *host, 
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all DMA interrupts, indicated by the setting 
+ * 	of the DIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ */
+
+static void 
+intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    unsigned char dstat;	/* DSTAT */	
+    u32 *dsp,
+	*next_dsp,		/* Current dsp */
+    	*dsa,
+	dbc_dcmd;		/* DCMD (high eight bits) + DBC */
+    int tmp;
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+
+    if (!hostdata->dstat_valid) {
+	hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	hostdata->dstat_valid = 1;
+    }
+    
+    dstat = hostdata->dstat;
+    
+    if (hostdata->options & OPTION_DEBUG_INTR)
+	printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
+
+    dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+    next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+    dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* XXX - check chip type */
+    dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+
+    /*
+     * DSTAT_ABRT is the aborted interrupt.  This is set whenever the 
+     * SCSI chip is aborted.  
+     * 
+     * With NCR53c700 and NCR53c700-66 style chips, we should only 
+     * get this when the chip is currently running the accept 
+     * reselect/select code and we have set the abort bit in the 
+     * ISTAT register.
+     *
+     */
+    
+    if (dstat & DSTAT_ABRT) {
+#if 0
+	/* XXX - add code here to deal with normal abort */
+	if ((hostdata->options & OPTION_700) && (hostdata->state ==
+	    STATE_ABORTING)) {
+	} else 
+#endif
+	{
+	    printk(KERN_ALERT "scsi%d : unexpected abort interrupt at\n" 
+		   "         ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "s ", 1);
+	    FATAL (host);
+	}
+    }
+
+    /*
+     * DSTAT_SSI is the single step interrupt.  Should be generated 
+     * whenever we have single stepped or are tracing.
+     */
+
+    if (dstat & DSTAT_SSI) {
+	if (hostdata->options & OPTION_DEBUG_TRACE) {
+	    /* Don't print instr. until we write DSP at end of intr function */
+	} else if (hostdata->options & OPTION_DEBUG_SINGLE) {
+	    print_insn (host, dsp, "s ", 0);
+	    save_flags(flags);
+	    cli();
+/* XXX - should we do this, or can we get away with writing dsp? */
+
+	    NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) & 
+    	    	~DCNTL_SSM) | DCNTL_STD);
+	    restore_flags(flags);
+	} else {
+	    printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
+		   "         ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "", 1);
+	    printk(KERN_ALERT "         mail drew@PoohSticks.ORG\n");
+    	    FATAL (host);
+    	}
+    }
+
+    /*
+     * DSTAT_IID / DSTAT_OPC (same bit, same meaning, only the name 
+     * is different) is generated whenever an illegal instruction is 
+     * encountered.  
+     * 
+     * XXX - we may want to emulate INTFLY here, so we can use 
+     *    the same SCSI SCRIPT (tm) for NCR53c710 through NCR53c810  
+     *	  chips.
+     */
+
+    if (dstat & DSTAT_OPC) {
+    /* 
+     * Ascertain if this IID interrupts occurred before or after a STO 
+     * interrupt.  Since the interrupt handling code now leaves 
+     * DSP unmodified until _after_ all stacked interrupts have been
+     * processed, reading the DSP returns the original DSP register.
+     * This means that if dsp lies between the select code, and 
+     * message out following the selection code (where the IID interrupt
+     * would have to have occurred by due to the implicit wait for REQ),
+     * we have an IID interrupt resulting from a STO condition and 
+     * can ignore it.
+     */
+
+	if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
+	    (dsp <= (hostdata->script + hostdata->E_select_msgout / 
+    	    sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
+	    if (hostdata->options & OPTION_DEBUG_INTR) 
+		printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
+		    host->host_no);
+	    if (hostdata->expecting_iid) {
+		hostdata->expecting_iid = 0;
+		hostdata->idle = 1;
+		if (hostdata->test_running == 2) {
+		    hostdata->test_running = 0;
+		    hostdata->test_completed = 3;
+		} else if (cmd) 
+			abnormal_finished (cmd, DID_BAD_TARGET << 16);
+	    } else {
+		hostdata->expecting_sto = 1;
+	    }
+    /*
+     * We can't guarantee we'll be able to execute the WAIT DISCONNECT
+     * instruction within the 3.4us of bus free and arbitration delay
+     * that a target can RESELECT in and assert REQ after we've dropped
+     * ACK.  If this happens, we'll get an illegal instruction interrupt.
+     * Doing away with the WAIT DISCONNECT instructions broke everything,
+     * so instead I'll settle for moving one WAIT DISCONNECT a few 
+     * instructions closer to the CLEAR ACK before it to minimize the
+     * chances of this happening, and handle it if it occurs anyway.
+     *
+     * Simply continue with what we were doing, and control should
+     * be transfered to the schedule routine which will ultimately
+     * pass control onto the reselection or selection (not yet)
+     * code.
+     */
+	} else if (dbc_dcmd == 0x48000000 && (NCR53c7x0_read8 (SBCL_REG) &
+	    SBCL_REQ)) {
+	    if (!(hostdata->options & OPTION_NO_PRINT_RACE))
+	    {
+		printk("scsi%d: REQ before WAIT DISCONNECT IID\n", 
+		    host->host_no);
+		hostdata->options |= OPTION_NO_PRINT_RACE;
+	    }
+	} else {
+	    printk(KERN_ALERT "scsi%d : illegal instruction\n", host->host_no);
+	    print_lots (host);
+	    printk(KERN_ALERT "         mail Richard@sleepie.demon.co.uk with ALL\n"
+		              "         boot messages and diagnostic output\n");
+    	    FATAL (host);
+	}
+    }
+
+    /* 
+     * DSTAT_BF are bus fault errors.  DSTAT_800_BF is valid for 710 also.
+     */
+    
+    if (dstat & DSTAT_800_BF) {
+	intr_bf (host, cmd);
+    }
+	
+
+    /* 
+     * DSTAT_SIR interrupts are generated by the execution of 
+     * the INT instruction.  Since the exact values available 
+     * are determined entirely by the SCSI script running, 
+     * and are local to a particular script, a unique handler
+     * is called for each script.
+     */
+
+    if (dstat & DSTAT_SIR) {
+	if (hostdata->options & OPTION_DEBUG_INTR)
+	    printk ("scsi%d : DSTAT_SIR\n", host->host_no);
+	switch ((tmp = hostdata->dstat_sir_intr (host, cmd))) {
+	case SPECIFIC_INT_NOTHING:
+	case SPECIFIC_INT_RESTART:
+	    break;
+	case SPECIFIC_INT_ABORT:
+	    abort_connected(host);
+	    break;
+	case SPECIFIC_INT_PANIC:
+	    printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "", 1);
+	    printk(KERN_ALERT "          dstat_sir_intr() returned SPECIFIC_INT_PANIC\n");
+    	    FATAL (host);
+	    break;
+	case SPECIFIC_INT_BREAK:
+	    intr_break (host, cmd);
+	    break;
+	default:
+	    printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "", 1);
+	    printk(KERN_ALERT"          dstat_sir_intr() returned unknown value %d\n", 
+		tmp);
+    	    FATAL (host);
+	}
+    } 
+}
+
+/*
+ * Function : static int print_insn (struct Scsi_Host *host, 
+ * 	u32 *insn, int kernel)
+ *
+ * Purpose : print numeric representation of the instruction pointed
+ * 	to by insn to the debugging or kernel message buffer
+ *	as appropriate.  
+ *
+ * 	If desired, a user level program can interpret this 
+ * 	information.
+ *
+ * Inputs : host, insn - host, pointer to instruction, prefix - 
+ *	string to prepend, kernel - use printk instead of debugging buffer.
+ *
+ * Returns : size, in u32s, of instruction printed.
+ */
+
+/*
+ * FIXME: should change kernel parameter so that it takes an ENUM
+ * 	specifying severity - either KERN_ALERT or KERN_PANIC so
+ *	all panic messages are output with the same severity.
+ */
+
+static int 
+print_insn (struct Scsi_Host *host, const u32 *insn, 
+    const char *prefix, int kernel) {
+    char buf[160], 		/* Temporary buffer and pointer.  ICKY 
+				   arbitrary length.  */
+
+		
+	*tmp;			
+    unsigned char dcmd;		/* dcmd register for *insn */
+    int size;
+
+    /* 
+     * Check to see if the instruction pointer is not bogus before 
+     * indirecting through it; avoiding red-zone at start of 
+     * memory.
+     *
+     * FIXME: icky magic needs to happen here on non-intel boxes which
+     * don't have kernel memory mapped in like this.  Might be reasonable
+     * to use vverify()?
+     */
+
+    if (MAP_NR(insn) < 1 || MAP_NR(insn + 8) > MAP_NR(high_memory) ||
+	((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
+	MAP_NR(insn + 12) > MAP_NR(high_memory))) {
+	size = 0;
+	sprintf (buf, "%s%p: address out of range\n",
+	    prefix, insn);
+    } else {
+/* 
+ * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
+ * 	it should take const void * as argument.
+ */
+#ifndef CONFIG_MVME166
+	sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)", 
+	    (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,  
+	    insn[0], insn[1], bus_to_virt (insn[1]));
+#else
+	/* Remove virtual addresses to reduce output, as they are the same */
+	sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x", 
+	    (prefix ? prefix : ""), (u32)insn, ((u32)insn -
+		(u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4, 
+	    insn[0], insn[1]);
+#endif
+	tmp = buf + strlen(buf);
+	if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
+#ifndef CONFIG_MVME166
+	    sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2], 
+		bus_to_virt(insn[2]));
+#else
+	    /* Remove virtual addr to reduce output, as it is the same */
+	    sprintf (tmp, " 0x%08x\n", insn[2]);
+#endif
+	    size = 3;
+	} else {
+	    sprintf (tmp, "\n");
+	    size = 2;
+	}
+    }
+
+    if (kernel) 
+	printk ("%s", buf);
+#ifdef NCR_DEBUG
+    else {
+	size_t len = strlen(buf);
+	debugger_kernel_write(host, buf, len);
+    }
+#endif
+    return size;
+}
+
+/*
+ * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : Abort an errant SCSI command, doing all necessary
+ *	cleanup of the issue_queue, running_list, shared Linux/NCR
+ *	dsa issue and reconnect queues.
+ *
+ * Inputs : cmd - command to abort, code - entire result field
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int 
+NCR53c7xx_abort (Scsi_Cmnd *cmd) {
+    NCR53c7x0_local_declare();
+    struct Scsi_Host *host = cmd->host;
+    struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
+	host->hostdata : NULL;
+    unsigned long flags;
+    struct NCR53c7x0_cmd *curr, **prev;
+    Scsi_Cmnd *me, **last;
+#if 0
+    static long cache_pid = -1;
+#endif
+
+
+    if (!host) {
+	printk ("Bogus SCSI command pid %ld; no host structure\n",
+	    cmd->pid);
+	return SCSI_ABORT_ERROR;
+    } else if (!hostdata) {
+	printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
+	return SCSI_ABORT_ERROR;
+    }
+    NCR53c7x0_local_setup(host);
+
+/*
+ * CHECK : I don't think that reading ISTAT will unstack any interrupts,
+ *	since we need to write the INTF bit to clear it, and SCSI/DMA
+ * 	interrupts don't clear until we read SSTAT/SIST and DSTAT registers.
+ *	
+ *	See that this is the case.  Appears to be correct on the 710, at least.
+ *
+ * I suspect that several of our failures may be coming from a new fatal
+ * interrupt (possibly due to a phase mismatch) happening after we've left
+ * the interrupt handler, but before the PIC has had the interrupt condition
+ * cleared.
+ */
+
+    if (NCR53c7x0_read8(hostdata->istat) & (ISTAT_DIP|ISTAT_SIP)) {
+	printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
+	    cmd->pid);
+	NCR53c7x0_intr (host->irq, NULL, NULL);
+	return SCSI_ABORT_BUSY;
+    }
+	
+    save_flags(flags);
+    cli();
+#if 0
+    if (cache_pid == cmd->pid) 
+	panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
+    else
+	cache_pid = cmd->pid;
+#endif
+	
+
+/*
+ * The command could be hiding in the issue_queue.  This would be very
+ * nice, as commands can't be moved from the high level driver's issue queue 
+ * into the shared queue until an interrupt routine is serviced, and this
+ * moving is atomic.  
+ *
+ * If this is the case, we don't have to worry about anything - we simply
+ * pull the command out of the old queue, and call it aborted.
+ */
+
+    for (me = (Scsi_Cmnd *) hostdata->issue_queue, 
+         last = (Scsi_Cmnd **) &(hostdata->issue_queue);
+	 me && me != cmd;  last = (Scsi_Cmnd **)&(me->SCp.ptr), 
+	 me = (Scsi_Cmnd *)me->SCp.ptr);
+
+    if (me) {
+	*last = (Scsi_Cmnd *) me->SCp.ptr;
+	if (me->host_scribble) {
+	    ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
+	    hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
+	    me->host_scribble = NULL;
+	}
+	cmd->result = DID_ABORT << 16;
+	cmd->scsi_done(cmd);
+	printk ("scsi%d : found command %ld in Linux issue queue\n", 
+	    host->host_no, me->pid);
+	restore_flags(flags);
+    	run_process_issue_queue();
+	return SCSI_ABORT_SUCCESS;
+    }
+
+/* 
+ * That failing, the command could be in our list of already executing 
+ * commands.  If this is the case, drastic measures are called for.  
+ */ 
+
+    for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list, 
+    	 prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
+	 curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **) 
+         &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+
+    if (curr) {
+	if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+	    if (prev)
+		*prev = (struct NCR53c7x0_cmd *) curr->next;
+	    curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
+	    cmd->host_scribble = NULL;
+	    hostdata->free = curr;
+	    cmd->scsi_done(cmd);
+	printk ("scsi%d : found finished command %ld in running list\n", 
+	    host->host_no, cmd->pid);
+	    restore_flags(flags);
+	    return SCSI_ABORT_NOT_RUNNING;
+	} else {
+	    printk ("scsi%d : DANGER : command running, can not abort.\n",
+		cmd->host->host_no);
+	    restore_flags(flags);
+	    return SCSI_ABORT_BUSY;
+	}
+    }
+
+/* 
+ * And if we couldn't find it in any of our queues, it must have been 
+ * a dropped interrupt.
+ */
+
+    curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+    if (curr) {
+	curr->next = hostdata->free;
+	hostdata->free = curr;
+	cmd->host_scribble = NULL;
+    }
+
+    if (((cmd->result & 0xff00) == 0xff00) ||
+	((cmd->result & 0xff) == 0xff)) {
+	printk ("scsi%d : did this command ever run?\n", host->host_no);
+	cmd->result = DID_ABORT << 16;
+    } else {
+	printk ("scsi%d : probably lost INTFLY, normal completion\n", 
+	    host->host_no);
+/* 
+ * FIXME : We need to add an additional flag which indicates if a 
+ * command was ever counted as BUSY, so if we end up here we can
+ * decrement the busy count if and only if it is necessary.
+ */
+        --hostdata->busy[cmd->target][cmd->lun];
+    }
+    restore_flags(flags);
+    cmd->scsi_done(cmd);
+
+/* 
+ * We need to run process_issue_queue since termination of this command 
+ * may allow another queued command to execute first? 
+ */
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+/*
+ * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd) 
+ * 
+ * Purpose : perform a hard reset of the SCSI bus and NCR
+ * 	chip.
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ */
+ 
+int 
+NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    int found = 0;
+    struct NCR53c7x0_cmd * c;
+    Scsi_Cmnd *tmp;
+    /*
+     * When we call scsi_done(), it's going to wake up anything sleeping on the
+     * resources which were in use by the aborted commands, and we'll start to 
+     * get new commands.
+     *
+     * We can't let this happen until after we've re-initialized the driver
+     * structures, and can't reinitialize those structures until after we've 
+     * dealt with their contents.
+     *
+     * So, we need to find all of the commands which were running, stick
+     * them on a linked list of completed commands (we'll use the host_scribble
+     * pointer), do our reinitialization, and then call the done function for
+     * each command.  
+     */
+    Scsi_Cmnd *nuke_list = NULL;
+    struct Scsi_Host *host = cmd->host;
+    struct NCR53c7x0_hostdata *hostdata = 
+    	(struct NCR53c7x0_hostdata *) host->hostdata;
+
+    NCR53c7x0_local_setup(host);
+    save_flags(flags);
+    cli();
+    ncr_halt (host);
+    print_lots (host);
+    dump_events (host, 30);
+    ncr_scsi_reset (host);
+    for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
+	0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
+	if (tmp == cmd) {
+	    found = 1;
+	    break;
+	}
+	    
+    /* 
+     * If we didn't find the command which caused this reset in our running
+     * list, then we've lost it.  See that it terminates normally anyway.
+     */
+    if (!found) {
+    	c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+    	if (c) {
+	    cmd->host_scribble = NULL;
+    	    c->next = hostdata->free;
+    	    hostdata->free = c;
+    	} else
+	    printk ("scsi%d: lost command %ld\n", host->host_no, cmd->pid);
+	cmd->SCp.buffer = (struct scatterlist *) nuke_list;
+	nuke_list = cmd;
+    }
+
+    NCR53c7x0_driver_init (host);
+    hostdata->soft_reset (host);
+    if (hostdata->resets == 0) 
+	disable(host);
+    else if (hostdata->resets != -1)
+	--hostdata->resets;
+    sti();
+    for (; nuke_list; nuke_list = tmp) {
+	tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+    	nuke_list->result = DID_RESET << 16;
+	nuke_list->scsi_done (nuke_list);
+    }
+    restore_flags(flags);
+    return SCSI_RESET_SUCCESS;
+}
+
+/*
+ * The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and 
+ * therefore shares the scsicam_bios_param function.
+ */
+
+/*
+ * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
+ *
+ * Purpose : convert instructions stored at NCR pointer into data 
+ *	pointer offset.
+ * 
+ * Inputs : cmd - SCSI command; insn - pointer to instruction.  Either current
+ *	DSP, or saved data pointer.
+ *
+ * Returns : offset on success, -1 on failure.
+ */
+
+
+static int 
+insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) cmd->host->hostdata;
+    struct NCR53c7x0_cmd *ncmd = 
+	(struct NCR53c7x0_cmd *) cmd->host_scribble;
+    int offset = 0, buffers;
+    struct scatterlist *segment;
+    char *ptr;
+    int found = 0;
+
+/*
+ * With the current code implementation, if the insn is inside dynamically 
+ * generated code, the data pointer will be the instruction preceding 
+ * the next transfer segment.
+ */
+
+    if (!check_address ((unsigned long) ncmd, sizeof (struct NCR53c7x0_cmd)) &&
+	((insn >= ncmd->data_transfer_start &&  
+    	    insn < ncmd->data_transfer_end) ||
+    	(insn >= ncmd->residual &&
+    	    insn < (ncmd->residual + 
+    	    	sizeof(ncmd->residual))))) {
+	    ptr = bus_to_virt(insn[3]);
+
+	    if ((buffers = cmd->use_sg)) {
+    	    	for (offset = 0, 
+		     	segment = (struct scatterlist *) cmd->buffer;
+    	    	     buffers && !((found = ((ptr >= segment->address) && 
+    	    	    	    (ptr < (segment->address + segment->length)))));
+    	    	     --buffers, offset += segment->length, ++segment)
+#if 0
+		    printk("scsi%d: comparing 0x%p to 0x%p\n", 
+			cmd->host->host_no, saved, segment->address);
+#else
+		    ;
+#endif
+    	    	    offset += ptr - segment->address;
+    	    } else {
+		found = 1;
+    	    	offset = ptr - (char *) (cmd->request_buffer);
+    	    }
+    } else if ((insn >= hostdata->script + 
+		hostdata->E_data_transfer / sizeof(u32)) &&
+	       (insn <= hostdata->script +
+		hostdata->E_end_data_transfer / sizeof(u32))) {
+    	found = 1;
+	offset = 0;
+    }
+    return found ? offset : -1;
+}
+
+
+
+/*
+ * Function : void print_progress (Scsi_Cmnd *cmd) 
+ * 
+ * Purpose : print the current location of the saved data pointer
+ *
+ * Inputs : cmd - command we are interested in
+ *
+ */
+
+static void 
+print_progress (Scsi_Cmnd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_cmd *ncmd = 
+	(struct NCR53c7x0_cmd *) cmd->host_scribble;
+    int offset, i;
+    char *where;
+    u32 *ptr;
+    NCR53c7x0_local_setup (cmd->host);
+    for (i = 0; i < 2; ++i) {
+	if (check_address ((unsigned long) ncmd, 
+	    sizeof (struct NCR53c7x0_cmd)) == -1) 
+	    continue;
+	if (!i) {
+	    where = "saved";
+	    ptr = bus_to_virt(ncmd->saved_data_pointer);
+	} else {
+	    where = "active";
+	    ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
+		NCR53c7x0_insn_size (NCR53c7x0_read8 (DCMD_REG)) *
+		sizeof(u32));
+	} 
+	offset = insn_to_offset (cmd, ptr);
+
+	if (offset != -1) 
+	    printk ("scsi%d : %s data pointer at offset %d\n",
+		cmd->host->host_no, where, offset);
+	else {
+	    int size;
+	    printk ("scsi%d : can't determine %s data pointer offset\n",
+		cmd->host->host_no, where);
+	    if (ncmd) {
+		size = print_insn (cmd->host, 
+		    bus_to_virt(ncmd->saved_data_pointer), "", 1);
+		print_insn (cmd->host, 
+		    bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+		    "", 1);
+	    }
+	}
+    }
+}
+
+
+static void 
+print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    int i, len;
+    char *ptr;
+    Scsi_Cmnd *cmd;
+
+    if (check_address ((unsigned long) dsa, hostdata->dsa_end - 
+	hostdata->dsa_start) == -1) {
+	printk("scsi%d : bad dsa virt 0x%p\n", host->host_no, dsa);
+	return;
+    }
+    printk("%sscsi%d : dsa at phys 0x%lx (virt 0x%p)\n"
+	    "        + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
+    	    prefix ? prefix : "",
+    	    host->host_no,  virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
+    	    dsa[hostdata->dsa_msgout / sizeof(u32)],
+	    dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
+	    bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+
+    /* 
+     * Only print messages if they're sane in length so we don't
+     * blow the kernel printk buffer on something which won't buy us
+     * anything.
+     */
+
+    if (dsa[hostdata->dsa_msgout / sizeof(u32)] < 
+	    sizeof (hostdata->free->select)) 
+	for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
+	    ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]); 
+	    i > 0 && !check_address ((unsigned long) ptr, 1);
+	    ptr += len, i -= len) {
+	    printk("               ");
+	    len = print_msg (ptr);
+	    printk("\n");
+	    if (!len)
+		break;
+	}
+
+    printk("        + %d : select_indirect = 0x%x\n",
+	hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
+    cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+    printk("        + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
+	   (u32) virt_to_bus(cmd));
+    if (cmd) {
+	printk("               result = 0x%x, target = %d, lun = %d, cmd = ",
+	    cmd->result, cmd->target, cmd->lun);
+	print_command(cmd->cmnd);
+    } else
+	printk("\n");
+    printk("        + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
+	dsa[hostdata->dsa_next / sizeof(u32)]);
+    if (cmd) { 
+	printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
+	       "                   script : ",
+	    host->host_no, cmd->target,
+	    hostdata->sync[cmd->target].sxfer_sanity,
+	    hostdata->sync[cmd->target].scntl3_sanity);
+	for (i = 0; i < (sizeof(hostdata->sync[cmd->target].script) / 4); ++i)
+	    printk ("0x%x ", hostdata->sync[cmd->target].script[i]);
+	printk ("\n");
+    	print_progress (cmd);
+    }
+}
+/*
+ * Function : void print_queues (Scsi_Host *host) 
+ * 
+ * Purpose : print the contents of the NCR issue and reconnect queues
+ *
+ * Inputs : host - SCSI host we are interested in
+ *
+ */
+
+static void 
+print_queues (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    u32 *dsa, *next_dsa;
+    volatile u32 *ncrcurrent;
+    int left;
+    Scsi_Cmnd *cmd, *next_cmd;
+    unsigned long flags;
+
+    printk ("scsi%d : issue queue\n", host->host_no);
+
+    for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue; 
+	    left >= 0 && cmd; 
+	    cmd = next_cmd) {
+	next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
+	save_flags(flags);
+	cli();
+	if (cmd->host_scribble) {
+	    if (check_address ((unsigned long) (cmd->host_scribble), 
+		sizeof (cmd->host_scribble)) == -1)
+		printk ("scsi%d: scsi pid %ld bad pointer to NCR53c7x0_cmd\n",
+		    host->host_no, cmd->pid);
+	    /* print_dsa does sanity check on address, no need to check */
+	    else
+	    	print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
+		    -> dsa, "");
+	} else 
+	    printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
+		host->host_no, cmd->pid, cmd->target, cmd->lun);
+	restore_flags(flags);
+    }
+
+    if (left <= 0) {
+	printk ("scsi%d : loop detected in issue queue\n",
+	    host->host_no);
+    }
+
+    /*
+     * Traverse the NCR reconnect and start DSA structures, printing out 
+     * each element until we hit the end or detect a loop.  Currently,
+     * the reconnect structure is a linked list; and the start structure
+     * is an array.  Eventually, the reconnect structure will become a 
+     * list as well, since this simplifies the code.
+     */
+
+    printk ("scsi%d : schedule dsa array :\n", host->host_no);
+    for (left = host->can_queue, ncrcurrent = hostdata->schedule;
+	    left > 0; ncrcurrent += 2, --left)
+	if (ncrcurrent[0] != hostdata->NOP_insn) 
+/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
+	    print_dsa (host, bus_to_virt (ncrcurrent[1] - 
+		(hostdata->E_dsa_code_begin - 
+		hostdata->E_dsa_code_template)), "");
+    printk ("scsi%d : end schedule dsa array\n", host->host_no);
+    
+    printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
+	    
+    for (left = host->can_queue, 
+	dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+	left >= 0 && dsa; 
+	dsa = next_dsa) {
+	save_flags (flags);
+	cli();
+	if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
+	    printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
+		dsa);
+	    next_dsa = NULL;
+	}
+	else 
+	{
+	    next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+	    print_dsa (host, dsa, "");
+	}
+	restore_flags(flags);
+    }
+    printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
+    if (left < 0)
+	printk("scsi%d: possible loop in ncr reconnect list\n",
+	    host->host_no);
+}
+
+static void
+print_lots (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata;
+    u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
+    unsigned char dcmd, sbcl;
+    int i, size;
+    NCR53c7x0_local_setup(host);
+
+    if ((dsp_next = bus_to_virt(NCR53c7x0_read32 (DSP_REG)))) {
+    	dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+    	dcmd = (dbc_dcmd & 0xff000000) >> 24;
+    	dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+	dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+	sbcl = NCR53c7x0_read8 (SBCL_REG);
+	    
+	/*
+	 * For the 53c710, the following will report value 0 for SCNTL3
+	 * and STEST0 - we dont have these registers.
+	 */
+    	printk ("scsi%d : DCMD|DBC=0x%x, DNAD=0x%x (virt 0x%p)\n"
+		"         DSA=0x%lx (virt 0x%p)\n"
+	        "         DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
+		"         SXFER=0x%x, SCNTL3=0x%x\n"
+		"         %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
+		"         STEST0=0x%x\n",
+	    host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
+		bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
+	    virt_to_bus(dsa), dsa,
+	    NCR53c7x0_read32(DSPS_REG), NCR53c7x0_read32(TEMP_REG), 
+	    bus_to_virt (NCR53c7x0_read32(TEMP_REG)),
+	    (int) NCR53c7x0_read8(hostdata->dmode),
+	    (int) NCR53c7x0_read8(SXFER_REG), 
+	    ((hostdata->chip / 100) == 8) ?
+		(int) NCR53c7x0_read8(SCNTL3_REG_800) : 0,
+	    (sbcl & SBCL_BSY) ? "BSY " : "",
+	    (sbcl & SBCL_SEL) ? "SEL " : "",
+	    (sbcl & SBCL_REQ) ? "REQ " : "",
+	    sstat2_to_phase(NCR53c7x0_read8 (((hostdata->chip / 100) == 8) ?
+	    	SSTAT1_REG : SSTAT2_REG)),
+	    (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ? 
+		SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
+	    ((hostdata->chip / 100) == 8) ?
+		NCR53c7x0_read8 (STEST0_REG_800) : 0);
+	printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no, 
+	    virt_to_bus(dsp), dsp);
+    	for (i = 6; i > 0; --i, dsp += size)
+	    size = print_insn (host, dsp, "", 1);
+	if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON)  {
+	    if ((hostdata->chip / 100) == 8)
+	        printk ("scsi%d : connected (SDID=0x%x, SSID=0x%x)\n",
+		    host->host_no, NCR53c7x0_read8 (SDID_REG_800),
+		    NCR53c7x0_read8 (SSID_REG_800));
+	    else
+		printk ("scsi%d : connected (SDID=0x%x)\n",
+		    host->host_no, NCR53c7x0_read8 (SDID_REG_700));
+	    print_dsa (host, dsa, "");
+	}
+
+#if 1
+	print_queues (host);
+#endif
+    }
+}
+
+/*
+ * Function : static int shutdown (struct Scsi_Host *host)
+ * 
+ * Purpose : does a clean (we hope) shutdown of the NCR SCSI 
+ *	chip.  Use prior to dumping core, unloading the NCR driver,
+ * 
+ * Returns : 0 on success
+ */
+static int 
+shutdown (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    NCR53c7x0_local_setup(host);
+    save_flags (flags);
+    cli();
+/* Get in a state where we can reset the SCSI bus */
+    ncr_halt (host);
+    ncr_scsi_reset (host);
+    hostdata->soft_reset(host);
+
+    disable (host);
+    restore_flags (flags);
+    return 0;
+}
+
+/*
+ * Function : void ncr_scsi_reset (struct Scsi_Host *host)
+ *
+ * Purpose : reset the SCSI bus.
+ */
+
+static void 
+ncr_scsi_reset (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+    save_flags (flags);
+    cli();
+    NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+    udelay(25);	/* Minimum amount of time to assert RST */
+    NCR53c7x0_write8(SCNTL1_REG, 0);
+    restore_flags (flags);
+}
+
+/* 
+ * Function : void hard_reset (struct Scsi_Host *host)
+ *
+ */
+
+static void 
+hard_reset (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    unsigned long flags;
+    save_flags (flags);
+    cli();
+    ncr_scsi_reset(host);
+    NCR53c7x0_driver_init (host);
+    if (hostdata->soft_reset)
+	hostdata->soft_reset (host);
+    restore_flags(flags);
+}
+
+
+/*
+ * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
+ *	int free, int issue)
+ *
+ * Purpose : return a linked list (using the SCp.buffer field as next,
+ *	so we don't perturb hostdata.  We don't use a field of the 
+ *	NCR53c7x0_cmd structure since we may not have allocated one 
+ *	for the command causing the reset.) of Scsi_Cmnd structures that 
+ *  	had propogated below the Linux issue queue level.  If free is set, 
+ *	free the NCR53c7x0_cmd structures which are associated with 
+ *	the Scsi_Cmnd structures, and clean up any internal 
+ *	NCR lists that the commands were on.  If issue is set,
+ *	also return commands in the issue queue.
+ *
+ * Returns : linked list of commands
+ *
+ * NOTE : the caller should insure that the NCR chip is halted
+ *	if the free flag is set. 
+ */
+
+static Scsi_Cmnd *
+return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    struct NCR53c7x0_cmd *c;
+    int i;
+    u32 *ncrcurrent;
+    Scsi_Cmnd *list = NULL, *tmp;
+    for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c; 
+    	c = (struct NCR53c7x0_cmd *) c->next)  {
+	if (c->cmd->SCp.buffer) {
+	    printk ("scsi%d : loop detected in running list!\n", host->host_no);
+	    break;
+	} else {
+	    printk ("The sti() implicit in a printk() prevents hangs\n");
+	    break;
+	}
+
+	c->cmd->SCp.buffer = (struct scatterlist *) list;
+	list = c->cmd;
+	if (free) {
+    	    c->next = hostdata->free;
+    	    hostdata->free = c;
+	}
+    }
+
+    if (free) { 
+	for (i = 0, ncrcurrent = (u32 *) hostdata->schedule; 
+	    i < host->can_queue; ++i, ncrcurrent += 2) {
+	    ncrcurrent[0] = hostdata->NOP_insn;
+	    ncrcurrent[1] = 0xdeadbeef;
+	}
+	hostdata->ncrcurrent = NULL;
+    }
+
+    if (issue) {
+	for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
+	    if (tmp->SCp.buffer) {
+		printk ("scsi%d : loop detected in issue queue!\n", 
+			host->host_no);
+		break;
+	    }
+	    tmp->SCp.buffer = (struct scatterlist *) list;
+	    list = tmp;
+	}
+	if (free)
+	    hostdata->issue_queue = NULL;
+		
+    }
+    return list;
+}
+
+/* 
+ * Function : static int disable (struct Scsi_Host *host)
+ *
+ * Purpose : disables the given NCR host, causing all commands
+ * 	to return a driver error.  Call this so we can unload the
+ * 	module during development and try again.  Eventually, 
+ * 	we should be able to find clean workarounds for these
+ * 	problems.
+ *
+ * Inputs : host - hostadapter to twiddle
+ *
+ * Returns : 0 on success.
+ */
+
+static int 
+disable (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    unsigned long flags;
+    Scsi_Cmnd *nuke_list, *tmp;
+    save_flags(flags);
+    cli();
+    if (hostdata->state != STATE_HALTED)
+	ncr_halt (host);
+    nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
+    hard_reset (host);
+    hostdata->state = STATE_DISABLED;
+    restore_flags(flags);
+    printk ("scsi%d : nuking commands\n", host->host_no);
+    for (; nuke_list; nuke_list = tmp) {
+	    tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+	    nuke_list->result = DID_ERROR << 16;
+	    nuke_list->scsi_done(nuke_list);
+    }
+    printk ("scsi%d : done. \n", host->host_no);
+    printk (KERN_ALERT "scsi%d : disabled.  Unload and reload\n",
+    	host->host_no);
+    return 0;
+}
+
+/*
+ * Function : static int ncr_halt (struct Scsi_Host *host)
+ * 
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int 
+ncr_halt (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    unsigned char istat, tmp;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    int stage;
+    NCR53c7x0_local_setup(host);
+
+    save_flags(flags);
+    cli();
+    /* Stage 0 : eat all interrupts
+       Stage 1 : set ABORT
+       Stage 2 : eat all but abort interrupts
+       Stage 3 : eat all interrupts
+     */
+    for (stage = 0;;) {
+	if (stage == 1) {
+	    NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
+	    ++stage;
+	}
+	istat = NCR53c7x0_read8 (hostdata->istat);
+	if (istat & ISTAT_SIP) {
+	    tmp = NCR53c7x0_read8(SSTAT0_REG);
+	} else if (istat & ISTAT_DIP) {
+	    tmp = NCR53c7x0_read8(DSTAT_REG);
+	    if (stage == 2) {
+		if (tmp & DSTAT_ABRT) {
+		    NCR53c7x0_write8(hostdata->istat, 0);
+		    ++stage;
+		} else {
+		    printk(KERN_ALERT "scsi%d : could not halt NCR chip\n", 
+			host->host_no);
+		    disable (host);
+	    	}
+    	    }
+	}
+	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) 
+	    if (stage == 0)
+	    	++stage;
+	    else if (stage == 3)
+		break;
+    }
+    hostdata->state = STATE_HALTED;
+    restore_flags(flags);
+#if 0
+    print_lots (host);
+#endif
+    return 0;
+}
+
+/* 
+ * Function: event_name (int event)
+ * 
+ * Purpose: map event enum into user-readable strings.
+ */
+
+static const char *
+event_name (int event) {
+    switch (event) {
+    case EVENT_NONE:		return "none";
+    case EVENT_ISSUE_QUEUE:	return "to issue queue";
+    case EVENT_START_QUEUE:	return "to start queue";
+    case EVENT_SELECT:		return "selected";
+    case EVENT_DISCONNECT:	return "disconnected";
+    case EVENT_RESELECT:	return "reselected";
+    case EVENT_COMPLETE:	return "completed";
+    case EVENT_IDLE:		return "idle";
+    case EVENT_SELECT_FAILED:	return "select failed";
+    case EVENT_BEFORE_SELECT:	return "before select";
+    case EVENT_RESELECT_FAILED:	return "reselect failed";
+    default:			return "unknown";
+    }
+}
+
+/*
+ * Function : void dump_events (struct Scsi_Host *host, count)
+ *
+ * Purpose : print last count events which have occurred.
+ */ 
+static void
+dump_events (struct Scsi_Host *host, int count) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata;
+    struct NCR53c7x0_event event;
+    int i;
+    unsigned long flags;
+    if (hostdata->events) {
+	if (count > hostdata->event_size)
+	    count = hostdata->event_size;
+	for (i = hostdata->event_index; count > 0; 
+	    i = (i ? i - 1 : hostdata->event_size -1), --count) {
+	    save_flags(flags);
+/*
+ * By copying the event we're currently examining with interrupts
+ * disabled, we can do multiple printk(), etc. operations and 
+ * still be guaranteed that they're happening on the same 
+ * event structure.
+ */
+	    cli();
+#if 0
+	    event = hostdata->events[i];
+#else
+	    memcpy ((void *) &event, (void *) &(hostdata->events[i]),
+		sizeof(event));
+#endif
+
+	    restore_flags(flags);
+	    printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
+		host->host_no, event_name (event.event), count,
+		(long) event.time.tv_sec, (long) event.time.tv_usec,
+		event.target, event.lun);
+	    if (event.dsa) 
+		printk ("         event for dsa 0x%lx (virt 0x%p)\n", 
+		    virt_to_bus(event.dsa), event.dsa);
+	    if (event.pid != -1) {
+		printk ("         event for pid %ld ", event.pid);
+		print_command (event.cmnd);
+	    }
+	}
+    }
+}
+
+/*
+ * Function: check_address
+ *
+ * Purpose: Check to see if a possibly corrupt pointer will fault the 
+ *	kernel.
+ *
+ * Inputs: addr - address; size - size of area
+ *
+ * Returns: 0 if area is OK, -1 on error.
+ *
+ * NOTES: should be implemented in terms of vverify on kernels 
+ *	that have it.
+ */
+
+static int 
+check_address (unsigned long addr, int size) {
+    return (MAP_NR(addr) < 1 || MAP_NR(addr + size) > MAP_NR(high_memory) ?
+	    -1 : 0);
+}
+
+#ifdef MODULE
+int 
+NCR53c7x0_release(struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata;
+    struct NCR53c7x0_cmd *cmd, *tmp;
+    shutdown (host);
+    if (host->irq != IRQ_NONE)
+	{
+	    int irq_count;
+	    struct Scsi_Host *tmp;
+	    for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
+		if (tmp->hostt == the_template && tmp->irq == host->irq)
+		    ++irq_count;
+	    if (irq_count == 1)
+		free_irq(host->irq, NULL);
+	}
+    if (host->dma_channel != DMA_NONE)
+	free_dma(host->dma_channel);
+    if (host->io_port)
+	release_region(host->io_port, host->n_io_port);
+    
+    for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp, 
+	--hostdata->num_cmds) {
+	tmp = (struct NCR53c7x0_cmd *) cmd->next;
+    /* 
+     * If we're going to loop, try to stop it to get a more accurate
+     * count of the leaked commands.
+     */
+	cmd->next = NULL;
+	if (cmd->free)
+	    cmd->free ((void *) cmd->real, cmd->size);
+    }
+    if (hostdata->num_cmds)
+	printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n",
+	    host->host_no, hostdata->num_cmds);
+    if (hostdata->events) 
+	vfree ((void *)hostdata->events);
+    return 1;
+}
+Scsi_Host_Template driver_template = NCR53c7xx;
+#include "scsi_module.c"
+#endif /* def MODULE */
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/53c7xx.h linux/drivers/scsi/53c7xx.h
--- v2.1.39/linux/drivers/scsi/53c7xx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/53c7xx.h	Sun May 18 17:10:37 1997
@@ -0,0 +1,1675 @@
+/*
+ * 53c710 driver.  Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * I have left the code for the 53c8xx family in here, because it didn't
+ * seem worth removing it.  The possibility of IO_MAPPED chips rather
+ * than MEMORY_MAPPED remains, in case someone wants to add support for
+ * 53c710 chips on Intel PCs (some older machines have them on the
+ * motherboard).
+ *
+ * NOTE THERE MAY BE PROBLEMS WITH CASTS IN read8 AND Co.
+ */
+
+/*
+ * NCR 53c{7,8}0x0 driver, header file
+ *
+ * Sponsored by
+ *      iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de	
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@PoohSticks.ORG
+ *	+1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ * 
+ * PRE-ALPHA
+ *
+ * For more information, please consult 
+ *
+ * NCR 53C700/53C700-66
+ * SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor 
+ * Data Manual
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * +1 (719) 578-3400
+ *
+ * Toll free literature number
+ * +1 (800) 334-5454
+ *
+ */
+
+#ifndef NCR53c710_H
+#define NCR53c710_H
+#if !defined(LINUX_1_2) && !defined(LINUX_1_3)
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > 65536 + 3 * 256
+#define LINUX_1_3
+#else
+#define LINUX_1_2
+#endif
+#endif
+
+/* 
+ * Prevent name space pollution in hosts.c, and only provide the 
+ * define we need to get the NCR53c7x0 driver into the host template
+ * array.
+ */
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern int NCR53c7xx_abort(Scsi_Cmnd *);
+extern int NCR53c7xx_detect(Scsi_Host_Template *tpnt);
+extern int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+#ifdef MODULE
+extern int NCR53c7xx_release(struct Scsi_Host *);
+#else
+#define NCR53c7xx_release NULL
+#endif
+
+#ifdef LINUX_1_2
+#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
+	NULL, /* info */ NULL, /* command, deprecated */ NULL, 		\
+	NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,	\
+	NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
+	/* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, 		\
+	/* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
+#else
+#define NCR53c7xx {NULL, NULL, NULL, NULL, \
+        "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
+        NULL, /* info */ NULL, /* command, deprecated */ NULL,		\
+	NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset,	\
+	NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
+	/* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, 		\
+	/* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */ 
+
+#ifndef HOSTS_C
+#ifdef LINUX_1_2
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
+ * make the kernel segment mapped at 0, we need to do translation
+ * on the i386 as well)
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{       
+	return (unsigned long) address;
+}       
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+	return (void *) address;      
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+#define mb()
+
+#endif /* def LINUX_1_2 */
+
+/* SCSI control 0 rw, default = 0xc0 */ 
+#define SCNTL0_REG 		0x00	
+#define SCNTL0_ARB1		0x80	/* 0 0 = simple arbitration */
+#define SCNTL0_ARB2		0x40	/* 1 1 = full arbitration */
+#define SCNTL0_STRT		0x20	/* Start Sequence */
+#define SCNTL0_WATN		0x10	/* Select with ATN */
+#define SCNTL0_EPC		0x08	/* Enable parity checking */
+/* Bit 2 is reserved on 800 series chips */
+#define SCNTL0_EPG_700		0x04	/* Enable parity generation */
+#define SCNTL0_AAP		0x02	/*  ATN/ on parity error */
+#define SCNTL0_TRG		0x01	/* Target mode */
+
+/* SCSI control 1 rw, default = 0x00 */
+
+#define SCNTL1_REG 		0x01	
+#define SCNTL1_EXC		0x80	/* Extra Clock Cycle of Data setup */
+#define SCNTL1_ADB		0x40	/*  contents of SODL on bus */
+#define SCNTL1_ESR_700		0x20	/* Enable SIOP response to selection 
+					   and reselection */
+#define SCNTL1_DHP_800		0x20	/* Disable halt on parity error or ATN
+					   target mode only */
+#define SCNTL1_CON		0x10	/* Connected */
+#define SCNTL1_RST		0x08	/* SCSI RST/ */
+#define SCNTL1_AESP		0x04	/* Force bad parity */
+#define SCNTL1_SND_700		0x02	/* Start SCSI send */
+#define SCNTL1_IARB_800		0x02	/* Immediate Arbitration, start
+					   arbitration immediately after
+					   busfree is detected */
+#define SCNTL1_RCV_700		0x01	/* Start SCSI receive */
+#define SCNTL1_SST_800		0x01	/* Start SCSI transfer */
+
+/* SCSI control 2 rw, */
+
+#define SCNTL2_REG_800		0x02	
+#define SCNTL2_800_SDU		0x80	/* SCSI disconnect unexpected */
+
+/* SCSI control 3 rw */
+
+#define SCNTL3_REG_800 		0x03	
+#define SCNTL3_800_SCF_SHIFT	4
+#define SCNTL3_800_SCF_MASK	0x70
+#define SCNTL3_800_SCF2		0x40	/* Synchronous divisor */
+#define SCNTL3_800_SCF1		0x20	/* 0x00 = SCLK/3 */
+#define SCNTL3_800_SCF0		0x10	/* 0x10 = SCLK/1 */
+					/* 0x20 = SCLK/1.5 
+					   0x30 = SCLK/2 
+					   0x40 = SCLK/3 */
+	    
+#define SCNTL3_800_CCF_SHIFT	0
+#define SCNTL3_800_CCF_MASK	0x07
+#define SCNTL3_800_CCF2		0x04	/* 0x00 50.01 to 66 */
+#define SCNTL3_800_CCF1		0x02	/* 0x01 16.67 to 25 */
+#define SCNTL3_800_CCF0		0x01	/* 0x02	25.01 - 37.5 
+					   0x03	37.51 - 50 
+					   0x04 50.01 - 66 */
+
+/*  
+ * SCSI destination ID rw - the appropriate bit is set for the selected
+ * target ID.  This is written by the SCSI SCRIPTS processor.
+ * default = 0x00
+ */
+#define SDID_REG_700  		0x02	
+#define SDID_REG_800		0x06
+
+#define GP_REG_800		0x07	/* General purpose IO */
+#define GP_800_IO1		0x02
+#define GP_800_IO2		0x01
+
+/* SCSI interrupt enable rw, default = 0x00 */
+#define SIEN_REG_700		0x03	
+#define SIEN0_REG_800		0x40
+#define SIEN_MA			0x80	/* Phase mismatch (ini) or ATN (tgt) */
+#define SIEN_FC			0x40	/* Function complete */
+#define SIEN_700_STO		0x20	/* Selection or reselection timeout */
+#define SIEN_800_SEL		0x20	/* Selected */
+#define SIEN_700_SEL		0x10	/* Selected or reselected */
+#define SIEN_800_RESEL		0x10	/* Reselected */
+#define SIEN_SGE		0x08	/* SCSI gross error */
+#define SIEN_UDC		0x04	/* Unexpected disconnect */
+#define SIEN_RST		0x02	/* SCSI RST/ received */
+#define SIEN_PAR		0x01	/* Parity error */
+
+/* 
+ * SCSI chip ID rw
+ * NCR53c700 : 
+ * 	When arbitrating, the highest bit is used, when reselection or selection
+ * 	occurs, the chip responds to all IDs for which a bit is set.
+ * 	default = 0x00 
+ * NCR53c810 : 
+ *	Uses bit mapping
+ */
+#define SCID_REG		0x04	
+/* Bit 7 is reserved on 800 series chips */
+#define SCID_800_RRE		0x40	/* Enable response to reselection */
+#define SCID_800_SRE		0x20	/* Enable response to selection */
+/* Bits four and three are reserved on 800 series chips */
+#define SCID_800_ENC_MASK	0x07	/* Encoded SCSI ID */
+
+/* SCSI transfer rw, default = 0x00 */
+#define SXFER_REG		0x05
+#define SXFER_DHP		0x80	/* Disable halt on parity */
+
+#define SXFER_TP2		0x40	/* Transfer period msb */
+#define SXFER_TP1		0x20
+#define SXFER_TP0		0x10	/* lsb */
+#define SXFER_TP_MASK		0x70
+/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
+#define SXFER_TP_SHIFT		5
+#define SXFER_TP_4		0x00	/* Divisors */
+#define SXFER_TP_5		0x10<<1
+#define SXFER_TP_6		0x20<<1
+#define SXFER_TP_7		0x30<<1
+#define SXFER_TP_8		0x40<<1
+#define SXFER_TP_9		0x50<<1
+#define SXFER_TP_10		0x60<<1
+#define SXFER_TP_11		0x70<<1
+
+#define SXFER_MO3		0x08	/* Max offset msb */
+#define SXFER_MO2		0x04
+#define SXFER_MO1		0x02
+#define SXFER_MO0		0x01	/* lsb */
+#define SXFER_MO_MASK		0x0f
+#define SXFER_MO_SHIFT		0
+
+/* 
+ * SCSI output data latch rw
+ * The contents of this register are driven onto the SCSI bus when 
+ * the Assert Data Bus bit of the SCNTL1 register is set and 
+ * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
+ */
+#define SODL_REG_700		0x06	
+#define SODL_REG_800		0x54
+
+
+/* 
+ * SCSI output control latch rw, default = 0 
+ * Note that when the chip is being manually programmed as an initiator,
+ * the MSG, CD, and IO bits must be set correctly for the phase the target
+ * is driving the bus in.  Otherwise no data transfer will occur due to 
+ * phase mismatch.
+ */
+
+#define SOCL_REG		0x07
+#define SOCL_REQ		0x80	/*  REQ */
+#define SOCL_ACK		0x40	/*  ACK */
+#define SOCL_BSY		0x20	/*  BSY */
+#define SOCL_SEL		0x10	/*  SEL */
+#define SOCL_ATN		0x08	/*  ATN */
+#define SOCL_MSG		0x04	/*  MSG */
+#define SOCL_CD			0x02	/*  C/D */
+#define SOCL_IO			0x01	/*  I/O */
+
+/* 
+ * SCSI first byte received latch ro 
+ * This register contains the first byte received during a block MOVE 
+ * SCSI SCRIPTS instruction, including
+ * 
+ * Initiator mode	Target mode
+ * Message in		Command
+ * Status		Message out
+ * Data in		Data out
+ *
+ * It also contains the selecting or reselecting device's ID and our 
+ * ID.
+ *
+ * Note that this is the register the various IF conditionals can 
+ * operate on.
+ */
+#define SFBR_REG		0x08	
+
+/* 
+ * SCSI input data latch ro
+ * In initiator mode, data is latched into this register on the rising
+ * edge of REQ/. In target mode, data is latched on the rising edge of 
+ * ACK/
+ */
+#define SIDL_REG_700		0x09
+#define SIDL_REG_800		0x50
+
+/* 
+ * SCSI bus data lines ro 
+ * This register reflects the instantaneous status of the SCSI data 
+ * lines.  Note that SCNTL0 must be set to disable parity checking, 
+ * otherwise reading this register will latch new parity.
+ */
+#define SBDL_REG_700		0x0a
+#define SBDL_REG_800		0x58
+
+#define SSID_REG_800		0x0a
+#define SSID_800_VAL		0x80	/* Exactly two bits asserted at sel */
+#define SSID_800_ENCID_MASK	0x07	/* Device which performed operation */
+
+
+/* 
+ * SCSI bus control lines rw, 
+ * instantaneous readout of control lines 
+ */
+#define SBCL_REG		0x0b 	
+#define SBCL_REQ		0x80	/*  REQ ro */
+#define SBCL_ACK		0x40	/*  ACK ro */
+#define SBCL_BSY		0x20	/*  BSY ro */
+#define SBCL_SEL		0x10	/*  SEL ro */
+#define SBCL_ATN		0x08	/*  ATN ro */
+#define SBCL_MSG		0x04	/*  MSG ro */
+#define SBCL_CD			0x02	/*  C/D ro */
+#define SBCL_IO			0x01	/*  I/O ro */
+#define SBCL_PHASE_CMDOUT	SBCL_CD
+#define SBCL_PHASE_DATAIN	SBCL_IO
+#define SBCL_PHASE_DATAOUT	0
+#define SBCL_PHASE_MSGIN	(SBCL_CD|SBCL_IO|SBCL_MSG)
+#define SBCL_PHASE_MSGOUT	(SBCL_CD|SBCL_MSG)
+#define SBCL_PHASE_STATIN	(SBCL_CD|SBCL_IO)
+#define SBCL_PHASE_MASK		(SBCL_CD|SBCL_IO|SBCL_MSG)
+/* 
+ * Synchronous SCSI Clock Control bits 
+ * 0 - set by DCNTL 
+ * 1 - SCLK / 1.0
+ * 2 - SCLK / 1.5
+ * 3 - SCLK / 2.0 
+ */
+#define SBCL_SSCF1		0x02	/* wo, -66 only */
+#define SBCL_SSCF0		0x01	/* wo, -66 only */
+#define SBCL_SSCF_MASK		0x03
+
+/* 
+ * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
+ * insure that 10 clocks elapse between the two  
+ */
+/* DMA status ro */
+#define DSTAT_REG		0x0c	
+#define DSTAT_DFE		0x80	/* DMA FIFO empty */
+#define DSTAT_800_MDPE		0x40	/* Master Data Parity Error */
+#define DSTAT_800_BF		0x20	/* Bus Fault */
+#define DSTAT_ABRT		0x10	/* Aborted - set on error */
+#define DSTAT_SSI		0x08	/* SCRIPTS single step interrupt */
+#define DSTAT_SIR		0x04	/* SCRIPTS interrupt received - 
+					   set when INT instruction is 
+					   executed */
+#define DSTAT_WTD		0x02	/* Watchdog timeout detected */
+#define DSTAT_OPC		0x01	/* Illegal instruction */
+#define DSTAT_800_IID		0x01	/* Same thing, different name */
+
+
+/* NCR53c800 moves this stuff into SIST0 */
+#define SSTAT0_REG		0x0d	/* SCSI status 0 ro */
+#define SIST0_REG_800		0x42	
+#define SSTAT0_MA		0x80	/* ini : phase mismatch,
+					 * tgt : ATN/ asserted 
+					 */
+#define SSTAT0_CMP		0x40	/* function complete */
+#define SSTAT0_700_STO		0x20	/* Selection or reselection timeout */
+#define SIST0_800_SEL		0x20	/* Selected */
+#define SSTAT0_700_SEL		0x10	/* Selected or reselected */
+#define SIST0_800_RSL		0x10	/* Reselected */
+#define SSTAT0_SGE		0x08	/* SCSI gross error */
+#define SSTAT0_UDC		0x04	/* Unexpected disconnect */
+#define SSTAT0_RST		0x02	/* SCSI RST/ received */
+#define SSTAT0_PAR		0x01	/* Parity error */
+
+/* And uses SSTAT0 for what was SSTAT1 */
+
+#define SSTAT1_REG		0x0e	/* SCSI status 1 ro */
+#define SSTAT1_ILF		0x80	/* SIDL full */
+#define SSTAT1_ORF		0x40	/* SODR full */
+#define SSTAT1_OLF		0x20	/* SODL full */
+#define SSTAT1_AIP		0x10	/* Arbitration in progress */
+#define SSTAT1_LOA		0x08	/* Lost arbitration */
+#define SSTAT1_WOA		0x04	/* Won arbitration */
+#define SSTAT1_RST		0x02	/* Instant readout of RST/ */
+#define SSTAT1_SDP		0x01	/* Instant readout of SDP/ */
+
+#define SSTAT2_REG		0x0f	/* SCSI status 2 ro */
+#define SSTAT2_FF3		0x80 	/* number of bytes in synchronous */
+#define SSTAT2_FF2		0x40	/* data FIFO */
+#define SSTAT2_FF1		0x20	
+#define SSTAT2_FF0		0x10
+#define SSTAT2_FF_MASK		0xf0
+#define SSTAT2_FF_SHIFT		4
+
+/* 
+ * Latched signals, latched on the leading edge of REQ/ for initiators,
+ * ACK/ for targets.
+ */
+#define SSTAT2_SDP		0x08	/* SDP */
+#define SSTAT2_MSG		0x04	/* MSG */
+#define SSTAT2_CD		0x02	/* C/D */
+#define SSTAT2_IO		0x01	/* I/O */
+#define SSTAT2_PHASE_CMDOUT	SSTAT2_CD
+#define SSTAT2_PHASE_DATAIN	SSTAT2_IO
+#define SSTAT2_PHASE_DATAOUT	0
+#define SSTAT2_PHASE_MSGIN	(SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+#define SSTAT2_PHASE_MSGOUT	(SSTAT2_CD|SSTAT2_MSG)
+#define SSTAT2_PHASE_STATIN	(SSTAT2_CD|SSTAT2_IO)
+#define SSTAT2_PHASE_MASK	(SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHA_REG_00		0x10    /* through  0x13 Scratch A rw */
+/* NCR53c710 and higher */
+#define DSA_REG			0x10	/* DATA structure address */
+
+#define CTEST0_REG_700		0x14	/* Chip test 0 ro */
+#define CTEST0_REG_800		0x18	/* Chip test 0 rw, general purpose */
+/* 0x80 - 0x04 are reserved */
+#define CTEST0_700_RTRG		0x02	/* Real target mode */
+#define CTEST0_700_DDIR		0x01	/* Data direction, 1 = 
+					 * SCSI bus to host, 0  =
+					 * host to SCSI.
+					 */
+
+#define CTEST1_REG_700		0x15	/* Chip test 1 ro */
+#define CTEST1_REG_800		0x19	/* Chip test 1 ro */
+#define CTEST1_FMT3		0x80	/* Identify which byte lanes are empty */
+#define CTEST1_FMT2		0x40 	/* in the DMA FIFO */
+#define CTEST1_FMT1		0x20
+#define CTEST1_FMT0		0x10
+
+#define CTEST1_FFL3		0x08	/* Identify which bytes lanes are full */
+#define CTEST1_FFL2		0x04	/* in the DMA FIFO */
+#define CTEST1_FFL1		0x02
+#define CTEST1_FFL0		0x01
+
+#define CTEST2_REG_700		0x16	/* Chip test 2 ro */
+#define CTEST2_REG_800		0x1a	/* Chip test 2 ro */
+
+#define CTEST2_800_DDIR		0x80	/* 1 = SCSI->host */
+#define CTEST2_800_SIGP		0x40	/* A copy of SIGP in ISTAT.
+					   Reading this register clears */
+#define CTEST2_800_CIO		0x20	/* Configured as IO */.
+#define CTEST2_800_CM		0x10	/* Configured as memory */
+
+/* 0x80 - 0x40 are reserved on 700 series chips */
+#define CTEST2_700_SOFF		0x20	/* SCSI Offset Compare,
+					 * As an initiator, this bit is 
+					 * one when the synchronous offset
+					 * is zero, as a target this bit 
+					 * is one when the synchronous 
+					 * offset is at the maximum
+					 * defined in SXFER
+					 */
+#define CTEST2_700_SFP		0x10	/* SCSI FIFO parity bit,
+					 * reading CTEST3 unloads a byte
+					 * from the FIFO and sets this
+					 */
+#define CTEST2_700_DFP		0x08	/* DMA FIFO parity bit,
+					 * reading CTEST6 unloads a byte
+					 * from the FIFO and sets this
+					 */
+#define CTEST2_TEOP		0x04	/* SCSI true end of process,
+					 * indicates a totally finished
+					 * transfer
+					 */
+#define CTEST2_DREQ		0x02	/* Data request signal */
+/* 0x01 is reserved on 700 series chips */
+#define CTEST2_800_DACK		0x01	
+
+/* 
+ * Chip test 3 ro 
+ * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
+ * check SSTAT2 FIFO full bits to determine size.  Note that a GROSS
+ * error results if a read is attempted on this register.  Also note 
+ * that 16 and 32 bit reads of this register will cause corruption.
+ */
+#define CTEST3_REG_700		0x17	
+/*  Chip test 3 rw */
+#define CTEST3_REG_800		0x1b
+#define CTEST3_800_V3		0x80	/* Chip revision */
+#define CTEST3_800_V2		0x40
+#define CTEST3_800_V1		0x20
+#define CTEST3_800_V0		0x10
+#define CTEST3_800_FLF		0x08	/* Flush DMA FIFO */
+#define CTEST3_800_CLF		0x04	/* Clear DMA FIFO */
+#define CTEST3_800_FM		0x02	/* Fetch mode pin */
+/* bit 0 is reserved on 800 series chips */
+
+#define CTEST4_REG_700		0x18	/* Chip test 4 rw */
+#define CTEST4_REG_800		0x21	/* Chip test 4 rw */
+/* 0x80 is reserved on 700 series chips */
+#define CTEST4_800_BDIS		0x80	/* Burst mode disable */
+#define CTEST4_ZMOD		0x40	/* High impedance mode */
+#define CTEST4_SZM		0x20	/* SCSI bus high impedance */
+#define CTEST4_700_SLBE		0x10	/* SCSI loopback enabled */
+#define CTEST4_800_SRTM		0x10	/* Shadow Register Test Mode */
+#define CTEST4_700_SFWR		0x08	/* SCSI FIFO write enable, 
+					 * redirects writes from SODL
+					 * to the SCSI FIFO.
+					 */
+#define CTEST4_800_MPEE		0x08	/* Enable parity checking
+					   during master cycles on PCI
+					   bus */
+
+/* 
+ * These bits send the contents of the CTEST6 register to the appropriate
+ * byte lane of the 32 bit DMA FIFO.  Normal operation is zero, otherwise 
+ * the high bit means the low two bits select the byte lane.
+ */
+#define CTEST4_FBL2		0x04	
+#define CTEST4_FBL1		0x02
+#define CTEST4_FBL0		0x01	
+#define CTEST4_FBL_MASK		0x07
+#define CTEST4_FBL_0		0x04	/* Select DMA FIFO byte lane 0 */
+#define CTEST4_FBL_1		0x05	/* Select DMA FIFO byte lane 1 */
+#define CTEST4_FBL_2		0x06	/* Select DMA FIFO byte lane 2 */
+#define CTEST4_FBL_3		0x07	/* Select DMA FIFO byte lane 3 */
+#define CTEST4_800_SAVE		(CTEST4_800_BDIS)
+
+
+#define CTEST5_REG_700		0x19	/* Chip test 5 rw */
+#define CTEST5_REG_800		0x22	/* Chip test 5 rw */
+/* 
+ * Clock Address Incrementor.  When set, it increments the 
+ * DNAD register to the next bus size boundary.  It automatically 
+ * resets itself when the operation is complete.
+ */
+#define CTEST5_ADCK		0x80
+/*
+ * Clock Byte Counter.  When set, it decrements the DBC register to
+ * the next bus size boundary.
+ */
+#define CTEST5_BBCK		0x40
+/*
+ * Reset SCSI Offset.  Setting this bit to 1 clears the current offset
+ * pointer in the SCSI synchronous offset counter (SSTAT).  This bit
+ * is set to 1 if a SCSI Gross Error Condition occurs.  The offset should
+ * be cleared when a synchronous transfer fails.  When written, it is 
+ * automatically cleared after the SCSI synchronous offset counter is 
+ * reset.
+ */
+/* Bit 5 is reserved on 800 series chips */
+#define CTEST5_700_ROFF		0x20
+/* 
+ * Master Control for Set or Reset pulses. When 1, causes the low 
+ * four bits of register to set when set, 0 causes the low bits to
+ * clear when set.
+ */
+#define CTEST5_MASR 		0x10	
+#define CTEST5_DDIR		0x08	/* DMA direction */
+/*
+ * Bits 2-0 are reserved on 800 series chips
+ */
+#define CTEST5_700_EOP		0x04	/* End of process */
+#define CTEST5_700_DREQ		0x02	/* Data request */
+#define CTEST5_700_DACK		0x01	/* Data acknowledge */
+
+/* 
+ * Chip test 6 rw - writing to this register writes to the byte 
+ * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
+ * register.
+ */
+#define CTEST6_REG_700		0x1a
+#define CTEST6_REG_800		0x23
+
+#define CTEST7_REG		0x1b	/* Chip test 7 rw */
+/* 0x80 - 0x40 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define CTEST7_10_CDIS		0x80	/* Cache burst disable */
+#define CTEST7_10_SC1		0x40	/* Snoop control bits */
+#define CTEST7_10_SC0		0x20	
+#define CTEST7_10_SC_MASK	0x60
+/* 0x20 is reserved on the NCR53c700 */
+#define CTEST7_0060_FM		0x20	/* Fetch mode */
+#define CTEST7_STD		0x10	/* Selection timeout disable */
+#define CTEST7_DFP		0x08	/* DMA FIFO parity bit for CTEST6 */
+#define CTEST7_EVP		0x04	/* 1 = host bus even parity, 0 = odd */
+#define CTEST7_10_TT1		0x02	/* Transfer type */
+#define CTEST7_00_DC		0x02	/* Set to drive DC low during instruction 
+					   fetch */
+#define CTEST7_DIFF		0x01	/* Differential mode */
+
+#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
+
+
+#define TEMP_REG		0x1c	/* through 0x1f Temporary stack rw */
+
+#define DFIFO_REG		0x20	/* DMA FIFO rw */
+/* 
+ * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
+ * moved into the CTEST8 register.
+ */
+#define DFIFO_00_FLF		0x80	/* Flush DMA FIFO to memory */
+#define DFIFO_00_CLF		0x40	/* Clear DMA and SCSI FIFOs */
+#define DFIFO_BO6		0x40
+#define DFIFO_BO5		0x20
+#define DFIFO_BO4		0x10
+#define DFIFO_BO3		0x08
+#define DFIFO_BO2		0x04 
+#define DFIFO_BO1		0x02
+#define DFIFO_BO0		0x01
+#define DFIFO_10_BO_MASK	0x7f	/* 7 bit counter */
+#define DFIFO_00_BO_MASK	0x3f	/* 6 bit counter */
+
+/* 
+ * Interrupt status rw 
+ * Note that this is the only register which can be read while SCSI
+ * SCRIPTS are being executed.
+ */
+#define ISTAT_REG_700		0x21
+#define ISTAT_REG_800		0x14
+#define ISTAT_ABRT		0x80	/* Software abort, write 
+					 *1 to abort, wait for interrupt. */
+/* 0x40 and 0x20 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define ISTAT_10_SRST		0x40	/* software reset */
+#define ISTAT_10_SIGP		0x20	/* signal script */
+/* 0x10 is reserved on NCR53c700 series chips */
+#define ISTAT_800_SEM		0x10	/* semaphore */
+#define ISTAT_CON		0x08	/* 1 when connected */
+#define ISTAT_800_INTF		0x04	/* Interrupt on the fly */
+#define ISTAT_700_PRE		0x04	/* Pointer register empty.
+					 * Set to 1 when DSPS and DSP
+					 * registers are empty in pipeline
+					 * mode, always set otherwise.
+					 */
+#define ISTAT_SIP		0x02	/* SCSI interrupt pending from
+					 * SCSI portion of SIOP see
+					 * SSTAT0
+					 */
+#define ISTAT_DIP		0x01	/* DMA interrupt pending 
+					 * see DSTAT
+					 */
+
+/* NCR53c700-66 and NCR53c710 only */
+#define CTEST8_REG		0x22	/* Chip test 8 rw */
+#define CTEST8_0066_EAS		0x80	/* Enable alternate SCSI clock,
+					 * ie read from SCLK/ rather than CLK/
+					 */
+#define CTEST8_0066_EFM		0x40	/* Enable fetch and master outputs */
+#define CTEST8_0066_GRP		0x20	/* Generate Receive Parity for 
+					 * pass through.  This insures that 
+					 * bad parity won't reach the host 
+					 * bus.
+					 */
+#define CTEST8_0066_TE		0x10	/* TolerANT enable.  Enable 
+					 * active negation, should only
+					 * be used for slow SCSI 
+					 * non-differential.
+					 */
+#define CTEST8_0066_HSC		0x08	/* Halt SCSI clock */
+#define CTEST8_0066_SRA		0x04	/* Shorten REQ/ACK filtering,
+					 * must be set for fast SCSI-II
+					 * speeds.
+					 */
+#define CTEST8_0066_DAS		0x02	/* Disable automatic target/initiator
+					 * switching.
+					 */
+#define CTEST8_0066_LDE		0x01	/* Last disconnect enable.
+					 * The status of pending 
+					 * disconnect is maintained by
+					 * the core, eliminating
+					 * the possibility of missing a 
+					 * selection or reselection
+					 * while waiting to fetch a 
+					 * WAIT DISCONNECT opcode.
+					 */
+
+#define CTEST8_10_V3		0x80	/* Chip revision */
+#define CTEST8_10_V2		0x40
+#define CTEST8_10_V1		0x20	
+#define CTEST8_10_V0		0x10
+#define CTEST8_10_V_MASK	0xf0	
+#define CTEST8_10_FLF		0x08	/* Flush FIFOs */
+#define CTEST8_10_CLF		0x04	/* Clear FIFOs */
+#define CTEST8_10_FM		0x02	/* Fetch pin mode */
+#define CTEST8_10_SM		0x01	/* Snoop pin mode */
+
+
+/* 
+ * The CTEST9 register may be used to differentiate between a
+ * NCR53c700 and a NCR53c710.  
+ *
+ * Write 0xff to this register.
+ * Read it.
+ * If the contents are 0xff, it is a NCR53c700
+ * If the contents are 0x00, it is a NCR53c700-66 first revision
+ * If the contents are some other value, it is some other NCR53c700-66
+ */
+#define CTEST9_REG_00		0x23	/* Chip test 9 ro */
+#define LCRC_REG_10		0x23	
+
+/*
+ * 0x24 through 0x27 are the DMA byte counter register.  Instructions
+ * write their high 8 bits into the DCMD register, the low 24 bits into
+ * the DBC register.
+ *
+ * Function is dependent on the command type being executed.
+ */
+
+ 
+#define DBC_REG			0x24
+/* 
+ * For Block Move Instructions, DBC is a 24 bit quantity representing 
+ *     the number of bytes to transfer.
+ * For Transfer Control Instructions, DBC is bit fielded as follows : 
+ */
+/* Bits 20 - 23 should be clear */
+#define DBC_TCI_TRUE		(1 << 19) 	/* Jump when true */
+#define DBC_TCI_COMPARE_DATA	(1 << 18)	/* Compare data */
+#define DBC_TCI_COMPARE_PHASE	(1 << 17)	/* Compare phase with DCMD field */
+#define DBC_TCI_WAIT_FOR_VALID	(1 << 16)	/* Wait for REQ */
+/* Bits 8 - 15 are reserved on some implementations ? */
+#define DBC_TCI_MASK_MASK	0xff00 		/* Mask for data compare */
+#define DBC_TCI_MASK_SHIFT	8
+#define DBC_TCI_DATA_MASK	0xff		/* Data to be compared */ 
+#define DBC_TCI_DATA_SHIFT	0
+
+#define DBC_RWRI_IMMEDIATE_MASK	0xff00		/* Immediate data */
+#define DBC_RWRI_IMMEDIATE_SHIFT 8		/* Amount to shift */
+#define DBC_RWRI_ADDRESS_MASK	0x3f0000	/* Register address */
+#define DBC_RWRI_ADDRESS_SHIFT 	16
+
+
+/*
+ * DMA command r/w
+ */
+#define DCMD_REG		0x27	
+#define DCMD_TYPE_MASK		0xc0	/* Masks off type */
+#define DCMD_TYPE_BMI		0x00	/* Indicates a Block Move instruction */
+#define DCMD_BMI_IO		0x01	/* I/O, CD, and MSG bits selecting   */
+#define DCMD_BMI_CD		0x02	/* the phase for the block MOVE      */
+#define DCMD_BMI_MSG		0x04	/* instruction 			     */
+
+#define DCMD_BMI_OP_MASK	0x18	/* mask for opcode */
+#define DCMD_BMI_OP_MOVE_T	0x00	/* MOVE */
+#define DCMD_BMI_OP_MOVE_I	0x08	/* MOVE Initiator */
+
+#define DCMD_BMI_INDIRECT	0x20	/*  Indirect addressing */
+
+#define DCMD_TYPE_TCI		0x80	/* Indicates a Transfer Control 
+					   instruction */
+#define DCMD_TCI_IO		0x01	/* I/O, CD, and MSG bits selecting   */
+#define DCMD_TCI_CD		0x02	/* the phase for the block MOVE      */
+#define DCMD_TCI_MSG		0x04	/* instruction 			     */
+#define DCMD_TCI_OP_MASK	0x38	/* mask for opcode */
+#define DCMD_TCI_OP_JUMP	0x00	/* JUMP */
+#define DCMD_TCI_OP_CALL	0x08	/* CALL */
+#define DCMD_TCI_OP_RETURN	0x10	/* RETURN */
+#define DCMD_TCI_OP_INT		0x18	/* INT */
+
+#define DCMD_TYPE_RWRI		0x40	/* Indicates I/O or register Read/Write
+					   instruction */
+#define DCMD_RWRI_OPC_MASK	0x38	/* Opcode mask */
+#define DCMD_RWRI_OPC_WRITE	0x28	/* Write SFBR to register */
+#define DCMD_RWRI_OPC_READ	0x30	/* Read register to SFBR */
+#define DCMD_RWRI_OPC_MODIFY	0x38	/* Modify in place */
+
+#define DCMD_RWRI_OP_MASK	0x07
+#define DCMD_RWRI_OP_MOVE	0x00
+#define DCMD_RWRI_OP_SHL	0x01
+#define DCMD_RWRI_OP_OR		0x02
+#define DCMD_RWRI_OP_XOR	0x03
+#define DCMD_RWRI_OP_AND	0x04
+#define DCMD_RWRI_OP_SHR	0x05
+#define DCMD_RWRI_OP_ADD	0x06
+#define DCMD_RWRI_OP_ADDC	0x07
+
+#define DCMD_TYPE_MMI		0xc0	/* Indicates a Memory Move instruction 
+					   (three words) */
+
+
+#define DNAD_REG		0x28	/* through 0x2b DMA next address for 
+					   data */
+#define DSP_REG			0x2c	/* through 0x2f DMA SCRIPTS pointer rw */
+#define DSPS_REG		0x30	/* through 0x33 DMA SCRIPTS pointer 
+					   save rw */
+#define DMODE_REG_00		0x34 	/* DMA mode rw */
+#define DMODE_00_BL1	0x80	/* Burst length bits */
+#define DMODE_00_BL0	0x40
+#define DMODE_BL_MASK	0xc0
+/* Burst lengths (800) */
+#define DMODE_BL_2	0x00	/* 2 transfer */
+#define DMODE_BL_4	0x40	/* 4 transfers */
+#define DMODE_BL_8	0x80	/* 8 transfers */
+#define DMODE_BL_16	0xc0	/* 16 transfers */
+
+#define DMODE_10_BL_1	0x00	/* 1 transfer */
+#define DMODE_10_BL_2	0x40	/* 2 transfers */
+#define DMODE_10_BL_4	0x80	/* 4 transfers */
+#define DMODE_10_BL_8	0xc0	/* 8 transfers */
+#define DMODE_10_FC2	0x20	/* Driven to FC2 pin */
+#define DMODE_10_FC1	0x10	/* Driven to FC1 pin */
+#define DMODE_710_PD	0x08	/* Program/data on FC0 pin */
+#define DMODE_710_UO	0x02	/* User prog. output */
+
+#define DMODE_700_BW16	0x20	/* Host buswidth = 16 */
+#define DMODE_700_286	0x10	/* 286 mode */
+#define DMODE_700_IOM	0x08	/* Transfer to IO port */
+#define DMODE_700_FAM	0x04	/* Fixed address mode */
+#define DMODE_700_PIPE	0x02	/* Pipeline mode disables 
+					 * automatic fetch / exec 
+					 */
+#define DMODE_MAN	0x01		/* Manual start mode, 
+					 * requires a 1 to be written
+					 * to the start DMA bit in the DCNTL
+					 * register to run scripts 
+					 */
+
+#define DMODE_700_SAVE ( DMODE_00_BL_MASK | DMODE_00_BW16 | DMODE_00_286 )
+
+/* NCR53c800 series only */
+#define SCRATCHA_REG_800	0x34	/* through 0x37 Scratch A rw */
+/* NCR53c710 only */
+#define SCRATCHB_REG_10		0x34	/* through 0x37 scratch B rw */
+
+#define DMODE_REG_10    	0x38	/* DMA mode rw, NCR53c710 and newer */
+#define DMODE_800_SIOM		0x20	/* Source IO = 1 */
+#define DMODE_800_DIOM		0x10	/* Destination IO = 1 */
+#define DMODE_800_ERL		0x08	/* Enable Read Line */
+
+/* 35-38 are reserved on 700 and 700-66 series chips */
+#define DIEN_REG		0x39	/* DMA interrupt enable rw */
+/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
+#define DIEN_800_MDPE		0x40	/* Master data parity error */
+#define DIEN_800_BF		0x20	/* BUS fault */
+#define DIEN_700_BF		0x20	/* BUS fault */
+#define DIEN_ABRT		0x10	/* Enable aborted interrupt */
+#define DIEN_SSI		0x08	/* Enable single step interrupt */
+#define DIEN_SIR		0x04	/* Enable SCRIPTS INT command 
+					 * interrupt
+					 */
+/* 0x02 is reserved on 800 series chips */
+#define DIEN_700_WTD		0x02	/* Enable watchdog timeout interrupt */
+#define DIEN_700_OPC		0x01	/* Enable illegal instruction 
+					 * interrupt 
+					 */
+#define DIEN_800_IID		0x01	/*  Same meaning, different name */ 
+
+/*
+ * DMA watchdog timer rw
+ * set in 16 CLK input periods.
+ */
+#define DWT_REG			0x3a
+
+/* DMA control rw */
+#define DCNTL_REG		0x3b
+#define DCNTL_700_CF1		0x80	/* Clock divisor bits */
+#define DCNTL_700_CF0		0x40
+#define DCNTL_700_CF_MASK	0xc0
+/* Clock divisors 			   Divisor SCLK range (MHZ) */
+#define DCNTL_700_CF_2		0x00    /* 2.0	   37.51-50.00 */
+#define DCNTL_700_CF_1_5	0x40	/* 1.5	   25.01-37.50 */
+#define DCNTL_700_CF_1		0x80	/* 1.0     16.67-25.00 */
+#define DCNTL_700_CF_3		0xc0	/* 3.0	   50.01-66.67 (53c700-66) */
+
+#define DCNTL_700_S16		0x20	/* Load scripts 16 bits at a time */
+#define DCNTL_SSM		0x10	/* Single step mode */
+#define DCNTL_700_LLM		0x08	/* Low level mode, can only be set 
+					 * after selection */
+#define DCNTL_800_IRQM		0x08	/* Totem pole IRQ pin */
+#define DCNTL_STD		0x04	/* Start DMA / SCRIPTS */
+/* 0x02 is reserved */
+#define DCNTL_00_RST		0x01	/* Software reset, resets everything
+					 * but 286 mode bit  in DMODE. On the
+					 * NCR53c710, this bit moved to CTEST8
+					 */
+#define DCNTL_10_COM		0x01	/* 700 software compatibility mode */
+#define DCNTL_10_EA		0x20	/* Enable Ack - needed for MVME166 */
+
+#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHB_REG_00		0x3c	/* through 0x3f scratch b rw */
+#define SCRATCHB_REG_800	0x5c	/* through 0x5f scratch b rw */
+/* NCR53c710 only */
+#define ADDER_REG_10		0x3c	/* Adder, NCR53c710 only */
+
+#define SIEN1_REG_800		0x41
+#define SIEN1_800_STO		0x04	/* selection/reselection timeout */
+#define SIEN1_800_GEN		0x02	/* general purpose timer */
+#define SIEN1_800_HTH		0x01	/* handshake to handshake */
+
+#define SIST1_REG_800		0x43
+#define SIST1_800_STO		0x04	/* selection/reselection timeout */
+#define SIST1_800_GEN		0x02	/* general purpose timer */
+#define SIST1_800_HTH		0x01	/* handshake to handshake */
+
+#define SLPAR_REG_800		0x44	/* Parity */
+
+#define MACNTL_REG_800		0x46	/* Memory access control */
+#define MACNTL_800_TYP3		0x80
+#define MACNTL_800_TYP2		0x40
+#define MACNTL_800_TYP1		0x20
+#define MACNTL_800_TYP0		0x10
+#define MACNTL_800_DWR		0x08
+#define MACNTL_800_DRD		0x04
+#define MACNTL_800_PSCPT	0x02
+#define MACNTL_800_SCPTS	0x01
+
+#define GPCNTL_REG_800		0x47	/* General Purpose Pin Control */
+
+/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
+#define STIME0_REG_800		0x48	/* SCSI Timer Register 0 */
+#define STIME0_800_HTH_MASK	0xf0	/* Handshake to Handshake timeout */
+#define STIME0_800_HTH_SHIFT	4
+#define STIME0_800_SEL_MASK	0x0f	/* Selection timeout */
+#define STIME0_800_SEL_SHIFT	0
+
+#define STIME1_REG_800		0x49
+#define STIME1_800_GEN_MASK	0x0f	/* General purpose timer */
+
+#define RESPID_REG_800		0x4a	/* Response ID, bit fielded.  8
+					   bits on narrow chips, 16 on WIDE */
+
+#define STEST0_REG_800		0x4c	
+#define STEST0_800_SLT		0x08	/* Selection response logic test */
+#define STEST0_800_ART		0x04	/* Arbitration priority encoder test */
+#define STEST0_800_SOZ		0x02	/* Synchronous offset zero */
+#define STEST0_800_SOM		0x01	/* Synchronous offset maximum */
+
+#define STEST1_REG_800		0x4d
+#define STEST1_800_SCLK		0x80	/* Disable SCSI clock */
+
+#define STEST2_REG_800		0x4e	
+#define STEST2_800_SCE		0x80	/* Enable SOCL/SODL */
+#define STEST2_800_ROF		0x40	/* Reset SCSI sync offset */
+#define STEST2_800_SLB		0x10	/* Enable SCSI loopback mode */
+#define STEST2_800_SZM		0x08	/* SCSI high impedance mode */
+#define STEST2_800_EXT		0x02	/* Extend REQ/ACK filter 30 to 60ns */
+#define STEST2_800_LOW		0x01	/* SCSI low level mode */
+
+#define STEST3_REG_800		0x4f	 
+#define STEST3_800_TE		0x80	/* Enable active negation */
+#define STEST3_800_STR		0x40	/* SCSI FIFO test read */
+#define STEST3_800_HSC		0x20	/* Halt SCSI clock */
+#define STEST3_800_DSI		0x10	/* Disable single initiator response */
+#define STEST3_800_TTM		0x04	/* Time test mode */
+#define STEST3_800_CSF		0x02	/* Clear SCSI FIFO */
+#define STEST3_800_STW		0x01	/* SCSI FIFO test write */
+
+#define OPTION_PARITY 		0x1	/* Enable parity checking */
+#define OPTION_TAGGED_QUEUE	0x2	/* Enable SCSI-II tagged queuing */
+#define OPTION_700		0x8	/* Always run NCR53c700 scripts */
+#define OPTION_INTFLY		0x10	/* Use INTFLY interrupts */
+#define OPTION_DEBUG_INTR	0x20	/* Debug interrupts */
+#define OPTION_DEBUG_INIT_ONLY	0x40	/* Run initialization code and 
+					   simple test code, return
+					   DID_NO_CONNECT if any SCSI
+					   commands are attempted. */
+#define OPTION_DEBUG_READ_ONLY	0x80	/* Return DID_ERROR if any 
+					   SCSI write is attempted */
+#define OPTION_DEBUG_TRACE	0x100	/* Animated trace mode, print 
+					   each address and instruction 
+					   executed to debug buffer. */
+#define OPTION_DEBUG_SINGLE	0x200	/* stop after executing one 
+					   instruction */
+#define OPTION_SYNCHRONOUS	0x400	/* Enable sync SCSI.  */
+#define OPTION_MEMORY_MAPPED	0x800	/* NCR registers have valid 
+					   memory mapping */
+#define OPTION_IO_MAPPED	0x1000  /* NCR registers have valid
+					     I/O mapping */
+#define OPTION_DEBUG_PROBE_ONLY	0x2000  /* Probe only, don't even init */
+#define OPTION_DEBUG_TESTS_ONLY	0x4000  /* Probe, init, run selected tests */
+#define OPTION_DEBUG_TEST0	0x08000 /* Run test 0 */
+#define OPTION_DEBUG_TEST1	0x10000 /* Run test 1 */
+#define OPTION_DEBUG_TEST2	0x20000 /* Run test 2 */
+#define OPTION_DEBUG_DUMP	0x40000 /* Dump commands */
+#define OPTION_DEBUG_TARGET_LIMIT 0x80000 /* Only talk to target+luns specified */
+#define OPTION_DEBUG_NCOMMANDS_LIMIT 0x100000 /* Limit the number of commands */
+#define OPTION_DEBUG_SCRIPT 0x200000 /* Print when checkpoints are passed */
+#define OPTION_DEBUG_FIXUP 0x400000 /* print fixup values */
+#define OPTION_DEBUG_DSA 0x800000
+#define OPTION_DEBUG_CORRUPTION	0x1000000	/* Detect script corruption */
+#define OPTION_DEBUG_SDTR       0x2000000	/* Debug SDTR problem */
+#define OPTION_DEBUG_MISMATCH 	0x4000000 	/* Debug phase mismatches */
+#define OPTION_DISCONNECT	0x8000000	/* Allow disconnect */
+#define OPTION_DEBUG_DISCONNECT 0x10000000	
+#define OPTION_ALWAYS_SYNCHRONOUS 0x20000000	/* Negotiate sync. transfers
+						   on power up */
+#define OPTION_DEBUG_QUEUES	0x80000000	
+#define OPTION_DEBUG_ALLOCATION 0x100000000LL
+#define OPTION_DEBUG_SYNCHRONOUS 0x200000000LL	/* Sanity check SXFER and 
+						   SCNTL3 registers */
+#define OPTION_NO_ASYNC	0x400000000LL		/* Don't automagically send
+						   SDTR for async transfers when
+						   we haven't been told to do
+						   a synchronous transfer. */
+#define OPTION_NO_PRINT_RACE 0x800000000LL	/* Don't print message when
+						   the reselect/WAIT DISCONNECT
+						   race condition hits */
+#if !defined(PERM_OPTIONS)
+#define PERM_OPTIONS 0
+#endif
+				
+/*
+ * Some data which is accessed by the NCR chip must be 4-byte aligned.
+ * For some hosts the default is less than that (eg. 68K uses 2-byte).
+ * Alignment has only been forced where it is important; also if one
+ * 32 bit structure field is aligned then it is assumed that following
+ * 32 bit fields are also aligned.  Take care when adding fields
+ * which are other than 32 bit.
+ */
+
+struct NCR53c7x0_synchronous {
+    u32 select_indirect			/* Value used for indirect selection */
+	__attribute__ ((aligned (4)));
+    u32 sscf_710;			/* Used to set SSCF bits for 710 */
+    u32 script[8];			/* Size ?? Script used when target is 
+						reselected */
+    unsigned char synchronous_want[5];	/* Per target desired SDTR */
+/* 
+ * Set_synchronous programs these, select_indirect and current settings after
+ * int_debug_should show a match.
+ */
+    unsigned char sxfer_sanity, scntl3_sanity;
+};
+
+#define CMD_FLAG_SDTR 		1	/* Initiating synchronous 
+					   transfer negotiation */
+#define CMD_FLAG_WDTR		2	/* Initiating wide transfer
+					   negotiation */
+#define CMD_FLAG_DID_SDTR	4	/* did SDTR */
+#define CMD_FLAG_DID_WDTR	8	/* did WDTR */
+
+struct NCR53c7x0_table_indirect {
+    u32 count;
+    void *address;
+};
+
+enum ncr_event { 
+    EVENT_NONE = 0,
+/* 
+ * Order is IMPORTANT, since these must correspond to the event interrupts
+ * in 53c7,8xx.scr 
+ */
+
+    EVENT_ISSUE_QUEUE = 0x5000000,	/* 0 Command was added to issue queue */
+    EVENT_START_QUEUE,			/* 1 Command moved to start queue */
+    EVENT_SELECT,			/* 2 Command completed selection */
+    EVENT_DISCONNECT,			/* 3 Command disconnected */
+    EVENT_RESELECT,			/* 4 Command reselected */
+    EVENT_COMPLETE,		        /* 5 Command completed */
+    EVENT_IDLE,				/* 6 */
+    EVENT_SELECT_FAILED,		/* 7 */
+    EVENT_BEFORE_SELECT,		/* 8 */
+    EVENT_RESELECT_FAILED		/* 9 */
+};
+
+struct NCR53c7x0_event {
+    enum ncr_event event;	/* What type of event */
+    unsigned char target;
+    unsigned char lun;
+    struct timeval time;	
+    u32 *dsa;			/* What's in the DSA register now (virt) */
+/* 
+ * A few things from that SCSI pid so we know what happened after 
+ * the Scsi_Cmnd structure in question may have disappeared.
+ */
+    unsigned long pid;		/* The SCSI PID which caused this 
+				   event */
+    unsigned char cmnd[12];
+};
+
+/*
+ * Things in the NCR53c7x0_cmd structure are split into two parts :
+ *
+ * 1.  A fixed portion, for things which are not accessed directly by static NCR
+ *	code (ie, are referenced only by the Linux side of the driver,
+ *	or only by dynamically generated code).  
+ *
+ * 2.  The DSA portion, for things which are accessed directly by static NCR
+ *	code.
+ *
+ * This is a little ugly, but it 
+ * 1.  Avoids conflicts between the NCR code's picture of the structure, and 
+ * 	Linux code's idea of what it looks like.
+ *
+ * 2.  Minimizes the pain in the Linux side of the code needed 
+ * 	to calculate real dsa locations for things, etc.
+ * 
+ */
+
+struct NCR53c7x0_cmd {
+    void *real;				/* Real, unaligned address for
+					   free function */
+    void (* free)(void *, int);		/* Command to deallocate; NULL
+					   for structures allocated with
+					   scsi_register, etc. */
+    Scsi_Cmnd *cmd;			/* Associated Scsi_Cmnd 
+					   structure, Scsi_Cmnd points
+					   at NCR53c7x0_cmd using 
+					   host_scribble structure */
+
+    int size;				/* scsi_malloc'd size of this 
+					   structure */
+
+    int flags;				/* CMD_* flags */
+
+/*
+ * SDTR and WIDE messages are an either/or affair
+ * in this message, since we will go into message out and send
+ * _the whole mess_ without dropping out of message out to 
+ * let the target go into message in after sending the first 
+ * message.
+ */
+
+    unsigned char select[11];		/* Select message, includes
+					   IDENTIFY
+					   (optional) QUEUE TAG
+ 				 	   (optional) SDTR or WDTR
+					 */
+
+
+    volatile struct NCR53c7x0_cmd *next; /* Linux maintained lists (free,
+					    running, eventually finished */
+    					 
+
+    u32 *data_transfer_start;		/* Start of data transfer routines */
+    u32 *data_transfer_end;		/* Address after end of data transfer o
+    	    	    	    	    	   routines */
+/* 
+ * The following three fields were moved from the DSA proper to here
+ * since only dynamically generated NCR code refers to them, meaning
+ * we don't need dsa_* absolutes, and it is simpler to let the 
+ * host code refer to them directly.
+ */
+
+/* 
+ * HARD CODED : residual and saved_residual need to agree with the sizes
+ * used in NCR53c7,8xx.scr.  
+ * 
+ * FIXME: we want to consider the case where we have odd-length 
+ *	scatter/gather buffers and a WIDE transfer, in which case 
+ *	we'll need to use the CHAIN MOVE instruction.  Ick.
+ */
+    u32 residual[6] __attribute__ ((aligned (4)));
+					/* Residual data transfer which
+					   allows pointer code to work
+					   right.
+
+    	    	    	    	    	    [0-1] : Conditional call to 
+    	    	    	    	    	    	appropriate other transfer 
+    	    	    	    	    	    	routine.
+    	    	    	    	    	    [2-3] : Residual block transfer
+    	    	    	    	    	    	instruction.
+    	    	    	    	    	    [4-5] : Jump to instruction
+    	    	    	    	    	    	after splice.
+					 */
+    u32 saved_residual[6]; 		/* Copy of old residual, so we 
+					   can get another partial 
+					   transfer and still recover 
+    	    	    	    	    	 */
+    	    	
+    u32 saved_data_pointer;		/* Saved data pointer */
+
+    u32 dsa_next_addr;		        /* _Address_ of dsa_next field  
+					   in this dsa for RISCy 
+					   style constant. */
+
+    u32 dsa_addr;			/* Address of dsa; RISCy style
+					   constant */
+
+    u32 dsa[0];				/* Variable length (depending
+					   on host type, number of scatter /
+					   gather buffers, etc).  */
+};
+
+struct NCR53c7x0_break {
+    u32 *address, old_instruction[2];
+    struct NCR53c7x0_break *next;
+    unsigned char old_size;		/* Size of old instruction */
+};
+
+/* Indicates that the NCR is not executing code */
+#define STATE_HALTED	0		
+/* 
+ * Indicates that the NCR is executing the wait for select / reselect 
+ * script.  Only used when running NCR53c700 compatible scripts, only 
+ * state during which an ABORT is _not_ considered an error condition.
+ */
+#define STATE_WAITING	1		
+/* Indicates that the NCR is executing other code. */
+#define STATE_RUNNING	2		
+/* 
+ * Indicates that the NCR was being aborted.
+ */
+#define STATE_ABORTING	3
+/* Indicates that the NCR was successfully aborted. */
+#define STATE_ABORTED 4
+/* Indicates that the NCR has been disabled due to a fatal error */
+#define STATE_DISABLED 5
+
+/* 
+ * Where knowledge of SCSI SCRIPT(tm) specified values are needed 
+ * in an interrupt handler, an interrupt handler exists for each 
+ * different SCSI script so we don't have name space problems.
+ * 
+ * Return values of these handlers are as follows : 
+ */
+#define SPECIFIC_INT_NOTHING 	0	/* don't even restart */
+#define SPECIFIC_INT_RESTART	1	/* restart at the next instruction */
+#define SPECIFIC_INT_ABORT	2	/* recoverable error, abort cmd */
+#define SPECIFIC_INT_PANIC	3	/* unrecoverable error, panic */
+#define SPECIFIC_INT_DONE	4	/* normal command completion */
+#define SPECIFIC_INT_BREAK	5	/* break point encountered */
+
+struct NCR53c7x0_hostdata {
+    int size;				/* Size of entire Scsi_Host
+					   structure */
+    int board;				/* set to board type, useful if 
+					   we have host specific things,
+					   ie, a general purpose I/O 
+					   bit is being used to enable
+					   termination, etc. */
+
+    int chip;				/* set to chip type; 700-66 is
+					   700-66, rest are last three
+					   digits of part number */
+
+    char valid_ids[8];			/* Valid SCSI ID's for adapter */
+    /*
+     * PCI bus, device, function, only for NCR53c8x0 chips.
+     * pci_valid indicates that the PCI configuration information
+     * is valid, and we can twiddle MAX_LAT, etc. as recommended
+     * for maximum performance in the NCR documentation.
+     */
+    unsigned char pci_bus, pci_device_fn;
+    unsigned pci_valid:1;
+
+    u32 *dsp;				/* dsp to restart with after
+					   all stacked interrupts are
+					   handled. */
+
+    unsigned dsp_changed:1;		/* Has dsp changed within this
+					   set of stacked interrupts ? */
+
+    unsigned char dstat;		/* Most recent value of dstat */
+    unsigned dstat_valid:1;
+
+    unsigned expecting_iid:1;		/* Expect IID interrupt */
+    unsigned expecting_sto:1;		/* Expect STO interrupt */
+    
+    /* 
+     * The code stays cleaner if we use variables with function
+     * pointers and offsets that are unique for the different
+     * scripts rather than having a slew of switch(hostdata->chip) 
+     * statements.
+     * 
+     * It also means that the #defines from the SCSI SCRIPTS(tm)
+     * don't have to be visible outside of the script-specific
+     * instructions, preventing name space pollution.
+     */
+
+    void (* init_fixup)(struct Scsi_Host *host);
+    void (* init_save_regs)(struct Scsi_Host *host);
+    void (* dsa_fixup)(struct NCR53c7x0_cmd *cmd);
+    void (* soft_reset)(struct Scsi_Host *host);
+    int (* run_tests)(struct Scsi_Host *host);
+
+    /*
+     * Called when DSTAT_SIR is set, indicating an interrupt generated
+     * by the INT instruction, where values are unique for each SCSI
+     * script.  Should return one of the SPEC_* values.
+     */
+
+    int (* dstat_sir_intr)(struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+
+    int dsa_len; /* Size of DSA structure */
+
+    /*
+     * Location of DSA fields for the SCSI SCRIPT corresponding to this 
+     * chip.  
+     */
+
+    s32 dsa_start;			
+    s32 dsa_end;			
+    s32 dsa_next;
+    s32 dsa_prev;
+    s32 dsa_cmnd;
+    s32 dsa_select;
+    s32 dsa_msgout;
+    s32 dsa_cmdout;
+    s32 dsa_dataout;
+    s32 dsa_datain;
+    s32 dsa_msgin;
+    s32 dsa_msgout_other;
+    s32 dsa_write_sync;
+    s32 dsa_write_resume;
+    s32 dsa_check_reselect;
+    s32 dsa_status;
+    s32 dsa_saved_pointer;
+    s32 dsa_jump_dest;
+
+    /* 
+     * Important entry points that generic fixup code needs
+     * to know about, fixed up.
+     */
+
+    s32 E_accept_message;
+    s32 E_command_complete;		
+    s32 E_data_transfer;
+    s32 E_dsa_code_template;
+    s32 E_dsa_code_template_end;
+    s32 E_end_data_transfer;
+    s32 E_msg_in;
+    s32 E_initiator_abort;
+    s32 E_other_transfer;
+    s32 E_other_in;
+    s32 E_other_out;
+    s32 E_target_abort;
+    s32 E_debug_break;	
+    s32 E_reject_message;
+    s32 E_respond_message;
+    s32 E_select;
+    s32 E_select_msgout;
+    s32 E_test_0;
+    s32 E_test_1;
+    s32 E_test_2;
+    s32 E_test_3;
+    s32 E_dsa_zero;
+    s32 E_cmdout_cmdout;
+    s32 E_wait_reselect;
+    s32 E_dsa_code_begin;
+
+    long long options;			/* Bitfielded set of options enabled */
+    volatile u32 test_completed;	/* Test completed */
+    int test_running;			/* Test currently running */
+    s32 test_source
+	__attribute__ ((aligned (4)));
+    volatile s32 test_dest;
+
+    volatile int state;			/* state of driver, only used for 
+					   OPTION_700 */
+
+    unsigned char  dmode;		/* 
+					 * set to the address of the DMODE 
+					 * register for this chip.
+					 */
+    unsigned char istat;		/* 
+    	    	    	    	    	 * set to the address of the ISTAT 
+    	    	    	    	    	 * register for this chip.
+    	    	    	    	    	 */
+  
+    int scsi_clock;			/* 
+					 * SCSI clock in HZ. 0 may be used 
+					 * for unknown, although this will
+					 * disable synchronous negotiation.
+					 */
+
+    volatile int intrs;			/* Number of interrupts */
+    volatile int resets;		/* Number of SCSI resets */
+    unsigned char saved_dmode;	
+    unsigned char saved_ctest4;
+    unsigned char saved_ctest7;
+    unsigned char saved_dcntl;
+    unsigned char saved_scntl3;
+
+    unsigned char this_id_mask;
+
+    /* Debugger information */
+    struct NCR53c7x0_break *breakpoints, /* Linked list of all break points */
+	*breakpoint_current;		/* Current breakpoint being stepped 
+					   through, NULL if we are running 
+					   normally. */
+#ifdef NCR_DEBUG
+    int debug_size;			/* Size of debug buffer */
+    volatile int debug_count;		/* Current data count */
+    volatile char *debug_buf;		/* Output ring buffer */
+    volatile char *debug_write;		/* Current write pointer */
+    volatile char *debug_read;		/* Current read pointer */
+#endif /* def NCR_DEBUG */
+
+    /* XXX - primitive debugging junk, remove when working ? */
+    int debug_print_limit;		/* Number of commands to print
+					   out exhaustive debugging
+					   information for if 
+					   OPTION_DEBUG_DUMP is set */ 
+
+    unsigned char debug_lun_limit[16];	/* If OPTION_DEBUG_TARGET_LIMIT
+					   set, puke if commands are sent
+					   to other target/lun combinations */
+
+    int debug_count_limit;		/* Number of commands to execute
+					   before puking to limit debugging 
+					   output */
+				    
+
+    volatile unsigned idle:1;			/* set to 1 if idle */
+
+    /* 
+     * Table of synchronous+wide transfer parameters set on a per-target
+     * basis.
+     */
+    
+    volatile struct NCR53c7x0_synchronous sync[16]
+	__attribute__ ((aligned (4)));
+
+    volatile Scsi_Cmnd *issue_queue
+	__attribute__ ((aligned (4)));
+						/* waiting to be issued by
+						   Linux driver */
+    volatile struct NCR53c7x0_cmd *running_list;	
+						/* commands running, maintained
+						   by Linux driver */
+
+    volatile struct NCR53c7x0_cmd *ncrcurrent;	/* currently connected 
+						   nexus, ONLY valid for
+						   NCR53c700/NCR53c700-66
+						 */
+
+    volatile struct NCR53c7x0_cmd *spare;	/* pointer to spare,
+    	    	    	    	    	    	   allocated at probe time,
+    	    	    	    	    	    	   which we can use for 
+						   initialization */
+    volatile struct NCR53c7x0_cmd *free;
+    int max_cmd_size;				/* Maximum size of NCR53c7x0_cmd
+					    	   based on number of 
+						   scatter/gather segments, etc.
+						   */
+    volatile int num_cmds;			/* Number of commands 
+						   allocated */
+    volatile int extra_allocate;
+    volatile unsigned char cmd_allocated[16];	/* Have we allocated commands
+						   for this target yet?  If not,
+						   do so ASAP */
+    volatile unsigned char busy[16][8];     	/* number of commands 
+						   executing on each target
+    	    	    	    	    	    	 */
+    /* 
+     * Eventually, I'll switch to a coroutine for calling 
+     * cmd->done(cmd), etc. so that we can overlap interrupt
+     * processing with this code for maximum performance.
+     */
+    
+    volatile struct NCR53c7x0_cmd *finished_queue;	
+						
+    /* Shared variables between SCRIPT and host driver */
+    volatile u32 *schedule
+	__attribute__ ((aligned (4)));		/* Array of JUMPs to dsa_begin
+						   routines of various DSAs.  
+						   When not in use, replace
+						   with jump to next slot */
+
+
+    volatile unsigned char msg_buf[16];		/* buffer for messages
+						   other than the command
+						   complete message */
+
+    /* Per-target default synchronous and WIDE messages */
+    volatile unsigned char synchronous_want[16][5];
+    volatile unsigned char wide_want[16][4];
+
+    /* Bit fielded set of targets we want to speak synchronously with */ 
+    volatile u16 initiate_sdtr;	
+    /* Bit fielded set of targets we want to speak wide with */
+    volatile u16 initiate_wdtr;
+    /* Bit fielded list of targets we've talked to. */
+    volatile u16 talked_to;
+
+    /* Array of bit-fielded lun lists that we need to request_sense */
+    volatile unsigned char request_sense[16];
+
+    u32 addr_reconnect_dsa_head
+	__attribute__ ((aligned (4)));		/* RISCy style constant,
+						   address of following */
+    volatile u32 reconnect_dsa_head;	
+    /* Data identifying nexus we are trying to match during reselection */
+    volatile unsigned char reselected_identify; /* IDENTIFY message */
+    volatile unsigned char reselected_tag;	/* second byte of queue tag 
+						   message or 0 */
+
+    /* These were static variables before we moved them */
+
+    s32 NCR53c7xx_zero
+	__attribute__ ((aligned (4)));
+    s32 NCR53c7xx_sink;
+    u32 NOP_insn;
+    char NCR53c7xx_msg_reject;
+    char NCR53c7xx_msg_abort;
+    char NCR53c7xx_msg_nop;
+
+    /*
+     * Following item introduced by RGH to support NCRc710, which is
+     * VERY brain-dead when it come to memory moves
+     */
+
+			  /* DSA save area used only by the NCR chip */
+    volatile unsigned long saved2_dsa
+	__attribute__ ((aligned (4)));
+
+    volatile unsigned long emulated_intfly
+	__attribute__ ((aligned (4)));
+
+    volatile int event_size, event_index;
+    volatile struct NCR53c7x0_event *events;
+
+    /* If we need to generate code to kill off the currently connected 
+       command, this is where we do it. Should have a BMI instruction
+       to source or sink the current data, followed by a JUMP
+       to abort_connected */
+
+    u32 *abort_script;
+
+    int script_count;				/* Size of script in words */
+    u32 script[0];				/* Relocated SCSI script */
+
+};
+
+#define IRQ_NONE	255
+#define DMA_NONE	255
+#define IRQ_AUTO	254
+#define DMA_AUTO	254
+
+#define BOARD_GENERIC	0
+
+#define NCR53c7x0_insn_size(insn)					\
+    (((insn) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI ? 3 : 2)
+    
+
+#define NCR53c7x0_local_declare()					\
+    volatile unsigned char *NCR53c7x0_address_memory;			\
+    unsigned int NCR53c7x0_address_io;					\
+    int NCR53c7x0_memory_mapped
+
+#define NCR53c7x0_local_setup(host)					\
+    NCR53c7x0_address_memory = (void *) (host)->base;			\
+    NCR53c7x0_address_io = (unsigned int) (host)->io_port;		\
+    NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) 		\
+	host->hostdata)-> options & OPTION_MEMORY_MAPPED 
+
+#ifdef BIG_ENDIAN
+/* These could be more efficient, given that we are always memory mapped,
+ * but they don't give the same problems as the write macros, so leave
+ * them. */
+#define NCR53c7x0_read8(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) :	\
+	inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) :	\
+	inw(NCR53c7x0_address_io + (address)))
+#else
+#define NCR53c7x0_read8(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readb((u32)NCR53c7x0_address_memory + (u32)(address)) :	\
+	inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readw((u32)NCR53c7x0_address_memory + (u32)(address)) :	\
+	inw(NCR53c7x0_address_io + (address)))
+#endif
+#define NCR53c7x0_read32(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int) readl((u32)NCR53c7x0_address_memory + (u32)(address)) : 	\
+	inl(NCR53c7x0_address_io + (address)))
+
+#ifdef BIG_ENDIAN
+/* If we are big-endian, then we are not Intel, so probably don't have
+ * an i/o map as well as a memory map.  So, lets assume memory mapped.
+ * Also, I am having terrible problems trying to persuade the compiler
+ * not to lay down code which does a read after write for these macros.
+ * If you remove 'volatile' from writeb() and friends it is ok....
+ */
+
+#define NCR53c7x0_write8(address,value) 				\
+	*(volatile unsigned char *)					\
+		((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) = (value)
+
+#define NCR53c7x0_write16(address,value) 				\
+	*(volatile unsigned short *)					\
+		((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) = (value)
+
+#define NCR53c7x0_write32(address,value) 				\
+	*(volatile unsigned long *)					\
+		((u32)NCR53c7x0_address_memory + ((u32)(address))) = (value)
+
+#else
+
+#define NCR53c7x0_write8(address,value) 				\
+    (NCR53c7x0_memory_mapped ? 						\
+     ({writeb((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) :	\
+	outb((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write16(address,value) 				\
+    (NCR53c7x0_memory_mapped ? 						\
+     ({writew((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) :	\
+	outw((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write32(address,value) 				\
+    (NCR53c7x0_memory_mapped ? 						\
+     ({writel((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) :	\
+	outl((value), NCR53c7x0_address_io + (address)))
+
+#endif
+
+/* Patch arbitrary 32 bit words in the script */
+#define patch_abs_32(script, offset, symbol, value)			\
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i) {					\
+	    (script)[A_##symbol##_used[i] - (offset)] += (value);	\
+	    if (hostdata->options & OPTION_DEBUG_FIXUP) 		\
+	      printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
+		host->host_no, #symbol, i, A_##symbol##_used[i] - 	\
+		(int)(offset), #script, (script)[A_##symbol##_used[i] -	\
+		(offset)]);						\
+    	}
+
+/* Patch read/write instruction immediate field */
+#define patch_abs_rwri_data(script, offset, symbol, value)		\
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i)					\
+    	    (script)[A_##symbol##_used[i] - (offset)] =			\
+	    	((script)[A_##symbol##_used[i] - (offset)] & 		\
+	    	~DBC_RWRI_IMMEDIATE_MASK) | 				\
+    	    	(((value) << DBC_RWRI_IMMEDIATE_SHIFT) &		\
+		 DBC_RWRI_IMMEDIATE_MASK)
+
+/* Patch transfer control instruction data field */
+#define patch_abs_tci_data(script, offset, symbol, value)	        \
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i)					\
+    	    (script)[A_##symbol##_used[i] - (offset)] =			\
+	    	((script)[A_##symbol##_used[i] - (offset)] & 		\
+	    	~DBC_TCI_DATA_MASK) | 					\
+    	    	(((value) << DBC_TCI_DATA_SHIFT) &			\
+		 DBC_TCI_DATA_MASK)
+
+/* Patch field in dsa structure (assignment should be +=?) */
+#define patch_dsa_32(dsa, symbol, word, value)				\
+	{								\
+	(dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32)	\
+	    + (word)] = (value);					\
+	if (hostdata->options & OPTION_DEBUG_DSA)			\
+	    printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",	\
+		#dsa, #symbol, hostdata->##symbol, 			\
+		(word), (u32) (value));					\
+	}
+
+/* Paranoid people could use panic() here. */
+#define FATAL(host) shutdown((host));
+
+#endif /* NCR53c710_C */
+#endif /* NCR53c710_H */
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/53c7xx.scr linux/drivers/scsi/53c7xx.scr
--- v2.1.39/linux/drivers/scsi/53c7xx.scr	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/53c7xx.scr	Sun May 18 17:10:37 1997
@@ -0,0 +1,1591 @@
+#undef DEBUG
+#undef EVENTS
+#undef NO_SELECTION_TIMEOUT
+#define BIG_ENDIAN
+
+; 53c710 driver.  Modified from Drew Eckhardts driver
+; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+;
+; I have left the script for the 53c8xx family in here, as it is likely
+; to be useful to see what I changed when bug hunting.
+
+; NCR 53c810 driver, main script
+; Sponsored by 
+;	iX Multiuser Multitasking Magazine
+;	hm@ix.de
+;
+; Copyright 1993, 1994, 1995 Drew Eckhardt
+;      Visionary Computing 
+;      (Unix and Linux consulting and custom programming)
+;      drew@PoohSticks.ORG
+;      +1 (303) 786-7975
+;
+; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+;
+; PRE-ALPHA
+;
+; For more information, please consult 
+;
+; NCR 53C810
+; PCI-SCSI I/O Processor
+; Data Manual
+;
+; NCR 53C710 
+; SCSI I/O Processor
+; Programmers Guide
+;
+; NCR Microelectronics
+; 1635 Aeroplaza Drive
+; Colorado Springs, CO 80916
+; 1+ (719) 578-3400
+;
+; Toll free literature number
+; +1 (800) 334-5454
+;
+; IMPORTANT : This code is self modifying due to the limitations of 
+;	the NCR53c7,8xx series chips.  Persons debugging this code with
+;	the remote debugger should take this into account, and NOT set
+;	breakpoints in modified instructions.
+;
+; Design:
+; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard 
+; microcontroller using a simple instruction set.   
+;
+; So, to minimize the effects of interrupt latency, and to maximize 
+; throughput, this driver offloads the practical maximum amount 
+; of processing to the SCSI chip while still maintaining a common
+; structure.
+;
+; Where tradeoffs were needed between efficiency on the older
+; chips and the newer NCR53c800 series, the NCR53c800 series 
+; was chosen.
+;
+; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
+; automate SCSI transfers without host processor intervention, this 
+; isn't the case with the NCR53c710 and newer chips which allow 
+;
+; - reads and writes to the internal registers from within the SCSI
+; 	scripts, allowing the SCSI SCRIPTS(tm) code to save processor
+; 	state so that multiple threads of execution are possible, and also
+; 	provide an ALU for loop control, etc.
+; 
+; - table indirect addressing for some instructions. This allows 
+;	pointers to be located relative to the DSA ((Data Structure
+;	Address) register.
+;
+; These features make it possible to implement a mailbox style interface,
+; where the same piece of code is run to handle I/O for multiple threads
+; at once minimizing our need to relocate code.  Since the NCR53c700/
+; NCR53c800 series have a unique combination of features, making a 
+; a standard ingoing/outgoing mailbox system, costly, I've modified it.
+;
+; - Mailboxes are a mixture of code and data.  This lets us greatly
+; 	simplify the NCR53c810 code and do things that would otherwise
+;	not be possible.
+;
+; The saved data pointer is now implemented as follows :
+;
+; 	Control flow has been architected such that if control reaches
+;	munge_save_data_pointer, on a restore pointers message or 
+;	reconnection, a jump to the address formerly in the TEMP register
+;	will allow the SCSI command to resume execution.
+;
+
+;
+; Note : the DSA structures must be aligned on 32 bit boundaries,
+; since the source and destination of MOVE MEMORY instructions 
+; must share the same alignment and this is the alignment of the
+; NCR registers.
+;
+
+; For some systems (MVME166, for example) dmode is always the same, so don't
+; waste time writing it
+
+#if 1
+#define DMODE_MEMORY_TO_NCR
+#define DMODE_MEMORY_TO_MEMORY
+#define DMODE_NCR_TO_MEMORY
+#else
+#define DMODE_MEMORY_TO_NCR    MOVE dmode_memory_to_ncr TO DMODE
+#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
+#define DMODE_NCR_TO_MEMORY    MOVE dmode_ncr_to_memory TO DMODE
+#endif
+
+ABSOLUTE dsa_temp_lun = 0		; Patch to lun for current dsa
+ABSOLUTE dsa_temp_next = 0		; Patch to dsa next for current dsa
+ABSOLUTE dsa_temp_addr_next = 0		; Patch to address of dsa next address 
+					; 	for current dsa
+ABSOLUTE dsa_temp_sync = 0		; Patch to address of per-target
+					;	sync routine
+ABSOLUTE dsa_sscf_710 = 0		; Patch to address of per-target
+					;	sscf value (53c710)
+ABSOLUTE dsa_temp_target = 0		; Patch to id for current dsa
+ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
+					; 	saved data pointer
+ABSOLUTE dsa_temp_addr_residual = 0	; Patch to address of per-command
+					;	current residual code
+ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
+					; saved residual code
+ABSOLUTE dsa_temp_addr_new_value = 0	; Address of value for JUMP operand
+ABSOLUTE dsa_temp_addr_array_value = 0 	; Address to copy to
+ABSOLUTE dsa_temp_addr_dsa_value = 0	; Address of this DSA value
+
+;
+; Once a device has initiated reselection, we need to compare it 
+; against the singly linked list of commands which have disconnected
+; and are pending reselection.  These commands are maintained in 
+; an unordered singly linked list of DSA structures, through the
+; DSA pointers at their 'centers' headed by the reconnect_dsa_head
+; pointer.
+; 
+; To avoid complications in removing commands from the list,
+; I minimize the amount of expensive (at eight operations per
+; addition @ 500-600ns each) pointer operations which must
+; be done in the NCR driver by precomputing them on the 
+; host processor during dsa structure generation.
+;
+; The fixed-up per DSA code knows how to recognize the nexus
+; associated with the corresponding SCSI command, and modifies
+; the source and destination pointers for the MOVE MEMORY 
+; instruction which is executed when reselected_ok is called
+; to remove the command from the list.  Similarly, DSA is 
+; loaded with the address of the next DSA structure and
+; reselected_check_next is called if a failure occurs.
+;
+; Perhaps more concisely, the net effect of the mess is 
+;
+; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, 
+;     src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
+; 	src = &dsa->next;
+; 	if (target_id == dsa->id && target_lun == dsa->lun) {
+; 		*dest = *src;
+; 		break;
+;         }	
+; }
+;
+; if (!dsa)
+;           error (int_err_unexpected_reselect);
+; else  
+;     longjmp (dsa->jump_resume, 0);
+;
+; 	
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Define DSA structure used for mailboxes
+ENTRY dsa_code_template
+dsa_code_template:
+ENTRY dsa_code_begin
+dsa_code_begin:
+; RGH: Don't care about TEMP and DSA here
+	DMODE_MEMORY_TO_NCR
+	MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
+	DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+	MOVE MEMORY 4, addr_scratch, saved_dsa
+	; We are about to go and select the device, so must set SSCF bits
+	MOVE MEMORY 4, dsa_sscf_710, addr_scratch
+#ifdef BIG_ENDIAN
+	MOVE SCRATCH3 TO SFBR
+#else
+	MOVE SCRATCH0 TO SFBR
+#endif
+	MOVE SFBR TO SBCL
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+	CALL scratch_to_dsa
+#endif
+	CALL select
+; Handle the phase mismatch which may have resulted from the 
+; MOVE FROM dsa_msgout if we returned here.  The CLEAR ATN 
+; may or may not be necessary, and we should update script_asm.pl
+; to handle multiple pieces.
+    CLEAR ATN
+    CLEAR ACK
+
+; Replace second operand with address of JUMP instruction dest operand
+; in schedule table for this DSA.  Becomes dsa_jump_dest in 53c7,8xx.c.
+ENTRY dsa_code_fix_jump
+dsa_code_fix_jump:
+	MOVE MEMORY 4, NOP_insn, 0
+	JUMP select_done
+
+; wrong_dsa loads the DSA register with the value of the dsa_next
+; field.
+;
+wrong_dsa:
+#if (CHIP == 710)
+;                NOTE DSA is corrupt when we arrive here!
+#endif
+;		Patch the MOVE MEMORY INSTRUCTION such that 
+;		the destination address is the address of the OLD 
+;		next pointer.
+;
+	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
+	DMODE_MEMORY_TO_NCR
+;
+; 	Move the _contents_ of the next pointer into the DSA register as 
+;	the next I_T_L or I_T_L_Q tupple to check against the established
+;	nexus.
+;
+	MOVE MEMORY 4, dsa_temp_next, addr_scratch
+	DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+	MOVE MEMORY 4, addr_scratch, saved_dsa
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+	CALL scratch_to_dsa
+#endif
+	JUMP reselected_check_next
+
+ABSOLUTE dsa_save_data_pointer = 0
+ENTRY dsa_code_save_data_pointer
+dsa_code_save_data_pointer:
+#if (CHIP == 710)
+	; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
+	; We MUST return with DSA correct
+    	MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+        CLEAR ACK
+#ifdef DEBUG
+        INT int_debug_saved
+#endif
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+	JUMP jump_temp
+#else
+    	DMODE_NCR_TO_MEMORY
+    	MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
+    	DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+        CLEAR ACK
+#ifdef DEBUG
+        INT int_debug_saved
+#endif
+    	RETURN
+#endif
+ABSOLUTE dsa_restore_pointers = 0
+ENTRY dsa_code_restore_pointers
+dsa_code_restore_pointers:
+#if (CHIP == 710)
+	; TEMP and DSA are corrupt when we get here, but who cares!
+    	MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+        CLEAR ACK
+	; Restore DSA, note we don't care about TEMP
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#ifdef DEBUG
+        INT int_debug_restored
+#endif
+	JUMP jump_temp
+#else
+    	DMODE_MEMORY_TO_NCR
+    	MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
+    	DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+        CLEAR ACK
+#ifdef DEBUG
+        INT int_debug_restored
+#endif
+    	RETURN
+#endif
+
+ABSOLUTE dsa_check_reselect = 0
+; dsa_check_reselect determines whether or not the current target and
+; lun match the current DSA
+ENTRY dsa_code_check_reselect
+dsa_code_check_reselect:
+#if (CHIP == 710)
+	/* Arrives here with DSA correct */
+	/* Assumes we are always ID 7 */
+	MOVE LCRC TO SFBR		; LCRC has our ID and his ID bits set
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
+#else
+	MOVE SSID TO SFBR		; SSID contains 3 bit target ID
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
+#endif
+;
+; Hack - move to scratch first, since SFBR is not writeable
+; 	via the CPU and hence a MOVE MEMORY instruction.
+;
+	DMODE_MEMORY_TO_NCR
+	MOVE MEMORY 1, reselected_identify, addr_scratch
+	DMODE_MEMORY_TO_MEMORY
+#ifdef BIG_ENDIAN
+	; BIG ENDIAN ON MVME166
+	MOVE SCRATCH3 TO SFBR
+#else
+	MOVE SCRATCH0 TO SFBR
+#endif
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+; Are you sure about that?  richard@sleepie.demon.co.uk
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
+;		Patch the MOVE MEMORY INSTRUCTION such that
+;		the source address is the address of this dsa's
+;		next pointer.
+	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
+	CALL reselected_ok
+#if (CHIP == 710)
+;	Restore DSA following memory moves in reselected_ok
+;	dsa_temp_sync doesn't really care about DSA, but it has an
+;	optional debug INT so a valid DSA is a good idea.
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+	CALL dsa_temp_sync	
+; Release ACK on the IDENTIFY message _after_ we've set the synchronous 
+; transfer parameters! 
+	CLEAR ACK
+; Implicitly restore pointers on reselection, so a RETURN
+; will transfer control back to the right spot.
+    	CALL REL (dsa_code_restore_pointers)
+    	RETURN
+ENTRY dsa_zero
+dsa_zero:
+ENTRY dsa_code_template_end
+dsa_code_template_end:
+
+; Perform sanity check for dsa_fields_start == dsa_code_template_end - 
+; dsa_zero, puke.
+
+ABSOLUTE dsa_fields_start =  0	; Sanity marker
+				; 	pad 48 bytes (fix this RSN)
+ABSOLUTE dsa_next = 48		; len 4 Next DSA
+ 				; del 4 Previous DSA address
+ABSOLUTE dsa_cmnd = 56		; len 4 Scsi_Cmnd * for this thread.
+ABSOLUTE dsa_select = 60	; len 4 Device ID, Period, Offset for 
+			 	;	table indirect select
+ABSOLUTE dsa_msgout = 64	; len 8 table indirect move parameter for 
+				;       select message
+ABSOLUTE dsa_cmdout = 72	; len 8 table indirect move parameter for 
+				;	command
+ABSOLUTE dsa_dataout = 80	; len 4 code pointer for dataout
+ABSOLUTE dsa_datain = 84	; len 4 code pointer for datain
+ABSOLUTE dsa_msgin = 88		; len 8 table indirect move for msgin
+ABSOLUTE dsa_status = 96 	; len 8 table indirect move for status byte
+ABSOLUTE dsa_msgout_other = 104	; len 8 table indirect for normal message out
+				; (Synchronous transfer negotiation, etc).
+ABSOLUTE dsa_end = 112
+
+ABSOLUTE schedule = 0 		; Array of JUMP dsa_begin or JUMP (next),
+				; terminated by a call to JUMP wait_reselect
+
+; Linked lists of DSA structures
+ABSOLUTE reconnect_dsa_head = 0	; Link list of DSAs which can reconnect
+ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
+				; address of reconnect_dsa_head
+
+; These select the source and destination of a MOVE MEMORY instruction
+ABSOLUTE dmode_memory_to_memory = 0x0
+ABSOLUTE dmode_memory_to_ncr = 0x0
+ABSOLUTE dmode_ncr_to_memory = 0x0
+
+ABSOLUTE addr_scratch = 0x0
+ABSOLUTE addr_temp = 0x0
+#if (CHIP == 710)
+ABSOLUTE saved_dsa = 0x0
+ABSOLUTE emulfly = 0x0
+ABSOLUTE addr_dsa = 0x0
+#endif
+#endif /* CHIP != 700 && CHIP != 70066 */
+
+; Interrupts - 
+; MSB indicates type
+; 0	handle error condition
+; 1 	handle message 
+; 2 	handle normal condition
+; 3	debugging interrupt
+; 4 	testing interrupt 
+; Next byte indicates specific error
+
+; XXX not yet implemented, I'm not sure if I want to - 
+; Next byte indicates the routine the error occurred in
+; The LSB indicates the specific place the error occurred
+ 
+ABSOLUTE int_err_unexpected_phase = 0x00000000	; Unexpected phase encountered
+ABSOLUTE int_err_selected = 0x00010000		; SELECTED (nee RESELECTED)
+ABSOLUTE int_err_unexpected_reselect = 0x00020000 
+ABSOLUTE int_err_check_condition = 0x00030000	
+ABSOLUTE int_err_no_phase = 0x00040000
+ABSOLUTE int_msg_wdtr = 0x01000000		; WDTR message received
+ABSOLUTE int_msg_sdtr = 0x01010000		; SDTR received
+ABSOLUTE int_msg_1 = 0x01020000			; single byte special message
+						; received
+
+ABSOLUTE int_norm_select_complete = 0x02000000	; Select complete, reprogram
+						; registers.
+ABSOLUTE int_norm_reselect_complete = 0x02010000	; Nexus established
+ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
+ABSOLUTE int_norm_disconnected = 0x02030000	; Disconnected 
+ABSOLUTE int_norm_aborted =0x02040000		; Aborted *dsa
+ABSOLUTE int_norm_reset = 0x02050000		; Generated BUS reset.
+ABSOLUTE int_norm_emulateintfly = 0x02060000	; 53C710 Emulated intfly
+ABSOLUTE int_debug_break = 0x03000000		; Break point
+#ifdef DEBUG
+ABSOLUTE int_debug_scheduled = 0x03010000	; new I/O scheduled 
+ABSOLUTE int_debug_idle = 0x03020000		; scheduler is idle
+ABSOLUTE int_debug_dsa_loaded = 0x03030000	; dsa reloaded
+ABSOLUTE int_debug_reselected = 0x03040000	; NCR reselected
+ABSOLUTE int_debug_head = 0x03050000		; issue head overwritten
+ABSOLUTE int_debug_disconnected = 0x03060000	; disconnected
+ABSOLUTE int_debug_disconnect_msg = 0x03070000	; got message to disconnect
+ABSOLUTE int_debug_dsa_schedule = 0x03080000	; in dsa_schedule
+ABSOLUTE int_debug_reselect_check = 0x03090000  ; Check for reselection of DSA
+ABSOLUTE int_debug_reselected_ok = 0x030a0000 	; Reselection accepted
+#endif
+ABSOLUTE int_debug_panic = 0x030b0000		; Panic driver
+#ifdef DEBUG
+ABSOLUTE int_debug_saved = 0x030c0000 		; save/restore pointers
+ABSOLUTE int_debug_restored = 0x030d0000
+ABSOLUTE int_debug_sync = 0x030e0000		; Sanity check synchronous 
+						; parameters. 
+ABSOLUTE int_debug_datain = 0x030f0000		; going into data in phase 
+						; now.
+ABSOLUTE int_debug_check_dsa = 0x03100000	; Sanity check DSA against
+						; SDID.
+#endif
+
+ABSOLUTE int_test_1 = 0x04000000		; Test 1 complete
+ABSOLUTE int_test_2 = 0x04010000		; Test 2 complete
+ABSOLUTE int_test_3 = 0x04020000		; Test 3 complete
+
+
+; These should start with 0x05000000, with low bits incrementing for 
+; each one.
+
+#ifdef EVENTS
+ABSOLUTE int_EVENT_SELECT = 0
+ABSOLUTE int_EVENT_DISCONNECT = 0
+ABSOLUTE int_EVENT_RESELECT = 0
+ABSOLUTE int_EVENT_COMPLETE = 0
+ABSOLUTE int_EVENT_IDLE = 0
+ABSOLUTE int_EVENT_SELECT_FAILED = 0
+ABSOLUTE int_EVENT_BEFORE_SELECT = 0
+ABSOLUTE int_EVENT_RESELECT_FAILED = 0
+#endif
+						
+ABSOLUTE NCR53c7xx_msg_abort = 0	; Pointer to abort message
+ABSOLUTE NCR53c7xx_msg_reject = 0       ; Pointer to reject message
+ABSOLUTE NCR53c7xx_zero	= 0		; long with zero in it, use for source
+ABSOLUTE NCR53c7xx_sink = 0		; long to dump worthless data in
+ABSOLUTE NOP_insn = 0			; NOP instruction
+
+; Pointer to message, potentially multi-byte
+ABSOLUTE msg_buf = 0
+
+; Pointer to holding area for reselection information
+ABSOLUTE reselected_identify = 0
+ABSOLUTE reselected_tag = 0
+
+; Request sense command pointer, it's a 6 byte command, should
+; be constant for all commands since we always want 16 bytes of 
+; sense and we don't need to change any fields as we did under 
+; SCSI-I when we actually cared about the LUN field.
+;EXTERNAL NCR53c7xx_sense		; Request sense command
+
+#if (CHIP != 700) && (CHIP != 70066)
+; dsa_schedule  
+; PURPOSE : after a DISCONNECT message has been received, and pointers
+;	saved, insert the current DSA structure at the head of the 
+; 	disconnected queue and fall through to the scheduler.
+;
+; CALLS : OK
+;
+; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
+;	of disconnected commands
+;
+; MODIFIES : SCRATCH, reconnect_dsa_head
+; 
+; EXITS : always passes control to schedule
+
+ENTRY dsa_schedule
+dsa_schedule:
+#ifdef DEBUG
+    INT int_debug_dsa_schedule
+#endif
+
+;
+; Calculate the address of the next pointer within the DSA 
+; structure of the command that is currently disconnecting
+;
+#if (CHIP == 710)
+    ; Read what should be the current DSA from memory - actual DSA
+    ; register is probably corrupt
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    MOVE SCRATCH0 + dsa_next TO SCRATCH0
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+
+; Point the next field of this DSA structure at the current disconnected 
+; list
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
+    DMODE_MEMORY_TO_MEMORY
+dsa_schedule_insert:
+    MOVE MEMORY 4, reconnect_dsa_head, 0 
+
+; And update the head pointer.
+#if (CHIP == 710)
+    ; Read what should be the current DSA from memory - actual DSA
+    ; register is probably corrupt
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
+    DMODE_MEMORY_TO_MEMORY
+/* Temporarily, see what happens. */
+#ifndef ORIGINAL
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    CLEAR ACK
+#endif
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+    WAIT DISCONNECT
+#ifdef EVENTS
+    INT int_EVENT_DISCONNECT;
+#endif
+#ifdef DEBUG
+    INT int_debug_disconnected
+#endif
+    JUMP schedule
+#endif 
+
+;
+; select
+;
+; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
+;	On success, the current DSA structure is removed from the issue 
+;	queue.  Usually, this is entered as a fall-through from schedule,
+;	although the contingent allegiance handling code will write
+;	the select entry address to the DSP to restart a command as a 
+;	REQUEST SENSE.  A message is sent (usually IDENTIFY, although
+;	additional SDTR or WDTR messages may be sent).  COMMAND OUT
+;	is handled.
+;
+; INPUTS : DSA - SCSI command, issue_dsa_head
+;
+; CALLS : NOT OK
+;
+; MODIFIES : SCRATCH, issue_dsa_head
+;
+; EXITS : on reselection or selection, go to select_failed
+;	otherwise, RETURN so control is passed back to 
+;	dsa_begin.
+;
+
+ENTRY select
+select:
+
+#ifdef EVENTS
+    INT int_EVENT_BEFORE_SELECT
+#endif
+
+#ifdef DEBUG
+    INT int_debug_scheduled
+#endif
+    CLEAR TARGET
+
+; XXX
+;
+; In effect, SELECTION operations are backgrounded, with execution
+; continuing until code which waits for REQ or a fatal interrupt is 
+; encountered.
+;
+; So, for more performance, we could overlap the code which removes 
+; the command from the NCRs issue queue with the selection, but 
+; at this point I don't want to deal with the error recovery.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+#if (CHIP == 710)
+    ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+    MOVE CTEST7 & 0xff TO CTEST7
+#else
+    MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+    SELECT ATN FROM dsa_select, select_failed
+    JUMP select_msgout, WHEN MSG_OUT
+ENTRY select_msgout
+select_msgout:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+    MOVE FROM dsa_msgout, WHEN MSG_OUT
+#else
+ENTRY select_msgout
+    SELECT ATN 0, select_failed
+select_msgout:
+    MOVE 0, 0, WHEN MSGOUT
+#endif
+
+#ifdef EVENTS
+   INT int_EVENT_SELECT
+#endif
+   RETURN
+
+; 
+; select_done
+; 
+; PURPOSE: continue on to normal data transfer; called as the exit 
+;	point from dsa_begin.
+;
+; INPUTS: dsa
+;
+; CALLS: OK
+;
+;
+
+select_done:
+#if (CHIP == 710)
+; NOTE DSA is corrupt when we arrive here!
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+#ifdef DEBUG
+ENTRY select_check_dsa
+select_check_dsa:
+    INT int_debug_check_dsa
+#endif
+
+; After a successful selection, we should get either a CMD phase or 
+; some transfer request negotiation message.
+
+    JUMP cmdout, WHEN CMD
+    INT int_err_unexpected_phase, WHEN NOT MSG_IN 
+
+select_msg_in:
+    CALL msg_in, WHEN MSG_IN
+    JUMP select_msg_in, WHEN MSG_IN
+
+cmdout:
+    INT int_err_unexpected_phase, WHEN NOT CMD
+#if (CHIP == 700)
+    INT int_norm_selected
+#endif
+ENTRY cmdout_cmdout
+cmdout_cmdout:
+#if (CHIP != 700) && (CHIP != 70066)
+    MOVE FROM dsa_cmdout, WHEN CMD
+#else
+    MOVE 0, 0, WHEN CMD
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+;
+; data_transfer  
+; other_out
+; other_in
+; other_transfer
+;
+; PURPOSE : handle the main data transfer for a SCSI command in 
+;	several parts.  In the first part, data_transfer, DATA_IN
+;	and DATA_OUT phases are allowed, with the user provided
+;	code (usually dynamically generated based on the scatter/gather
+;	list associated with a SCSI command) called to handle these 
+;	phases.
+;
+;	After control has passed to one of the user provided 
+;	DATA_IN or DATA_OUT routines, back calls are made to 
+;	other_transfer_in or other_transfer_out to handle non-DATA IN
+;	and DATA OUT phases respectively, with the state of the active
+;	data pointer being preserved in TEMP.
+;
+;	On completion, the user code passes control to other_transfer
+;	which causes DATA_IN and DATA_OUT to result in unexpected_phase
+;	interrupts so that data overruns may be trapped.
+;
+; INPUTS : DSA - SCSI command
+;
+; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
+;	other_transfer
+;
+; MODIFIES : SCRATCH
+;
+; EXITS : if STATUS IN is detected, signifying command completion,
+;	the NCR jumps to command_complete.  If MSG IN occurs, a 
+;	CALL is made to msg_in.  Otherwise, other_transfer runs in 
+;	an infinite loop.
+;	
+
+ENTRY data_transfer
+data_transfer:
+    JUMP cmdout_cmdout, WHEN CMD
+    CALL msg_in, WHEN MSG_IN
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    JUMP do_dataout, WHEN DATA_OUT
+    JUMP do_datain, WHEN DATA_IN
+    JUMP command_complete, WHEN STATUS
+    JUMP data_transfer
+ENTRY end_data_transfer
+end_data_transfer:
+
+;
+; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain 
+; should be fixed up whenever the nexus changes so it can point to the 
+; correct routine for that command.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Nasty jump to dsa->dataout
+do_dataout:
+#if (CHIP == 710)
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    MOVE SCRATCH0 + dsa_dataout TO SCRATCH0	
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
+    DMODE_MEMORY_TO_MEMORY
+dataout_to_jump:
+    MOVE MEMORY 4, 0, dataout_jump + 4 
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+dataout_jump:
+    JUMP 0
+
+; Nasty jump to dsa->dsain
+do_datain:
+#if (CHIP == 710)
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    MOVE SCRATCH0 + dsa_datain TO SCRATCH0	
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
+    DMODE_MEMORY_TO_MEMORY
+ENTRY datain_to_jump
+datain_to_jump:
+    MOVE MEMORY 4, 0, datain_jump + 4
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef DEBUG
+    INT int_debug_datain
+#endif
+datain_jump:
+    JUMP 0
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+
+; Note that other_out and other_in loop until a non-data phase
+; is discovered, so we only execute return statements when we
+; can go on to the next data phase block move statement.
+
+ENTRY other_out
+other_out:
+#if 0
+    INT 0x03ffdead
+#endif
+    INT int_err_unexpected_phase, WHEN CMD
+    JUMP msg_in_restart, WHEN MSG_IN 
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    INT int_err_unexpected_phase, WHEN DATA_IN
+    JUMP command_complete, WHEN STATUS
+    JUMP other_out, WHEN NOT DATA_OUT
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user dataout code.
+#endif
+    RETURN
+
+ENTRY other_in
+other_in:
+#if 0
+    INT 0x03ffdead
+#endif
+    INT int_err_unexpected_phase, WHEN CMD
+    JUMP msg_in_restart, WHEN MSG_IN 
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    INT int_err_unexpected_phase, WHEN DATA_OUT
+    JUMP command_complete, WHEN STATUS
+    JUMP other_in, WHEN NOT DATA_IN
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user datain code.
+#endif
+    RETURN
+
+
+ENTRY other_transfer
+other_transfer:
+    INT int_err_unexpected_phase, WHEN CMD
+    CALL msg_in, WHEN MSG_IN
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    INT int_err_unexpected_phase, WHEN DATA_OUT
+    INT int_err_unexpected_phase, WHEN DATA_IN
+    JUMP command_complete, WHEN STATUS
+    JUMP other_transfer
+
+;
+; msg_in_restart
+; msg_in
+; munge_msg
+;
+; PURPOSE : process messages from a target.  msg_in is called when the 
+;	caller hasn't read the first byte of the message.  munge_message
+;	is called when the caller has read the first byte of the message,
+;	and left it in SFBR.  msg_in_restart is called when the caller 
+;	hasn't read the first byte of the message, and wishes RETURN
+;	to transfer control back to the address of the conditional
+;	CALL instruction rather than to the instruction after it.
+;
+;	Various int_* interrupts are generated when the host system
+;	needs to intervene, as is the case with SDTR, WDTR, and
+;	INITIATE RECOVERY messages.
+;
+;	When the host system handles one of these interrupts,
+;	it can respond by reentering at reject_message, 
+;	which rejects the message and returns control to
+;	the caller of msg_in or munge_msg, accept_message
+;	which clears ACK and returns control, or reply_message
+;	which sends the message pointed to by the DSA 
+;	msgout_other table indirect field.
+;
+;	DISCONNECT messages are handled by moving the command
+;	to the reconnect_dsa_queue.
+#if (CHIP == 710)
+; NOTE: DSA should be valid when we get here - we cannot save both it
+;	and TEMP in this routine.
+#endif
+;
+; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
+;	only)
+;
+; CALLS : NO.  The TEMP register isn't backed up to allow nested calls.
+;
+; MODIFIES : SCRATCH, DSA on DISCONNECT
+;
+; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
+;	and normal return from message handlers running under
+;	Linux, control is returned to the caller.  Receipt
+;	of DISCONNECT messages pass control to dsa_schedule.
+;
+ENTRY msg_in_restart
+msg_in_restart:
+; XXX - hackish
+;
+; Since it's easier to debug changes to the statically 
+; compiled code, rather than the dynamically generated 
+; stuff, such as
+;
+; 	MOVE x, y, WHEN data_phase
+; 	CALL other_z, WHEN NOT data_phase
+; 	MOVE x, y, WHEN data_phase
+;
+; I'd like to have certain routines (notably the message handler)
+; restart on the conditional call rather than the next instruction.
+;
+; So, subtract 8 from the return address
+
+    MOVE TEMP0 + 0xf8 TO TEMP0
+    MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
+    MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
+    MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
+
+ENTRY msg_in
+msg_in:
+    MOVE 1, msg_buf, WHEN MSG_IN
+
+munge_msg:
+    JUMP munge_extended, IF 0x01		; EXTENDED MESSAGE
+    JUMP munge_2, IF 0x20, AND MASK 0xdf	; two byte message
+;
+; XXX - I've seen a handful of broken SCSI devices which fail to issue
+; 	a SAVE POINTERS message before disconnecting in the middle of 
+; 	a transfer, assuming that the DATA POINTER will be implicitly 
+; 	restored.  
+;
+; Historically, I've often done an implicit save when the DISCONNECT
+; message is processed.  We may want to consider having the option of 
+; doing that here. 
+;
+    JUMP munge_save_data_pointer, IF 0x02	; SAVE DATA POINTER
+    JUMP munge_restore_pointers, IF 0x03	; RESTORE POINTERS 
+    JUMP munge_disconnect, IF 0x04		; DISCONNECT
+    INT int_msg_1, IF 0x07			; MESSAGE REJECT
+    INT int_msg_1, IF 0x0f			; INITIATE RECOVERY
+#ifdef EVENTS 
+    INT int_EVENT_SELECT_FAILED 
+#endif
+    JUMP reject_message
+
+munge_2:
+    JUMP reject_message
+;
+; The SCSI standard allows targets to recover from transient 
+; error conditions by backing up the data pointer with a 
+; RESTORE POINTERS message.  
+;	
+; So, we must save and restore the _residual_ code as well as 
+; the current instruction pointer.  Because of this messiness,
+; it is simpler to put dynamic code in the dsa for this and to
+; just do a simple jump down there. 
+;
+
+munge_save_data_pointer:
+#if (CHIP == 710)
+    ; We have something in TEMP here, so first we must save that
+    MOVE TEMP0 TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE TEMP1 TO SFBR
+    MOVE SFBR TO SCRATCH1
+    MOVE TEMP2 TO SFBR
+    MOVE SFBR TO SCRATCH2
+    MOVE TEMP3 TO SFBR
+    MOVE SFBR TO SCRATCH3
+    MOVE MEMORY 4, addr_scratch, jump_temp + 4
+    ; Now restore DSA
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+    MOVE DSA0 + dsa_save_data_pointer TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE DSA1 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH1
+    MOVE DSA2 + 0xff TO SFBR WITH CARRY 
+    MOVE SFBR TO SCRATCH2
+    MOVE DSA3 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH3
+
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
+    DMODE_MEMORY_TO_MEMORY
+jump_dsa_save:
+    JUMP 0
+
+munge_restore_pointers:
+#if (CHIP == 710)
+    ; The code at dsa_restore_pointers will RETURN, but we don't care
+    ; about TEMP here, as it will overwrite it anyway.
+#endif
+    MOVE DSA0 + dsa_restore_pointers TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE DSA1 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH1
+    MOVE DSA2 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH2
+    MOVE DSA3 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH3
+
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
+    DMODE_MEMORY_TO_MEMORY
+jump_dsa_restore:
+    JUMP 0
+
+
+munge_disconnect:
+#ifdef DEBUG
+    INT int_debug_disconnect_msg
+#endif
+
+/* 
+ * Before, we overlapped processing with waiting for disconnect, but
+ * debugging was beginning to appear messy.  Temporarily move things
+ * to just before the WAIT DISCONNECT.
+ */
+ 
+#ifdef ORIGINAL
+#if (CHIP == 710)
+; Following clears Unexpected Disconnect bit.  What do we do?
+#else
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    CLEAR ACK
+#endif
+
+#if (CHIP != 700) && (CHIP != 70066)
+    JUMP dsa_schedule
+#else
+    WAIT DISCONNECT
+    INT int_norm_disconnected
+#endif
+
+munge_extended:
+    CLEAR ACK
+    INT int_err_unexpected_phase, WHEN NOT MSG_IN
+    MOVE 1, msg_buf + 1, WHEN MSG_IN
+    JUMP munge_extended_2, IF 0x02
+    JUMP munge_extended_3, IF 0x03 
+    JUMP reject_message
+
+munge_extended_2:
+    CLEAR ACK
+    MOVE 1, msg_buf + 2, WHEN MSG_IN
+    JUMP reject_message, IF NOT 0x02	; Must be WDTR
+    CLEAR ACK
+    MOVE 1, msg_buf + 3, WHEN MSG_IN
+    INT int_msg_wdtr
+
+munge_extended_3:
+    CLEAR ACK
+    MOVE 1, msg_buf + 2, WHEN MSG_IN
+    JUMP reject_message, IF NOT 0x01	; Must be SDTR
+    CLEAR ACK
+    MOVE 2, msg_buf + 3, WHEN MSG_IN
+    INT int_msg_sdtr
+
+ENTRY reject_message
+reject_message:
+    SET ATN
+    CLEAR ACK
+    MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
+    RETURN
+
+ENTRY accept_message
+accept_message:
+    CLEAR ATN
+    CLEAR ACK
+    RETURN
+
+ENTRY respond_message
+respond_message:
+    SET ATN
+    CLEAR ACK
+    MOVE FROM dsa_msgout_other, WHEN MSG_OUT
+    RETURN
+
+;
+; command_complete
+;
+; PURPOSE : handle command termination when STATUS IN is detected by reading
+;	a status byte followed by a command termination message. 
+;
+;	Normal termination results in an INTFLY instruction, and 
+;	the host system can pick out which command terminated by 
+;	examining the MESSAGE and STATUS buffers of all currently 
+;	executing commands;
+;
+;	Abnormal (CHECK_CONDITION) termination results in an
+;	int_err_check_condition interrupt so that a REQUEST SENSE
+;	command can be issued out-of-order so that no other command
+;	clears the contingent allegiance condition.
+;	
+;
+; INPUTS : DSA - command	
+;
+; CALLS : OK
+;
+; EXITS : On successful termination, control is passed to schedule.
+;	On abnormal termination, the user will usually modify the 
+;	DSA fields and corresponding buffers and return control
+;	to select.
+;
+
+ENTRY command_complete
+command_complete:
+    MOVE FROM dsa_status, WHEN STATUS
+#if (CHIP != 700) && (CHIP != 70066)
+    MOVE SFBR TO SCRATCH0		; Save status
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+ENTRY command_complete_msgin
+command_complete_msgin:
+    MOVE FROM dsa_msgin, WHEN MSG_IN
+; Indicate that we should be expecting a disconnect
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#else
+    ; Above code cleared the Unexpected Disconnect bit, what do we do?
+#endif
+    CLEAR ACK
+#if (CHIP != 700) && (CHIP != 70066)
+    WAIT DISCONNECT
+
+;
+; The SCSI specification states that when a UNIT ATTENTION condition
+; is pending, as indicated by a CHECK CONDITION status message,
+; the target shall revert to asynchronous transfers.  Since
+; synchronous transfers parameters are maintained on a per INITIATOR/TARGET 
+; basis, and returning control to our scheduler could work on a command
+; running on another lun on that target using the old parameters, we must
+; interrupt the host processor to get them changed, or change them ourselves.
+;
+; Once SCSI-II tagged queueing is implemented, things will be even more
+; hairy, since contingent allegiance conditions exist on a per-target/lun
+; basis, and issuing a new command with a different tag would clear it.
+; In these cases, we must interrupt the host processor to get a request 
+; added to the HEAD of the queue with the request sense command, or we
+; must automatically issue the request sense command.
+
+#if 0
+    MOVE SCRATCH0 TO SFBR			
+    JUMP command_failed, IF 0x02
+#endif
+#if (CHIP == 710)
+#if defined(MVME166_INTFLY)
+; For MVME166 (ie CHIP=710) we will force an INTFLY by triggering a software
+; interupt (SW7).  We can use SCRATCH, as we are about to jump to
+; schedule, which corrupts it anyway.  Will probably remove this later,
+; but want to check performance effects first.
+
+#define INTFLY_ADDR     0xfff40070
+
+    MOVE 0 TO SCRATCH0
+    MOVE 0x80 TO SCRATCH1
+    MOVE 0 TO SCRATCH2
+    MOVE 0 TO SCRATCH3
+    MOVE MEMORY 4, addr_scratch, INTFLY_ADDR
+#else
+    INT int_norm_emulateintfly
+#endif
+#else
+    INTFLY
+#endif
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef EVENTS
+    INT int_EVENT_COMPLETE
+#endif
+#if (CHIP != 700) && (CHIP != 70066)
+    JUMP schedule
+command_failed:
+    INT int_err_check_condition
+#else
+    INT int_norm_command_complete
+#endif
+
+;
+; wait_reselect
+;
+; PURPOSE : This is essentially the idle routine, where control lands
+;	when there are no new processes to schedule.  wait_reselect
+;	waits for reselection, selection, and new commands.
+;
+;	When a successful reselection occurs, with the aid 
+;	of fixed up code in each DSA, wait_reselect walks the 
+;	reconnect_dsa_queue, asking each dsa if the target ID
+;	and LUN match its.
+;
+;	If a match is found, a call is made back to reselected_ok,
+;	which through the miracles of self modifying code, extracts
+;	the found DSA from the reconnect_dsa_queue and then 
+;	returns control to the DSAs thread of execution.
+;
+; INPUTS : NONE
+;
+; CALLS : OK
+;
+; MODIFIES : DSA,
+;
+; EXITS : On successful reselection, control is returned to the 
+;	DSA which called reselected_ok.  If the WAIT RESELECT
+;	was interrupted by a new commands arrival signaled by 
+;	SIG_P, control is passed to schedule.  If the NCR is 
+;	selected, the host system is interrupted with an 
+;	int_err_selected which is usually responded to by
+;	setting DSP to the target_abort address.
+
+ENTRY wait_reselect
+wait_reselect:
+#ifdef EVENTS
+    int int_EVENT_IDLE
+#endif
+#ifdef DEBUG
+    int int_debug_idle
+#endif
+    WAIT RESELECT wait_reselect_failed
+
+reselected:
+#ifdef EVENTS
+    int int_EVENT_RESELECT
+#endif
+    CLEAR TARGET
+    DMODE_MEMORY_TO_MEMORY
+    ; Read all data needed to reestablish the nexus - 
+    MOVE 1, reselected_identify, WHEN MSG_IN
+    ; We used to CLEAR ACK here.
+#if (CHIP != 700) && (CHIP != 70066)
+#ifdef DEBUG
+    int int_debug_reselected
+#endif
+
+    ; Point DSA at the current head of the disconnected queue.
+    DMODE_MEMORY_TO_NCR
+    MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
+    DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+    MOVE MEMORY 4, addr_scratch, saved_dsa
+#else
+    CALL scratch_to_dsa
+#endif
+
+    ; Fix the update-next pointer so that the reconnect_dsa_head
+    ; pointer is the one that will be updated if this DSA is a hit 
+    ; and we remove it from the queue.
+
+    MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+ENTRY reselected_check_next
+reselected_check_next:
+#ifdef DEBUG
+    INT int_debug_reselect_check
+#endif
+    ; Check for a NULL pointer.
+    MOVE DSA0 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    MOVE DSA1 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    MOVE DSA2 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    MOVE DSA3 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    INT int_err_unexpected_reselect
+
+reselected_not_end:
+    ;
+    ; XXX the ALU is only eight bits wide, and the assembler
+    ; wont do the dirt work for us.  As long as dsa_check_reselect
+    ; is negative, we need to sign extend with 1 bits to the full
+    ; 32 bit width of the address.
+    ;
+    ; A potential work around would be to have a known alignment 
+    ; of the DSA structure such that the base address plus 
+    ; dsa_check_reselect doesn't require carrying from bytes 
+    ; higher than the LSB.
+    ;
+
+    MOVE DSA0 TO SFBR
+    MOVE SFBR + dsa_check_reselect TO SCRATCH0
+    MOVE DSA1 TO SFBR
+    MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
+    MOVE DSA2 TO SFBR
+    MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
+    MOVE DSA3 TO SFBR
+    MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
+
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, reselected_check + 4
+    DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+reselected_check:
+    JUMP 0
+
+
+;
+;
+#if (CHIP == 710)
+; We have problems here - the memory move corrupts TEMP and DSA.  This
+; routine is called from DSA code, and patched from many places.  Scratch
+; is probably free when it is called.
+; We have to:
+;   copy temp to scratch, one byte at a time
+;   write scratch to patch a jump in place of the return
+;   do the move memory
+;   jump to the patched in return address
+; DSA is corrupt when we get here, and can be left corrupt
+
+ENTRY reselected_ok
+reselected_ok:
+    MOVE TEMP0 TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE TEMP1 TO SFBR
+    MOVE SFBR TO SCRATCH1
+    MOVE TEMP2 TO SFBR
+    MOVE SFBR TO SCRATCH2
+    MOVE TEMP3 TO SFBR
+    MOVE SFBR TO SCRATCH3
+    MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
+reselected_ok_patch:
+    MOVE MEMORY 4, 0, 0
+reselected_ok_jump:
+    JUMP 0
+#else
+ENTRY reselected_ok
+reselected_ok:
+reselected_ok_patch:
+    MOVE MEMORY 4, 0, 0				; Patched : first word
+						; 	is address of 
+						;       successful dsa_next
+						; Second word is last 
+						;	unsuccessful dsa_next,
+						;	starting with 
+						;       dsa_reconnect_head
+    ; We used to CLEAR ACK here.
+#ifdef DEBUG
+    INT int_debug_reselected_ok
+#endif
+#ifdef DEBUG
+    INT int_debug_check_dsa
+#endif
+    RETURN					; Return control to where
+#endif
+#else
+    INT int_norm_reselected
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+selected:
+    INT int_err_selected;
+
+;
+; A select or reselect failure can be caused by one of two conditions : 
+; 1.  SIG_P was set.  This will be the case if the user has written
+;	a new value to a previously NULL head of the issue queue.
+;
+; 2.  The NCR53c810 was selected or reselected by another device.
+;
+; 3.  The bus was already busy since we were selected or reselected
+;	before starting the command.
+
+wait_reselect_failed:
+#ifdef EVENTS 
+	INT int_EVENT_RESELECT_FAILED
+#endif
+; Check selected bit.  
+#if (CHIP == 710)
+    ; Must work out how to tell if we are selected....
+#else
+    MOVE SIST0 & 0x20 TO SFBR
+    JUMP selected, IF 0x20
+#endif
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+    MOVE CTEST2 & 0x40 TO SFBR	
+    JUMP schedule, IF 0x40
+; Check connected bit.  
+; FIXME: this needs to change if we support target mode
+    MOVE ISTAT & 0x08 TO SFBR
+    JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+    JUMP schedule
+#else
+    INT int_debug_panic
+#endif
+
+
+select_failed:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+#ifdef EVENTS
+  int int_EVENT_SELECT_FAILED
+#endif
+; Otherwise, mask the selected and reselected bits off SIST0
+#if (CHIP ==710)
+    ; Let's assume we don't get selected for now
+    MOVE SSTAT0 & 0x10 TO SFBR
+#else
+    MOVE SIST0 & 0x30 TO SFBR
+    JUMP selected, IF 0x20
+#endif
+    JUMP reselected, IF 0x10 
+; If SIGP is set, the user just gave us another command, and
+; we should restart or return to the scheduler.
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+    MOVE CTEST2 & 0x40 TO SFBR	
+    JUMP select, IF 0x40
+; Check connected bit.  
+; FIXME: this needs to change if we support target mode
+; FIXME: is this really necessary? 
+    MOVE ISTAT & 0x08 TO SFBR
+    JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+    JUMP schedule
+#else
+    INT int_debug_panic
+#endif
+
+;
+; test_1
+; test_2
+;
+; PURPOSE : run some verification tests on the NCR.  test_1
+;	copies test_src to test_dest and interrupts the host
+;	processor, testing for cache coherency and interrupt
+; 	problems in the processes.
+;
+;	test_2 runs a command with offsets relative to the 
+;	DSA on entry, and is useful for miscellaneous experimentation.
+;
+
+; Verify that interrupts are working correctly and that we don't 
+; have a cache invalidation problem.
+
+ABSOLUTE test_src = 0, test_dest = 0
+ENTRY test_1
+test_1:
+    MOVE MEMORY 4, test_src, test_dest
+    INT int_test_1
+
+;
+; Run arbitrary commands, with test code establishing a DSA
+;
+ 
+ENTRY test_2
+test_2:
+    CLEAR TARGET
+#if (CHIP == 710)
+    ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+    MOVE CTEST7 & 0xff TO CTEST7
+#else
+    MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+    SELECT ATN FROM 0, test_2_fail
+    JUMP test_2_msgout, WHEN MSG_OUT
+ENTRY test_2_msgout
+test_2_msgout:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+    MOVE FROM 8, WHEN MSG_OUT
+    MOVE FROM 16, WHEN CMD 
+    MOVE FROM 24, WHEN DATA_IN
+    MOVE FROM 32, WHEN STATUS
+    MOVE FROM 40, WHEN MSG_IN
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    CLEAR ACK
+    WAIT DISCONNECT
+test_2_fail:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+    INT int_test_2
+
+ENTRY debug_break
+debug_break:
+    INT int_debug_break
+
+;
+; initiator_abort
+; target_abort
+;
+; PURPOSE : Abort the currently established nexus from with initiator
+;	or target mode.
+;
+;  
+
+ENTRY target_abort
+target_abort:
+    SET TARGET
+    DISCONNECT
+    CLEAR TARGET
+    JUMP schedule
+    
+ENTRY initiator_abort
+initiator_abort:
+    SET ATN
+;
+; The SCSI-I specification says that targets may go into MSG out at 
+; their leisure upon receipt of the ATN single.  On all versions of the 
+; specification, we can't change phases until REQ transitions true->false, 
+; so we need to sink/source one byte of data to allow the transition.
+;
+; For the sake of safety, we'll only source one byte of data in all 
+; cases, but to accommodate the SCSI-I dain bramage, we'll sink an  
+; arbitrary number of bytes.
+    JUMP spew_cmd, WHEN CMD
+    JUMP eat_msgin, WHEN MSG_IN
+    JUMP eat_datain, WHEN DATA_IN
+    JUMP eat_status, WHEN STATUS
+    JUMP spew_dataout, WHEN DATA_OUT
+    JUMP sated
+spew_cmd:
+    MOVE 1, NCR53c7xx_zero, WHEN CMD
+    JUMP sated
+eat_msgin:
+    MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
+    JUMP eat_msgin, WHEN MSG_IN
+    JUMP sated
+eat_status:
+    MOVE 1, NCR53c7xx_sink, WHEN STATUS
+    JUMP eat_status, WHEN STATUS
+    JUMP sated
+eat_datain:
+    MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
+    JUMP eat_datain, WHEN DATA_IN
+    JUMP sated
+spew_dataout:
+    MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
+sated:
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
+    WAIT DISCONNECT
+    INT int_norm_aborted
+
+#if (CHIP != 710)
+;
+; dsa_to_scratch
+; scratch_to_dsa
+;
+; PURPOSE :
+; 	The NCR chips cannot do a move memory instruction with the DSA register 
+; 	as the source or destination.  So, we provide a couple of subroutines
+; 	that let us switch between the DSA register and scratch register.
+;
+; 	Memory moves to/from the DSPS  register also don't work, but we 
+; 	don't use them.
+;
+;
+
+ 
+dsa_to_scratch:
+    MOVE DSA0 TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE DSA1 TO SFBR
+    MOVE SFBR TO SCRATCH1
+    MOVE DSA2 TO SFBR
+    MOVE SFBR TO SCRATCH2
+    MOVE DSA3 TO SFBR
+    MOVE SFBR TO SCRATCH3
+    RETURN
+
+scratch_to_dsa:
+    MOVE SCRATCH0 TO SFBR
+    MOVE SFBR TO DSA0
+    MOVE SCRATCH1 TO SFBR
+    MOVE SFBR TO DSA1
+    MOVE SCRATCH2 TO SFBR
+    MOVE SFBR TO DSA2
+    MOVE SCRATCH3 TO SFBR
+    MOVE SFBR TO DSA3
+    RETURN
+#endif
+ 
+#if (CHIP == 710)
+; Little patched jump, used to overcome problems with TEMP getting
+; corrupted on memory moves.
+
+jump_temp:
+    JUMP 0
+#endif
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.39/linux/drivers/scsi/Makefile	Tue May 13 22:41:12 1997
+++ linux/drivers/scsi/Makefile	Sun May 18 17:10:37 1997
@@ -95,6 +95,30 @@
   endif
 endif
 
+ifeq ($(CONFIG_A4000T_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+  ifeq ($(CONFIG_A4000T_SCSI),m)
+  M_OBJS += amiga7xx.o 53c7xx.o
+  endif
+endif
+
+ifeq ($(CONFIG_A4091_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+  ifeq ($(CONFIG_A4091_SCSI),m)
+  M_OBJS += amiga7xx.o 53c7xx.o
+  endif
+endif
+
+ifeq ($(CONFIG_WARPENGINE_SCSI),y)
+L_OBJS += amiga7xx.o 53c7xx.o
+else
+  ifeq ($(CONFIG_WARPENGINE_SCSI),m)
+  M_OBJS += amiga7xx.o 53c7xx.o
+  endif
+endif
+
 ifeq ($(CONFIG_A3000_SCSI),y)
 L_OBJS += a3000.o wd33c93.o
 else
@@ -416,6 +440,16 @@
 	$(CPP) -traditional -DCHIP=810 fake.c | grep -v '^#' | perl script_asm.pl 
 	mv script.h 53c8xx_d.h
 	mv scriptu.h 53c8xx_u.h
+	rm fake.c
+
+53c7xx.o : 53c7xx_d.h 53c7xx.c
+	$(CC) $(CFLAGS) -c 53c7xx.c
+
+53c7xx_d.h 53c7xx_u.h : 53c7xx.scr script_asm.pl
+	ln -sf 53c7xx.scr fake.c
+	$(CPP) -traditional -DCHIP=710 fake.c | grep -v '^#' | perl -s script_asm.pl -ncr7x0_family
+	mv script.h 53c7xx_d.h
+	mv scriptu.h 53c7xx_u.h
 	rm fake.c
 
 ncr53c8xx.o : ncr53c8xx.c
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/amiga7xx.c linux/drivers/scsi/amiga7xx.c
--- v2.1.39/linux/drivers/scsi/amiga7xx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/amiga7xx.c	Sun May 18 17:10:37 1997
@@ -0,0 +1,107 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ *  		Amiga MacroSystemUS WarpEngine SCSI controller.
+ *		Amiga Technologies A4000T SCSI controller.
+ *		Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/zorro.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "amiga7xx.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_amiga7xx = {
+    PROC_SCSI_AMIGA7XX, 8, "Amiga7xx",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+int amiga7xx_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    int key;
+    int num = 0;
+    unsigned long address;
+    long long options;
+    struct ConfigDev *cd;
+
+    if (called || !MACH_IS_AMIGA)
+	return 0;
+
+    tpnt->proc_dir = &proc_scsi_amiga7xx;
+
+#ifdef CONFIG_WARPENGINE_SCSI
+    if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0)))
+    {
+    	cd = zorro_get_board(key);
+    	address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+		cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
+
+    	options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+	clock = 50000000;	/* 50MHz SCSI Clock */
+
+    	ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
+			0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE, 
+			options, clock);
+
+    	zorro_config_board(key, 0);
+    	num++;
+    }
+#endif
+
+#ifdef CONFIG_A4000T_SCSI
+    if (AMIGAHW_PRESENT(A4000_SCSI))
+    { 
+    	options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+	clock = 50000000;	/* 50MHz SCSI Clock */
+
+    	ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)ZTWO_VADDR(0xDD0040),
+			0, IRQ_AMIGA_PORTS, DMA_NONE,
+			options, clock);
+    	num++;
+    }
+#endif
+
+#ifdef CONFIG_A4091_SCSI
+    while ( (key = zorro_find(MANUF_COMMODORE, PROD_A4091, 0, 0)) ||
+	 (key = zorro_find(MANUF_COMMODORE2, PROD_A4091_2, 0, 0)) )
+    {
+	cd = zorro_get_board(key);
+	address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+		cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
+
+    	options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+	clock = 50000000;	/* 50MHz SCSI Clock */
+
+    	ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000),
+			0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE, 
+			options, clock);
+
+	zorro_config_board(key, 0);
+	num++;
+    }
+#endif
+
+    called = 1;
+    return num;
+}
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/amiga7xx.h linux/drivers/scsi/amiga7xx.h
--- v2.1.39/linux/drivers/scsi/amiga7xx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/amiga7xx.h	Sun May 18 17:10:37 1997
@@ -0,0 +1,52 @@
+#ifndef AMIGA7XX_H
+
+#include <linux/types.h>
+
+int amiga7xx_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (Scsi_Host_Template *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_amiga7xx;
+
+#define AMIGA7XX_SCSI {/* next */                NULL,            \
+		      /* usage_count */         NULL,	         \
+		      /* proc_dir_entry */      NULL, \
+		      /* proc_info */           NULL,            \
+		      /* name */                "Amiga NCR53c710 SCSI", \
+		      /* detect */              amiga7xx_detect,    \
+		      /* release */             NULL,   \
+		      /* info */                NULL,	         \
+		      /* command */             NULL,            \
+		      /* queuecommand */        NCR53c7xx_queue_command, \
+		      /* abort */               NCR53c7xx_abort,   \
+		      /* reset */               NCR53c7xx_reset,   \
+		      /* slave_attach */        NULL,            \
+		      /* bios_param */          scsicam_bios_param,   \
+		      /* can_queue */           24,       \
+		      /* this_id */             7,               \
+		      /* sg_tablesize */        127,          \
+		      /* cmd_per_lun */	        3,     \
+		      /* present */             0,               \
+		      /* unchecked_isa_dma */   0,               \
+		      /* use_clustering */      DISABLE_CLUSTERING }
+#endif
+#endif /* AMIGA7XX_H */
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v2.1.39/linux/drivers/scsi/atari_scsi.c	Tue May 13 22:41:13 1997
+++ linux/drivers/scsi/atari_scsi.c	Sun May 18 17:10:38 1997
@@ -1026,6 +1026,10 @@
 {
 	unsigned long	possible_len, limit;
 
+	if (is_hades)
+		/* Hades has no SCSI DMA at all :-( Always force use of PIO */
+		return( 0 );
+	
 	if (IS_A_TT())
 		/* TT SCSI DMA can transfer arbitrary #bytes */
 		return( wanted_len );
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.39/linux/drivers/scsi/hosts.c	Tue May 13 22:41:13 1997
+++ linux/drivers/scsi/hosts.c	Sun May 18 17:10:38 1997
@@ -42,6 +42,10 @@
 
 #include "hosts.h"
 
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+#include "amiga7xx.h"
+#endif
+
 #ifdef CONFIG_A3000_SCSI
 #include "a3000.h"
 #endif
@@ -221,6 +225,9 @@
 static Scsi_Host_Template builtin_scsi_hosts[] =
 {
 #ifdef CONFIG_AMIGA
+#if defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4000T_SCSI) || defined(CONFIG_A4091_SCSI)
+	AMIGA7XX_SCSI,
+#endif
 #ifdef CONFIG_A3000_SCSI
 	A3000_SCSI,
 #endif
diff -u --recursive --new-file v2.1.39/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.1.39/linux/drivers/scsi/scsi.h	Mon Apr 14 16:28:16 1997
+++ linux/drivers/scsi/scsi.h	Wed May 21 16:16:17 1997
@@ -218,7 +218,13 @@
 
 #include <asm/scatterlist.h>
 
+#ifdef __mc68000__
+#include <asm/pgtable.h>
+#define CONTIGUOUS_BUFFERS(X,Y) \
+	(VTOP((X)->b_data+(X)->b_size-1)+1 == VTOP((Y)->b_data))
+#else
 #define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+#endif
 
 
 /*
diff -u --recursive --new-file v2.1.39/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.39/linux/fs/autofs/root.c	Thu May 15 16:48:03 1997
+++ linux/fs/autofs/root.c	Wed May 21 17:10:23 1997
@@ -376,6 +376,8 @@
 	struct autofs_packet_expire pkt;
 	struct autofs_dirhash *dh = &(sbi->dirhash);
 	
+	memset(&pkt,0,sizeof pkt);
+
 	pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
 	pkt.hdr.type = autofs_ptype_expire;
 
diff -u --recursive --new-file v2.1.39/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c
--- v2.1.39/linux/fs/autofs/waitq.c	Thu May 15 16:48:03 1997
+++ linux/fs/autofs/waitq.c	Wed May 21 17:10:23 1997
@@ -77,6 +77,8 @@
 	DPRINTK(("autofs_wait: wait id = 0x%08lx, name = ", wq->wait_queue_token));
 	autofs_say(wq->name,wq->len);
 
+	memset(&pkt,0,sizeof pkt); /* For security reasons */
+
 	pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
 	pkt.hdr.type = autofs_ptype_missing;
 	pkt.wait_queue_token = wq->wait_queue_token;
@@ -96,7 +98,7 @@
 	for ( wq = sbi->queues ; wq ; wq = wq->next ) {
 		if ( wq->hash == hash &&
 		     wq->len == len &&
-		     !memcmp(wq->name,name,len) )
+		     wq->name && !memcmp(wq->name,name,len) )
 			break;
 	}
 	
@@ -115,12 +117,13 @@
 		init_waitqueue(&wq->queue);
 		wq->hash = hash;
 		wq->len = len;
+		wq->status = -EINTR; /* Status return if interrupted */
 		memcpy(wq->name, name, len);
 		wq->next = sbi->queues;
 		sbi->queues = wq;
 
 		/* autofs_notify_daemon() may block */
-		wq->wait_ctr++;
+		wq->wait_ctr = 1;
 		autofs_notify_daemon(sbi,wq);
 	} else
 		wq->wait_ctr++;
@@ -132,7 +135,8 @@
 		DPRINTK(("autofs_wait: skipped sleeping\n"));
 	}
 
-	status = (current->signal & ~current->blocked) ? -EINTR : wq->status;
+	status = wq->status;
+
 	if ( ! --wq->wait_ctr )	/* Are we the last process to need status? */
 		kfree(wq);
 
diff -u --recursive --new-file v2.1.39/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.39/linux/fs/binfmt_elf.c	Mon May 19 12:57:39 1997
+++ linux/fs/binfmt_elf.c	Mon May 19 12:39:25 1997
@@ -47,6 +47,11 @@
 extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
 #endif
 
+#ifndef elf_addr_t
+#define elf_addr_t unsigned long
+#define elf_caddr_t char *
+#endif
+
 /*
  * If we don't support core dumping, then supply a NULL so we
  * don't even try.
@@ -59,6 +64,7 @@
 
 #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
 #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
+#define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
 
 static struct linux_binfmt elf_format = {
 #ifndef MODULE
@@ -70,8 +76,8 @@
 
 static void set_brk(unsigned long start, unsigned long end)
 {
-	start = PAGE_ALIGN(start);
-	end = PAGE_ALIGN(end);
+	start = ELF_PAGEALIGN(start);
+	end = ELF_PAGEALIGN(end);
 	if (end <= start)
 		return;
 	do_mmap(NULL, start, end - start,
@@ -90,28 +96,30 @@
 {
 	unsigned long nbyte;
 
-	nbyte = elf_bss & (PAGE_SIZE-1);
+	nbyte = ELF_PAGEOFFSET(elf_bss);
 	if (nbyte) {
-		nbyte = PAGE_SIZE - nbyte;
+		nbyte = ELF_EXEC_PAGESIZE - nbyte;
 		clear_user((void *) elf_bss, nbyte);
 	}
 }
 
-unsigned long * create_elf_tables(char *p, int argc, int envc,
-				  struct elfhdr * exec,
-				  unsigned long load_addr,
-				  unsigned long interp_load_addr, int ibcs)
+static elf_addr_t * 
+create_elf_tables(char *p, int argc, int envc,
+		  struct elfhdr * exec,
+		  unsigned long load_addr,
+		  unsigned long interp_load_addr, int ibcs)
 {
-	char **argv, **envp;
-	unsigned long *sp;
+	elf_caddr_t *argv;
+	elf_caddr_t *envp;
+	elf_addr_t *sp;
 
 	/*
 	 * Force 16 byte alignment here for generality.
 	 */
-	sp = (unsigned long *) (~15UL & (unsigned long) p);
+	sp = (elf_addr_t *) (~15UL & (unsigned long) p);
 #ifdef __sparc__
 {
-	unsigned long *csp;
+	elf_addr_t *csp;
 	csp = sp;
 	csp -= exec ? DLINFO_ITEMS*2 : 2;
 	csp -= envc+1;
@@ -137,36 +145,36 @@
 	  NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
 	  NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
 	  NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
-	  NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
+	  NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
 	  NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
 	  NEW_AUX_ENT (5, AT_FLAGS, 0);
-	  NEW_AUX_ENT (6, AT_ENTRY, (unsigned long) exec->e_entry);
-	  NEW_AUX_ENT (7, AT_UID, (unsigned long) current->uid);
-	  NEW_AUX_ENT (8, AT_EUID, (unsigned long) current->euid);
-	  NEW_AUX_ENT (9, AT_GID, (unsigned long) current->gid);
-	  NEW_AUX_ENT (10, AT_EGID, (unsigned long) current->egid);
+	  NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry);
+	  NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid);
+	  NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid);
+	  NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid);
+	  NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid);
 	}
 #undef NEW_AUX_ENT
 
 	sp -= envc+1;
-	envp = (char **) sp;
+	envp = (elf_caddr_t *) sp;
 	sp -= argc+1;
-	argv = (char **) sp;
+	argv = (elf_caddr_t *) sp;
 	if (!ibcs) {
-		__put_user((unsigned long) envp,--sp);
-		__put_user((unsigned long) argv,--sp);
+		__put_user((elf_addr_t)(unsigned long) envp,--sp);
+		__put_user((elf_addr_t)(unsigned long) argv,--sp);
 	}
 
-	__put_user((unsigned long)argc,--sp);
+	__put_user((elf_addr_t)argc,--sp);
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
-		__put_user(p,argv++);
+		__put_user((elf_caddr_t)(unsigned long)p,argv++);
 		p += strlen_user(p);
 	}
 	__put_user(NULL, argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
-		__put_user(p,envp++);
+		__put_user((elf_caddr_t)(unsigned long)p,envp++);
 		p += strlen_user(p);
 	}
 	__put_user(NULL, envp);
@@ -210,7 +218,7 @@
 
 	/* Now read in all of the header information */
 
-	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
+	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > ELF_EXEC_PAGESIZE) {
 	    return ~0UL;
 	}
 
@@ -579,8 +587,8 @@
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
 	current->mm->rss = 0;
-#ifdef __sparc_v9__
-	current->tss.flags &= ~(SPARC_FLAG_32BIT);
+#ifdef ELF_FLAGS_INIT
+	ELF_FLAGS_INIT;
 #endif
 	bprm->p = setup_arg_pages(bprm->p, bprm);
 	current->mm->start_stack = bprm->p;
@@ -799,7 +807,7 @@
 
 	/* Now read in all of the header information */
 
-	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > ELF_EXEC_PAGESIZE)
 		return -ENOEXEC;
 
 	elf_phdata =  (struct elf_phdr *)
@@ -903,6 +911,10 @@
 {
 	if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
 		return 0;
+
+	/* Do not dump I/O mapped devices! -DaveM */
+	if(vma->vm_flags & VM_IO)
+		return 0;
 #if 1
 	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
 		return 1;
@@ -1012,7 +1024,7 @@
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
 
-	if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
+	if (!current->dumpable || limit < ELF_EXEC_PAGESIZE || current->mm->count != 1)
 		return 0;
 	current->dumpable = 0;
 
@@ -1114,14 +1126,14 @@
 	psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
 	psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
 	psinfo.pr_sid = prstatus.pr_sid = current->session;
-	prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
-	prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
-	prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
-	prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
-	prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
-	prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
-	prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
-	prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+	prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
+	prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
+	prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
+	prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
+	prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
+	prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
+	prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
+	prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
 
 	/*
 	 * This transfers the registers from regs into the standard
@@ -1133,7 +1145,7 @@
 	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
 	{
 		printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
-			sizeof(elf_gregset_t), sizeof(struct pt_regs));
+			(long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs));
 	}
 	else
 		*(struct pt_regs *)&prstatus.pr_reg = *regs;
@@ -1215,7 +1227,7 @@
 	}
 
 	/* Page-align dumped data */
-	dataoff = offset = roundup(offset, PAGE_SIZE);
+	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
 	/* Write program headers for segments dump */
 	for(vma = current->mm->mmap, i = 0;
@@ -1237,7 +1249,7 @@
 		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
 		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
 		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
-		phdr.p_align = PAGE_SIZE;
+		phdr.p_align = ELF_EXEC_PAGESIZE;
 
 		DUMP_WRITE(&phdr, sizeof(phdr));
 	}
diff -u --recursive --new-file v2.1.39/linux/fs/locks.c linux/fs/locks.c
--- v2.1.39/linux/fs/locks.c	Tue May 13 22:41:14 1997
+++ linux/fs/locks.c	Sun May 18 17:10:38 1997
@@ -366,8 +366,7 @@
 		do {
 			if (vma->vm_flags & VM_MAYSHARE)
 				return (-EAGAIN);
-			vma = vma->vm_next_share;
-		} while (vma != inode->i_mmap);
+		} while ((vma = vma->vm_next_share) != NULL);
 	}
 
 	if (copy_from_user(&flock, l, sizeof(flock)))
diff -u --recursive --new-file v2.1.39/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.39/linux/fs/proc/array.c	Tue May 13 22:41:15 1997
+++ linux/fs/proc/array.c	Mon May 19 12:37:57 1997
@@ -268,7 +268,7 @@
 	unsigned long idle;
 
 	uptime = jiffies;
-	idle = task[0]->utime + task[0]->stime;
+	idle = task[0]->times.tms_utime + task[0]->times.tms_stime;
 
 	/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
 	   that would overflow about every five days at HZ == 100.
@@ -748,10 +748,10 @@
 		tsk->cmin_flt,
 		tsk->maj_flt,
 		tsk->cmaj_flt,
-		tsk->utime,
-		tsk->stime,
-		tsk->cutime,
-		tsk->cstime,
+		tsk->times.tms_utime,
+		tsk->times.tms_stime,
+		tsk->times.tms_cutime,
+		tsk->times.tms_cstime,
 		priority,
 		nice,
 		tsk->timeout,
diff -u --recursive --new-file v2.1.39/linux/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h
--- v2.1.39/linux/include/asm-alpha/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/keyboard.h	Wed May 21 09:57:45 1997
@@ -0,0 +1,44 @@
+/*
+ *  linux/include/asm-alpha/keyboard.h
+ *
+ *  Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+/*
+ *  This file contains the alpha architecture specific keyboard definitions
+ */
+
+#ifndef _ALPHA_KEYBOARD_H
+#define _ALPHA_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#define KEYBOARD_IRQ			1
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode		pckbd_setkeycode
+#define kbd_getkeycode		pckbd_getkeycode
+#define kbd_pretranslate	pckbd_pretranslate
+#define kbd_translate		pckbd_translate
+#define kbd_unexpected_up	pckbd_unexpected_up
+#define kbd_leds		pckbd_leds
+#define kbd_init_hw		pckbd_init_hw
+
+#define INIT_KBD
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMalpha_KEYBOARD_H */
diff -u --recursive --new-file v2.1.39/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h
--- v2.1.39/linux/include/asm-i386/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/keyboard.h	Wed May 21 09:57:45 1997
@@ -0,0 +1,42 @@
+/*
+ *  linux/include/asm-i386/keyboard.h
+ *
+ *  Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+/*
+ *  This file contains the i386 architecture specific keyboard definitions
+ */
+
+#ifndef _I386_KEYBOARD_H
+#define _I386_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#define KEYBOARD_IRQ			1
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode		pckbd_setkeycode
+#define kbd_getkeycode		pckbd_getkeycode
+#define kbd_pretranslate	pckbd_pretranslate
+#define kbd_translate		pckbd_translate
+#define kbd_unexpected_up	pckbd_unexpected_up
+#define kbd_leds		pckbd_leds
+#define kbd_init_hw		pckbd_init_hw
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMi386_KEYBOARD_H */
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h
--- v2.1.39/linux/include/asm-m68k/atomic.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/atomic.h	Sun May 18 17:10:38 1997
@@ -11,7 +11,7 @@
  */
 
 typedef struct { int counter; } atomic_t;
-#define ATOMIC_INIT	{ 0 }
+#define ATOMIC_INIT(i)	{ (i) }
 
 #define atomic_read(v)		((v)->counter)
 #define atomic_set(v, i)	(((v)->counter) = i)
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v2.1.39/linux/include/asm-m68k/bitops.h	Wed Sep 25 00:47:41 1996
+++ linux/include/asm-m68k/bitops.h	Sun May 18 17:10:38 1997
@@ -14,7 +14,7 @@
  * They use the standard big-endian m680x0 bit ordering.
  */
 
-extern __inline__ int set_bit(int nr,void * vaddr)
+extern __inline__ int test_and_set_bit(int nr,void * vaddr)
 {
 	char retval;
 
@@ -24,7 +24,13 @@
 	return retval;
 }
 
-extern __inline__ int clear_bit(int nr, void * vaddr)
+extern __inline__ void set_bit(int nr, void * vaddr)
+{
+	__asm__ __volatile__ ("bfset %1@{%0:#1}"
+	     : : "d" (nr^31), "a" (vaddr));
+}
+
+extern __inline__ int test_and_clear_bit(int nr, void * vaddr)
 {
 	char retval;
 
@@ -34,7 +40,13 @@
 	return retval;
 }
 
-extern __inline__ int change_bit(int nr, void * vaddr)
+extern __inline__ void clear_bit(int nr, void * vaddr)
+{
+	__asm__ __volatile__ ("bfclr %1@{%0:#1}"
+	     : : "d" (nr^31), "a" (vaddr));
+}
+
+extern __inline__ int test_and_change_bit(int nr, void * vaddr)
 {
 	char retval;
 
@@ -42,6 +54,12 @@
 	     : "=d" (retval) : "d" (nr^31), "a" (vaddr));
 
 	return retval;
+}
+
+extern __inline__ void change_bit(int nr, void * vaddr)
+{
+	__asm__ __volatile__ ("bfchg %1@{%0:#1}"
+	     : : "d" (nr^31), "a" (vaddr));
 }
 
 extern __inline__ int test_bit(int nr, const void * vaddr)
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/current.h linux/include/asm-m68k/current.h
--- v2.1.39/linux/include/asm-m68k/current.h	Mon Dec 30 01:58:35 1996
+++ linux/include/asm-m68k/current.h	Sun May 18 17:10:38 1997
@@ -1,12 +1,6 @@
 #ifndef _M68K_CURRENT_H
 #define _M68K_CURRENT_H
 
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.  For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()])	/* Current on this processor */
+register struct task_struct *current __asm__("%a2");
 
 #endif /* !(_M68K_CURRENT_H) */
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h
--- v2.1.39/linux/include/asm-m68k/elf.h	Fri Nov 22 05:56:36 1996
+++ linux/include/asm-m68k/elf.h	Sun May 18 17:10:38 1997
@@ -44,6 +44,7 @@
 	pr_reg[4] = regs->d5;						\
 	pr_reg[7] = regs->a0;						\
 	pr_reg[8] = regs->a1;						\
+	pr_reg[9] = regs->a2;						\
 	pr_reg[14] = regs->d0;						\
 	pr_reg[15] = rdusp();						\
 	pr_reg[16] = regs->orig_d0;					\
@@ -54,7 +55,6 @@
 	  struct switch_stack *sw = ((struct switch_stack *)regs) - 1;	\
 	  pr_reg[5] = sw->d6;						\
 	  pr_reg[6] = sw->d7;						\
-	  pr_reg[9] = sw->a2;						\
 	  pr_reg[10] = sw->a3;						\
 	  pr_reg[11] = sw->a4;						\
 	  pr_reg[12] = sw->a5;						\
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h
--- v2.1.39/linux/include/asm-m68k/hardirq.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/hardirq.h	Sun May 18 17:10:38 1997
@@ -1,11 +1,13 @@
 #ifndef __M68K_HARDIRQ_H
 #define __M68K_HARDIRQ_H
 
+#include <linux/tasks.h>
+
 extern unsigned int local_irq_count[NR_CPUS];
 #define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
 
-#define hardirq_trylock(cpu)	((cpu)==0)	/* always true */
-#define hardirq_endlock(cpu)	do { } while (0)
+#define hardirq_trylock(cpu)	(++local_irq_count[cpu], (cpu) == 0)
+#define hardirq_endlock(cpu)	(--local_irq_count[cpu])
 
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
 #define hardirq_exit(cpu)	(local_irq_count[cpu]--)
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/keyboard.h linux/include/asm-m68k/keyboard.h
--- v2.1.39/linux/include/asm-m68k/keyboard.h	Fri Dec 20 01:20:02 1996
+++ linux/include/asm-m68k/keyboard.h	Wed May 21 09:57:45 1997
@@ -13,9 +13,43 @@
 
 #ifdef __KERNEL__
 
-#define TRANSLATE_SCANCODES		0
-#define USE_MACHDEP_ABSTRACTION		1
 #include <asm/machdep.h>
+
+static __inline__ int kbd_setkeycode(unsigned int scancode,
+				     unsigned int keycode)
+{
+    return -EOPNOTSUPP;
+}
+
+static __inline__ int kbd_getkeycode(unsigned int scancode)
+{
+    return -EOPNOTSUPP;
+}
+
+static __inline__ int kbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+    return 1;
+}
+
+static __inline__ int kbd_translate(unsigned char scancode,
+				    unsigned char *keycode, char raw_mode)
+{
+    *keycode = scancode;
+    return 1;
+}
+
+static __inline__ char kbd_unexpected_up(unsigned char keycode)
+{
+    return 0200;
+}
+
+static __inline__ void kbd_leds(unsigned char leds)
+{
+    if (mach_kbd_leds)
+	mach_kbd_leds(leds);
+}
+
+#define kbd_init_hw	mach_keyb_init
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.1.39/linux/include/asm-m68k/pgtable.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/pgtable.h	Sun May 18 17:10:38 1997
@@ -175,7 +175,7 @@
 }
 
 /*
- * flush all atc entries (user-space entries only for the 680[46]0).
+ * flush all user-space atc entries.
  */
 static inline void __flush_tlb(void)
 {
@@ -184,7 +184,7 @@
 				     "pflushan\n\t"
 				     ".chip 68k");
 	else
-		__asm__ __volatile__("pflusha");
+		__asm__ __volatile__("pflush #0,#4");
 }
 
 static inline void __flush_tlb_one(unsigned long addr)
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.1.39/linux/include/asm-m68k/processor.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/processor.h	Sun May 18 17:10:38 1997
@@ -47,7 +47,7 @@
 #define INIT_MMAP { &init_mm, 0, 0x40000000, __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED), VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
-	sizeof(init_kernel_stack) + (long) init_kernel_stack, 0, \
+	sizeof(init_stack) + (unsigned long) init_stack, 0, \
 	PS_S, KERNEL_DS, \
 	{0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \
 }
@@ -93,9 +93,11 @@
 }
 
 /* Allocation and freeing of basic task resources. */
-#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define alloc_kernel_stack(p)	__get_free_page(GFP_KERNEL)
-#define free_task_struct(p)	kfree(p)
-#define free_kernel_stack(page) free_page((page))
+#define alloc_task_struct() \
+	((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p)	free_pages((unsigned long)(p),1)
+
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
 
 #endif
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/ptrace.h linux/include/asm-m68k/ptrace.h
--- v2.1.39/linux/include/asm-m68k/ptrace.h	Wed Mar 20 12:03:24 1996
+++ linux/include/asm-m68k/ptrace.h	Sun May 18 17:10:38 1997
@@ -34,6 +34,7 @@
   long     d5;
   long     a0;
   long     a1;
+  long     a2;
   long     d0;
   long     orig_d0;
   long     stkadj;
@@ -50,7 +51,6 @@
 struct switch_stack {
 	unsigned long  d6;
 	unsigned long  d7;
-	unsigned long  a2;
 	unsigned long  a3;
 	unsigned long  a4;
 	unsigned long  a5;
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.1.39/linux/include/asm-m68k/semaphore.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/semaphore.h	Sun May 18 17:10:38 1997
@@ -73,41 +73,26 @@
  * "down_failed" is a special asm handler that calls the C
  * routine that actually waits. See arch/m68k/lib/semaphore.S
  */
-extern inline void down(struct semaphore * sem)
+extern inline void do_down(struct semaphore * sem, void (*failed)(void))
 {
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
 	__asm__ __volatile__(
 		"| atomic down operation\n\t"
-		"lea %%pc@(1f),%%a0\n\t"
 		"subql #1,%0@\n\t"
-		"jmi " SYMBOL_NAME_STR(__down_failed) "\n"
-		"1:"
+		"jmi 2f\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		".even\n"
+		"2:\tpea 1b\n\t"
+		"jbra %1\n"
+		".previous"
 		: /* no outputs */
-		: "a" (sem1)
-		: "%a0", "memory");
+		: "a" (sem1), "m" (*(unsigned char *)failed)
+		: "memory");
 }
 
-/*
- * This version waits in interruptible state so that the waiting
- * process can be killed.  The down_failed_interruptible routine
- * returns negative for signalled and zero for semaphore acquired.
- */
-extern inline int down_interruptible(struct semaphore * sem)
-{
-	register int ret __asm__ ("%d0");
-	register struct semaphore *sem1 __asm__ ("%a1") = sem;
-	__asm__ __volatile__(
-		"| atomic interruptible down operation\n\t"
-		"lea %%pc@(1f),%%a0\n\t"
-		"subql #1,%1@\n\t"
-		"jmi " SYMBOL_NAME_STR(__down_failed_interruptible) "\n\t"
-		"clrl %0\n"
-		"1:"
-		: "=d" (ret)
-		: "a" (sem1)
-		: "%d0", "%a0", "memory");
-	return ret;
-}
+#define down(sem) do_down((sem),__down_failed)
+#define down_interruptible(sem) do_down((sem),__down_failed_interruptible)
 
 /*
  * Note! This is subtle. We jump to wake people up only if
@@ -120,13 +105,17 @@
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
 	__asm__ __volatile__(
 		"| atomic up operation\n\t"
-		"lea %%pc@(1f),%%a0\n\t"
-		"addql #1,%0\n\t"
-		"jle " SYMBOL_NAME_STR(__up_wakeup) "\n"
-		"1:"
+		"addql #1,%0@\n\t"
+		"jle 2f\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		".even\n"
+		"2:\tpea 1b\n\t"
+		"jbra %1\n"
+		".previous"
 		: /* no outputs */
-		: "m" (sem->count), "a" (sem1)
-		: "%a0", "memory");
+		: "a" (sem1), "m" (*(unsigned char *)__up_wakeup)
+		: "memory");
 }
 
 #endif
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/softirq.h linux/include/asm-m68k/softirq.h
--- v2.1.39/linux/include/asm-m68k/softirq.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/softirq.h	Sun May 18 17:10:38 1997
@@ -4,6 +4,9 @@
 /*
  * Software interrupts.. no SMP here either.
  */
+
+#include <asm/atomic.h>
+
 #define get_active_bhs()	(bh_mask & bh_active)
 #define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
 
@@ -14,12 +17,6 @@
 	bh_mask |= 1 << nr;
 }
 
-extern inline void remove_bh(int nr)
-{
-	bh_base[nr] = NULL;
-	bh_mask &= ~(1 << nr);
-}
-
 extern inline void mark_bh(int nr)
 {
 	set_bit(nr, &bh_active);
@@ -39,6 +36,12 @@
 {
 	if (!--bh_mask_count[nr])
 		bh_mask |= 1 << nr;
+}
+
+extern inline void remove_bh(int nr)
+{
+	bh_base[nr] = NULL;
+	bh_mask &= ~(1 << nr);
 }
 
 extern int __m68k_bh_counter;
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/spinlock.h linux/include/asm-m68k/spinlock.h
--- v2.1.39/linux/include/asm-m68k/spinlock.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/spinlock.h	Sun May 18 17:10:38 1997
@@ -5,8 +5,8 @@
  * We don't do SMP on the m68k .... at least not yet.
  */
 
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
+typedef struct { int dummy; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0 }
 
 #define spin_lock_init(lock)	do { } while(0)
 #define spin_lock(lock)		do { } while(0)
@@ -31,8 +31,8 @@
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
  */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+typedef struct { int dummy; } rwlock_t;
+#define RW_LOCK_UNLOCKED { 0 }
 
 #define read_lock(lock)		do { } while(0)
 #define read_unlock(lock)	do { } while(0)
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v2.1.39/linux/include/asm-m68k/system.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/system.h	Sun May 18 17:10:38 1997
@@ -83,6 +83,7 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
 
 #ifndef CONFIG_RMW_INSNS
 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
diff -u --recursive --new-file v2.1.39/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.1.39/linux/include/asm-m68k/unistd.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/unistd.h	Sun May 18 17:10:38 1997
@@ -322,9 +322,11 @@
 	set_fs (KERNEL_DS);
 
 	__asm__ __volatile__
-	  ("trap #0\n\t"		/* Linux/m68k system call */
+	  ("clrl %%d2\n\t"
+	   "trap #0\n\t"		/* Linux/m68k system call */
 	   "tstl %0\n\t"		/* child or parent */
 	   "jne 1f\n\t"			/* parent - jump */
+	   "lea %%sp@(-8192),%6\n\t"	/* reload current */
 	   "movel %3,%%sp@-\n\t"	/* push argument */
 	   "jsr %4@\n\t"		/* call fn */
 	   "movel %0,%%d1\n\t"		/* pass exit value */
@@ -333,8 +335,8 @@
 	   "1:"
 	   : "=d" (retval)
 	   : "0" (__NR_clone), "i" (__NR_exit),
-	     "r" (arg), "a" (fn), "d" (clone_arg)
-	   : "d0");
+	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current)
+	   : "d0", "d2");
 
 	set_fs (fs);
 	return retval;
diff -u --recursive --new-file v2.1.39/linux/include/asm-mips/bootinfo.h linux/include/asm-mips/bootinfo.h
--- v2.1.39/linux/include/asm-mips/bootinfo.h	Wed Dec 13 22:16:53 1995
+++ linux/include/asm-mips/bootinfo.h	Sun May 18 17:10:38 1997
@@ -8,7 +8,7 @@
  * Copyright (C) 1992 by Greg Harp
  *
  * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
+ * License.  See the file COPYING in the main directory of this archive
  * for more details.
  */
 #ifndef __ASM_MIPS_BOOTINFO_H
diff -u --recursive --new-file v2.1.39/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h
--- v2.1.39/linux/include/asm-mips/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/keyboard.h	Wed May 21 09:57:46 1997
@@ -0,0 +1,44 @@
+/*
+ *  linux/include/asm-mips/keyboard.h
+ *
+ *  Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+/*
+ *  This file contains the mips architecture specific keyboard definitions
+ */
+
+#ifndef __ASMMIPS_KEYBOARD_H
+#define __ASMMIPS_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#define KEYBOARD_IRQ			1
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode		pckbd_setkeycode
+#define kbd_getkeycode		pckbd_getkeycode
+#define kbd_pretranslate	pckbd_pretranslate
+#define kbd_translate		pckbd_translate
+#define kbd_unexpected_up	pckbd_unexpected_up
+#define kbd_leds		pckbd_leds
+#define kbd_init_hw		pckbd_init_hw
+
+#define INIT_KBD
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMMIPS_KEYBOARD_H */
diff -u --recursive --new-file v2.1.39/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.1.39/linux/include/asm-ppc/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/keyboard.h	Wed May 21 09:57:45 1997
@@ -0,0 +1,44 @@
+/*
+ *  linux/include/asm-ppc/keyboard.h
+ *
+ *  Created 3 Nov 1996 by Geert Uytterhoeven
+ */
+
+/*
+ *  This file contains the ppc architecture specific keyboard definitions
+ */
+
+#ifndef __ASMPPC_KEYBOARD_H
+#define __ASMPPC_KEYBOARD_H
+
+#ifdef __KERNEL__
+
+#define KEYBOARD_IRQ			1
+#define DISABLE_KBD_DURING_INTERRUPTS	0
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+/* #define KBD_IS_FOCUS_9000 */
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+
+#define kbd_setkeycode		pckbd_setkeycode
+#define kbd_getkeycode		pckbd_getkeycode
+#define kbd_pretranslate	pckbd_pretranslate
+#define kbd_translate		pckbd_translate
+#define kbd_unexpected_up	pckbd_unexpected_up
+#define kbd_leds		pckbd_leds
+#define kbd_init_hw		pckbd_init_hw
+
+#define INIT_KBD
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMPPC_KEYBOARD_H */
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- v2.1.39/linux/include/asm-sparc64/elf.h	Thu May 15 16:48:04 1997
+++ linux/include/asm-sparc64/elf.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.4 1997/05/04 07:21:21 davem Exp $ */
+/* $Id: elf.h,v 1.6 1997/05/17 11:51:27 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -7,6 +7,7 @@
  */
 
 #include <asm/ptrace.h>
+#include <asm/processor.h>
 
 typedef unsigned long elf_greg_t;
 
@@ -19,9 +20,13 @@
  * These are used to set parameters in the core dumps.
  */
 #ifndef ELF_ARCH
-#define ELF_ARCH	EM_SPARC64
-#define ELF_CLASS	ELFCLASS64
-#define ELF_DATA	ELFDATA2MSB;
+#define ELF_ARCH		EM_SPARC64
+#define ELF_CLASS		ELFCLASS64
+#define ELF_DATA		ELFDATA2MSB;
+#endif
+
+#ifndef ELF_FLAGS_INIT
+#define ELF_FLAGS_INIT current->tss.flags &= ~SPARC_FLAG_32BIT
 #endif
 
 /*
@@ -30,7 +35,6 @@
 #define elf_check_arch(x) ((x) == ELF_ARCH)	/* Might be EM_SPARC64 or EM_SPARC */
 
 #define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE	4096
-
+#define ELF_EXEC_PAGESIZE	8192
 
 #endif /* !(__ASM_SPARC64_ELF_H) */
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h
--- v2.1.39/linux/include/asm-sparc64/head.h	Tue May 13 22:41:18 1997
+++ linux/include/asm-sparc64/head.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.17 1997/04/28 14:57:13 davem Exp $ */
+/* $Id: head.h,v 1.19 1997/05/18 08:42:18 davem Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
@@ -147,6 +147,9 @@
 	flushw;							\
 	done; nop; nop; nop; nop; nop; nop;
 	        
+/* Before touching these macros, you owe it to yourself to go and
+ * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ */
 
 /* Normal kernel spill */
 #define SPILL_0_NORMAL					\
@@ -189,23 +192,25 @@
 	stxa	%i6, [%sp + STACK_BIAS + 0x70] %asi;	\
 	stxa	%i7, [%sp + STACK_BIAS + 0x78] %asi;	\
 	saved; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop; nop; nop;
+	nop; nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, spill_fixup;
 
 /* Normal 32bit spill */
 #define SPILL_2_GENERIC(xxx)				\
 	wr	%g0, xxx, %asi;				\
 	srl	%sp, 0, %sp;				\
 	stda	%l0, [%sp + 0x00] %asi;			\
-	stda	%l2, [%sp + 0x10] %asi;			\
-	stda	%l4, [%sp + 0x20] %asi;			\
-	stda	%l6, [%sp + 0x30] %asi;			\
-	stda	%i0, [%sp + 0x40] %asi;			\
-	stda	%i2, [%sp + 0x50] %asi;			\
-	stda	%i4, [%sp + 0x60] %asi;			\
-	stda	%i6, [%sp + 0x70] %asi;			\
+	stda	%l2, [%sp + 0x08] %asi;			\
+	stda	%l4, [%sp + 0x10] %asi;			\
+	stda	%l6, [%sp + 0x18] %asi;			\
+	stda	%i0, [%sp + 0x20] %asi;			\
+	stda	%i2, [%sp + 0x28] %asi;			\
+	stda	%i4, [%sp + 0x30] %asi;			\
+	stda	%i6, [%sp + 0x38] %asi;			\
 	saved; retry; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop; nop; nop; nop;
+	nop; nop; nop; nop; nop; nop; nop;		\
+	b,a,pt	%xcc, spill_fixup;
 
 #define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
 #define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
@@ -265,23 +270,25 @@
 	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
 	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
 	restored; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop; nop; nop;
+	nop; nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, fill_fixup;
 
 /* Normal 32bit fill */
 #define FILL_2_GENERIC(xxx)				\
 	wr	%g0, xxx, %asi;				\
 	srl	%sp, 0, %sp;				\
 	ldda	[%sp + 0x00] %asi, %l0;			\
-	ldda	[%sp + 0x10] %asi, %l2;			\
-	ldda	[%sp + 0x20] %asi, %l4;			\
-	ldda	[%sp + 0x30] %asi, %l6;			\
-	ldda	[%sp + 0x40] %asi, %i0;			\
-	ldda	[%sp + 0x50] %asi, %i2;			\
-	ldda	[%sp + 0x60] %asi, %i4;			\
-	ldda	[%sp + 0x70] %asi, %i6;			\
+	ldda	[%sp + 0x08] %asi, %l2;			\
+	ldda	[%sp + 0x10] %asi, %l4;			\
+	ldda	[%sp + 0x18] %asi, %l6;			\
+	ldda	[%sp + 0x20] %asi, %i0;			\
+	ldda	[%sp + 0x28] %asi, %i2;			\
+	ldda	[%sp + 0x30] %asi, %i4;			\
+	ldda	[%sp + 0x38] %asi, %i6;			\
 	restored; retry; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop; nop; nop; nop;
+	nop; nop; nop; nop; nop; nop; nop;		\
+	b,a,pt	%xcc, fill_fixup;
 
 #define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
 #define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.1.39/linux/include/asm-sparc64/mmu_context.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/mmu_context.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.7 1997/04/04 00:50:23 davem Exp $ */
+/* $Id: mmu_context.h,v 1.8 1997/05/18 20:44:23 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -63,11 +63,21 @@
 	   !(tsk->tss.flags & SPARC_FLAG_KTHREAD)	&&
 	   !(tsk->flags & PF_EXITING)) {
 		unsigned long ctx = tlb_context_cache;
+		register unsigned long paddr asm("o5");
 
 		flushw_user();
 		if((mm->context ^ ctx) & CTX_VERSION_MASK)
 			get_new_mmu_context(mm, ctx);
 		spitfire_set_secondary_context(mm->context);
+		paddr = __pa(mm->pgd);
+		__asm__ __volatile__("
+			rdpr		%%pstate, %%o4
+			wrpr		%%o4, %1, %%pstate
+			mov		%0, %%g7
+			wrpr		%%o4, 0x0, %%pstate
+		" : /* no outputs */
+		  : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
+		  : "o4");
 	}
 }
 
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.39/linux/include/asm-sparc64/pgtable.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc64/pgtable.h	Sun May 18 17:10:38 1997
@@ -1,7 +1,7 @@
-/* $Id: pgtable.h,v 1.28 1997/04/14 17:05:19 jj Exp $
+/* $Id: pgtable.h,v 1.31 1997/05/18 21:11:42 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
- * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef _SPARC64_PGTABLE_H
@@ -204,13 +204,8 @@
 	unsigned long addr;
 
 	flushw_all();
-	for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+	for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
 		spitfire_put_icache_tag(addr, 0x0UL);
-		membar("#Sync");
-	}
-
-	/* Kill the pipeline. */
-	flushi(PAGE_OFFSET);
 }
 
 extern __inline__ void flush_cache_mm(struct mm_struct *mm)
@@ -219,13 +214,8 @@
 		unsigned long addr;
 
 		flushw_user();
-		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
 			spitfire_put_icache_tag(addr, 0x0UL);
-			membar("#Sync");
-		}
-
-		/* Kill the pipeline. */
-		flushi(PAGE_OFFSET);
 	}
 }
 
@@ -236,13 +226,8 @@
 		unsigned long addr;
 
 		flushw_user();
-		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
 			spitfire_put_icache_tag(addr, 0x0UL);
-			membar("#Sync");
-		}
-
-		/* Kill the pipeline. */
-		flushi(PAGE_OFFSET);
 	}
 }
 
@@ -254,13 +239,8 @@
 		unsigned long addr;
 
 		flushw_user();
-		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32)
 			spitfire_put_icache_tag(addr, 0x0UL);
-			membar("#Sync");
-		}
-
-		/* Kill the pipeline. */
-		flushi(PAGE_OFFSET);
 	}
 }
 
@@ -290,15 +270,28 @@
 extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
 {
 	if(mm->context != NO_CONTEXT) {
-		unsigned long orig_ctx = spitfire_get_secondary_context();
-		unsigned long flags;
-
-		save_and_cli(flags);
-		spitfire_set_secondary_context(mm->context);
-		spitfire_flush_dtlb_secondary_context();
-		spitfire_flush_itlb_secondary_context();
-		spitfire_set_secondary_context(orig_ctx);
-		restore_flags(flags);
+		__asm__ __volatile__("
+	/* flush_tlb_mm() */
+	rdpr		%%pil, %%g1
+	mov		%1, %%g7
+	wrpr		%%g0, 15, %%pil
+	ldxa		[%%g7] %2, %%g2
+	cmp		%%g2, %0
+	be,pt		%%icc, 1f
+	 mov		0x50, %%g3
+	stxa		%0, [%%g7] %2
+1:
+	stxa		%%g0, [%%g3] %3
+	stxa		%%g0, [%%g3] %4
+	bne,a,pn	%%icc, 1f
+	 stxa		%%g2, [%%g7] %2
+1:
+	flush		%%g4
+	wrpr		%%g1, 0x0, %%pil
+"	: /* no outputs */
+	: "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+	  "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP)
+	: "g1", "g2", "g3", "g7", "cc");
 	}
 }
 
@@ -307,17 +300,21 @@
 {
 	if(mm->context != NO_CONTEXT) {
 		unsigned long old_ctx = spitfire_get_secondary_context();
+		unsigned long new_ctx = mm->context;
 		unsigned long flags;
 
 		start &= PAGE_MASK;
 		save_and_cli(flags);
-		spitfire_set_secondary_context(mm->context);
+		if(new_ctx != old_ctx)
+			spitfire_set_secondary_context(mm->context);
 		while(start < end) {
 			spitfire_flush_dtlb_secondary_page(start);
 			spitfire_flush_itlb_secondary_page(start);
 			start += PAGE_SIZE;
 		}
-		spitfire_set_secondary_context(old_ctx);
+		if(new_ctx != old_ctx)
+			spitfire_set_secondary_context(old_ctx);
+		__asm__ __volatile__("flush %g4");
 		restore_flags(flags);
 	}
 }
@@ -327,17 +324,31 @@
 	struct mm_struct *mm = vma->vm_mm;
 
 	if(mm->context != NO_CONTEXT) {
-		unsigned long old_ctx = spitfire_get_secondary_context();
-		unsigned long flags;
-
-		page &= PAGE_MASK;
-		save_and_cli(flags);
-		spitfire_set_secondary_context(mm->context);
-		if(vma->vm_flags & VM_EXEC)
-			spitfire_flush_itlb_secondary_page(page);
-		spitfire_flush_dtlb_secondary_page(page);
-		spitfire_set_secondary_context(old_ctx);
-		restore_flags(flags);
+	__asm__ __volatile__("
+	/* flush_tlb_page() */
+	rdpr		%%pil, %%g1
+	mov		%1, %%g7
+	wrpr		%%g0, 15, %%pil
+	ldxa		[%%g7] %2, %%g2
+	cmp		%%g2, %0
+	be,pt		%%icc, 1f
+	 or		%5, 0x10, %5
+	stxa		%0, [%%g7] %2
+1:
+	stxa		%%g0, [%5] %3
+	brnz,a		%6, 1f
+	 stxa		%%g0, [%5] %4
+1:
+	bne,a,pn	%%icc, 1f
+	 stxa		%%g2, [%%g7] %2
+1:
+	flush		%%g4
+	wrpr		%%g1, 0x0, %%pil
+"	: /* no outputs */
+	: "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+	  "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK),
+	  "r" (vma->vm_flags & VM_EXEC)
+	: "g1", "g2", "g3", "g7", "cc");
 	}
 }
 
@@ -649,7 +660,7 @@
 					start += PAGE_SIZE;
 				}
 			}
-		} while((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+		} while((vmaring = vmaring->vm_next_share) != NULL);
 
 		if(alias_found && (pte_val(pte) & _PAGE_CV)) {
 			pgdp = pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.1.39/linux/include/asm-sparc64/processor.h	Thu May 15 16:48:04 1997
+++ linux/include/asm-sparc64/processor.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.24 1997/05/04 07:21:21 davem Exp $
+/* $Id: processor.h,v 1.26 1997/05/17 05:59:10 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -115,6 +115,7 @@
 	regs->tpc = ((pc & (~3)) - 4); \
 	regs->tnpc = regs->tpc + 4; \
 	regs->y = 0; \
+	current->tss.flags &= ~SPARC_FLAG_32BIT; \
 	__asm__ __volatile__( \
 	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
 	"stx		%%g0, [%0 + %2 + 0x08]\n\t" \
@@ -132,7 +133,7 @@
 	"stx		%%g0, [%0 + %2 + 0x68]\n\t" \
 	"stx		%1,   [%0 + %2 + 0x70]\n\t" \
 	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
-	"wrpr		%%g0, 1, %%wstate\n\t" \
+	"wrpr		%%g0, (1 << 3), %%wstate\n\t" \
 	: \
 	: "r" (regs), "r" (sp - REGWIN_SZ), \
 	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
@@ -168,7 +169,7 @@
 	"stx		%%g0, [%0 + %2 + 0x68]\n\t" \
 	"stx		%1,   [%0 + %2 + 0x70]\n\t" \
 	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
-	"wrpr		%%g0, 2, %%wstate\n\t" \
+	"wrpr		%%g0, (2 << 3), %%wstate\n\t" \
 	: \
 	: "r" (regs), "r" (sp - REGWIN32_SZ), \
 	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])), \
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h
--- v2.1.39/linux/include/asm-sparc64/spitfire.h	Mon Apr 14 16:28:24 1997
+++ linux/include/asm-sparc64/spitfire.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.7 1997/04/04 00:50:29 davem Exp $
+/* $Id: spitfire.h,v 1.8 1997/05/18 04:16:56 davem Exp $
  * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -209,28 +209,28 @@
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
 			     : /* No outputs */
-			     : "r" (0x41), "i" (ASI_DMMU_DEMAP));
+			     : "r" (0x50), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_secondary_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
 			     : /* No outputs */
-			     : "r" (0x41), "i" (ASI_IMMU_DEMAP));
+			     : "r" (0x50), "i" (ASI_IMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_dtlb_nucleus_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
 			     : /* No outputs */
-			     : "r" (0x42), "i" (ASI_DMMU_DEMAP));
+			     : "r" (0x60), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_nucleus_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
 			     : /* No outputs */
-			     : "r" (0x42), "i" (ASI_IMMU_DEMAP));
+			     : "r" (0x60), "i" (ASI_IMMU_DEMAP));
 }
 
 /* Page level flushes. */
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h
--- v2.1.39/linux/include/asm-sparc64/string.h	Mon Apr 14 16:28:24 1997
+++ linux/include/asm-sparc64/string.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.4 1997/04/01 09:34:41 davem Exp $
+/* $Id: string.h,v 1.5 1997/05/18 04:16:57 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -41,14 +41,18 @@
 		if(n <= 32) {
 			__builtin_memcpy(to, from, n);
 		} else {
+#if 0
 			switch(n) {
 			case 8192:
 				__copy_1page(to, from);
 				break;
 			default:
+#endif
 				__memcpy(to, from, n);
+#if 0
 				break;
 			}
+#endif
 		}
 	}
 	return to;
@@ -74,9 +78,11 @@
 	extern __kernel_size_t __bzero(void *, __kernel_size_t);
 
 	if(!c) {
+#if 0
 		if(count == 8192)
 			bzero_1page(s);
 		else
+#endif
 			__bzero(s, count);
 	} else {
 		__memset(s, c, count);
diff -u --recursive --new-file v2.1.39/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.39/linux/include/asm-sparc64/system.h	Thu May 15 16:48:04 1997
+++ linux/include/asm-sparc64/system.h	Sun May 18 17:10:38 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.16 1997/05/14 20:48:07 davem Exp $ */
+/* $Id: system.h,v 1.19 1997/05/18 22:52:32 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -89,18 +89,24 @@
 
 #ifndef __ASSEMBLY__
 
+extern void synchronize_user_stack(void);
+
 extern __inline__ void flushw_user(void)
 {
 	__asm__ __volatile__("
 		rdpr		%%otherwin, %%g1
+		brz,pt		%%g1, 2f
+		 clr		%%g2
 1:
-		rdpr		%%otherwin, %%g2
-		brnz,pn		%%g2, 1b
-		 save		%%sp, %0, %%sp
+		save		%%sp, %0, %%sp
+		rdpr		%%otherwin, %%g1
+		brnz,pt		%%g1, 1b
+		 add		%%g2, 1, %%g2
 1:
-		subcc		%%g1, 1, %%g1
-		bne,pn		%%xcc, 1b
+		subcc		%%g2, 1, %%g2
+		bne,pt		%%xcc, 1b
 		 restore	%%g0, %%g0, %%g0
+2:
 	" : : "i" (-REGWIN_SZ)
 	  : "g1", "g2", "cc");
 }
@@ -122,9 +128,9 @@
 
 	/* See what happens when you design the chip correctly?
 	 * NOTE NOTE NOTE this is extremely non-trivial what I
-	 * am doing here.  GCC needs only two registers to stuff
-	 * things into ('next' and &current_set[cpu])  So I "claim"
-	 * that I do not clobber them, when in fact I do.  Please,
+	 * am doing here.  GCC needs only one register to stuff
+	 * things into ('next' in particular)  So I "claim" that
+	 * I do not clobber it, when in fact I do.  Please,
 	 * when modifying this code inspect output of sched.s very
 	 * carefully to make sure things still work.  -DaveM
 	 */
@@ -132,7 +138,6 @@
 do {											\
 	__label__ switch_continue;							\
 	register unsigned long task_pc asm("o7");					\
-	extern struct task_struct *current_set[NR_CPUS];				\
 	SWITCH_DO_LAZY_FPU(next);							\
 	task_pc = ((unsigned long) &&switch_continue) - 0x8;				\
 	__asm__ __volatile__(								\
@@ -142,14 +147,12 @@
 	"stx	%%o6, [%%g6 + %3]\n\t"							\
 	"rdpr	%%wstate, %%o5\n\t"							\
 	"stx	%%o7, [%%g6 + %4]\n\t"							\
-	"mov	%6, %%o4\n\t"								\
 	"stx	%%o5, [%%g6 + %2]\n\t"							\
-	"st	%%o4, [%%g6 + %7]\n\t"							\
 	"rdpr	%%cwp, %%o5\n\t"							\
-	"stx	%%o5, [%%g6 + %8]\n\t"							\
-	"mov	%1, %%g6\n\t"								\
-	"stx	%%g6, [%0]\n\t"								\
-	"ldx	[%%g6 + %8], %%g1\n\t"							\
+	"stx	%%o5, [%%g6 + %5]\n\t"							\
+	"mov	%0, %%g6\n\t"								\
+	"wr	%0, 0x0, %%pic\n\t"							\
+	"ldx	[%%g6 + %5], %%g1\n\t"							\
 	"wrpr	%%g1, %%cwp\n\t"							\
 	"ldx	[%%g6 + %2], %%o5\n\t"							\
 	"ldx	[%%g6 + %3], %%o6\n\t"							\
@@ -159,15 +162,13 @@
 	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
 	" ldx	[%%sp + 2047 + 0x78], %%i7\n\t"						\
 	: /* No outputs */								\
-	: "r" (&(current_set[smp_processor_id()])), "r" (next),				\
+	: "r" (next), "r" (task_pc),							\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)),		\
-	  "r" (task_pc), "i" (255),							\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->processor)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))		\
 	: "cc", "g1", "g2", "g3", "g5", "g7",						\
-	  "l2", "l3", "l4", "l5", "l6", "l7",						\
+	  "l1", "l2", "l3", "l4", "l5", "l6", "l7",					\
 	  "i0", "i1", "i2", "i3", "i4", "i5",						\
 	  "o0", "o1", "o2", "o3", "o4", "o5");						\
 switch_continue: } while(0)
diff -u --recursive --new-file v2.1.39/linux/include/linux/elf.h linux/include/linux/elf.h
--- v2.1.39/linux/include/linux/elf.h	Thu Mar 27 14:40:10 1997
+++ linux/include/linux/elf.h	Sun May 18 17:10:38 1997
@@ -3,11 +3,20 @@
 
 #include <asm/elf.h>
 
-typedef unsigned long	Elf32_Addr;
-typedef unsigned short	Elf32_Half;
-typedef unsigned long	Elf32_Off;
-typedef long		Elf32_Sword;
-typedef unsigned long	Elf32_Word;
+/* 32-bit ELF base types. */
+typedef __u32	Elf32_Addr;
+typedef __u16	Elf32_Half;
+typedef __u32	Elf32_Off;
+typedef __s32	Elf32_Sword;
+typedef __u32	Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef __u64	Elf64_Addr;
+typedef __u16	Elf64_Half;
+typedef __s16	Elf64_SHalf;
+typedef __u64	Elf64_Off;
+typedef __s64	Elf64_Sword;
+typedef __u64	Elf64_Word;
 
 /* These constants are for the segment types stored in the image headers */
 #define PT_NULL    0
@@ -128,10 +137,10 @@
 } Elf32_Dyn;
 
 typedef struct {
-  unsigned long long d_tag;		/* entry tag value */
+  Elf64_Word d_tag;		/* entry tag value */
   union {
-    unsigned long long d_val;
-    unsigned long long d_ptr;
+    Elf64_Word d_val;
+    Elf64_Word d_ptr;
   } d_un;
 } Elf64_Dyn;
 
@@ -226,8 +235,8 @@
 } Elf32_Rel;
 
 typedef struct elf64_rel {
-  unsigned long long r_offset;	/* Location at which to apply the action */
-  unsigned long long r_info;	/* index and type of relocation */
+  Elf64_Addr r_offset;	/* Location at which to apply the action */
+  Elf64_Word r_info;	/* index and type of relocation */
 } Elf64_Rel;
 
 typedef struct elf32_rela{
@@ -237,9 +246,9 @@
 } Elf32_Rela;
 
 typedef struct elf64_rela {
-  unsigned long long r_offset;	/* Location at which to apply the action */
-  unsigned long long r_info;	/* index and type of relocation */
-  unsigned long long r_addend;	/* Constant addend used to compute value */
+  Elf64_Addr r_offset;	/* Location at which to apply the action */
+  Elf64_Word r_info;	/* index and type of relocation */
+  Elf64_Word r_addend;	/* Constant addend used to compute value */
 } Elf64_Rela;
 
 typedef struct elf32_sym{
@@ -252,12 +261,12 @@
 } Elf32_Sym;
 
 typedef struct elf64_sym {
-  unsigned int	st_name;		/* Symbol name, index in string tbl */
-  unsigned char	st_info;		/* Type and binding attributes */
-  unsigned char	st_other;		/* No defined meaning, 0 */
-  unsigned short st_shndx;		/* Associated section index */
-  unsigned long long st_value;		/* Value of the symbol */
-  unsigned long long st_size;		/* Associated symbol size */
+  Elf32_Word st_name;		/* Symbol name, index in string tbl (yes, Elf32) */
+  unsigned char	st_info;	/* Type and binding attributes */
+  unsigned char	st_other;	/* No defined meaning, 0 */
+  Elf64_Half st_shndx;		/* Associated section index */
+  Elf64_Addr st_value;		/* Value of the symbol */
+  Elf64_Word st_size;		/* Associated symbol size */
 } Elf64_Sym;
 
 
@@ -282,19 +291,19 @@
 
 typedef struct elf64_hdr {
   unsigned char	e_ident[16];		/* ELF "magic number" */
-  short int e_type;
-  short unsigned int e_machine;
-  int   e_version;
-  unsigned long long e_entry;		/* Entry point virtual address */
-  unsigned long long e_phoff;		/* Program header table file offset */
-  unsigned long long e_shoff;		/* Section header table file offset */
-  int   e_flags;
-  short int e_ehsize;
-  short int e_phentsize;
-  short int e_phnum;
-  short int e_shentsize;
-  short int e_shnum;
-  short int e_shstrndx;
+  Elf64_SHalf e_type;
+  Elf64_Half e_machine;
+  __s32 e_version;
+  Elf64_Addr e_entry;		/* Entry point virtual address */
+  Elf64_Off e_phoff;		/* Program header table file offset */
+  Elf64_Off e_shoff;		/* Section header table file offset */
+  __s32 e_flags;
+  Elf64_SHalf e_ehsize;
+  Elf64_SHalf e_phentsize;
+  Elf64_SHalf e_phnum;
+  Elf64_SHalf e_shentsize;
+  Elf64_SHalf e_shnum;
+  Elf64_SHalf e_shstrndx;
 } Elf64_Ehdr;
 
 /* These constants define the permissions on sections in the program
@@ -315,14 +324,14 @@
 } Elf32_Phdr;
 
 typedef struct elf64_phdr {
-  int p_type;
-  int p_flags;
-  unsigned long long p_offset;		/* Segment file offset */
-  unsigned long long p_vaddr;		/* Segment virtual address */
-  unsigned long long p_paddr;		/* Segment physical address */
-  unsigned long long p_filesz;		/* Segment size in file */
-  unsigned long long p_memsz;		/* Segment size in memory */
-  unsigned long long p_align;		/* Segment alignment, file & memory */
+  __s32 p_type;
+  __s32 p_flags;
+  Elf64_Off p_offset;		/* Segment file offset */
+  Elf64_Addr p_vaddr;		/* Segment virtual address */
+  Elf64_Addr p_paddr;		/* Segment physical address */
+  Elf64_Word p_filesz;		/* Segment size in file */
+  Elf64_Word p_memsz;		/* Segment size in memory */
+  Elf64_Word p_align;		/* Segment alignment, file & memory */
 } Elf64_Phdr;
 
 /* sh_type */
@@ -373,16 +382,16 @@
 } Elf32_Shdr;
 
 typedef struct elf64_shdr {
-  unsigned int	sh_name;		/* Section name, index in string tbl */
-  unsigned int	sh_type;		/* Type of section */
-  unsigned long long sh_flags;		/* Miscellaneous section attributes */
-  unsigned long long sh_addr;		/* Section virtual addr at execution */
-  unsigned long long sh_offset;		/* Section file offset */
-  unsigned long long sh_size;		/* Size of section in bytes */
-  unsigned int	sh_link;		/* Index of another section */
-  unsigned int	sh_info;		/* Additional section information */
-  unsigned long long sh_addralign;	/* Section alignment */
-  unsigned long long sh_entsize;	/* Entry size if section holds table */
+  Elf32_Word sh_name;		/* Section name, index in string tbl (yes Elf32) */
+  Elf32_Word sh_type;		/* Type of section (yes Elf32) */
+  Elf64_Word sh_flags;		/* Miscellaneous section attributes */
+  Elf64_Addr sh_addr;		/* Section virtual addr at execution */
+  Elf64_Off sh_offset;		/* Section file offset */
+  Elf64_Word sh_size;		/* Size of section in bytes */
+  Elf32_Word sh_link;		/* Index of another section (yes Elf32) */
+  Elf32_Word sh_info;		/* Additional section information (yes Elf32) */
+  Elf64_Word sh_addralign;	/* Section alignment */
+  Elf64_Word sh_entsize;	/* Entry size if section holds table */
 } Elf64_Shdr;
 
 #define	EI_MAG0		0		/* e_ident[] indexes */
@@ -434,9 +443,9 @@
  * is only 32 bits.
  */
 typedef struct elf64_note {
-  unsigned int	n_namesz;	/* Name size */
-  unsigned int	n_descsz;	/* Content size */
-  unsigned int	n_type;		/* Content type */
+  Elf32_Word n_namesz;	/* Name size */
+  Elf32_Word n_descsz;	/* Content size */
+  Elf32_Word n_type;	/* Content type */
 } Elf64_Nhdr;
 
 #define ELF_START_MMAP 0x80000000
diff -u --recursive --new-file v2.1.39/linux/include/linux/keyboard.h linux/include/linux/keyboard.h
--- v2.1.39/linux/include/linux/keyboard.h	Fri Apr  4 08:52:25 1997
+++ linux/include/linux/keyboard.h	Wed May 21 09:57:45 1997
@@ -302,7 +302,7 @@
 #define K_F243		K(KT_FN,252)
 #define K_F244		K(KT_FN,253)
 #define K_F245		K(KT_FN,254)
-#define K_F246		K(KT_FN,255)
+#define K_UNDO		K(KT_FN,255)
 
 
 #define K_HOLE		K(KT_SPEC,0)
@@ -347,8 +347,10 @@
 #define K_PCOMMA	K(KT_PAD,15)	/* key-pad comma: kludge... */
 #define K_PDOT		K(KT_PAD,16)	/* key-pad dot (period): kludge... */
 #define K_PPLUSMINUS	K(KT_PAD,17)	/* key-pad plus/minus */
+#define K_PPARENL	K(KT_PAD,18)	/* key-pad left parenthesis */
+#define K_PPARENR	K(KT_PAD,19)	/* key-pad right parenthesis */
 
-#define NR_PAD		18
+#define NR_PAD		20
 
 #define K_DGRAVE	K(KT_DEAD,0)
 #define K_DACUTE	K(KT_DEAD,1)
diff -u --recursive --new-file v2.1.39/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.39/linux/include/linux/pci.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/pci.h	Mon May 19 12:49:29 1997
@@ -331,6 +331,7 @@
 
 #define PCI_VENDOR_ID_HP		0x103c
 #define PCI_DEVICE_ID_HP_J2585A		0x1030
+#define PCI_DEVICE_ID_HP_J2585B		0x1031
 
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
@@ -408,6 +409,9 @@
 #define PCI_DEVICE_ID_VISION_QD8500	0x0001
 #define PCI_DEVICE_ID_VISION_QD8580	0x0002
 
+#define PCI_VENDOR_ID_BROOKTREE		0x109e
+#define PCI_DEVICE_ID_BT848     	0x0350     /* 0x350 = 848 */
+
 #define PCI_VENDOR_ID_SIERRA		0x10a8
 #define PCI_DEVICE_ID_SIERRA_STB	0x0000
 
@@ -595,6 +599,7 @@
 #define PCI_DEVICE_ID_INTEL_82437VX	0x7030
 #define PCI_DEVICE_ID_INTEL_82371AB	0x7111
 #define PCI_DEVICE_ID_INTEL_P6		0x84c4
+#define PCI_DEVICE_ID_INTEL_P6_2	0x84c5
 
 #define PCI_VENDOR_ID_KTI		0x8e2e
 #define PCI_DEVICE_ID_KTI_ET32P2	0x3000
diff -u --recursive --new-file v2.1.39/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.39/linux/include/linux/proc_fs.h	Tue May 13 22:41:19 1997
+++ linux/include/linux/proc_fs.h	Wed May 21 16:14:44 1997
@@ -169,6 +169,7 @@
 	PROC_SCSI_PPA,
 	PROC_SCSI_ESP,
 	PROC_SCSI_QLOGICPTI,
+	PROC_SCSI_AMIGA7XX,
 	PROC_SCSI_A3000,
 	PROC_SCSI_A2091,
 	PROC_SCSI_GVP11,
diff -u --recursive --new-file v2.1.39/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.39/linux/include/linux/sched.h	Mon May 19 12:57:39 1997
+++ linux/include/linux/sched.h	Wed May 21 16:14:44 1997
@@ -9,6 +9,8 @@
 #include <linux/personality.h>
 #include <linux/tasks.h>
 #include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/times.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -223,7 +225,8 @@
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
-	long utime, stime, cutime, cstime, start_time;
+	struct tms times;
+	unsigned long start_time;
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
 	unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
 	int swappable:1;
@@ -319,7 +322,7 @@
 /* uid etc */	0,0,0,0,0,0,0,0, \
 /* timeout */	0,SCHED_OTHER,0,0,0,0,0,0,0, \
 /* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
-/* utime */	0,0,0,0,0, \
+/* utime */	{0,0,0,0},0, \
 /* flt */	0,0,0,0,0,0, \
 /* swp */	0,0,0,0,0, \
 /* rlimits */   INIT_RLIMITS, \
diff -u --recursive --new-file v2.1.39/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.39/linux/include/linux/sysctl.h	Thu May 15 16:48:05 1997
+++ linux/include/linux/sysctl.h	Sun May 18 17:10:38 1997
@@ -148,6 +148,8 @@
 	NET_IPV4_SECURE_REDIRECTS,
 	NET_IPV4_RFC1620_REDIRECTS,
 	NET_TCP_SYN_RETRIES,
+	NET_IPFRAG_HIGH_THRESH,
+	NET_IPFRAG_LOW_THRESH,
 };
 
 
diff -u --recursive --new-file v2.1.39/linux/include/linux/zorro.h linux/include/linux/zorro.h
--- v2.1.39/linux/include/linux/zorro.h	Tue May 13 22:41:19 1997
+++ linux/include/linux/zorro.h	Sun May 18 17:10:38 1997
@@ -301,9 +301,6 @@
 #define PROD_MASTER_CARD_SCSI  (0x04)	/* Master Card SCSI Controller */
 #define PROD_MVD_819           (0x07)	/* MVD 819 */
 
-#define MANUF_DELACOMP         (0x0873)	/* DelaComp */
-#define PROD_DELACOMP_RAM_2000 (0x01)	/* RAM Expansion 2000 */
-
 #define MANUF_VILLAGE_TRONIC   (0x0877)	/* Village Tronic */
 #define PROD_DOMINO_RAM        (0x01)	/* Domino Graphics Board */
 #define PROD_DOMINO_REG        (0x02)
diff -u --recursive --new-file v2.1.39/linux/init/main.c linux/init/main.c
--- v2.1.39/linux/init/main.c	Thu May 15 16:48:05 1997
+++ linux/init/main.c	Sun May 18 17:10:38 1997
@@ -193,6 +193,7 @@
 #endif
 extern void wd33c93_setup (char *str, int *ints);
 extern void gvp11_setup (char *str, int *ints);
+extern void ncr53c7xx_setup (char *str, int *ints);
 
 #ifdef CONFIG_CYCLADES
 extern void cy_setup(char *str, int *ints);
@@ -476,6 +477,9 @@
 #endif
 #ifdef CONFIG_ATARI_SCSI
 	{ "atascsi=", atari_scsi_setup },
+#endif
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+        { "53c7xx=", ncr53c7xx_setup },
 #endif
 #if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
 	    || defined(CONFIG_GVP11_SCSI)
diff -u --recursive --new-file v2.1.39/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.39/linux/kernel/exit.c	Tue May 13 22:41:20 1997
+++ linux/kernel/exit.c	Mon May 19 12:32:52 1997
@@ -625,8 +625,8 @@
 				retval = p->pid;
 				goto end_wait4;
 			case TASK_ZOMBIE:
-				current->cutime += p->utime + p->cutime;
-				current->cstime += p->stime + p->cstime;
+				current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
+				current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
 				read_unlock(&tasklist_lock);
 				if (ru != NULL)
 					getrusage(p, RUSAGE_BOTH, ru);
diff -u --recursive --new-file v2.1.39/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.39/linux/kernel/fork.c	Thu May 15 16:48:05 1997
+++ linux/kernel/fork.c	Mon May 19 12:34:30 1997
@@ -395,8 +395,8 @@
 	p->real_timer.data = (unsigned long) p;
 	p->leader = 0;		/* session leadership doesn't inherit */
 	p->tty_old_pgrp = 0;
-	p->utime = p->stime = 0;
-	p->cutime = p->cstime = 0;
+	p->times.tms_utime = p->times.tms_stime = 0;
+	p->times.tms_cutime = p->times.tms_cstime = 0;
 #ifdef __SMP__
 	p->has_cpu = 0;
 	p->processor = NO_PROC_ID;
diff -u --recursive --new-file v2.1.39/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.39/linux/kernel/ksyms.c	Thu May 15 16:48:05 1997
+++ linux/kernel/ksyms.c	Sun May 18 17:10:38 1997
@@ -52,10 +52,6 @@
 #include <linux/ctype.h>
 #include <linux/file.h>
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
-extern struct drive_info_struct drive_info;
-#endif
-
 extern unsigned char aux_device_present, kbd_read_mask;
 
 #ifdef CONFIG_PCI
@@ -217,10 +213,6 @@
 EXPORT_SYMBOL(gendisk_head);
 EXPORT_SYMBOL(resetup_one_dev);
 EXPORT_SYMBOL(unplug_device);
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
-EXPORT_SYMBOL(drive_info);
-#endif
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
diff -u --recursive --new-file v2.1.39/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.39/linux/kernel/sched.c	Tue May 13 22:41:20 1997
+++ linux/kernel/sched.c	Mon May 19 11:38:12 1997
@@ -1000,16 +1000,14 @@
 {
 	long psecs;
 
-	p->utime += user;
-	p->stime += system;
-
-	psecs = (p->stime + p->utime) / HZ;
-	if (psecs > p->rlim[RLIMIT_CPU].rlim_cur) {
+	psecs = (p->times.tms_utime += user);
+	psecs += (p->times.tms_stime += system);
+	if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_cur) {
 		/* Send SIGXCPU every second.. */
-		if (psecs * HZ == p->stime + p->utime)
+		if (!(psecs % HZ))
 			send_sig(SIGXCPU, p, 1);
 		/* and SIGKILL when we go over max.. */
-		if (psecs > p->rlim[RLIMIT_CPU].rlim_max)
+		if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_max)
 			send_sig(SIGKILL, p, 1);
 	}
 }
diff -u --recursive --new-file v2.1.39/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.39/linux/kernel/sys.c	Tue May 13 22:41:20 1997
+++ linux/kernel/sys.c	Mon May 19 12:27:22 1997
@@ -370,8 +370,8 @@
    if (acct_active) {
       strncpy(ac.ac_comm, current->comm, ACCT_COMM);
       ac.ac_comm[ACCT_COMM-1] = '\0';
-      ac.ac_utime = current->utime;
-      ac.ac_stime = current->stime;
+      ac.ac_utime = current->times.tms_utime;
+      ac.ac_stime = current->times.tms_stime;
       ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
       ac.ac_etime = CURRENT_TIME - ac.ac_btime;
       ac.ac_uid   = current->uid;
@@ -695,16 +695,9 @@
 	 *	atomically safe type this is just fine. Conceptually its
 	 *	as if the syscall took an instant longer to occur.
 	 */
-	if (tbuf) 
-	{
-		/* ?? use copy_to_user() */
-		if(!access_ok(VERIFY_READ, tbuf, sizeof(struct tms)) ||
-		   __put_user(current->utime,&tbuf->tms_utime)||
-		   __put_user(current->stime,&tbuf->tms_stime) ||
-		   __put_user(current->cutime,&tbuf->tms_cutime) ||
-		   __put_user(current->cstime,&tbuf->tms_cstime))
+	if (tbuf)
+		if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
 			return -EFAULT;
-	}
 	return jiffies;
 }
 
@@ -1030,28 +1023,28 @@
 	memset((char *) &r, 0, sizeof(r));
 	switch (who) {
 		case RUSAGE_SELF:
-			r.ru_utime.tv_sec = CT_TO_SECS(p->utime);
-			r.ru_utime.tv_usec = CT_TO_USECS(p->utime);
-			r.ru_stime.tv_sec = CT_TO_SECS(p->stime);
-			r.ru_stime.tv_usec = CT_TO_USECS(p->stime);
+			r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
+			r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
+			r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
+			r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
 			r.ru_minflt = p->min_flt;
 			r.ru_majflt = p->maj_flt;
 			r.ru_nswap = p->nswap;
 			break;
 		case RUSAGE_CHILDREN:
-			r.ru_utime.tv_sec = CT_TO_SECS(p->cutime);
-			r.ru_utime.tv_usec = CT_TO_USECS(p->cutime);
-			r.ru_stime.tv_sec = CT_TO_SECS(p->cstime);
-			r.ru_stime.tv_usec = CT_TO_USECS(p->cstime);
+			r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
+			r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
+			r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
+			r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
 			r.ru_minflt = p->cmin_flt;
 			r.ru_majflt = p->cmaj_flt;
 			r.ru_nswap = p->cnswap;
 			break;
 		default:
-			r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime);
-			r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime);
-			r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime);
-			r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime);
+			r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
+			r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
+			r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
+			r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
 			r.ru_minflt = p->min_flt + p->cmin_flt;
 			r.ru_majflt = p->maj_flt + p->cmaj_flt;
 			r.ru_nswap = p->nswap + p->cnswap;
diff -u --recursive --new-file v2.1.39/linux/mm/memory.c linux/mm/memory.c
--- v2.1.39/linux/mm/memory.c	Mon May 19 12:57:39 1997
+++ linux/mm/memory.c	Tue May 20 10:17:15 1997
@@ -833,10 +833,6 @@
 }
 
 /*
- * The above separate functions for the no-page and wp-page
- * cases will go away (they mostly do the same thing anyway),
- * and we'll instead use only a general "handle_mm_fault()".
- *
  * These routines also need to handle stuff like marking pages dirty
  * and/or accessed for architectures that don't do it in hardware (most
  * RISC architectures).  The early dirtying is also good on the i386.
diff -u --recursive --new-file v2.1.39/linux/mm/slab.c linux/mm/slab.c
--- v2.1.39/linux/mm/slab.c	Thu May 15 16:48:05 1997
+++ linux/mm/slab.c	Sun May 18 17:10:38 1997
@@ -105,10 +105,10 @@
 #include	<linux/interrupt.h>
 #include	<linux/config.h>
 #include	<linux/init.h>
+#include	<linux/smp.h>
 
 #include	<asm/system.h>
 #include	<asm/atomic.h>
-#include	<asm/smp.h>
 #include	<asm/smp_lock.h>
 #include	<asm/spinlock.h>
 
diff -u --recursive --new-file v2.1.39/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.39/linux/net/core/dev.c	Wed Apr 23 19:01:29 1997
+++ linux/net/core/dev.c	Sun May 18 16:38:35 1997
@@ -986,6 +986,9 @@
 	/*
 	 *	Loop over the interfaces, and write an info block for each. 
 	 */
+	 
+	dev_lock_wait();
+	dev_lock_list();
 
 	for (dev = dev_base; dev != NULL; dev = dev->next) 
 	{
@@ -1013,6 +1016,8 @@
 		len -= sizeof(struct ifreq);		
   	}
 
+	dev_unlock_list();
+	
 	/*
 	 *	All done.  Write the updated control block back to the caller. 
 	 */
diff -u --recursive --new-file v2.1.39/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.39/linux/net/ipv4/ip_fragment.c	Thu May 15 16:48:06 1997
+++ linux/net/ipv4/ip_fragment.c	Sun May 18 17:10:38 1997
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.21 1997/05/13 07:45:08 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.22 1997/05/17 05:21:56 freitag Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -13,6 +13,7 @@
  * Fixes:
  *		Alan Cox	:	Split from ip.c , see ip_input.c for history.
  *		David S. Miller :	Begin massive cleanup...
+ *		Andi Kleen	:	Add sysctls.
  */
 
 #include <linux/types.h>
@@ -37,8 +38,8 @@
  * even the most extreme cases without allowing an attacker to measurably
  * harm machine performance.
  */
-#define IPFRAG_HIGH_THRESH		(256*1024)
-#define IPFRAG_LOW_THRESH		(192*1024)
+int sysctl_ipfrag_high_thresh = 256*1024;
+int sysctl_ipfrag_low_thresh = 192*1024;
 
 /* Describe an IP fragment. */
 struct ipfrag {
@@ -203,7 +204,7 @@
  */
 static void ip_evictor(void)
 {
-	while(atomic_read(&ip_frag_mem)>IPFRAG_LOW_THRESH) {
+	while(atomic_read(&ip_frag_mem)>sysctl_ipfrag_low_thresh) {
 		int i;
 
 		/* FIXME: Make LRU queue of frag heads. -DaveM */
@@ -382,7 +383,7 @@
 	ip_statistics.IpReasmReqds++;
 
 	/* Start by cleaning up the memory. */
-	if(atomic_read(&ip_frag_mem)>IPFRAG_HIGH_THRESH)
+	if(atomic_read(&ip_frag_mem)>sysctl_ipfrag_high_thresh)
 		ip_evictor();
 
 	/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
diff -u --recursive --new-file v2.1.39/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.1.39/linux/net/ipv4/sysctl_net_ipv4.c	Thu May 15 16:48:06 1997
+++ linux/net/ipv4/sysctl_net_ipv4.c	Sun May 18 17:10:38 1997
@@ -35,6 +35,10 @@
 extern int sysctl_arp_confirm_interval;
 extern int sysctl_arp_confirm_timeout;
 
+/* From ip_fragment.c */
+extern int sysctl_ipfrag_low_thresh;
+extern int sysctl_ipfrag_high_thresh; 
+
 extern int sysctl_tcp_cong_avoidance;
 extern int sysctl_tcp_hoe_retransmits;
 extern int sysctl_tcp_sack;
@@ -147,6 +151,10 @@
          &proc_dointvec},
 	{NET_TCP_SYN_RETRIES, "tcp_syn_retries",
 	&sysctl_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
+	&sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
+	&sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -u --recursive --new-file v2.1.39/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.39/linux/net/ipv4/udp.c	Wed Apr 23 19:01:30 1997
+++ linux/net/ipv4/udp.c	Wed May 21 18:21:45 1997
@@ -154,7 +154,7 @@
 	return retval;
 }
 
-static inline int udp_lport_inuse(int num)
+static inline int udp_lport_inuse(u16 num)
 {
 	struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)];
 
@@ -168,36 +168,42 @@
 /* Shared by v4/v6 tcp. */
 unsigned short udp_good_socknum(void)
 {
-	static int start = 0;
-	unsigned short base;
-	int i, best = 0, size = 32767; /* a big num. */
 	int result;
-
-	base = PROT_SOCK + (start & 1023) + 1;
+	static int start = 0;
+	int i, best, best_size_so_far;
 
 	SOCKHASH_LOCK();
-	for(i = 0; i < UDP_HTABLE_SIZE; i++) {
-		struct sock *sk = udp_hash[i];
-		if(!sk) {
-			start = (i + 1 + start) & 1023;
-			result = i + base + 1;
+
+	/* Select initial not-so-random "best" */
+	best = PROT_SOCK + 1 + (start & 1023);
+	best_size_so_far = 32767;	/* "big" num */
+	result = best;
+	for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+		struct sock *sk;
+		int size;
+
+		sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+
+		/* No clashes - take it */
+		if (!sk)
 			goto out;
-		} else {
-			int j = 0;
-			do {
-				if(++j >= size)
-					goto next;
-			} while((sk = sk->next));
-			best = i;
-			size = j;
-		}
-	next:
+
+		/* Is this one better than our best so far? */
+		size = 0;
+		do {
+			if(++size >= best_size_so_far)
+				goto next;
+		} while((sk = sk->next) != NULL);
+		best_size_so_far = size;
+		best = result;
+next:
 	}
 
-	while(udp_lport_inuse(base + best + 1))
+	while (udp_lport_inuse(best))
 		best += UDP_HTABLE_SIZE;
-	result = (best + base + 1);
+	result = best;
 out:
+	start = result;
 	SOCKHASH_UNLOCK();
 	return result;
 }
