diff -u --recursive --new-file v1.3.3/linux/CREDITS linux/CREDITS
--- v1.3.3/linux/CREDITS	Sun Jun 11 21:54:36 1995
+++ linux/CREDITS	Mon Jun 26 08:53:57 1995
@@ -807,6 +807,13 @@
 S: Kanata, Ontario
 S: CANADA K2L 1S2
 
+N: Andrew Tridgell
+E: Andrew.Tridgell@anu.edu.au
+D: dosemu, networking, samba
+S: 3 Ballow Crescent
+S: MacGregor A.C.T
+S: 2615 Australia
+
 N: Theodore Ts'o
 E: tytso@mit.edu
 D: Random Linux hacker
diff -u --recursive --new-file v1.3.3/linux/Makefile linux/Makefile
--- v1.3.3/linux/Makefile	Tue Jun 20 09:10:31 1995
+++ linux/Makefile	Wed Jun 21 12:27:40 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 3
+SUBLEVEL = 4
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.3/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.3.3/linux/arch/alpha/kernel/entry.S	Fri Jun 16 22:02:54 1995
+++ linux/arch/alpha/kernel/entry.S	Mon Jun 26 11:06:50 1995
@@ -504,23 +504,23 @@
 	.quad sys_umask, do_entSys, do_entSys, sys_getpgrp, sys_getpagesize
 	.quad do_entSys, osf_vfork, sys_newstat, sys_newlstat, do_entSys
 	.quad do_entSys, osf_mmap, do_entSys, sys_munmap, sys_mprotect
-	.quad sys_madvise, do_entSys, do_entSys, do_entSys, sys_getgroups
+	.quad sys_madvise, sys_vhangup, do_entSys, do_entSys, sys_getgroups
 	/* map BSD's setpgrp to sys_setpgid for binary compatibility: */
 	.quad sys_setgroups, do_entSys, sys_setpgid, sys_setitimer, do_entSys
 	.quad do_entSys, sys_getitimer, sys_gethostname, sys_sethostname, sys_getdtablesize
 	.quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, do_entSys
-	.quad sys_fsync, sys_setpriority, sys_socket, do_entSys, do_entSys
-/*100*/	.quad do_entSys, do_entSys, do_entSys, sys_sigreturn, sys_bind
-	.quad do_entSys, sys_listen, do_entSys, do_entSys, do_entSys
+	.quad sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/	.quad sys_getpriority, sys_send, sys_recv, sys_sigreturn, sys_bind
+	.quad sys_setsockopt, sys_listen, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, sys_sigsuspend, do_entSys, do_entSys, do_entSys
-	.quad do_entSys, sys_gettimeofday, sys_getrusage, do_entSys, do_entSys
+	.quad do_entSys, sys_gettimeofday, sys_getrusage, sys_getsockopt, do_entSys
 	.quad do_entSys, do_entSys, sys_settimeofday, sys_fchown, sys_fchmod
-	.quad do_entSys, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-	.quad sys_ftruncate, do_entSys, sys_setgid, do_entSys, do_entSys
-	.quad do_entSys, sys_mkdir, sys_rmdir, sys_utimes, do_entSys
-	.quad do_entSys, do_entSys, do_entSys, do_entSys, sys_getrlimit
+	.quad sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+	.quad sys_ftruncate, do_entSys, sys_setgid, sys_sendto, sys_shutdown
+	.quad sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, do_entSys
+	.quad do_entSys, sys_getpeername, do_entSys, do_entSys, sys_getrlimit
 	.quad sys_setrlimit, do_entSys, sys_setsid, do_entSys, do_entSys
-/*150*/	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+/*150*/	.quad sys_getsockname, do_entSys, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries
 	.quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys
 	.quad osf_getdomainname, do_entSys, do_entSys, do_entSys, do_entSys
@@ -538,7 +538,7 @@
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
-	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+	.quad do_entSys, do_entSys, do_entSys, do_entSys, osf_proplist_syscall
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 /*250*/	.quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
@@ -552,4 +552,4 @@
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 /* linux-specific system calls start at 300 */
 /*300*/	.quad sys_bdflush, sys_sethae, sys_mount, sys_adjtimex, sys_swapoff
-	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+	.quad sys_getdents, sys_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms
diff -u --recursive --new-file v1.3.3/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v1.3.3/linux/arch/alpha/kernel/osf_sys.c	Fri Jun 16 22:02:54 1995
+++ linux/arch/alpha/kernel/osf_sys.c	Mon Jun 26 11:06:50 1995
@@ -68,7 +68,7 @@
 	int error;
 };
 
-static int osf_filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+static int osf_filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
 {
 	struct osf_dirent * dirent;
 	struct osf_dirent_callback * buf = (struct osf_dirent_callback *) __buf;
@@ -508,4 +508,125 @@
 	 * non-negative longs!
 	 */
 	return raddr;
+}
+
+
+/*
+ * The following stuff should move into a header file should it ever
+ * be labeled "officially supported."  Right now, there is just enough
+ * support to avoid applications (such as tar) printing error
+ * messages.  The attributes are not really implemented.
+ */
+
+/*
+ * Values for Property list entry flag
+ */
+#define PLE_PROPAGATE_ON_COPY		0x1	/* cp(1) will copy entry
+						   by default */
+#define PLE_FLAG_MASK			0x1	/* Valid flag values */
+#define PLE_FLAG_ALL			-1	/* All flag value */
+
+struct proplistname_args {
+	unsigned int	pl_mask;
+	unsigned int	pl_numnames;
+	char		**pl_names;
+};
+
+union pl_args {
+	struct setargs {
+		char *path;
+		long follow;
+		long nbytes;
+		char *buf;
+	} set;
+	struct fsetargs {
+		long fd;
+		long nbytes;
+		char *buf;
+	} fset;
+	struct getargs {
+		char *path;
+		long follow;
+		struct proplistname_args *name_args;
+		long nbytes;
+		char *buf;
+		int *min_buf_size;
+	} get;
+	struct fgetargs {
+		long fd;
+		struct proplistname_args *name_args;
+		long nbytes;
+		char *buf;
+		int *min_buf_size;
+	} fget;
+	struct delargs {
+		char *path;
+		long follow;
+		struct proplistname_args *name_args;
+	} del;
+	struct fdelargs {
+		long fd;
+		struct proplistname_args *name_args;
+	} fdel;
+};
+
+enum pl_code {
+	PL_SET	= 1,	PL_FSET	= 2,
+	PL_GET	= 3,	PL_FGET	= 4,
+	PL_DEL	= 5,	PL_FDEL	= 6
+};
+
+asmlinkage long osf_proplist_syscall (enum pl_code code, union pl_args *args)
+{
+	long error;
+	int *min_buf_size_ptr;
+
+	switch (code) {
+	      case PL_SET:
+		error = verify_area(VERIFY_READ, &args->set.nbytes,
+				    sizeof(args->set.nbytes));
+		if (error)
+		  return error;
+		return args->set.nbytes;
+
+	      case PL_FSET:
+		error = verify_area(VERIFY_READ, &args->fset.nbytes,
+				    sizeof(args->fset.nbytes));
+		if (error)
+		  return error;
+		return args->fset.nbytes;
+
+	      case PL_GET:
+		error = verify_area(VERIFY_READ, &args->get.min_buf_size,
+				    sizeof(args->get.min_buf_size));
+		if (error)
+		  return error;
+		min_buf_size_ptr = get_user(&args->get.min_buf_size);
+		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
+				    sizeof(*min_buf_size_ptr));
+		if (error)
+		  return error;
+		put_user(0, min_buf_size_ptr);
+		return 0;
+
+	      case PL_FGET:
+		error = verify_area(VERIFY_READ, &args->fget.min_buf_size,
+				    sizeof(args->fget.min_buf_size));
+		if (error)
+		  return error;
+		min_buf_size_ptr = get_user(&args->fget.min_buf_size);
+		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
+				    sizeof(*min_buf_size_ptr));
+		if (error)
+		  return error;
+		put_user(0, min_buf_size_ptr);
+		return 0;
+
+	      case PL_DEL:
+	      case PL_FDEL:
+		return 0;
+
+	      default:
+		return -EOPNOTSUPP;
+	}
 }
diff -u --recursive --new-file v1.3.3/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v1.3.3/linux/arch/alpha/kernel/setup.c	Fri Jun 16 22:02:54 1995
+++ linux/arch/alpha/kernel/setup.c	Mon Jun 26 11:06:50 1995
@@ -35,7 +35,7 @@
 
 struct hwrpb_struct *hwrpb;
 
-unsigned char aux_device_present;
+unsigned char aux_device_present = 0xaa;
 
 /*
  * This is setup by the secondary bootstrap loader.  Because
@@ -52,7 +52,7 @@
 /*
  * The format of "screen_info" is strange, and due to early
  * i386-setup code. This is just enough to make the console
- * code think we're on a EGA+ colour display.
+ * code think we're on a VGA color display.
  */
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
@@ -62,6 +62,7 @@
 	80,			/* orig-video-cols */
 	0,0,0,			/* ega_ax, ega_bx, ega_cx */
 	25,			/* orig-video-lines */
+	1,			/* orig-video-isVGA */
 	16			/* orig-video-points */
 };
 
@@ -95,7 +96,6 @@
 	set_hae(hae.cache);		/* sync HAE register w/hae_cache */
 
 	ROOT_DEV = 0x0802;		/* sda2 */
-	aux_device_present = 0xaa;
 	command_line[COMMAND_LINE_SIZE - 1] = '\0';
 	strcpy(command_line, COMMAND_LINE);
 
diff -u --recursive --new-file v1.3.3/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.3/linux/arch/i386/config.in	Mon Jun 12 19:52:46 1995
+++ linux/arch/i386/config.in	Mon Jun 26 12:42:51 1995
@@ -92,7 +92,9 @@
 bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
 bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
 bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
+if [ "$CONFIG_PCI" = "y" ]; then
+  bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
+fi
 bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
 bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
 bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
@@ -163,7 +165,7 @@
 	bool 'EtherWorks 3 support' CONFIG_EWRK3 n
 	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
 		bool 'AT1700 support' CONFIG_AT1700 n
-#		bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
+		bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
 		bool 'EtherExpress support' CONFIG_EEXPRESS n
 		bool 'NI5210 support' CONFIG_NI52 n
 		bool 'NI6510 support' CONFIG_NI65 n
@@ -230,8 +232,7 @@
 bool 'xiafs filesystem support' CONFIG_XIA_FS n
 bool 'msdos fs support' CONFIG_MSDOS_FS y
 if [ "$CONFIG_MSDOS_FS" = "y" ]; then
-#bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
-comment 'Umsdos is not supported in 1.3.0: wait for 1.3.1'
+bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
 fi
 bool '/proc filesystem support' CONFIG_PROC_FS y
 if [ "$CONFIG_INET" = "y" ]; then
diff -u --recursive --new-file v1.3.3/linux/arch/i386/ibcs/binfmt_elf.c linux/arch/i386/ibcs/binfmt_elf.c
--- v1.3.3/linux/arch/i386/ibcs/binfmt_elf.c	Sun Jan 22 14:38:19 1995
+++ linux/arch/i386/ibcs/binfmt_elf.c	Thu Jun 22 10:34:40 1995
@@ -482,7 +482,7 @@
 					elf_ppnt->p_offset & 0xfffff000);
 			
 #ifdef LOW_ELF_STACK
-			if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack) 
+			if((elf_ppnt->p_vaddr & 0xfffff000) < elf_stack) 
 				elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
 #endif
 			
@@ -635,7 +635,7 @@
 	if(k > elf_bss) elf_bss = k;
 	
 	sys_close(fd);
-	if (error != elf_phdata->p_vaddr & 0xfffff000) {
+	if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
 	        kfree(elf_phdata);
 		return error;
 	}
diff -u --recursive --new-file v1.3.3/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v1.3.3/linux/arch/i386/kernel/entry.S	Sun Jun 11 19:03:28 1995
+++ linux/arch/i386/kernel/entry.S	Mon Jun 26 11:11:29 1995
@@ -490,7 +490,7 @@
 	.long _sys_swapon
 	.long _sys_reboot
 	.long _old_readdir
-	.long _sys_mmap			/* 90 */
+	.long _old_mmap			/* 90 */
 	.long _sys_munmap
 	.long _sys_truncate
 	.long _sys_ftruncate
@@ -544,4 +544,4 @@
 	.long _sys_getdents
 	.long _sys_select
 	.long _sys_flock
-	.space (NR_syscalls-140)*4
+	.space (NR_syscalls-143)*4
diff -u --recursive --new-file v1.3.3/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v1.3.3/linux/arch/i386/kernel/head.S	Tue Jun  6 14:51:20 1995
+++ linux/arch/i386/kernel/head.S	Tue Jun 20 08:24:03 1995
@@ -14,7 +14,6 @@
 .globl _empty_bad_page
 .globl _empty_bad_page_table
 .globl _empty_zero_page
-.globl _floppy_track_buffer
 
 #define __ASSEMBLY__
 #include <linux/tasks.h>
@@ -288,15 +287,7 @@
 _empty_zero_page:
 
 .org 0x6000
-/*
- * floppy_track_buffer is used to buffer one track of floppy data: it
- * has to be separate from the tmp_floppy area, as otherwise a single-
- * sector read/write can mess it up. It can contain one full cylinder (sic) of
- * data (36*2*512 bytes).
- */
-_floppy_track_buffer:
-	.fill 512*2*MAX_BUFFER_SECTORS,1,0
-	
+
 stack_start:
 	.long _init_user_stack+4096
 	.long KERNEL_DS
diff -u --recursive --new-file v1.3.3/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v1.3.3/linux/arch/i386/kernel/process.c	Fri Jun  2 14:34:28 1995
+++ linux/arch/i386/kernel/process.c	Wed Jun 21 11:37:42 1995
@@ -39,22 +39,6 @@
 	hlt_counter--;
 }
 
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
-	int fd[2];
-	int error;
-
-	error = verify_area(VERIFY_WRITE,fildes,8);
-	if (error)
-		return error;
-	error = do_pipe(fd);
-	if (error)
-		return error;
-	put_fs_long(fd[0],0+fildes);
-	put_fs_long(fd[1],1+fildes);
-	return 0;
-}
-
 /*
  * The idle loop on a i386..
  */
diff -u --recursive --new-file v1.3.3/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c
--- v1.3.3/linux/arch/i386/kernel/sys_i386.c	Fri Jun 16 22:02:54 1995
+++ linux/arch/i386/kernel/sys_i386.c	Mon Jun 26 12:06:14 1995
@@ -14,15 +14,56 @@
 #include <linux/msg.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
+#include <linux/mman.h>
 
 #include <asm/segment.h>
 
 /*
- * Perform the select(nd, in, out, ex, tv) system call.
- * Linux/i386 didn't use to be able to handle 5 system call
- * parameters, so the old select used a memory block for
- * parameter passing..
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix tranditionally does this, though.
  */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+	int fd[2];
+	int error;
+
+	error = verify_area(VERIFY_WRITE,fildes,8);
+	if (error)
+		return error;
+	error = do_pipe(fd);
+	if (error)
+		return error;
+	put_fs_long(fd[0],0+fildes);
+	put_fs_long(fd[1],1+fildes);
+	return 0;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+asmlinkage int old_mmap(unsigned long *buffer)
+{
+	int error;
+	unsigned long flags;
+	struct file * file = NULL;
+
+	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
+	if (error)
+		return error;
+	flags = get_user(buffer+3);
+	if (!(flags & MAP_ANONYMOUS)) {
+		unsigned long fd = get_user(buffer+4);
+		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+			return -EBADF;
+	}
+	return do_mmap(file, get_user(buffer), get_user(buffer+1),
+		       get_user(buffer+2), flags, get_user(buffer+5));
+}
+
+
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 
 asmlinkage int old_select(unsigned long *buffer)
diff -u --recursive --new-file v1.3.3/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
--- v1.3.3/linux/arch/mips/kernel/traps.c	Wed Jan 25 08:54:22 1995
+++ linux/arch/mips/kernel/traps.c	Thu Jun 22 10:35:00 1995
@@ -82,7 +82,7 @@
 	unsigned long *stack, addr, module_start, module_end;
 	extern char start_kernel, etext;
 
-	if (regs->cp0_status & (ST0_ERL|ST0_EXL) == 0)
+	if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
 		return;
 
 	sp = (unsigned long *)regs->reg29;
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v1.3.3/linux/arch/sparc/Makefile	Sun Jan 22 23:02:20 1995
+++ linux/arch/sparc/Makefile	Wed Jun  7 13:02:30 1995
@@ -19,15 +19,25 @@
 # I ignore it and eliminate those mappings during vm initialization and
 # just leave the low mapping.
 #
-LINKFLAGS = -N -Ttext 0x00004000
+LINKFLAGS = -N -Ttext 0xf0004000
 CFLAGS := $(CFLAGS) -pipe
 
 HEAD := arch/sparc/kernel/head.o
 
-SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm
+SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \
+	arch/sparc/prom
+
 ARCHIVES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(ARCHIVES)
-LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/lib/lib.a
+
+aoutimage: vmlinux
+	elftoaout -o aoutimage vmlinux
+
+
+LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/lib/lib.a \
+	$(TOPDIR)/arch/sparc/prom/promlib.a
+
 
 archclean:
+	rm -f $(TOPDIR)/arch/sparc/boot/boot
 
 archdep:
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile
--- v1.3.3/linux/arch/sparc/boot/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/boot/Makefile	Sun May 14 06:13:04 1995
@@ -0,0 +1,35 @@
+# Makefile for the Sparc low level /boot module.
+#
+# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+
+OBJS	=bare.o init_me.o ../kernel/promops.o ../lib/lib.a
+BOOTLINKFLAGS = -N -Ttext 0x200000 -e _first_adr_in_text
+
+.c.s:
+	$(CC) $(CFLAGS) -S -o $*.s $<
+.s.o:
+	$(AS) -o $*.o $<
+.c.o:
+	$(CC) $(CFLAGS) -c -o $*.o $<
+.S.s:
+	$(CC) -D__ASSEMBLY__ -D__KERNEL__ -ansi -E -o $*.o $<
+.S.o:
+	$(CC) -D__ASSEMBLY__ -D__KERNEL__ -ansi -c -o $*.o $<
+
+all: boot
+
+boot: $(OBJS)
+	$(LD) $(BOOTLINKFLAGS) $(OBJS) -o boot
+
+dep:
+	$(CPP) -M *.c > .depend
+	$(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/boot/README linux/arch/sparc/boot/README
--- v1.3.3/linux/arch/sparc/boot/README	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/boot/README	Sat May 13 03:01:11 1995
@@ -0,0 +1,21 @@
+This directory will contain the code necessary to compile and link the
+/boot program which is necessary to boot on the Sparc.  This program
+is real ugly and it knows too much.  It must be able to not only boot
+off of the root partition but also be able to netboot.  This means
+that it knows about RPC and NFS (bleech, yuck, eeewwwww!!) so that it
+can remote mount the root directory to fetch the kernel.  Also it must
+be able to ARP for it's IP address and who it's boot server is.  I
+think I'm getting sick.
+
+Regardless for now I will concentrate on the low-level stuff necessary
+to get the thing going.  This means the low-level entry code, etc.
+The prom knows how to get "us" if we have the proper boot blocks,
+actually the boot blocks live in our logical partition on a hard drive
+whereas over NFS this isn't applicable.  We have the boot blocks in
+our data area either way because we can be dual purpose.
+
+More will come....
+
+Hopefully I can write this such that it will work on almost all SUN
+machines in existance.  We'll see ;(
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/boot/bare.S linux/arch/sparc/boot/bare.S
--- v1.3.3/linux/arch/sparc/boot/bare.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/boot/bare.S	Sat May 13 07:09:29 1995
@@ -0,0 +1,158 @@
+/* base.S:      Ugly low-level boot program entry code.  The job of this
+ *              module is to parse the boot flags, try to mount the remote
+ *              root filesystem and load the kernel into virtual memory.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include "bare.h"
+
+	.data
+	.globl C_LABEL(romvec)
+	.globl C_LABEL(idp_ptr)
+
+C_LABEL(romvec):
+	.word 0
+C_LABEL(idp_ptr):
+	.word 0
+
+	.text
+	.align 8
+	.globl C_LABEL(first_adr_in_text)
+
+C_LABEL(first_adr_in_text):
+
+	/* Grrr, boot block, scratching my head... */
+	.globl C_LABEL(b_block)       /* Start of actual boot block */
+	.globl C_LABEL(b_block_size)  /* In bytes */
+	.globl C_LABEL(b_block_cksum) /* Checksum of boot block bytes */
+
+	b	start_of_execution    /* XXX Hack */
+	nop
+
+	.align	8
+C_LABEL(b_block):	
+	.skip	(BOOTBLOCK_NENTRIES * BOOTBLOCK_ENTSIZE)
+
+C_LABEL(b_block_size):
+	.word	0
+
+C_LABEL(b_block_cksum):
+	.word	0
+
+/* Ok, the prom has left in %o0 the PROM pointer.  We leave it here
+ * for when we jump into the kernel.  So save out of this window before
+ * you dick with %o0.  As far as I know we could be loaded *anywhere*, so
+ * we relocate ourselves to the "linked" location.  Self modifying code rules.
+ */
+
+start_of_execution:
+	sethi	%hi(C_LABEL(first_adr_in_text)), %o1		! This is our top
+	or	%o1, %lo(C_LABEL(first_adr_in_text)), %o1	! of stack too.
+	sub	%o1, C_STACK, %o1
+	add	%o1, 0x7, %o1
+	andn	%o1, 0x7, %o1
+	save	%o1, 0x0, %sp					! save is an add
+here:
+	call	there
+	sethi	%hi(here), %o4
+there:	
+	sub	%o7, here-C_LABEL(first_adr_in_text), %o5
+	or	%o4, %lo(here), %o4
+	cmp	%o4, %o7
+	be	loaded_ok
+	nop
+
+	/* Gotta relocate, compute our size sans bss segment. */
+	set	C_LABEL(edata)+4, %o3
+	set	C_LABEL(first_adr_in_text), %o2
+	sub	%o3, %o2, %o3
+rel_loop:
+	ld	[%o5], %o4
+	add	%o5, 0x4, %o5
+	st	%o4, [%o2]
+	subcc	%o3, 0x4, %o3
+	bg	rel_loop
+	add	%o2, 0x4, %o2
+
+	/* Pray that we are now in a sane place in memory */
+	sethi	%hi(loaded_ok), %o2
+	or	%o2, %lo(loaded_ok), %o2
+	jmp	%o2
+	nop
+
+loaded_ok:
+	/* Save the PROM pointer */
+	sethi	%hi(C_LABEL(romvec)), %o1
+	or	%o1, %lo(C_LABEL(romvec)), %o1
+	st	%i0, [%o1]
+
+	/* Build a PSR we can live with */
+	rd	%psr, %o1
+
+#if 0
+	andn	%o1, PSR_PIL, %o1
+	sethi	%hi(SANE_PSR), %g4
+	or	%g4, %lo(SANE_PSR), %g4
+	or	%o1, %g4, %o1
+#endif
+
+	/* V8 book says this works to calculate num_windows */
+	sethi	%hi(0xffffffff), %g2
+	rd	%wim, %g3
+	or	%g2, %lo(0xffffffff), %g2
+	wr	%g2, 0x0, %wim
+	WRITE_PAUSE
+
+	rd	%wim, %g4
+	WRITE_PAUSE
+
+	wr	%g3, 0x0, %wim
+	WRITE_PAUSE
+
+	/* Restore old %psr */
+	wr	%o1, 0x0, %psr
+	WRITE_PAUSE
+
+	or	%g0, 0x0, %g3
+1:
+	srl	%g4, 0x1, %g4
+	subcc	%g4, 0x0, %g0
+	bne	1b
+	add	%g3, 0x1, %g3
+	
+	/* %g3 now contains nwindows */
+	sethi	%hi(C_LABEL(nwindows)), %o4
+	st	%g3, [%o4 + %lo(C_LABEL(nwindows))]
+
+	/* Now zero out our bss segment, lord knows the nasty prom monster
+	 * didn't do it for us.
+	 */
+	sethi	%hi(C_LABEL(end)), %g1
+	or	%g1, %lo(C_LABEL(end)), %g1
+	add	%g1, 0x4, %g1
+	sethi	%hi(C_LABEL(edata)), %g2
+	or	%g2, %lo(C_LABEL(edata)), %g2
+
+	/* Slow, inefficient, who cares, this is messy boot code */
+bzero_bss_loop:
+	st	%g0, [%g2]
+	add	%g2, 0x4, %g2
+	cmp	%g2, %g1
+	bl	bzero_bss_loop
+	nop
+
+	call	C_LABEL(init_me)	! Fun with imperical constants and prom
+	nop
+
+	/* Dump back into the prom */
+get_me_out_of_here:
+	set	C_LABEL(romvec), %g2
+	ld	[%g2], %g2
+	ld	[%g2 + 0x74], %g2
+	restore
+	call	%g2
+	nop
+
+
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/boot/bare.h linux/arch/sparc/boot/bare.h
--- v1.3.3/linux/arch/sparc/boot/bare.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/boot/bare.h	Sat May 13 07:09:46 1995
@@ -0,0 +1,17 @@
+/* bare.h:  Defines for the low level entry code of the BOOT program.
+ *          We include in the head.h stuff that the real kernel uses
+ *          and this saves a lot of repetition here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/cprefix.h>
+
+#define     SANE_PIL  (0xd00)    /* No interrupts except clock and unmaskable NMI's */
+#define     SANE_PSR  (SANE_PIL|PSR_S|PSR_ET)
+
+#define     BOOTBLOCK_NENTRIES   0x40      /* Number of entries in the boot block */
+#define     BOOTBLOCK_ENTSIZE    0x04      /* Size in bytes of each boot block entry */
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/boot/imperical.h linux/arch/sparc/boot/imperical.h
--- v1.3.3/linux/arch/sparc/boot/imperical.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/boot/imperical.h	Sat May 13 07:09:38 1995
@@ -0,0 +1,7 @@
+/* imperical.h:  Nasty hacks....
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#define DEF_BOGO     25
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/boot/init_me.c linux/arch/sparc/boot/init_me.c
--- v1.3.3/linux/arch/sparc/boot/init_me.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/boot/init_me.c	Thu Jun  8 23:49:39 1995
@@ -0,0 +1,68 @@
+/* init_me.c:  Initialize imperical constants and gather some info from
+ *             the boot prom.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>  /* For property declarations and the prom structs */
+#include <asm/oplib.h>
+#include <asm/vac-ops.h>
+
+#include "imperical.h"   /* Don't ask... */
+
+#define DEBUG_INIT_ME    /* Tell me whats goin on */
+
+unsigned int nwindows;   /* Set in bare.S */
+unsigned int nwindowsm1;
+unsigned int pac_or_vac; /* 0 means "dunno" 1 means "VAC" 2 means "PAC" */
+unsigned int pvac_size;  /* Use the same two variables for a PAC and VAC */
+unsigned int pvac_linesize;
+unsigned int pac_size;
+int num_segmaps;
+int num_contexts;
+unsigned int BOGOMIPS;        /* bogosity without the VAC cache on */
+unsigned int BOGOMIPS_WCACHE; /* bogosity with the VAC cache */
+unsigned int delay_factor;
+
+extern int prom_node_root;
+void (*printk)(const char *str, ...);
+
+void init_me(void)
+{
+	unsigned int grrr;
+
+	printk = romvec->pv_printf;
+	prom_node_root = prom_nextnode(0);
+	prom_getprop(prom_node_root, "mmu-npmg", &num_segmaps,
+		     sizeof(unsigned int));
+
+	pvac_size = prom_getint_default(prom_node_root, "vac-size", 65536);
+
+	pvac_linesize = prom_getint_default(prom_node_root, "vac-linesize", 16);
+	
+	grrr = prom_getint_default(prom_node_root, "mips-on", 0);
+	if(!grrr) {
+		grrr = prom_getint_default(prom_node_root, "clock-frequency", 0);
+		if(grrr > 15000000 && grrr < 100000000) {
+			BOGOMIPS = 3;
+			BOGOMIPS_WCACHE = grrr / 1000000;
+		} else {
+			BOGOMIPS = DEF_BOGO;
+			BOGOMIPS_WCACHE = DEF_BOGO;
+		}
+	} else (BOGOMIPS_WCACHE = grrr, 
+		BOGOMIPS = prom_getint(prom_node_root, "mips-off"));
+
+#ifdef DEBUG_INIT_ME
+	(*(romvec->pv_printf))("\nBOGOMIPS        %d\n", (int) BOGOMIPS);
+	(*(romvec->pv_printf))("BOGOMIPS_WCACHE %d\n", (int) BOGOMIPS_WCACHE);
+	(*(romvec->pv_printf))("pvac_size        %d\n", (int) pvac_size);
+	(*(romvec->pv_printf))("pvac_linesize    %d\n", (int) pvac_linesize);
+	(*(romvec->pv_printf))("num_segmaps     %d\n", (int) num_segmaps);
+#endif
+
+	delay_factor = (BOGOMIPS > 3) ? ((BOGOMIPS - 2) >> 1) : 11;
+
+	(*(romvec->pv_printf))("\nLILO: \n");
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v1.3.3/linux/arch/sparc/config.in	Fri Apr 28 11:17:56 1995
+++ linux/arch/sparc/config.in	Mon Jun 12 03:58:31 1995
@@ -9,12 +9,12 @@
 # see the Configure script.
 #
 
+echo "#define CONFIG_SPARCDEVS 1" >> $CONFIG_H
+echo "CONFIG_SPARCDEVS=y" >> $CONFIG
+
 comment 'Sparc Kernel setup'
 
-bool 'Sparc V8 kernel' CONFIG_SPARC_V8 y
-bool 'Sparc SMP support' CONFIG_LINUX_SMP n
-bool 'Sparc SUN4M support' CONFIG_SUN4M n
-bool 'Sparc Reference MMU' CONFIG_SRMMU n
+bool 'Sun floppy controller support' CONFIG_BLK_DEV_SUNFD n
 bool 'Networking support' CONFIG_NET n
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'System V IPC' CONFIG_SYSVIPC y
@@ -57,26 +57,8 @@
 
 comment 'SCSI low-level drivers'
 
-bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
-bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
-bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
-bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
-bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
-if [ "$CONFIG_PCI" = "y" ]; then
-  bool 'NCR53c7,8xx SCSI support'  CONFIG_SCSI_NCR53C7xx n
-fi
-bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n
-bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
-bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
-bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
-bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
-bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
-bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
-bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
-#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
+bool 'Sun ESP Scsi support' CONFIG_SCSI_SUN_ESP n
+
 fi
 
 
@@ -100,143 +82,42 @@
 bool 'PPP (point-to-point) support' CONFIG_PPP n
 bool 'PLIP (parallel port) support' CONFIG_PLIP n
 bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
-bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
-bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
-if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
-	bool 'WD80*3 support' CONFIG_WD80x3 n
-	bool 'SMC Ultra support' CONFIG_ULTRA n
-fi
-bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
-bool '3COM cards' CONFIG_NET_VENDOR_3COM y
-if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
-	bool '3c501 support' CONFIG_EL1 n
-	bool '3c503 support' CONFIG_EL2 n
-	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-		bool '3c505 support' CONFIG_ELPLUS n
-		bool '3c507 support' CONFIG_EL16 n
-	fi
-	bool '3c509/3c579 support' CONFIG_EL3 y
-fi
-bool 'Other ISA cards' CONFIG_NET_ISA n
-if [ "$CONFIG_NET_ISA" = "y" ]; then
-	bool 'Cabletron E21xx support' CONFIG_E2100 n
-	bool 'DEPCA support' CONFIG_DEPCA n
-	bool 'EtherWorks 3 support' CONFIG_EWRK3 n
-	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-#		bool 'Arcnet support' CONFIG_ARCNET n
-		bool 'AT1700 support' CONFIG_AT1700 n
-#		bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
-		bool 'EtherExpress support' CONFIG_EEXPRESS n
-		bool 'NI5210 support' CONFIG_NI52 n
-		bool 'NI6510 support' CONFIG_NI65 n
-	fi
-	bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
-	bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
-	bool 'NE2000/NE1000 support' CONFIG_NE2000 y
-	bool 'SK_G16 support' CONFIG_SK_G16 n
-fi
-bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
-if [ "$CONFIG_NET_EISA" = "y" ]; then
-	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-		bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
-	fi
-	bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
-#	bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
-#	bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
-#	bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
-	bool 'Zenith Z-Note support' CONFIG_ZNET y
-fi
-bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
-if [ "$CONFIG_NET_POCKET" = "y" ]; then
-	bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
-	bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
-	bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
-#	bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
-#	bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
-#	bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
-fi
-fi
-fi
-
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
-bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
-bool 'Mitsumi (not IDE/ATAPI) CDROM driver support' CONFIG_MCD n
-bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
-if [ "$CONFIG_SBPCD" = "y" ]; then
-  bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
-  if [ "$CONFIG_SBPCD2" = "y" ]; then
-    bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
-    if [ "$CONFIG_SBPCD3" = "y" ]; then
-      bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
-    fi
-  fi
+bool 'Sun LANCE Ethernet support' CONFIG_SUN_LANCE n
+bool 'Sun Intel Ethernet support' CONFIG_SUN_INTEL n
+fi
 fi
-bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n
 
 comment 'Filesystems'
 
-bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
-bool 'Extended fs support' CONFIG_EXT_FS y
+bool 'Standard (minix) fs support' CONFIG_MINIX_FS n
+bool 'Extended fs support' CONFIG_EXT_FS n
 bool 'Second extended fs support' CONFIG_EXT2_FS y
-bool 'xiafs filesystem support' CONFIG_XIA_FS y
-bool 'msdos fs support' CONFIG_MSDOS_FS y
-if [ "$CONFIG_MSDOS_FS" = "y" ]; then
-bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
-fi
+bool 'xiafs filesystem support' CONFIG_XIA_FS n
+bool 'msdos fs support' CONFIG_MSDOS_FS n
 bool '/proc filesystem support' CONFIG_PROC_FS n
 if [ "$CONFIG_INET" = "y" ]; then
 bool 'NFS filesystem support' CONFIG_NFS_FS n
 fi
 if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
-	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
+	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
 else
 	bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
 fi
 bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
-bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS y
+bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
 
 
 comment 'character devices'
 
-bool 'Cyclades async mux support' CONFIG_CYCLADES n
-bool 'Parallel printer support' CONFIG_PRINTER n
-bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
-bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
-if [ "$CONFIG_PSMOUSE" = "y" ]; then
-bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
-fi
-bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
-bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
-
-
-bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
-if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
-bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF y
-if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
-
-comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!'
-
-else
-
-comment '>>> Setting runtime QIC-02 configuration is done with qic02conf'
-comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/'
-
-fi
-fi
-
-bool 'QIC-117 tape support' CONFIG_FTAPE n
-if [ "$CONFIG_FTAPE" = "y" ]; then
-int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
-fi
+bool 'Zilog serial support' CONFIG_SUN_ZS n
 
 comment 'Sound'
 
-bool 'Sound card support' CONFIG_SOUND n
+bool 'Sun Audio support' CONFIG_SUN_AUDIO n
 
 comment 'Kernel hacking'
 
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
+bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
 bool 'Kernel profiling support' CONFIG_PROFILE n
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v1.3.3/linux/arch/sparc/kernel/Makefile	Sun Jan 22 23:02:31 1995
+++ linux/arch/sparc/kernel/Makefile	Tue Jun 13 05:24:46 1995
@@ -18,15 +18,15 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-OBJS  = entry.o traps.o irq.o process.o promops.o signal.o ioport.o setup.o \
-	idprom.o probe.o
+OBJS  = entry.o traps.o irq.o process.o signal.o ioport.o setup.o \
+	idprom.o probe.o mp.o c_mp.o
 
 all: kernel.o head.o
 
 head.o: head.s
 
-head.s: head.S $(TOPDIR)/include/asm-sparc/head.h
-	$(CPP) -D__ASSEMBLY__ -ansi -o $*.s $<
+head.s: head.S
+	$(CPP) -D__KERNEL__ -D__ASSEMBLY__ -ansi -o $*.s $<
 
 kernel.o: $(OBJS)
 	$(LD) -r -o kernel.o $(OBJS)
@@ -34,6 +34,7 @@
 
 dep:
 	$(CPP) -M *.c > .depend
+	$(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend
 
 dummy:
 
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/V9head.S linux/arch/sparc/kernel/V9head.S
--- v1.3.3/linux/arch/sparc/kernel/V9head.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/V9head.S	Fri Jun 16 09:50:48 1995
@@ -0,0 +1,16 @@
+/* V9head.S: Initial boot code for the V9 Sparc under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ */
+
+#include <asm/cprefix.h>
+
+	.text
+
+	.globl	start
+	.globl	_start
+	.globl	C_LABEL(trapbase)
+_start:
+start:
+C_LABEL(trapbase):
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/c_mp.c linux/arch/sparc/kernel/c_mp.c
--- v1.3.3/linux/arch/sparc/kernel/c_mp.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/c_mp.c	Tue Jun 13 10:41:52 1995
@@ -0,0 +1,47 @@
+/* mp.c:  SMP cpu idling and dispatch on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller
+ */
+
+#include <asm/mp.h>
+#include <asm/mbus.h>
+
+struct sparc_percpu *percpu_table;
+
+void
+sparc_cpu_init(void)
+{
+	/* We now have our per-cpu mappings ok, and we should
+	 * be good to go.
+	 */
+
+	/* Do cache crap here. */
+
+	/* CPU initted, idle the puppy. */
+
+	return;
+}
+
+extern thiscpus_mid;
+
+void
+sparc_cpu_idle(void)
+{
+	int cpuid;
+
+/*	cpuid = get_cpuid(); */
+	cpuid = (thiscpus_mid&(~8));
+/*	printk("SMP: cpu%d has entered idle loop", cpuid); */
+
+	/* Say that we exist and set up. */
+	percpu_table[cpuid].cpuid = cpuid;
+	percpu_table[cpuid].cpu_is_alive = 0x1;
+	percpu_table[cpuid].cpu_is_idling = 0x1;
+
+	/* Let other cpus catch up. */
+	while(linux_smp_still_initting) ;
+	printk("cpu%d done spinning\n", get_cpuid());
+	for(;;) ;  /* Do something useful here... */
+
+	return;
+}	
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v1.3.3/linux/arch/sparc/kernel/entry.S	Mon Feb 20 08:59:51 1995
+++ linux/arch/sparc/kernel/entry.S	Sat Jun 17 11:36:33 1995
@@ -5,18 +5,52 @@
  * the trap table and how it works, this will show you how we get
  * to these routines.
  *
- * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+
 #include <asm/head.h>
 #include <asm/asi.h>
+#include <asm/contregs.h>
 #include <asm/psr.h>
 #include <asm/cprefix.h>
 #include <asm/vaddrs.h>
+#include <asm/memreg.h>
+#include <asm/page.h>
+
+#define NR_SYSCALLS 255      /* Each OS is different... */
+
+/* A debugging macro, it just prints a dot on the screen.  For now
+ * it is only used in the context switch code since it is so delicate
+ * I need to use the prom putchar() routines and reload the pointers
+ * every time.  This clobbers %l7 and %o0.
+ */
+#define DO_SPARC_DOT \
+	sethi	%hi(C_LABEL(romvec)), %l7; \
+	ld	[%l7 + %lo(C_LABEL(romvec))], %l7; \
+	ld	[%l7 + 0x54], %l7; \
+	or	%g0, '.', %o0; \
+	call	%l7; \
+	nop; \
+	nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \
+
+/* Another macro, the name speaks for itself. */
+#define DROP_THE_BOMB \
+	sethi	%hi(C_LABEL(romvec)), %l7;  \
+	ld	[%l7 + %lo(C_LABEL(romvec))], %l7;  \
+	ld	[%l7 + 0x74], %l7;  \
+	call	%l7;  \
+	nop;  \
+
+/* Turn off interrupts while we change contexts. Clobbers %l7 */
+#define TRAPS_OFF \
+	rd	%psr, %l7; \
+	andn	%l7, (PSR_ET), %l7; \
+	wr	%l7, 0x0, %psr; \
 
 /* Here are macros for routines we do often, this allows me to inline this
- * without making the code look real ugly. Well, the macro looks ugly too but
- * makes the trap entry code easier to understand.
+ * without making the code look real ugly.  Well, the macro looks ugly too
+ * but makes the trap entry code easier to understand.
  */
 
 /* I really don't like synthetic instructions. So I avoid them like the
@@ -27,14 +61,13 @@
  * have to check that the pages of memory that I am going to throw the window(s)
  * onto are valid and are writable by the user (this is %sp to %sp + 64) before
  * I start dumping stuff there. We always assume that kernels stack is ok.
+ * XXX Will change on MP's XXX
  *
  * If we have to save a kernel window, only one branch is taken. This should
  * make trap handlers quicker in this scenario.
  *
  * Once 'current' is loaded into %g6, it stays there until we leave
  * this macro.
- *
- * XXX must do some checking on the assumption that kernel stack is always ok
  */
 
 /* I will document how this works real soon. TODO */
@@ -62,6 +95,8 @@
 	sll	%g5, %g7, %g5; \
 	wr	%g5, 0x0, %wim;                 /* update %wim to 'now' invalid */ \
 	and	%g7, 0x1f, %g7; \
+	sethi	%hi( C_LABEL(current) ), %g6; \
+	ld	[%g6 + %lo( C_LABEL(current) )], %g6; \
 	st	%g7, [%g6 + THREAD_WIM];        /* save 'this' threads mask */ \
 	restore	%g0, %g0, %g0; \
 	or	%g0, %l5, %g5;                  /* restore the globals we used */ \
@@ -69,6 +104,8 @@
 	b	8f;                             /* we are done */ \
 	or	%g0, %l7, %g7; \
 2:	sub	%g7, 0x1, %g7; \
+	sethi	%hi( C_LABEL(current) ), %g6; \
+	ld	[%g6 + %lo( C_LABEL(current) )], %g6; \
 	st	%g7, [%g6 + THREAD_UWINDOWS];   /* There are user windows if we */ \
 	andcc	%sp, 0x7, %g0;                  /* get here. Check for stack alignment. */ \
 	bne	5f;                             /* Stack is unaligned, yuck. */ \
@@ -136,366 +173,193 @@
  * upon entry to most traps and interrupts. This is save away the current window
  * if it is the trap window, clean it, and adjust the stack for the handler c-code
  * to work.
+ *
+ * See asm-sparc/cprefix.h to see how the CONCAT macros work.
+ */
+/* NOTE: The system call entry code ASSUMES that the ENTER_TRAP macro
+ *       does NOT touch register %l7 and leaves the same contents after
+ *       the macro is done. Keep in mind if you change this code.
  */
 
-#define ENTER_TRAP \
+#define ENTER_TRAP(label) \
 	rd	%wim, %l4; \
 	or	%g0, 0x1, %l5; \
 	sll	%l5, %l0, %l5; \
-	andcc	%l0, 0x40, %g0; \
-	bz	1f; \
+	andcc	%l0, PSR_PS, %g0; \
+	bz	CONCAT1(label, 1); \
 	andcc	%l4, %l5, %g0; \
-	bz,a	3f; \
+	bz,a	CONCAT1(label, 3); \
 	sub	%fp, 0xb0, %sp; \
 	TRAP_WIN_CLEAN \
-	b	3f; \
+	b	CONCAT1(label, 3); \
 	sub	%fp, 0xb0, %sp; \
-1:	sethi	%hi( C_LABEL(current) ), %l6; \
+CONCAT1(label, 1): \
+	sethi	%hi( C_LABEL(current) ), %l6; \
 	ld	[%l6 + %lo( C_LABEL(current) )], %l6; \
 	ld	[%l6 + THREAD_WIM], %l5; \
 	and	%l0, 0x1f, %l4; \
 	cmp	%l5, %l3; \
-	ble,a	4f; \
+	ble,a	CONCAT1(label, 4); \
 	sethi	%hi( C_LABEL(nwindowsm1) ), %l4; \
 	sub	%l5, %l3, %l3; \
-	b	5f; \
+	b	CONCAT1(label, 5); \
 	sub	%l3, 0x1, %l5; \
-4:	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+CONCAT1(label, 4): \
+	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
 	sub	%l4, %l3, %l4; \
 	add	%l5, %l4, %l5; \
-5:	st	%l5, [%l6 + THREAD_UWINDOWS]; \
-	bz,a	2f; \
-	sethi	%hi(TASK_SIZE-176), %l5; \
-	TRAP_WIN_CLEAN; \
-	sethi	%hi( C_LABEL(current) ), %l6; \
-	ld	[%l6 + %lo( C_LABEL(current) )], %l6; \
-	sethi	%hi(TASK_SIZE-176), %l5; \
-2:	or	%l5, %lo(TASK_SIZE-176), %l5; \
-	add	%l6, %l5, %sp; \
-3: \
+CONCAT1(label, 5): \
+	st	%l5, [%l6 + THREAD_UWINDOWS]; \
+	bz,a	CONCAT1(label, 2); \
+	sethi	%hi(C_LABEL(current)), %l6; \
+	TRAP_WIN_CLEAN \
+	sethi	%hi(C_LABEL(current)), %l6; \
+CONCAT1(label, 2): \
+	ld	[%l6 + %lo(C_LABEL(current))], %l6; \
+	ld	[%l6 + TASK_KSTACK_PG], %l6; \
+	add	%l6, (PAGE_SIZE - 96 - 80), %l6; \
+	andn	%l6, 0x7, %l6; \
+	or	%g0, %l6, %sp; \
+CONCAT1(label, 3):
 
-#define ENTER_IRQ \
+/* What needs to be executed upon entry to an interrupt.
+ *
+ * See asm-sparc/cprefix.h to see how the CONCAT macros work.
+ */
+
+#define ENTER_IRQ(label) \
 	rd	%wim, %l4; \
 	or	%g0, 0x1, %l5; \
 	sll	%l5, %l0, %l5; \
-	andcc	%l0, 0x40, %g0; \
-	bz	1f; \
+	andcc	%l0, PSR_PS, %g0; \
+	bz	CONCAT1(label, 1); \
 	andcc	%l4, %l5, %g0; \
+	bz,a	CONCAT1(label, 0); \
 	sethi	%hi( C_LABEL(eintstack) ), %l7; \
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7; \
-	bz	0f; \
-	nop; \
 	TRAP_WIN_CLEAN \
 	sethi	%hi( C_LABEL(eintstack) ), %l7; \
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7; \
-0:	subcc	%fp, %l7, %g0; \
-	bg,a	3f; \
+CONCAT1(label, 0): \
+	subcc	%fp, %l7, %g0; \
+	bge,a	CONCAT1(label, 3); \
 	sub	%l7, 0xb0, %sp; \
-	b	3f; \
+	b	CONCAT1(label, 3); \
 	sub	%fp, 0xb0, %sp; \
-1: 	sethi	%hi( C_LABEL(current) ), %l6; \
+CONCAT1(label, 1): \
+	sethi	%hi( C_LABEL(current) ), %l6; \
 	ld	[%l6 + %lo( C_LABEL(current) )], %l6; \
 	ld	[%l6 + THREAD_WIM], %l5; \
 	and	%l0, 0x1f, %l7; \
 	cmp	%l5, %l7; \
-	ble,a	4f; \
+	ble,a	CONCAT1(label, 4); \
 	sethi	%hi( C_LABEL(nwindowsm1) ), %l4; \
 	sub	%l5, %l7, %l7; \
-	b	5f; \
+	b	CONCAT1(label, 5); \
 	sub	%l7, 0x1, %l5; \
-4:	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+CONCAT1(label, 4): \
+	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
 	sub	%l4, %l7, %l4; \
 	add	%l5, %l4, %l5; \
-5:	st	%l5, [%l6 + THREAD_UWINDOWS]; \
-	bz,a	2f; \
+CONCAT1(label, 5): \
+	st	%l5, [%l6 + THREAD_UWINDOWS]; \
+	bz,a	CONCAT1(label, 2); \
 	sethi	%hi( C_LABEL(eintstack) ), %l7; \
 	TRAP_WIN_CLEAN \
 	sethi	%hi( C_LABEL(eintstack) ), %l7; \
-2: \
+CONCAT1(label, 2): \
 	sub	%l7, 0xb0, %sp; \
-3:
+CONCAT1(label, 3):
 
 
 	.text
 	.align 4
 
-/* Default trap handler */
-	.globl my_trap_handler
-my_trap_handler:
-#if 1
-		jmp	%l1
-		rett	%l2
-		nop
-#else
-		rd %wim, %l4
-		or %g0, 0x1, %l5
-		sll %l5, %l0, %l5
-		cmp %l4, %l5        ! are we in the invalid window?
-	
-		TRAP_WIN_CLEAN
+/* Bad trap handler */
+	.globl bad_trap_handler
+bad_trap_handler:
+	ENTER_TRAP(bad_trap_handler)
 
-		nop
-		or %g0, %l3, %o0
-		call C_LABEL(do_hw_interrupt)
-		or %g0, %g0, %o1
-		wr %l0, 0x20, %psr  ! re-enable traps and reset the condition codes
-		nop
-		nop
-		nop                 ! click our heels three times, "no place like home"
-		jmp %l1
-		rett %l2
-#endif /* bogon */
+	or	%g0, %l3, %o0
+	or	%g0, %l0, %o1
+	call	C_LABEL(do_hw_interrupt)
+	or	%g0, %l1, %o2
+
+	jmp	%l1
+	rett %	l2
 	
 	.align 4
 	.globl sparc_timer
 sparc_timer:
-	sethi	%hi(TIMER_VADDR), %l4
-	or	%l4, %lo(TIMER_VADDR), %l4	! read the limit register
-	ld	[%l4 + 0xc], %l4		! to clear the interrupt
-	rd	%wim, %l4
-	or	%g0, 0x1, %l5
-	sll	%l5, %l0, %l5
-	andcc	%l0, 0x40, %g0
-	bz	st1
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	andcc	%l4, %l5, %g0
-	bz	st0
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-	TRAP_WIN_CLEAN
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-st0:	subcc	%fp, %l7, %g0
-	bg,a	st3
-	sub	%l7, 0xb0, %sp
-	b	st3
-	sub	%fp, 0xb0, %sp
-st1: 	sethi	%hi( C_LABEL(current) ), %l6
-	ld	[%l6 + %lo( C_LABEL(current) )], %l6
-	ld	[%l6 + THREAD_WIM], %l5
-	and	%l0, 0x1f, %l7
-	cmp	%l5, %l7
-	ble,a	st4
-	sethi	%hi( C_LABEL(nwindowsm1) ), %l4
-	sub	%l5, %l7, %l7
-	b	st5
-	sub	%l7, 0x1, %l5
-st4:	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
-	sub	%l4, %l7, %l4
-	add	%l5, %l4, %l5
-st5:	st	%l5, [%l6 + THREAD_UWINDOWS]
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	bz,a	st2
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-	TRAP_WIN_CLEAN
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-st2:	sub	%l7, 0xb0, %sp
+	ENTER_IRQ(sparc_timer)
+
+	sethi	%hi(C_LABEL(master_l10_limit)), %l4
+	ld	[%l4 + %lo(C_LABEL(master_l10_limit))], %l4
+	ld	[%l4], %g0			! read the limit register
 
-st3:	std	%g2, [%sp + 96 + 24]
+	std	%g2, [%sp + C_STACK + PT_G2]
 	or	%g0, %g1, %l7
 	rd	%y, %l6
-	std	%g4, [%sp + 96 + 32]
+	std	%g4, [%sp + C_STACK + PT_G4]
 	andn	%l0, PSR_PIL, %l4
-	sll	%l3, 0x8, %l5
-	std	%g6, [%sp + 96 + 40]
-	or	%l5, %l4, %l4
-
-	wr	%l4, 0x0, %psr
+/*	sll	%l3, 0x8, %l5 */
+	std	%g6, [%sp + C_STACK + PT_G6]
+/*	or	%l5, %l4, %l4 */
+
+	/* Magic, we can't increase PIL and set ET at the same
+	 * time or the chip calls prom_panic().
+	 */
+/*	wr	%l4, 0x0, %psr */
 	wr	%l4, PSR_ET, %psr
 
-	std	%l0, [%sp + 96 + 0]
-	std	%l2, [%sp + 96 + 8]
-	st	%fp, [%sp + 96 + 16]
-	
-	or	%g0, 14, %o0	
-	or	%g0, %g0, %o1
-	call	C_LABEL(do_sparc_timer)
+	or	%g0, 10, %o0
+	add	%sp, C_STACK, %o1
+	call	C_LABEL(do_IRQ)
 	nop
 
 	or	%g0, %l7, %g1
 	wr	%l6, 0x0, %y
-	ldd	[%sp + 96 + 24], %g2
-	ldd	[%sp + 96 + 32], %g4
-	ldd	[%sp + 96 + 40], %g6
-	wr	%l0, 0x0, %psr
-	nop
-	nop
-	nop
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
 
-	and	%l0, 31, %l5
-	sethi	%hi(lnx_winmask), %l6
-	or	%l6, %lo(lnx_winmask), %l6
-	ldub	[%l6 + %l5], %l5
-	andcc	%l0, PSR_PS, %g0
-	bnz	1f
-	rd	%wim, %l4
-
-1:	andcc	%l5, %l4, %g0
-	bnz	2f
+	b	ret_trap_entry
 	wr	%l0, 0x0, %psr
-	nop
-	nop
-	nop
-
-	jmp	%l1
-	rett	%l2
 
-2:	wr	%g0, 0x0, %wim
-	nop
-	nop
-	nop
-
-	restore
-	restore	%g0, 0x1, %l1
-	rd	%psr, %l0
-	and	%l0, 31, %l0
-	sll	%l1, %l0, %l1
-	wr	%l1, 0x0, %wim
-	sethi	%hi( C_LABEL(current) ), %l1
-	ld	[%l1 + %lo( C_LABEL(current) ) ], %l1
-	st	%l0, [%l1 + THREAD_WIM]
-	save	%g0, %g0, %g0
-	
-	ldd	[%sp], %l0
-	ldd	[%sp + 0x8], %l2
-	ldd	[%sp + 0x10], %l4
-	ldd	[%sp + 0x18], %l6
-	ldd	[%sp + 0x20], %i0
-	ldd	[%sp + 0x28], %i2
-	ldd	[%sp + 0x30], %i4
-	ldd	[%sp + 0x38], %i6
-	
-	save	%g0, %g0, %g0
-	
-	jmp	%l1
-	rett	%l2
-
-
-/* For now all IRQ's not registered get sent here so I can see
- * what is poking the chip.
+/* For now all IRQ's not registered get sent here. handler_irq() will
+ * see if a routine is registered to handle this interrupt and if not
+ * it will say so on the console.
  */
 
 	.align 4
-	.globl stray_irq_entry
-stray_irq_entry:
-	rd	%wim, %l4
-	or	%g0, 0x1, %l5
-	sll	%l5, %l0, %l5
-	andcc	%l0, 0x40, %g0
-	bz	tt1
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	andcc	%l4, %l5, %g0
-	bz	tt0
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-	TRAP_WIN_CLEAN
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-tt0:	subcc	%fp, %l7, %g0
-	bg,a	tt3
-	sub	%l7, 0xb0, %sp
-	b	tt3
-	sub	%fp, 0xb0, %sp
-tt1: 	sethi	%hi( C_LABEL(current) ), %l6
-	ld	[%l6 + %lo( C_LABEL(current) )], %l6
-	ld	[%l6 + THREAD_WIM], %l5
-	and	%l0, 0x1f, %l7
-	cmp	%l5, %l7
-	ble,a	tt4
-	sethi	%hi( C_LABEL(nwindowsm1) ), %l4
-	sub	%l5, %l7, %l7
-	b	tt5
-	sub	%l7, 0x1, %l5
-tt4:	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
-	sub	%l4, %l7, %l4
-	add	%l5, %l4, %l5
-tt5:	st	%l5, [%l6 + THREAD_UWINDOWS]
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	bz,a	tt2
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-	TRAP_WIN_CLEAN
-	sethi	%hi( C_LABEL(eintstack) ), %l7
-	or	%l7, %lo( C_LABEL(eintstack) ), %l7
-tt2:	sub	%l7, 0xb0, %sp
-
-tt3:	std	%g2, [%sp + 96 + 24]
+	.globl real_irq_entry
+real_irq_entry:
+	ENTER_IRQ(real_irq_entry)
+	std	%g2, [%sp + C_STACK + PT_G2]
 	or	%g0, %g1, %l7
 	rd	%y, %l6
-	std	%g4, [%sp + 96 + 32]
+	std	%g4, [%sp + C_STACK + PT_G4]
 	andn	%l0, PSR_PIL, %l4
 	sll	%l3, 0x8, %l5
-	std	%g6, [%sp + 96 + 40]
+	std	%g6, [%sp + C_STACK + PT_G6]
 	or	%l5, %l4, %l4
 
 	wr	%l4, 0x0, %psr
 	wr	%l4, PSR_ET, %psr
 
-	std	%l0, [%sp + 96 + 0]
-	std	%l2, [%sp + 96 + 8]
-	st	%fp, [%sp + 96 + 16]
+	std	%l0, [%sp + C_STACK + PT_PSR]
+	std	%l2, [%sp + C_STACK + PT_NPC]
 	
 	or	%g0, %l3, %o0	
-	or	%g0, %g0, %o1
-	call	C_LABEL(unexpected_irq)
+	add	%sp, C_STACK, %o1
+	call	C_LABEL(handler_irq)
 	nop
 
 	or	%g0, %l7, %g1
 	wr	%l6, 0x0, %y
-	ldd	[%sp + 96 + 24], %g2
-	ldd	[%sp + 96 + 32], %g4
-	ldd	[%sp + 96 + 40], %g6
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
 	wr	%l0, 0x0, %psr
-	nop
-	nop
-	nop
-
-	and	%l0, 31, %l5
-	sethi	%hi(lnx_winmask), %l6
-	or	%l6, %lo(lnx_winmask), %l6
-	ldub	[%l6 + %l5], %l5
-	andcc	%l0, PSR_PS, %g0
-	bnz	1f
-	rd	%wim, %l4
-
-1:	andcc	%l5, %l4, %g0
-	bnz	2f
-	wr	%l0, 0x0, %psr
-	nop
-	nop
-	nop
-
-	jmp	%l1
-	rett	%l2
-
-2:	wr	%g0, 0x0, %wim
-	nop
-	nop
-	nop
-
-	restore
-	restore	%g0, 0x1, %l1
-	rd	%psr, %l0
-	and	%l0, 31, %l0
-	sll	%l1, %l0, %l1
-	wr	%l1, 0x0, %wim
-	sethi	%hi( C_LABEL(current) ), %l1
-	ld	[%l1 + %lo( C_LABEL(current) ) ], %l1
-	st	%l0, [%l1 + THREAD_WIM]
-	save	%g0, %g0, %g0
-	
-	ldd	[%sp], %l0
-	ldd	[%sp + 0x8], %l2
-	ldd	[%sp + 0x10], %l4
-	ldd	[%sp + 0x18], %l6
-	ldd	[%sp + 0x20], %i0
-	ldd	[%sp + 0x28], %i2
-	ldd	[%sp + 0x30], %i4
-	ldd	[%sp + 0x38], %i6
-	
-	save	%g0, %g0, %g0
-	
-	jmp	%l1
-	rett	%l2
-
 
 
 /* This routine is optimized for kernel window fills. User fills take about two
@@ -503,14 +367,14 @@
  */
 
 /* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is
- * full of them! If you think this routine is hairy, window spills are worse,
+ * full of them! If you think this routine is hairy, window fills are worse,
  * see below.
  */
 
 	.align 4
 	.globl spill_window_entry
 spill_window_entry:
-	andcc	%l0, 0x40, %g0		! see if this is a user window fill
+	andcc	%l0, PSR_PS, %g0	! see if this is a user window fill
 	bz,a	spill_from_user
 	nop
 
@@ -535,10 +399,12 @@
 	sub	%l5, %l3, %l3
 	b	2f
 	sub	%l3, 0x1, %l5
-1:	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+1:
+	ld	[%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
 	sub	%l4, %l3, %l4
 	add	%l5, %l4, %l5
-2:	st	%l5, [%l6 + THREAD_UWINDOWS]
+2:
+	st	%l5, [%l6 + THREAD_UWINDOWS]
 
 	TRAP_WIN_CLEAN		   /* danger, danger... */
 	sethi	%hi( C_LABEL(current) ), %l6
@@ -607,7 +473,8 @@
 	cmp	%l7, -1
 	bne	fill_bad_stack
 	andn	%sp, 0xfff, %l7
-1:	lda	[%l7] ASI_PTE, %l7
+1:
+	lda	[%l7] ASI_PTE, %l7
 	srl	%l7, 0x1d, %l7
 	andn	%l7, 0x2, %l7
 	cmp	%l7, 0x4
@@ -624,7 +491,8 @@
 	cmp	%l7, -1
 	bne	fill_bad_stack
 	andn	%sp, 0xfff, %l7
-1:	lda	[%l7] ASI_PTE, %l7
+1:
+	lda	[%l7] ASI_PTE, %l7
 	srl	%l7, 0x1d, %l7
 	andn	%l7, 0x2, %l7
 	cmp	%l7, 0x4
@@ -641,8 +509,8 @@
 	sll	%l4, %l5, %l4
 	wr	%l4, 0x0, %wim
 	ld	[%l6 + THREAD_KSP], %sp		! set to kernel stack pointer
-	wr	%l0, 0x20, %psr			! turn off traps
-	std	%l0, [%sp + C_STACK]		! set up thread_frame on stack
+	wr	%l0, PSR_ET, %psr		! turn off traps
+	std	%l0, [%sp + C_STACK]		! set up thread_frame XXX
 	rd	%y, %l3
 	std	%l2, [%sp + C_STACK + 0x8]
 	or	%g0, 0x6, %o0			! so _sparc_trap knows what to do
@@ -656,7 +524,7 @@
 	std	%i0, [%sp + C_STACK + 0x30]
 	std	%i2, [%sp + C_STACK + 0x38]
 	std	%i4, [%sp + C_STACK + 0x40]
-	call	sparc_trap
+	nop					/* SHould trap here */
 	std	%i6, [%sp + C_STACK + 0x48]
 	
 	ldd	[%sp + C_STACK], %l0
@@ -677,9 +545,10 @@
 	cmp	%l7, 0x0
 	bl,a	1f
 	wr	%g0, 0x0, %wim
-	b,a	leave_trap
+	/* Should trap here */
 
-1:	or	%g0, %g6, %l3
+1:
+	or	%g0, %g6, %l3
 	or	%g0, %l6, %g6
 	st	%g0, [%g6 + THREAD_W_SAVED]
 	restore	%g0, %g0, %g0
@@ -739,46 +608,1120 @@
 	jmp	%l1
 	rett	%l2
 
+	/* This routine handles illegal isntructions and privileged
+	 * instruction attempts from user code.
+	 */
 	.align 4
-	.globl trap_entry
-trap_entry:
-	TRAP_WIN_CLEAN
-	jmp	%l1
-	rett	%l2
+	.globl bad_instruction
+bad_instruction:
+	ENTER_TRAP(bad_instruction)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	cmp	%l3, 0x2
+	bne	1f
+	call	C_LABEL(do_illegal_instruction)
+	mov	%l0, %o3
+	b	2f
+	ld	[%sp + C_STACK + PT_G1], %g1
+
+1:
+	call	C_LABEL(do_priv_instruction)
+	mov	%l0, %o3
+	ld	[%sp + C_STACK + PT_G1], %g1
+2:
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles unaligned data accesses.
+	 */
+	.align 4
+	.globl mna_handler
+mna_handler:
+	ENTER_TRAP(mna_handler)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(do_memaccess_unaligned)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles floating point disabled traps.
+	 */
+	.align 4
+	.globl fpd_trap_handler
+fpd_trap_handler:
+	ENTER_TRAP(fpd_trap_handler)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(do_fpd_trap)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Floating Point Exceptions.
+	 */
+	.align 4
+	.globl fpe_trap_handler
+fpe_trap_handler:
+	ENTER_TRAP(fpe_trap_handler)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(do_fpe_trap)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Tag Overflow Exceptions.
+	 */
+	.align 4
+	.globl do_tag_overflow
+do_tag_overflow:
+	ENTER_TRAP(do_tag_overflow)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_tag_overflow)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Watchpoint Exceptions.
+	 */
+	.align 4
+	.globl do_watchpoint
+do_watchpoint:
+	ENTER_TRAP(do_watchpoint)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_watchpoint)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Register Access Exceptions.
+	 */
+	.align 4
+	.globl do_reg_access
+do_reg_access:
+	ENTER_TRAP(do_reg_access)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_reg_access)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Instruction Access Errors.
+	 */
+	.align 4
+	.globl do_iacc_error
+do_iacc_error:
+	ENTER_TRAP(do_iacc_error)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_iacc_error)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Co-Processor Disabled Exceptions.
+	 */
+	.align 4
+	.globl do_cp_disabled
+do_cp_disabled:
+	ENTER_TRAP(do_cp_disabled)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_cp_disabled)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Unimplemented FLUSH Exceptions.
+	 */
+	.align 4
+	.globl do_bad_flush
+do_bad_flush:
+	ENTER_TRAP(do_bad_flush)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_bad_flush)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Co-Processor Exceptions.
+	 */
+	.align 4
+	.globl do_cp_exception
+do_cp_exception:
+	ENTER_TRAP(do_cp_exception)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_cp_exception)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Data Access Errors.
+	 */
+	.align 4
+	.globl do_dacc_error
+do_dacc_error:
+	ENTER_TRAP(do_dacc_error)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_dacc_error)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Hardware Divide By Zero Exceptions.
+	 */
+	.align 4
+	.globl do_hw_divzero
+do_hw_divzero:
+	ENTER_TRAP(do_hw_divzero)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_hw_divzero)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Data Store Errors.
+	 */
+	.align 4
+	.globl do_dstore_err
+do_dstore_err:
+	ENTER_TRAP(do_dstore_err)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_dstore_error)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Data Access MMU-Miss Exceptions.
+	 */
+	.align 4
+	.globl do_dacc_mmu_miss
+do_dacc_mmu_miss:
+	ENTER_TRAP(do_dacc_mmu_miss)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_dacc_mmu_miss)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* This routine handles Instruction Access MMU-Miss Exceptions.
+	 */
+	.align 4
+	.globl do_iacc_mmu_miss
+do_iacc_mmu_miss:
+	ENTER_TRAP(do_iacc_mmu_miss)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	rd	%y, %l4
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	wr	%l0, PSR_ET, %psr		! re-enable traps
+	add	%sp, C_STACK, %o0
+	mov	%l1, %o1
+	mov	%l2, %o2
+	call	C_LABEL(handle_iacc_mmu_miss)
+	mov	%l0, %o3
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+	/* The getcc software trap.  The user wants the condition codes from
+	 * the %psr in register %g1.
+	 */
+
+	.align 4
+	.globl getcc_trap_handler
+getcc_trap_handler:
+	/* Shit, one more instruction and I could do this inline. */
+	sll	%l0, 0x8, %g1
+	srl	%g1, 28, %g1
+	jmp	%l2
+	rett	%l2+0x4
+
+	/* The setcc software trap.  The user has condition codes in %g1
+	 * that it would like placed in the %psr.  Be careful not to flip
+	 * any unintention bits!
+	 */
+
+	.align 4
+	.globl setcc_trap_handler
+setcc_trap_handler:
+	sll	%g1, 0x14, %l4
+	set	PSR_ICC, %l5
+	andn	%l0, %l5, %l0
+	or	%l4, %l0, %l4
+	wr	%l4, 0x0, %psr
+	WRITE_PAUSE
+	jmp	%l2
+	rett	%l2+0x4
+
+	.align 4
+NMI_STRING:	.asciz	"NMI received, dazed and confused, halting...\n"
 
 	.align 4
 	.globl linux_trap_nmi
+	.globl C_LABEL(interrupt_enable)
 linux_trap_nmi:
-	TRAP_WIN_CLEAN
+	sethi	%hi(C_LABEL(prom_vector_p)), %o0
+	ld	[%o0 + %lo(C_LABEL(prom_vector_p))], %o0
+	ld	[%o0 + 0x74], %o0
+	/* Ugh, until I figure out how to clear the IRQ line ;( */
+	call	%o0
+	nop
+
+	.align 4
+	.globl sparc_text_fault
+sparc_text_fault:
+	ENTER_TRAP(sparc_text_fault)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	rd	%y, %l4
+	sethi	%hi(AC_SYNC_ERR), %o0
+	lda	[%o0] ASI_CONTROL, %o1
+	add	%o0, 0x4, %o0           ! go to sync vaddr
+	lda	[%o0] ASI_CONTROL, %o2
+	andcc	%o1, SUN4C_SYNC_NOMEM, %g0
+	bz,a	normal_page_fault
+	wr	%l0, PSR_ET, %psr	! re-enable traps
+
+	add	%o0, 0x4, %o0           ! go to async error register
+	lda	[%o0] ASI_CONTROL, %o3
+	add	%o0, 0x4, %o0		! go to async vaddr
+	subcc	%o4, %o2, %g0
+	be,a	is_sync_fault		! not an async fault
+	wr	%l0, PSR_ET, %psr
+
+	/* crap, an asynchronous error has occurred */
+	sethi	%hi(C_LABEL(interrupt_enable)), %l5
+	ldub	[%l5 + %lo(C_LABEL(interrupt_enable))], %o0
+	andn	%o0, INTS_ENAB, %o0
+	stb	%o0, [%l5 + %lo(C_LABEL(interrupt_enable))]
+	wr	%l0, PSR_ET, %psr		! enable traps
+	call	C_LABEL(sparc_txtmem_error)	! call high level c-code
+	or	%g0, FAULT_ASYNC, %o0
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldub	[%l5 + %lo(C_LABEL(interrupt_enable))], %o1
+	or	%o1, INTS_ENAB, %o1
+	stb	%o1, [%l5 + %lo(C_LABEL(interrupt_enable))]
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+is_sync_fault:
+	call	C_LABEL(sparc_txtmem_error)	! call high level c-code
+	or	%g0, FAULT_SYNC, %o0
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ld	[%sp + C_STACK + PT_G2], %g2
+	ld	[%sp + C_STACK + PT_G4], %g4
+	ld	[%sp + C_STACK + PT_G6], %g6
+	wr	%l4, 0x0, %y
+	b	ret_trap_entry
+	wr	%l0, 0x0, %psr
+
+normal_page_fault:
+	std	%l0, [%sp + C_STACK + PT_PSR]
+	or	%g0, %l3, %o0
+	st	%l2, [%sp + C_STACK + PT_NPC]
+	st	%l4, [%sp + C_STACK + PT_Y]
+	or	%g0, %l1, %o3
+	std	%i0, [%sp + C_STACK + PT_I0]
+	std	%i2, [%sp + C_STACK + PT_I2]
+	or	%g0, %l0, %o4
+	std	%i4, [%sp + C_STACK + PT_I4]
+	std	%i6, [%sp + C_STACK + PT_I6]
+	call	C_LABEL(sparc_text_access_fault)
+	add	%sp, C_STACK, %o5
+
+	ldd	[%sp + C_STACK + PT_PSR], %l0
+	ldd	[%sp + C_STACK + PT_NPC], %l2
+	wr	%l3, 0x0, %y
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldd	[%sp + C_STACK + PT_I0], %i0
+	ldd	[%sp + C_STACK + PT_I2], %i2
+	ldd	[%sp + C_STACK + PT_I4], %i4
+	ldd	[%sp + C_STACK + PT_I6], %i6
+
+	b	ret_trap_entry
+	wr	%l0, 0x0, %psr
+
+	.align 4
+	.globl sparc_data_fault
+sparc_data_fault:
+	ENTER_TRAP(sparc_data_fault)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	rd	%y, %l4
+	sethi	%hi(AC_SYNC_ERR), %o0
+	lda	[%o0] ASI_CONTROL, %o1
+	add	%o0, 0x4, %o0           ! go to sync vaddr
+	lda	[%o0] ASI_CONTROL, %o2
+	andcc	%o1, SUN4C_SYNC_NOMEM, %g0
+	bz,a	normal_data_page_fault
+	wr	%l0, PSR_ET, %psr
+
+	add	%o0, 0x4, %o0           ! go to async error register
+	lda	[%o0] ASI_CONTROL, %o3
+	add	%o0, 0x4, %o0		! go to async vaddr
+	subcc	%o4, %o2, %g0
+	be,a	is_data_sync_fault	! not an async fault
+	wr	%l0, PSR_ET, %psr
+
+	/* crap, an asynchronous error has occurred */
+	sethi	%hi(C_LABEL(interrupt_enable)), %l5
+	ldub	[%l5 + %lo(C_LABEL(interrupt_enable))], %o0
+	andn	%o0, INTS_ENAB, %o0
+	stb	%o0, [%l5 + %lo(C_LABEL(interrupt_enable))]
+	wr	%l0, PSR_ET, %psr
+	call	C_LABEL(sparc_datamem_error)	! call high level c-code
+	or	%g0, FAULT_ASYNC, %o0
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	wr	%l0, 0x0, %psr
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldub	[%l5 + %lo(C_LABEL(interrupt_enable))], %o1
+	or	%o1, INTS_ENAB, %o1
+	stb	%o1, [%l5 + %lo(C_LABEL(interrupt_enable))]
+	b	ret_trap_entry
+	wr	%l4, 0, %y
+
+is_data_sync_fault:
+	call	C_LABEL(sparc_datamem_error)	! call high level c-code
+	or	%g0, FAULT_SYNC, %o0
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	wr	%l4, 0x0, %y
+	b	ret_trap_entry
+	wr	%l0, 0x0, %psr
+
+normal_data_page_fault:
+	std	%l0, [%sp + C_STACK + PT_PSR]	! store %psr and pc
+	or	%g0, %l3, %o0
+	st	%l2, [%sp + C_STACK + PT_NPC]	! store npc
+	st	%l4, [%sp + C_STACK + PT_Y]	! store %y
+	or	%g0, %l1, %o3
+
+	/* The globals have already been placed on the stack */
+	std	%i0, [%sp + C_STACK + PT_I0]	! store ins
+	std	%i2, [%sp + C_STACK + PT_I2]
+	or	%g0, %l0, %o4
+	std	%i4, [%sp + C_STACK + PT_I4]
+	std	%i6, [%sp + C_STACK + PT_I6]
+	call	C_LABEL(sparc_data_access_fault)
+	add	%sp, C_STACK, %o5
+
+	ldd	[%sp + C_STACK + PT_PSR], %l0
+	ldd	[%sp + C_STACK + PT_NPC], %l2
+	wr	%l3, 0x0, %y
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldd	[%sp + C_STACK + PT_I0], %i0
+	ldd	[%sp + C_STACK + PT_I2], %i2
+	ldd	[%sp + C_STACK + PT_I4], %i4
+	ldd	[%sp + C_STACK + PT_I6], %i6
+
+	b	ret_trap_entry
+	wr	%l0, 0x0, %psr
+
+
+	.align 4
+	.globl C_LABEL(srmmu_text_fault)
+C_LABEL(srmmu_text_fault):
+	ENTER_TRAP(srmmu_text_fault)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	rd	%y, %l4
+	set	0x300, %o0
+	lda	[%o0] ASI_M_MMUREGS, %o1	! fault status
+	set	0x400, %o0
+	lda	[%o0] ASI_M_MMUREGS, %o2	! fault address
+	wr	%l0, PSR_ET, %psr		! traps back on
+	WRITE_PAUSE
+	std	%l0, [%sp + C_STACK + PT_PSR]
+	or	%g0, %l3, %o0
+	st	%l2, [%sp + C_STACK + PT_NPC]
+	st	%l4, [%sp + C_STACK + PT_Y]
+	or	%g0, %l1, %o3
+	std	%i0, [%sp + C_STACK + PT_I0]
+	std	%i2, [%sp + C_STACK + PT_I2]
+	or	%g0, %l0, %o4
+	std	%i4, [%sp + C_STACK + PT_I4]
+	std	%i6, [%sp + C_STACK + PT_I6]
+	call	C_LABEL(srmmu_text_access_fault)
+	add	%sp, C_STACK, %o5
+
+	ldd	[%sp + C_STACK + PT_PSR], %l0
+	ldd	[%sp + C_STACK + PT_NPC], %l2
+	wr	%l3, 0x0, %y
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldd	[%sp + C_STACK + PT_I0], %i0
+	ldd	[%sp + C_STACK + PT_I2], %i2
+	ldd	[%sp + C_STACK + PT_I4], %i4
+	ldd	[%sp + C_STACK + PT_I6], %i6
+
+	b	ret_trap_entry
+	wr	%l0, 0x0, %psr
+
+	.align 4
+	.globl C_LABEL(srmmu_data_fault)
+C_LABEL(srmmu_data_fault):
+	ENTER_TRAP(srmmu_data_fault)
+	st	%g1, [%sp + C_STACK + PT_G1]
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	rd	%y, %l4
+
+	set	AC_M_SFSR, %o0
+	lda	[%o0] ASI_M_MMUREGS, %o1	! fault status
+	set	AC_M_SFAR, %o0
+	lda	[%o0] ASI_M_MMUREGS, %o2	! fault address
+	set	AC_M_AFSR, %o0
+	lda	[%o0] ASI_M_MMUREGS, %o3
+	set	AC_M_AFAR, %o0
+	lda	[%o0] ASI_M_MMUREGS, %o4
+	wr	%l0, PSR_ET, %psr		! traps back on
+	WRITE_PAUSE
+	std	%l0, [%sp + C_STACK + PT_PSR]
+	or	%g0, %l3, %o0
+	st	%l2, [%sp + C_STACK + PT_NPC]
+	st	%l4, [%sp + C_STACK + PT_Y]
+	std	%i0, [%sp + C_STACK + PT_I0]
+	std	%i2, [%sp + C_STACK + PT_I2]
+	std	%i4, [%sp + C_STACK + PT_I4]
+	std	%i6, [%sp + C_STACK + PT_I6]
+	call	C_LABEL(srmmu_data_access_fault)
+	add	%sp, C_STACK, %o5
+
+	ldd	[%sp + C_STACK + PT_PSR], %l0
+	ldd	[%sp + C_STACK + PT_NPC], %l2
+	wr	%l3, 0x0, %y
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldd	[%sp + C_STACK + PT_I0], %i0
+	ldd	[%sp + C_STACK + PT_I2], %i2
+	ldd	[%sp + C_STACK + PT_I4], %i4
+	ldd	[%sp + C_STACK + PT_I6], %i6
+
+	b	ret_trap_entry
+	wr	%l0, 0x0, %psr
+
+/* Normal Linux system calls enter here... */
+/* Trying to make this as generic and simple as possible. */
+
+	.align 4
+	.globl linux_sparc_syscall
+linux_sparc_syscall:
+	/* Don't dork with %l7, it holds the pointer to the
+	 * system call vector table.  ENTER_TRAP does not
+	 * modify its value.
+	 */
+	ENTER_TRAP(linux_sparc_syscall)
+
+	/* setup pt_regs stack frame, leave ints off...
+	 * First save all but the current window onto the stack.
+	 * This means nwindows-2 saves and nwindows-2 restores.
+	 */
+	andn	%l0, PSR_PIL, %l5
+	wr	%l5, 0xf00, %psr
+	wr	%l5, 0xf20, %psr	! no ints, traps on
+	WRITE_PAUSE
+	
+	.globl nop7
+	/* Flush windows */
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+nop7:	save	%sp, -C_STACK, %sp
+	restore
+	restore
+	restore
+	restore
+	restore
+	restore
+
+	rd	%psr, %l6
+	and	%l6, PSR_CWP, %l6		! only care about CWP
+	andn	%l0, PSR_CWP, %l0
+	or	%l0, %l6, %l0			! %l0 is now the new %psr
+	
+	std	%l0, [%sp + C_STACK + PT_PSR]	! save it away
+	rd	%y, %l3
+	std	%l2, [%sp + C_STACK + PT_NPC]
+
+	/* Put %wim in %g0 slot, a hack.  This way we ensure that %wim
+	 * sits right behind the current window in %psr, which is what
+	 * we want.
+	 */
+	rd	%wim, %l4
+	st	%l4, [%sp + C_STACK + PT_G0]
+	st	%g1, [%sp + C_STACK + PT_G1]
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	std	%i0, [%sp + C_STACK + PT_I0]
+	std	%i2, [%sp + C_STACK + PT_I2]
+	std	%i4, [%sp + C_STACK + PT_I4]
+	std	%i6, [%sp + C_STACK + PT_I6]
+
+	wr	%l0, PSR_ET, %psr /* Turn on traps + interrupts */
+	WRITE_PAUSE
+
+	cmp	%i0, NR_SYSCALLS
+	bgu,a	C_LABEL(ret_sys_call)
+	or	%g0, -1, %i0
+
+	cmp	%i0, 0x2		! fork? Same number for all OSs
+	bne	not_fork
+	nop
+	call	C_LABEL(sys_fork)	! yep, load pt_regs into first arg
+	add	%sp, C_STACK, %o0
+	b	C_LABEL(ret_sys_call)
+	nop
+not_fork:
+	/* Remember, trap table entry loaded syscall table ptr in %l7 */
+	sll	%i0, 0x2, %o0
+	add	%l7, %o0, %l7
+	ld	[%l7], %o5		! load up ptr to syscall handler
+
+	mov	%i1, %o0		! load up arguments
+	mov	%i2, %o1
+	mov	%i3, %o2
+	mov	%i4, %o3
+	jmpl	%o5, %o7		! Make syscall
+	mov	%i5, %o4
+
+	.globl C_LABEL(ret_sys_call)  /* exported for copy_process() */
+C_LABEL(ret_sys_call):	 /* Child of a fork returns here */
+	/* dump the pt_regs back into their rightful places */
+	ldd	[%sp + C_STACK + PT_PSR], %l0
+	ldd	[%sp + C_STACK + PT_NPC], %l2
+	wr	%l3, 0x0, %y
+
+	ld	[%sp + C_STACK + PT_G1], %g1
+	ldd	[%sp + C_STACK + PT_G2], %g2
+	ldd	[%sp + C_STACK + PT_G4], %g4
+	ldd	[%sp + C_STACK + PT_G6], %g6
+	ldd	[%sp + C_STACK + PT_I0], %i0
+	ldd	[%sp + C_STACK + PT_I2], %i2
+	ldd	[%sp + C_STACK + PT_I4], %i4
+	ldd	[%sp + C_STACK + PT_I6], %i6
+
+	/* %i6 is our frame pointer, the restore done by the rett
+	 * instruction will automatically put us back on the users
+	 * stack.
+	 * Advance the pc and npc past the trap instruction, the copy_process()
+	 * code for fork() depends on this being done right before trap return.
+	 */
+	or	%l2, 0x0, %l5
+
+	or	%l5, 0x0, %l1    /* pc = npc */
+	add	%l5, 0x4, %l2    /* npc= npc+4 */
+
+	wr	%l0, 0x0, %psr
+	WRITE_PAUSE	
+
+	/* Fall through to ret_trap_entry */
+
+/* Return from trap code.  I realized that I was duplicating a lot
+ * of logic in the various trap handlers. Traps are off upon entry.
+ */
+
+ret_trap_entry:
+	and	%l0, 0x1f, %l5
+	sethi	%hi(lnx_winmask), %l6
+	or	%l6, %lo(lnx_winmask), %l6
+	ldub	[%l6 + %l5], %l5
+	andcc	%l0, PSR_PS, %g0
+	bnz	ret_trap_kernel
+	rd	%wim, %l4
+
+	sethi	%hi(C_LABEL(current)), %l6
+	ld	[%l6 + %lo(C_LABEL(current))], %l6
+	ld	[%l6 + THREAD_W_SAVED], %l7
+	subcc	%g0, %l7, %g0
+	bz,a	ret_trap_user
+	nop
+
+	wr	%g0, 0, %wim
+	or	%g0, %g6, %l3
+	or	%g0, %l6, %g6
+	st	%g0, [%g6 + THREAD_W_SAVED]
+	restore
+	restore %g0, 1, %l1
+	rd	%psr, %l0
+	sll	%l1, %l0, %l1
+	wr	%l1, 0x0, %wim
+	and	%l0, 0x1f, %l0
+	st	%l0, [%g6 + THREAD_WIM]
+	nop
+	save	%g0, %g0, %g0
+	add	%g6, THREAD_REG_WINDOW, %g6
+	ldd	[%g6], %l0
+	ldd	[%g6 + 0x8], %l2
+	ldd	[%g6 + 0x10], %l4
+	ldd	[%g6 + 0x18], %l6
+	ldd	[%g6 + 0x20], %i0
+	ldd	[%g6 + 0x28], %i2
+	ldd	[%g6 + 0x30], %i4
+	ldd	[%g6 + 0x38], %i6
+
+	save	%g0, %g0, %g0
+	wr	%l0, 0x0, %psr
+	or	%g0, %l3, %g6
 	jmp	%l1
 	rett	%l2
 
-	.align 4
-	.globl sparc_trap
-sparc_trap:
-	TRAP_WIN_CLEAN
+ret_trap_kernel:
+	andcc	%l4, %l5, %g0
+	bnz	1f
+	wr	%l0, 0x0, %psr       ! reset condition codes
+	nop
 	jmp	%l1
 	rett	%l2
 
-	.align 4
-	.globl leave_trap
-leave_trap:
+1:
+	wr	%g0, 0x0, %wim
+	WRITE_PAUSE
+	restore
+	restore %g0, 0x1, %l1
+	rd	%psr, %l0
+	and	%l0, 0x1f, %l0
+	sll	%l1, %l0, %l1
+	wr	%l1, 0x0, %wim
+	sethi	%hi(C_LABEL(current)), %l1
+	ld	[%l1 + %lo(C_LABEL(current))], %l1
+	st	%l0, [%l1 + THREAD_WIM]
+	save	%g0, %g0, %g0
+	ldd	[%sp], %l0
+	ldd	[%sp + 0x8], %l2
+	ldd	[%sp + 0x10], %l4
+	ldd	[%sp + 0x18], %l6
+	ldd	[%sp + 0x20], %i0
+	ldd	[%sp + 0x28], %i2
+	ldd	[%sp + 0x30], %i4
+	ldd	[%sp + 0x38], %i6
+
+	save	%g0, %g0, %g0
+	jmp	%l1
+	rett	%l2
+
+ret_trap_user:
+	andcc	%l4, %l5, %g0
+	bnz	1f
+	wr	%l0, 0x0, %psr
+	nop
+	jmp	%l1
+	rett	%l2
+
+1:
+	wr	%g0, 0x0, %wim
+	wr	%l0, 0x0, %psr
+	WRITE_PAUSE
+	restore
+	restore	%g0, 0x1, %l1
+	rd	%psr, %l0
+	sll	%l1, %l0, %l1
+	wr	%l1, 0x0, %wim
+	sethi	%hi(C_LABEL(current)), %l1
+	ld	[%l1 + %lo(C_LABEL(current))], %l1
+	and	%l0, 0x1f, %l0
+	st	%l0, [%l1 + THREAD_WIM]
+	save	%g0, %g0, %g0
+	ldd	[%sp], %l0
+	ldd	[%sp + 0x8], %l2
+	ldd	[%sp + 0x10], %l4
+	ldd	[%sp + 0x18], %l6
+	ldd	[%sp + 0x20], %i0
+	ldd	[%sp + 0x28], %i2
+	ldd	[%sp + 0x30], %i4
+	ldd	[%sp + 0x38], %i6
+	save	%g0, %g0, %g0
 	jmp	%l1
 	rett	%l2
 
+/* Context switch code.  I don't feel like playing around with
+ * inline gcc-assembly to do this right, so here it is.  The new
+ * process's task_struct ptr is passed in %o0.
+ *
+ * This is still work in progress.
+ * ONLY MAKE PROM CALLS FOR DIAGNOSTICS WHEN TRAPS ARE ON!!!!!
+ *
+ * First successful task switch 05/13/95 21:52:37
+ *
+ */
+	.align 4
+	.globl C_LABEL(sparc_switch_to)
+C_LABEL(sparc_switch_to):
+	or	%g0, %o0, %l5
+	sethi	%hi(C_LABEL(current)), %l6
+	ld	[%l6 + %lo(C_LABEL(current))], %l6
+	rd	%psr, %l0
+
+	or	%g0, %l0, %l4
+	andn	%l0, PSR_PIL, %l0   /* turn off IRQ level bits leave PSR_ET on */
+
+	wr	%l0, 0xf00, %psr    /* NO interrupts */
+	WRITE_PAUSE
+
+	/* Save state of old process */
+	.globl rnop7
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+	save	%sp, -C_STACK, %sp
+rnop7:	save	%sp, -C_STACK, %sp
+	restore
+	restore
+	restore
+	restore
+	restore
+	restore
+
+	rd	%psr, %l3
+	and	%l3, PSR_CWP, %l3		! only care about CWP bits now
+	andn	%l0, PSR_CWP, %l0		! integrate with old %psr
+	or	%l3, %l0, %l0
+	
+	st	%l0, [%sp + C_STACK + PT_PSR]	! save new %psr
+	/* ??? We backtrack the PC two instructions due to retl's semantics ??? */
+	/*sub	%o7, 0x8, %o7 */
+	st	%o7, [%sp + C_STACK + PT_PC]	! save return PC
+	add	%o7, 0x4, %l3
+	st	%l3, [%sp + C_STACK + PT_NPC]   ! and NPC
+
+	rd	%y, %l3
+	st	%l3, [%sp + C_STACK + PT_Y]	! save %y
+
+	/* Save the %wim into %g0 slot, ensures that it sits behind CWP */
+	rd	%wim, %l3
+	st	%l3, [%sp + C_STACK + PT_G0]	! save new %wim
+	st	%g1, [%sp + C_STACK + PT_G1]
+	std	%g2, [%sp + C_STACK + PT_G2]
+	std	%g4, [%sp + C_STACK + PT_G4]
+	std	%g6, [%sp + C_STACK + PT_G6]
+	std	%i0, [%sp + C_STACK + PT_I0]
+	std	%i2, [%sp + C_STACK + PT_I2]
+	std	%i4, [%sp + C_STACK + PT_I4]
+	std	%i6, [%sp + C_STACK + PT_I6]
+
+	wr	%l0, (0xf20), %psr		! no traps, no intrs
+	WRITE_PAUSE
+
+	/* TRAPS ARE OFF, NO PROM CALLS WHATSOEVER FOR DEBUGGING!!! */
+	/* SO what we do is we put an imperical constant in %g2 and
+	 * a 'counter' in %g1 which we increment after every instruction
+	 * so we can figure out where the thing prom panics.  Then at the
+	 * prom prompt we print out the saved registers.  To drop into the
+	 * prom and look at the registers just execute 7 saves since that
+	 * will induce a window trap before the last one and traps are off,
+	 * thus a watchdog reset will occur.
+	 */
+
+	/* Grrr, this is hairy... be careful, again NO PROM CALLS YET! */
+	/* Load up the new 'current' */
+	sethi	%hi(C_LABEL(current)), %g1
+	st	%l5, [%g1 + %lo(C_LABEL(current))]
+	
+	/* Load up new processes stack, we always switch onto the kernel stack */
+	/* Be CAREFUL, use globals for temporaries, because after we change the
+	 * %psr the window could change and you will most likely be accessing
+	 * different outs, ins, and locals than you origionally were.
+	 */
+	or	%g0, %l5, %g6
+	ld	[%l5 + THREAD_KSP], %g3
+
+	/* New procs %psr */
+	ld	[%g3 + C_STACK + PT_PSR], %g4
+	wr	%g4, 0xf00, %psr         /* No ints, no traps */
+	WRITE_PAUSE
+
+	/* We could be in a different window NOW. Assume nothing about the
+	 * current set of in, out and local registers.
+	 */
+
+	/* New procs %wim */
+	ld	[%g3 + C_STACK + PT_G0], %l4 /* %wim is here */
+	st	%l4, [%g6 + THREAD_WIM]      /* Update tss */
+	wr	%l4, 0x0, %wim               /* Use it */
+	WRITE_PAUSE
+
+	/* Finally, load the stack */
+	or	%g0, %g3, %sp
+
+	/* We are now sane, we have a good stack and our state is reflected
+	 * properly in 'current'.  Let it rip.
+	 */
+	/* Remember, you can't increase PIL and turn on traps at the
+	 * same time.
+	 */
+	wr	%g4, 0xf00, %psr  /* Traps on, no interrupts. */
+	wr	%g4, 0xf20, %psr
+	WRITE_PAUSE
+	
+	sethi	%hi(C_LABEL(current)), %o0
+	ld	[%o0 + %lo(C_LABEL(current))], %o0
+	ld	[%o0 + THREAD_PC], %o7 /* Setup return address */
+
+	/* cross fingers */
+	retl
+	nop
+
 /* The following two things point to window management tables. The first
-   one is used to quickly look up how many user windows there are from
-   trap-land. The second is used in a trap handler to determine if a rett
-   instruction will land us smack inside the invalid window that possibly
-   the trap was called to fix-up.
-*/
+ * one is used to quickly look up how many user windows there are from
+ * trap-land. The second is used in a trap handler to determine if a rett
+ * instruction will land us smack inside the invalid window that possibly
+ * the trap was called to fix-up.
+ */
+
+/* For now these are static tables geared for a 7 window sparc.
+ * But in head.S after we calculate this table based upon the
+ * nwindows value.  This table is big enough for a 16 window sparc.
+ */
 
-/* For now these are static tables geared for a 7 window sparc. */
 
 		.data
 		.align 4
-lnx_winmask:	.byte	2, 4, 8, 16, 32, 64, 128, 1  ! lnx_winmask[0..7]
-
+		.globl lnx_winmask
+lnx_winmask:
+		.byte	2, 4, 8, 16, 32, 64, 1, 0
+		.byte	0, 0, 0, 0, 0, 0, 0, 0
 	
 		.align 4
 		.globl C_LABEL(sys_call_table)
@@ -918,10 +1861,90 @@
 	.long C_LABEL(sys_getpgid)
 	.long C_LABEL(sys_fchdir)
 	.long C_LABEL(sys_bdflush)
-	.long C_LABEL(sys_sysfs)	/* 135 */
+	.long C_LABEL(sys_sysfs)		/* 135 */
 	.long C_LABEL(sys_personality)
-	.long 0				/* for afs_syscall */
+	.long C_LABEL(sys_ni_syscall)		/* for afs_syscall */
 	.long C_LABEL(sys_setfsuid)
 	.long C_LABEL(sys_setfsgid)
 	.long C_LABEL(sys_llseek)		/* 140 */
+	.long C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 150 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 160 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 170 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 180 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 190 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 200 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 210 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 220 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 230 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 240 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+
+	/* 250 */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall)		/* 255 */
 	.align 4
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v1.3.3/linux/arch/sparc/kernel/head.S	Mon Mar  6 11:22:09 1995
+++ linux/arch/sparc/kernel/head.S	Mon Jun 26 11:22:42 1995
@@ -1,52 +1,53 @@
-/* boot.S: The initial boot code for the Sparc port of Linux.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-
-           This file has to serve three purposes.
-
-	   1) determine the prom-version and cpu/architecture
-	   2) print enough useful info before we start to execute
-	      c-code that I can possibly begin to debug things
-	   3) Hold the vector of trap entry points
-
-   The Sparc offers many challenges to kernel design. Here I will
-   document those I have come across thus far. Upon bootup the boot
-   prom loads your a.out image into memory. This memory the prom has
-   already mapped for you in two places, however as far as I can tell
-   the virtual address cache is not turned on although the MMU is
-   translating things. You get loaded at 0x4000 exactly and you are
-   aliased to 0xf8004000 with the appropriate mmu entries. So, when
-   you link a boot-loadable object you want to do something like:
-
-        ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o ....
-
-   to produce a proper image.
-
-   At boot time you are given (as far as I can tell at this time)
-   one key to figure out what machine you are one and what devices
-   are available. The prom when it loads you leaves a pointer to
-   the 'rom vector' in register %o0 right before it jumps to your
-   starting address. This is a pointer to a struct that is full of
-   pointer to functions (ie. printf, halt, reboot), pointers to
-   linked lists (ie. memory mappings), and pointer to empirical
-   constants (ie. stdin and stdout magic cookies + rom version).
-   Starting with this piece of information you can figure out 
-   just about anything you want about the machine you are on.
-
-   Although I don't use it now, if you are on a Multiprocessor and
-   therefore a v3 or above prom, register %o2 at boot contains a
-   function pointer you must call before you proceed to invoke the
-   other cpu's on the machine. I have no idea what kind of magic this
-   is, give me time.
-*/
+/* head.S: The initial boot code for the Sparc port of Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *         This file has to serve three purposes.
+ *
+ *	   1) determine the prom-version and cpu/architecture
+ *	   2) print enough useful info before we start to execute
+ *	      c-code that I can possibly begin to debug things
+ *	   3) Hold the vector of trap entry points
+ *
+ *  The Sparc offers many challenges to kernel design. Here I will
+ * document those I have come across thus far. Upon bootup the boot
+ * prom loads your a.out image into memory. This memory the prom has
+ * already mapped for you in two places, however as far as I can tell
+ * the virtual address cache is not turned on although the MMU is
+ * translating things. You get loaded at 0x4000 exactly and you are
+ * aliased to 0xf8004000 with the appropriate mmu entries. So, when
+ * you link a boot-loadable object you want to do something like
+ *
+ *      ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o ....
+ *
+ * to produce a proper image.
+ *
+ * At boot time you are given (as far as I can tell at this time)
+ * one key to figure out what machine you are one and what devices
+ * are available. The prom when it loads you leaves a pointer to
+ * the 'rom vector' in register %o0 right before it jumps to your
+ * starting address. This is a pointer to a struct that is full of
+ * pointer to functions (ie. printf, halt, reboot), pointers to
+ * linked lists (ie. memory mappings), and pointer to empirical
+ * constants (ie. stdin and stdout magic cookies + rom version).
+ * Starting with this piece of information you can figure out 
+ * just about anything you want about the machine you are on.
+ *
+ * Although I don't use it now, if you are on a Multiprocessor and
+ * therefore a v3 or above prom, register %o2 at boot contains a
+ * function pointer you must call before you proceed to invoke the
+ * other cpu's on the machine. I have no idea what kind of magic this
+ * is, give me time.
+ */
 
 #include <asm/cprefix.h>
 #include <asm/head.h>
-#include <asm/version.h>
+#include <linux/version.h>
 #include <asm/asi.h>
 #include <asm/contregs.h>
 #include <asm/psr.h>
 #include <asm/page.h>
+#include <asm/kdebug.h>
 
 	.data
 
@@ -54,6 +55,7 @@
 
         .globl  C_LABEL(intstack)
         .globl  C_LABEL(eintstack)
+	.align 4
 C_LABEL(intstack):
         .skip   4 * PAGE_SIZE                ! 16k = 128 128-byte stack frames
 C_LABEL(eintstack):
@@ -61,19 +63,24 @@
 
 
 /* 
-   The following are used with the prom_vector node-ops to figure out
-   the cpu-type 
-*/
+ * The following are used with the prom_vector node-ops to figure out
+ * the cpu-type 
+ */
 
+	.align 4
         .globl  C_LABEL(cputyp)
-
 C_LABEL(cputyp):
         .word   1
 
+	.align 4
+	.globl C_LABEL(cputypval)
 C_LABEL(cputypval):
 	.asciz "sun4c"
 	.ascii "     "
 
+C_LABEL(cputypvalend):
+C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
+
 	.align 4
 /*
  * Sun people can't spell worth damn. "compatability" indeed.
@@ -86,501 +93,740 @@
 C_LABEL(cputypvar):
 	.asciz "compatability"
 
-C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
-
-/* This hold the prom-interface-version number for either v0 or v2. */
-
+/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. --P3 */
 	.align 4
-	.globl 	C_LABEL(prom_iface_vers)
-
-C_LABEL(prom_iface_vers):	.skip 4
+C_LABEL(cputypvar_sun4m):
+	.asciz "compatible"
 
 /* WARNING: evil messages follow */
 
 	.align 4
 
 sun4_notsup:
-	.asciz  "Sparc-Linux: sun4 support not implemented yet\n\n"
-	.align 4
-
-sun4m_notsup:
-        .asciz  "Sparc-Linux: sun4m support does not exist\n\n"
+	.asciz  "Sparc-Linux sun4 support not implemented yet\n\n"
 	.align 4
 
 sun4d_notsup:
-        .asciz  "Sparc-Linux: sun4d support does not exist\n\n"
+        .asciz  "Sparc-Linux sun4d support does not exist\n\n"
 	.align 4
 
-you_lose:
-	.asciz	"You lose..... Thanks for playing...\n"
+sun4e_notsup:
+        .asciz  "Sparc-Linux sun4e support does not exist\n\n"
 	.align 4
 
+sun4u_notsup:
+        .asciz  "Sparc-Linux sun4u support does not exist\n\n"
+	.align 4
 
-	.globl boot_msg
-
-/* memory descriptor property strings, v2 = yuk yuk yuk  */
-/* XXX how to figure out vm mapped by prom? May have to scan magic addresses */
-
-mem_prop_physavail:	.asciz "available"
-	
-			.align 4
-mem_prop_phystot:	.asciz "reg"
-
-/* v2_memory descriptor struct kludged here for assembly, if it ain't broke */
-
-		.align 4
-v2_mem_struct: 	.skip 0xff
-
-			.align 4
-v2_printf_physavail:	.asciz "Physical Memory Available: 0x%x bytes"
-	
-			.align 4
-v2_printf_phystot:	.asciz "Physical Memory: 0x%x bytes"
-
-/* A place to store property strings returned from the prom 'node' funcs */
-
-			.align 4
-prop_string_buf:	.skip 32
-
-		.align 4
-prop_name:	.asciz "name"
-	
-		.align 4
-current_node:	.skip 4
-
-
-/* nice little boot message */
+/* Ok, things start to get interesting. We get linked such that 'start'
+ * is the entry symbol. However, it is real low in kernel address space
+ * and as such a nifty place to place the trap table. We achieve this goal
+ * by just jumping to 'gokernel' for the first trap's entry as the sparc
+ * never receives the zero trap as it is real special (hw reset).
+ *
+ * Each trap entry point is the size of 4 sparc instructions (or 4 bytes
+ * * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
+ * or unimplemented) and 128 software traps (sys-calls, etc.).
+ *
+ * One of the instructions must be a branch. More often than not this
+ * will be to a trap handler entry point because it is completely
+ * impossible to handle any trap in 4 insns. I welcome anyone to 
+ * challenge this theory. :-)
+ *
+ * On entry into this table the hardware has loaded the program counter
+ * at which the trap occurred into register %l1 and the next program
+ * counter into %l2, this way we can return from the trap with a simple
+ *
+ *         jmp %l1; rett %l2  ! poof...
+ *
+ * after properly servicing the trap. It wouldn't be a bad idea to load
+ * some more information into the local regs since we have technically
+ * 2 or 3 instructions to play with besides the jmp to the 'real' trap
+ * handler (one can even go in the delay slot). For now I am going to put
+ * the %psr (processor status register) and the trap-type value in %l0
+ * and %l3 respectively. Also, for IRQ's I'll put the level in %l4.
+ */
 
-		.align 4
-boot_msg:	
-	.ascii "Booting Sparc-Linux V0.00PRE-ALPHA "
-	.ascii WHO_COMPILED_ME 
-	.ascii "\r\n"
-	.align 4
+	.text
 
-	.globl boot_msg2
+	.globl	start
+	.globl 	_start  /* warning, solaris hack */
+	.globl  C_LABEL(trapbase)
+_start:   /* danger danger */
+start:
+C_LABEL(trapbase):
+/* XXX Grrr, this table is basically sun4c specific, sort of... XXX */
+/* We get control passed to us here at t_zero. */
+t_zero:	b gokernel; nop; nop; nop;
+
+t_tflt:	TRAP_ENTRY(0x1, sparc_text_fault)    /* Inst. Access Exception        */
+t_bins:	TRAP_ENTRY(0x2, bad_instruction)     /* Illegal Instruction           */
+t_pins:	TRAP_ENTRY(0x3, bad_instruction)     /* Privileged Instruction        */
+t_fpd:	TRAP_ENTRY(0x4, fpd_trap_handler)    /* Floating Point Disabled       */
+t_wovf:	TRAP_ENTRY(0x5, spill_window_entry)  /* Window Overflow               */
+t_wunf:	TRAP_ENTRY(0x6, fill_window_entry)   /* Window Underflow              */
+t_mna:	TRAP_ENTRY(0x7, mna_handler)         /* Memory Address Not Aligned    */
+t_fpe:	TRAP_ENTRY(0x8, fpe_trap_handler)    /* Floating Point Exception      */
+t_dflt:	TRAP_ENTRY(0x9, sparc_data_fault)    /* Data Miss Exception           */
+t_tio:	TRAP_ENTRY(0xa, do_tag_overflow)     /* Tagged Instruction Ovrflw     */
+t_wpt:	TRAP_ENTRY(0xb, do_watchpoint)       /* Watchpoint Detected           */
+t_badc:	TRAP_ENTRY(0xc, bad_trap_handler)    /* Undefined...                  */
+t_badd:	TRAP_ENTRY(0xd, bad_trap_handler)    /* Undefined...                  */
+t_bade:	TRAP_ENTRY(0xe, bad_trap_handler)    /* Undefined...                  */
+t_badf:	TRAP_ENTRY(0xf, bad_trap_handler)    /* Undefined...                  */
+t_bad10:TRAP_ENTRY(0x10, bad_trap_handler)   /* Undefined...                  */
+t_irq1:	TRAP_ENTRY_INTERRUPT(1)	             /* IRQ Software/SBUS Level 1     */
+t_irq2:	TRAP_ENTRY_INTERRUPT(2)              /* IRQ SBUS Level 2              */
+t_irq3:	TRAP_ENTRY_INTERRUPT(3)              /* IRQ SCSI/DMA/SBUS Level 3     */
+t_irq4:	TRAP_ENTRY_INTERRUPT(4)              /* IRQ Software Level 4          */
+t_irq5:	TRAP_ENTRY_INTERRUPT(5)              /* IRQ SBUS/Ethernet Level 5     */
+t_irq6:	TRAP_ENTRY_INTERRUPT(6)              /* IRQ Software Level 6          */
+t_irq7:	TRAP_ENTRY_INTERRUPT(7)              /* IRQ Video/SBUS Level 5        */
+t_irq8:	TRAP_ENTRY_INTERRUPT(8)              /* IRQ SBUS Level 6              */
+t_irq9:	TRAP_ENTRY_INTERRUPT(9)              /* IRQ SBUS Level 7              */
+t_irq10:TRAP_ENTRY_TIMER                     /* IRQ Timer #1 (one we use)     */
+t_irq11:TRAP_ENTRY_INTERRUPT(11)             /* IRQ Floppy Intr.              */
+t_irq12:TRAP_ENTRY_INTERRUPT(12)             /* IRQ Zilog serial chip         */
+t_irq13:TRAP_ENTRY_INTERRUPT(13)             /* IRQ Audio Intr.               */
+t_irq14:TRAP_ENTRY_INTERRUPT(14)             /* IRQ Timer #2                  */
+t_nmi:	NMI_TRAP                             /* Level 15 (NMI)                */
+t_racc:	TRAP_ENTRY(0x20, do_reg_access)      /* General Register Access Error */
+t_iacce:TRAP_ENTRY(0x21, do_iacc_error)      /* Instruction Access Error      */
+t_bad22:TRAP_ENTRY(0x22, bad_trap_handler)   /* Undefined...                  */
+t_bad23:TRAP_ENTRY(0x23, bad_trap_handler)   /* Undefined...                  */
+t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)     /* Co-Processor Disabled         */
+t_uflsh:TRAP_ENTRY(0x25, do_bad_flush)       /* Unimplemented FLUSH inst.     */
+t_bad26:TRAP_ENTRY(0x26, bad_trap_handler)   /* Undefined...                  */
+t_bad27:TRAP_ENTRY(0x27, bad_trap_handler)   /* Undefined...                  */
+t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)    /* Co-Processor Exception        */
+t_dacce:TRAP_ENTRY(0x29, do_dacc_error)      /* Data Access Error             */
+t_hwdz:	TRAP_ENTRY(0x2a, do_hw_divzero)      /* Division by zero, you lose... */
+t_dserr:TRAP_ENTRY(0x2b, do_dstore_err)      /* Data Store Error              */
+t_daccm:TRAP_ENTRY(0x2c, do_dacc_mmu_miss)   /* Data Access MMU-Miss          */
+t_bad2d:TRAP_ENTRY(0x2d, bad_trap_handler)   /* Undefined...                  */
+t_bad2e:TRAP_ENTRY(0x2e, bad_trap_handler)   /* Undefined...                  */
+t_bad2f:TRAP_ENTRY(0x2f, bad_trap_handler)   /* Undefined...                  */
+t_bad30:TRAP_ENTRY(0x30, bad_trap_handler)   /* Undefined...                  */
+t_bad31:TRAP_ENTRY(0x31, bad_trap_handler)   /* Undefined...                  */
+t_bad32:TRAP_ENTRY(0x32, bad_trap_handler)   /* Undefined...                  */
+t_bad33:TRAP_ENTRY(0x33, bad_trap_handler)   /* Undefined...                  */
+t_bad34:TRAP_ENTRY(0x34, bad_trap_handler)   /* Undefined...                  */
+t_bad35:TRAP_ENTRY(0x35, bad_trap_handler)   /* Undefined...                  */
+t_bad36:TRAP_ENTRY(0x36, bad_trap_handler)   /* Undefined...                  */
+t_bad37:TRAP_ENTRY(0x37, bad_trap_handler)   /* Undefined...                  */
+t_bad38:TRAP_ENTRY(0x38, bad_trap_handler)   /* Undefined...                  */
+t_bad39:TRAP_ENTRY(0x39, bad_trap_handler)   /* Undefined...                  */
+t_bad3a:TRAP_ENTRY(0x3a, bad_trap_handler)   /* Undefined...                  */
+t_bad3b:TRAP_ENTRY(0x3b, bad_trap_handler)   /* Undefined...                  */
+t_iaccm:TRAP_ENTRY(0x3c, do_iacc_mmu_miss)   /* Instruction Access MMU-Miss   */
+t_bad3d:TRAP_ENTRY(0x3d, bad_trap_handler)   /* Undefined...                  */
+t_bad3e:TRAP_ENTRY(0x3e, bad_trap_handler)   /* Undefined...                  */
+t_bad3f:TRAP_ENTRY(0x3f, bad_trap_handler)   /* Undefined...                  */
+t_bad40:TRAP_ENTRY(0x40, bad_trap_handler)   /* Undefined...                  */
+t_bad41:TRAP_ENTRY(0x41, bad_trap_handler)   /* Undefined...                  */
+t_bad42:TRAP_ENTRY(0x42, bad_trap_handler)   /* Undefined...                  */
+t_bad43:TRAP_ENTRY(0x43, bad_trap_handler)   /* Undefined...                  */
+t_bad44:TRAP_ENTRY(0x44, bad_trap_handler)   /* Undefined...                  */
+t_bad45:TRAP_ENTRY(0x45, bad_trap_handler)   /* Undefined...                  */
+t_bad46:TRAP_ENTRY(0x46, bad_trap_handler)   /* Undefined...                  */
+t_bad47:TRAP_ENTRY(0x47, bad_trap_handler)   /* Undefined...                  */
+t_bad48:TRAP_ENTRY(0x48, bad_trap_handler)   /* Undefined...                  */
+t_bad49:TRAP_ENTRY(0x49, bad_trap_handler)   /* Undefined...                  */
+t_bad4a:TRAP_ENTRY(0x4a, bad_trap_handler)   /* Undefined...                  */
+t_bad4b:TRAP_ENTRY(0x4b, bad_trap_handler)   /* Undefined...                  */
+t_bad4c:TRAP_ENTRY(0x4c, bad_trap_handler)   /* Undefined...                  */
+t_bad4d:TRAP_ENTRY(0x4d, bad_trap_handler)   /* Undefined...                  */
+t_bad4e:TRAP_ENTRY(0x4e, bad_trap_handler)   /* Undefined...                  */
+t_bad4f:TRAP_ENTRY(0x4f, bad_trap_handler)   /* Undefined...                  */
+t_bad50:TRAP_ENTRY(0x50, bad_trap_handler)   /* Undefined...                  */
+t_bad51:TRAP_ENTRY(0x51, bad_trap_handler)   /* Undefined...                  */
+t_bad52:TRAP_ENTRY(0x52, bad_trap_handler)   /* Undefined...                  */
+t_bad53:TRAP_ENTRY(0x53, bad_trap_handler)   /* Undefined...                  */
+t_bad54:TRAP_ENTRY(0x54, bad_trap_handler)   /* Undefined...                  */
+t_bad55:TRAP_ENTRY(0x55, bad_trap_handler)   /* Undefined...                  */
+t_bad56:TRAP_ENTRY(0x56, bad_trap_handler)   /* Undefined...                  */
+t_bad57:TRAP_ENTRY(0x57, bad_trap_handler)   /* Undefined...                  */
+t_bad58:TRAP_ENTRY(0x58, bad_trap_handler)   /* Undefined...                  */
+t_bad59:TRAP_ENTRY(0x59, bad_trap_handler)   /* Undefined...                  */
+t_bad5a:TRAP_ENTRY(0x5a, bad_trap_handler)   /* Undefined...                  */
+t_bad5b:TRAP_ENTRY(0x5b, bad_trap_handler)   /* Undefined...                  */
+t_bad5c:TRAP_ENTRY(0x5c, bad_trap_handler)   /* Undefined...                  */
+t_bad5d:TRAP_ENTRY(0x5d, bad_trap_handler)   /* Undefined...                  */
+t_bad5e:TRAP_ENTRY(0x5e, bad_trap_handler)   /* Undefined...                  */
+t_bad5f:TRAP_ENTRY(0x5f, bad_trap_handler)   /* Undefined...                  */
+t_bad60:TRAP_ENTRY(0x60, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad61:TRAP_ENTRY(0x61, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad62:TRAP_ENTRY(0x62, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad63:TRAP_ENTRY(0x63, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad64:TRAP_ENTRY(0x64, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad65:TRAP_ENTRY(0x65, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad66:TRAP_ENTRY(0x66, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad67:TRAP_ENTRY(0x67, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad68:TRAP_ENTRY(0x68, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad69:TRAP_ENTRY(0x69, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6a:TRAP_ENTRY(0x6a, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6b:TRAP_ENTRY(0x6b, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6c:TRAP_ENTRY(0x6c, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6d:TRAP_ENTRY(0x6d, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6e:TRAP_ENTRY(0x6e, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad6f:TRAP_ENTRY(0x6f, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad70:TRAP_ENTRY(0x70, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad71:TRAP_ENTRY(0x71, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad72:TRAP_ENTRY(0x72, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad73:TRAP_ENTRY(0x73, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad74:TRAP_ENTRY(0x74, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad75:TRAP_ENTRY(0x75, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad76:TRAP_ENTRY(0x76, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad77:TRAP_ENTRY(0x77, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad78:TRAP_ENTRY(0x78, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad79:TRAP_ENTRY(0x79, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7a:TRAP_ENTRY(0x7a, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7b:TRAP_ENTRY(0x7b, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7c:TRAP_ENTRY(0x7c, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7d:TRAP_ENTRY(0x7d, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7e:TRAP_ENTRY(0x7e, bad_trap_handler)   /* Impl-Dep Exception            */
+t_bad7f:TRAP_ENTRY(0x7f, bad_trap_handler)   /* Impl-Dep Exception            */
+t_sunos:SUNOS_SYSCALL_TRAP                   /* SunOS System Call             */
+t_sbkpt:TRAP_ENTRY(0x81, bad_trap_handler)   /* Software Breakpoint           */
+t_divz:	TRAP_ENTRY(0x82, bad_trap_handler)   /* Divide by zero trap           */
+t_flwin:TRAP_ENTRY(0x83, bad_trap_handler)   /* Flush Windows Trap            */
+t_clwin:TRAP_ENTRY(0x84, bad_trap_handler)   /* Clean Windows Trap            */
+t_rchk:	TRAP_ENTRY(0x85, bad_trap_handler)   /* Range Check                   */
+t_funal:TRAP_ENTRY(0x86, bad_trap_handler)   /* Fix Unaligned Access Trap     */
+t_iovf:	TRAP_ENTRY(0x87, bad_trap_handler)   /* Integer Overflow Trap         */
+t_slowl:SOLARIS_SYSCALL_TRAP                 /* Slowaris System Call          */
+t_netbs:NETBSD_SYSCALL_TRAP                  /* Net-B.S. System Call          */
+t_bad8a:TRAP_ENTRY(0x8a, bad_trap_handler)   /* Software Trap                 */
+t_bad8b:TRAP_ENTRY(0x8b, bad_trap_handler)   /* Software Trap                 */
+t_bad8c:TRAP_ENTRY(0x8c, bad_trap_handler)   /* Software Trap                 */
+t_bad8d:TRAP_ENTRY(0x8d, bad_trap_handler)   /* Software Trap                 */
+t_bad8e:TRAP_ENTRY(0x8e, bad_trap_handler)   /* Software Trap                 */
+t_bad8f:TRAP_ENTRY(0x8f, bad_trap_handler)   /* Software Trap                 */
+t_linux:LINUX_SYSCALL_TRAP                   /* Linux System Call             */
+t_bad91:TRAP_ENTRY(0x91, bad_trap_handler)   /* Software Trap                 */
+t_bad92:TRAP_ENTRY(0x92, bad_trap_handler)   /* Software Trap                 */
+t_bad93:TRAP_ENTRY(0x93, bad_trap_handler)   /* Software Trap                 */
+t_bad94:TRAP_ENTRY(0x94, bad_trap_handler)   /* Software Trap                 */
+t_bad95:TRAP_ENTRY(0x95, bad_trap_handler)   /* Software Trap                 */
+t_bad96:TRAP_ENTRY(0x96, bad_trap_handler)   /* Software Trap                 */
+t_bad97:TRAP_ENTRY(0x97, bad_trap_handler)   /* Software Trap                 */
+t_bad98:TRAP_ENTRY(0x98, bad_trap_handler)   /* Software Trap                 */
+t_bad99:TRAP_ENTRY(0x99, bad_trap_handler)   /* Software Trap                 */
+t_bad9a:TRAP_ENTRY(0x9a, bad_trap_handler)   /* Software Trap                 */
+t_bad9b:TRAP_ENTRY(0x9b, bad_trap_handler)   /* Software Trap                 */
+t_bad9c:TRAP_ENTRY(0x9c, bad_trap_handler)   /* Software Trap                 */
+t_bad9d:TRAP_ENTRY(0x9d, bad_trap_handler)   /* Software Trap                 */
+t_bad9e:TRAP_ENTRY(0x9e, bad_trap_handler)   /* Software Trap                 */
+t_bad9f:TRAP_ENTRY(0x9f, bad_trap_handler)   /* Software Trap                 */
+t_getcc:GETCC_TRAP                           /* Get Condition Codes           */
+t_setcc:SETCC_TRAP                           /* Set Condition Codes           */
+t_bada2:TRAP_ENTRY(0xa2, bad_trap_handler)   /* Software Trap                 */
+t_bada3:TRAP_ENTRY(0xa3, bad_trap_handler)   /* Software Trap                 */
+t_bada4:TRAP_ENTRY(0xa4, bad_trap_handler)   /* Software Trap                 */
+t_bada5:TRAP_ENTRY(0xa5, bad_trap_handler)   /* Software Trap                 */
+t_bada6:TRAP_ENTRY(0xa6, bad_trap_handler)   /* Software Trap                 */
+t_bada7:TRAP_ENTRY(0xa7, bad_trap_handler)   /* Software Trap                 */
+t_bada8:TRAP_ENTRY(0xa8, bad_trap_handler)   /* Software Trap                 */
+t_bada9:TRAP_ENTRY(0xa9, bad_trap_handler)   /* Software Trap                 */
+t_badaa:TRAP_ENTRY(0xaa, bad_trap_handler)   /* Software Trap                 */
+t_badab:TRAP_ENTRY(0xab, bad_trap_handler)   /* Software Trap                 */
+t_badac:TRAP_ENTRY(0xac, bad_trap_handler)   /* Software Trap                 */
+t_badad:TRAP_ENTRY(0xad, bad_trap_handler)   /* Software Trap                 */
+t_badae:TRAP_ENTRY(0xae, bad_trap_handler)   /* Software Trap                 */
+t_badaf:TRAP_ENTRY(0xaf, bad_trap_handler)   /* Software Trap                 */
+t_badb0:TRAP_ENTRY(0xb0, bad_trap_handler)   /* Software Trap                 */
+t_badb1:TRAP_ENTRY(0xb1, bad_trap_handler)   /* Software Trap                 */
+t_badb2:TRAP_ENTRY(0xb2, bad_trap_handler)   /* Software Trap                 */
+t_badb3:TRAP_ENTRY(0xb3, bad_trap_handler)   /* Software Trap                 */
+t_badb4:TRAP_ENTRY(0xb4, bad_trap_handler)   /* Software Trap                 */
+t_badb5:TRAP_ENTRY(0xb5, bad_trap_handler)   /* Software Trap                 */
+t_badb6:TRAP_ENTRY(0xb6, bad_trap_handler)   /* Software Trap                 */
+t_badb7:TRAP_ENTRY(0xb7, bad_trap_handler)   /* Software Trap                 */
+t_badb8:TRAP_ENTRY(0xb8, bad_trap_handler)   /* Software Trap                 */
+t_badb9:TRAP_ENTRY(0xb9, bad_trap_handler)   /* Software Trap                 */
+t_badba:TRAP_ENTRY(0xba, bad_trap_handler)   /* Software Trap                 */
+t_badbb:TRAP_ENTRY(0xbb, bad_trap_handler)   /* Software Trap                 */
+t_badbc:TRAP_ENTRY(0xbc, bad_trap_handler)   /* Software Trap                 */
+t_badbd:TRAP_ENTRY(0xbd, bad_trap_handler)   /* Software Trap                 */
+t_badbe:TRAP_ENTRY(0xbe, bad_trap_handler)   /* Software Trap                 */
+t_badbf:TRAP_ENTRY(0xbf, bad_trap_handler)   /* Software Trap                 */
+t_badc0:TRAP_ENTRY(0xc0, bad_trap_handler)   /* Software Trap                 */
+t_badc1:TRAP_ENTRY(0xc1, bad_trap_handler)   /* Software Trap                 */
+t_badc2:TRAP_ENTRY(0xc2, bad_trap_handler)   /* Software Trap                 */
+t_badc3:TRAP_ENTRY(0xc3, bad_trap_handler)   /* Software Trap                 */
+t_badc4:TRAP_ENTRY(0xc4, bad_trap_handler)   /* Software Trap                 */
+t_badc5:TRAP_ENTRY(0xc5, bad_trap_handler)   /* Software Trap                 */
+t_badc6:TRAP_ENTRY(0xc6, bad_trap_handler)   /* Software Trap                 */
+t_badc7:TRAP_ENTRY(0xc7, bad_trap_handler)   /* Software Trap                 */
+t_badc8:TRAP_ENTRY(0xc8, bad_trap_handler)   /* Software Trap                 */
+t_badc9:TRAP_ENTRY(0xc9, bad_trap_handler)   /* Software Trap                 */
+t_badca:TRAP_ENTRY(0xca, bad_trap_handler)   /* Software Trap                 */
+t_badcb:TRAP_ENTRY(0xcb, bad_trap_handler)   /* Software Trap                 */
+t_badcc:TRAP_ENTRY(0xcc, bad_trap_handler)   /* Software Trap                 */
+t_badcd:TRAP_ENTRY(0xcd, bad_trap_handler)   /* Software Trap                 */
+t_badce:TRAP_ENTRY(0xce, bad_trap_handler)   /* Software Trap                 */
+t_badcf:TRAP_ENTRY(0xcf, bad_trap_handler)   /* Software Trap                 */
+t_badd0:TRAP_ENTRY(0xd0, bad_trap_handler)   /* Software Trap                 */
+t_badd1:TRAP_ENTRY(0xd1, bad_trap_handler)   /* Software Trap                 */
+t_badd2:TRAP_ENTRY(0xd2, bad_trap_handler)   /* Software Trap                 */
+t_badd3:TRAP_ENTRY(0xd3, bad_trap_handler)   /* Software Trap                 */
+t_badd4:TRAP_ENTRY(0xd4, bad_trap_handler)   /* Software Trap                 */
+t_badd5:TRAP_ENTRY(0xd5, bad_trap_handler)   /* Software Trap                 */
+t_badd6:TRAP_ENTRY(0xd6, bad_trap_handler)   /* Software Trap                 */
+t_badd7:TRAP_ENTRY(0xd7, bad_trap_handler)   /* Software Trap                 */
+t_badd8:TRAP_ENTRY(0xd8, bad_trap_handler)   /* Software Trap                 */
+t_badd9:TRAP_ENTRY(0xd9, bad_trap_handler)   /* Software Trap                 */
+t_badda:TRAP_ENTRY(0xda, bad_trap_handler)   /* Software Trap                 */
+t_baddb:TRAP_ENTRY(0xdb, bad_trap_handler)   /* Software Trap                 */
+t_baddc:TRAP_ENTRY(0xdc, bad_trap_handler)   /* Software Trap                 */
+t_baddd:TRAP_ENTRY(0xdd, bad_trap_handler)   /* Software Trap                 */
+t_badde:TRAP_ENTRY(0xde, bad_trap_handler)   /* Software Trap                 */
+t_baddf:TRAP_ENTRY(0xdf, bad_trap_handler)   /* Software Trap                 */
+t_bade0:TRAP_ENTRY(0xe0, bad_trap_handler)   /* Software Trap                 */
+t_bade1:TRAP_ENTRY(0xe1, bad_trap_handler)   /* Software Trap                 */
+t_bade2:TRAP_ENTRY(0xe2, bad_trap_handler)   /* Software Trap                 */
+t_bade3:TRAP_ENTRY(0xe3, bad_trap_handler)   /* Software Trap                 */
+t_bade4:TRAP_ENTRY(0xe4, bad_trap_handler)   /* Software Trap                 */
+t_bade5:TRAP_ENTRY(0xe5, bad_trap_handler)   /* Software Trap                 */
+t_bade6:TRAP_ENTRY(0xe6, bad_trap_handler)   /* Software Trap                 */
+t_bade7:TRAP_ENTRY(0xe7, bad_trap_handler)   /* Software Trap                 */
+t_bade8:TRAP_ENTRY(0xe8, bad_trap_handler)   /* Software Trap                 */
+t_bade9:TRAP_ENTRY(0xe9, bad_trap_handler)   /* Software Trap                 */
+t_badea:TRAP_ENTRY(0xea, bad_trap_handler)   /* Software Trap                 */
+t_badeb:TRAP_ENTRY(0xeb, bad_trap_handler)   /* Software Trap                 */
+t_badec:TRAP_ENTRY(0xec, bad_trap_handler)   /* Software Trap                 */
+t_baded:TRAP_ENTRY(0xed, bad_trap_handler)   /* Software Trap                 */
+t_badee:TRAP_ENTRY(0xee, bad_trap_handler)   /* Software Trap                 */
+t_badef:TRAP_ENTRY(0xef, bad_trap_handler)   /* Software Trap                 */
+t_badf0:TRAP_ENTRY(0xf0, bad_trap_handler)   /* Software Trap                 */
+t_badf1:TRAP_ENTRY(0xf1, bad_trap_handler)   /* Software Trap                 */
+t_badf2:TRAP_ENTRY(0xf2, bad_trap_handler)   /* Software Trap                 */
+t_badf3:TRAP_ENTRY(0xf3, bad_trap_handler)   /* Software Trap                 */
+t_badf4:TRAP_ENTRY(0xf4, bad_trap_handler)   /* Software Trap                 */
+t_badf5:TRAP_ENTRY(0xf5, bad_trap_handler)   /* Software Trap                 */
+t_badf6:TRAP_ENTRY(0xf6, bad_trap_handler)   /* Software Trap                 */
+t_badf7:TRAP_ENTRY(0xf7, bad_trap_handler)   /* Software Trap                 */
+t_badf8:TRAP_ENTRY(0xf8, bad_trap_handler)   /* Software Trap                 */
+t_badf9:TRAP_ENTRY(0xf9, bad_trap_handler)   /* Software Trap                 */
+t_badfa:TRAP_ENTRY(0xfa, bad_trap_handler)   /* Software Trap                 */
+t_badfb:TRAP_ENTRY(0xfb, bad_trap_handler)   /* Software Trap                 */
+t_badfc:TRAP_ENTRY(0xfc, bad_trap_handler)   /* Software Trap                 */
+t_badfd:TRAP_ENTRY(0xfd, bad_trap_handler)   /* Software Trap                 */
+dbtrap:	TRAP_ENTRY(0xfe, bad_trap_handler)   /* Debugger/PROM breakpoint #1   */
+dbtrap2:TRAP_ENTRY(0xff, bad_trap_handler)   /* Debugger/PROM breakpoint #2   */	
 
-boot_msg2:
-	.asciz "Booting Sparclinux V0.00 PRE-ALPHA on a (SUN4C)\r\n\n"
+	.globl	C_LABEL(end_traptable)
+C_LABEL(end_traptable):
 
-	.align 4
+	.skip 4096
 
-pstring1:
-	.asciz "Prom Magic Cookie: 0x%x  \n"
-	.align 4
+/* This was the only reasonable way I could think of to properly align
+ * these page-table data structures.
+ *
+ * XXX swapper_pg_dir is going to have to be 'per-CPU' for SMP support
+ */
 
-pstring2:
-	.asciz "Interface Version: v%d\n"
-	.align 4
+	.globl C_LABEL(auxio_reg_addr)
+C_LABEL(auxio_reg_addr):	.skip	(PAGE_SIZE)
 
-pstring3:
-	.asciz "Prom Revision: V%d\n\n"
-	.align 4
+	.globl C_LABEL(clock_reg_addr)
+C_LABEL(clock_reg_addr):	.skip	(PAGE_SIZE*5)
 
-pstring4:
-	.ascii "Total Physical Memory: %d bytes\nVM mapped by Prom: %d bytes\n"
-	.asciz "Available Physical Memory: %d bytes\n"
-	.align 4
+	.globl C_LABEL(int_reg_addr)
+C_LABEL(int_reg_addr):		.skip	(PAGE_SIZE*5)
 
+	.globl C_LABEL(pg0)
+	.globl C_LABEL(empty_bad_page)
+	.globl C_LABEL(empty_bad_page_table)
+	.globl C_LABEL(empty_zero_page)
+	.globl C_LABEL(swapper_pg_dir)
+C_LABEL(swapper_pg_dir):		.skip 0x1000
+C_LABEL(pg0):				.skip 0x1000
+C_LABEL(empty_bad_page):		.skip 0x1000
+C_LABEL(empty_bad_page_table):		.skip 0x1000
+C_LABEL(empty_zero_page):		.skip 0x1000
 
-	.text
 
-        .globl  C_LABEL(msgbuf)
-msgbufsize = PAGE_SIZE                       ! 1 page for msg buffer
-C_LABEL(msgbuf) =  PAGE_SIZE
+/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
+ * %g7 and at prom_vector_p. And also quickly check whether we are on
+ * a v0, v2, or v3 prom.  We also get a debug structure of some sort from
+ * the boot loader (or is it the prom?) in %o1.  Finally a call back vector
+ * is passed in %o2.  I think this is how you register yourself with a
+ * debugger.  I do know that it wants my %o7 (return PC - 8) as it's
+ * first argument.  I will poke around and figure out what the debug
+ * vector is, it could contain useful stuff.
+ */
 
+/* Grrr, in order to be Sparc ABI complient, the kernel has to live in
+ * an address space above 0xe0000000  ;(  Must remain position independant
+ * until we 'remap' ourselves from low to high addresses.  We only map the
+ * first 3MB of addresses into upper ram as that is how much the PROM
+ * promises to set up for us.
+ */
+gokernel:
+		/* Ok, it's nice to know, as early as possible, if we
+		 * are already mapped where we expect to be in virtual
+		 * memory.  The Solaris /boot elf format bootloader
+		 * will peek into our elf header and load us where
+		 * we want to be, otherwise we have to re-map.
+		 *
+		 * Some boot loaders don't place the jmp'rs address
+		 * in %o7, so we do a pc-relative call to a local
+		 * label, then see what %o7 has.
+		 */
+
+		/* XXX Sparc V9 detection goes here XXX */
+
+		or	%g0, %o7, %g4		! Save %o7
+
+		/* Jump to it, and pray... */
+current_pc:
+		call	1f
+		nop
 
-IE_reg_addr = C_LABEL(msgbuf) + msgbufsize   ! this page not used; points to IEreg
+1:
+		or	%g0, %o7, %g3
 
+got_pc:
+		or	%g0, %g4, %o7	/* Previous %o7. */
 	
-/* Ok, things start to get interesting. We get linked such that 'start'
-   is the entry symbol. However, it is real low in kernel address space
-   and as such a nifty place to place the trap table. We achieve this goal
-   by just jumping to 'gokernel' for the first trap's entry as the sparc
-   never receives the zero trap as it is real special (hw reset).
-
-   Each trap entry point is the size of 4 sparc instructions (or 4 bytes
-   * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
-   or unimplemented) and 128 software traps (sys-calls, etc.).
-
-   One of the instructions must be a branch. More often than not this
-   will be to a trap handler entry point because it is completely
-   impossible to handle any trap in 4 insns. I welcome anyone to 
-   challenge this theory. :-)
-
-   On entry into this table the hardware has loaded the program counter
-   at which the trap occurred into register %l1 and the next program
-   counter into %l2, this way we can return from the trap with a simple
-
-           jmp %l1; rett %l2  ! poof...
-
-   after properly servicing the trap. It wouldn't be a bad idea to load
-   some more information into the local regs since we have technically
-   2 or 3 instructions to play with besides the jmp to the 'real' trap
-   handler (one can even go in the delay slot). For now I am going to put
-   the %psr (processor status register) and the trap-type value in %l0
-   and %l3 respectively. Also, for IRQ's I'll put the level in %l4.
+		or	%g0, %o0, %l0		! stash away romvec
+		or	%g0, %o0, %g7		! put it here too
+		or	%g0, %o1, %l1		! stash away debug_vec too
+		rd	%psr, %l2		! Save psr
+		rd	%wim, %l3		! wim
+		rd	%tbr, %l4		! tbr
+		or	%g0, %o2, %l5		! and the possible magic func
+
+		/* Ok, let's check out our run time program counter. */
+		set	current_pc, %g5
+		cmp	%g3, %g5
+		be	already_mapped
+
+		/* %l6 will hold the offset we have to subtract
+		 * from absolute symbols in order to access areas
+		 * in our own image.  If already mapped this is
+		 * just plain zero, else it is PAGE_OFFSET which is
+		 * also KERNBASE.
+		 */
+		set	PAGE_OFFSET, %l6
+		b	copy_prom_lvl14
+		nop
+
+already_mapped:
+		or	%g0, %g0, %l6
+
+		/* Copy over the Prom's level 14 clock handler. */
+copy_prom_lvl14:
+		rd	%tbr, %g1
+		andn	%g1, 0xfff, %g1		! proms trap table base
+		or	%g0, (0x1e<<4), %g2	! offset to lvl14 intr
+		or	%g1, %g2, %g2
+		set	t_irq14, %g3
+		sub	%g3, %l6, %g3
+		ldd	[%g2], %g4
+		std	%g4, [%g3]
+		ldd	[%g2 + 0x8], %g4
+		std	%g4, [%g3 + 0x8]	! Copy proms handler
+
+		/* Copy over the Prom/debugger's trap entry points. */
+copy_prom_bpoint:
+		or	%g0, (0xfe<<4), %g2
+		or	%g1, %g2, %g2
+		set	dbtrap, %g3
+		sub	%g3, %l6, %g3
+		ldd	[%g2], %g4
+		std	%g4, [%g3]
+		ldd	[%g2 + 0x8], %g4
+		std	%g4, [%g3 + 0x8]
+		ldd	[%g2 + 0x10], %g4
+		std	%g4, [%g3 + 0x10]
+		ldd	[%g2 + 0x18], %g4
+		std	%g4, [%g3 + 0x18]
+
+copy_prom_done:
+		ld	[%o0 + 0x4], %g1
+		and	%g1, 0x3, %g1
+		subcc	%g1, 0x0, %g0
+		be	set_sane_psr		! Not on v0 proms
+		nop
+
+		subcc	%o2, 0x0, %g0		! check for boot routine pointer
+		bz	set_sane_psr
+		nop
+		jmpl    %o2, %o7		! call boot setup func
+		add	%o7, 0x8, %o0
+
+set_sane_psr:
+		/* Traps are on, kadb can be tracing through here.  But
+		 * we have no clue what the PIL is. So we set up a sane
+		 * %psr, but preserve CWP or our locals could disappear!
+		 */
+		rd	%psr, %g2
+		and	%g2, 0x1f, %g2			! %g2 has CWP now
+		set	(PSR_S|PSR_PIL), %g1		! Supervisor + PIL high
+		or	%g1, %g2, %g1			! mix mix mix
+		wr	%g1, 0x0, %psr			! let PIL set in
+		wr	%g1, PSR_ET, %psr		! now turn on traps
+
+		/* A note about the last two instructions...
+		 * If you are going to increase PIL and turn on
+		 * traps at the same time you are asking for trouble.
+		 * You MUST set a %psr with traps off containing
+		 * your new PIL, then turn on the ET bit with the
+		 * next write.  On certain buggy Sparc chips if you
+		 * set both at the same time you can get a Watchdog
+		 * Reset under certain conditions.  This is no fun.
+		 * Basically the PIL bits get there before the
+		 * EnableTrap bit does or something like that.
+		 */
 
-*/
+		/* Insane asylum... */
+		WRITE_PAUSE
 
-	.globl	start
-	.globl 	_start  /* warning, solaris hack */
-	.globl  C_LABEL(trapbase)
-_start:   /* danger danger */
-start:
-C_LABEL(trapbase):
-	b gokernel; nop; nop; nop;	! we never get trap #0 it is special 
+/* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
+ * MMU so we can remap ourselves properly.  DONT TOUCH %l0 thru %l5 in these
+ * remapping routines, we need their values afterwards!
+ *
+ * XXX UGH, need to write some sun4u SpitFire remapping V9 code RSN... XXX
+ */
+		/* Now check whether we are already mapped, if we
+		 * are we can skip all this garbage coming up.
+		 */
+		subcc	%l6, 0x0, %g0
+		bz	go_to_highmem		! this will be a nop then
+		nop
 
-	TRAP_ENTRY(0x1, my_trap_handler) /* Instruction Access Exception */
-	TRAP_ENTRY(0x2, my_trap_handler) /* Illegal Instruction */
-	TRAP_ENTRY(0x3, my_trap_handler) /* Privileged Instruction */
-	TRAP_ENTRY(0x4, my_trap_handler) /* Floating Point Disabled */
-	TRAP_ENTRY(0x5, spill_window_entry)   /* Window Overflow */
-	TRAP_ENTRY(0x6, fill_window_entry)  /* Window Underflow */
-	TRAP_ENTRY(0x7, my_trap_handler) /* Memory Address Not Aligned */
-	TRAP_ENTRY(0x8, my_trap_handler) /* Floating Point Exception */
-	TRAP_ENTRY(0x9, my_trap_handler) /* Data Miss Exception */
-	TRAP_ENTRY(0xa, my_trap_handler) /* Tagged Instruction Overflow */
-	TRAP_ENTRY(0xb, my_trap_handler) /* Watchpoint Detected */
-	TRAP_ENTRY(0xc, my_trap_handler) /* Undefined... */
-	TRAP_ENTRY(0xd, my_trap_handler) /* Undefined... */
-	TRAP_ENTRY(0xe, my_trap_handler) /* Undefined... */
-	TRAP_ENTRY(0xf, my_trap_handler) /* Undefined... */
-	TRAP_ENTRY(0x10, my_trap_handler) /* Undefined... */
-
-/* Level'd interrupt entry points, see macro defs above */
-
-        TRAP_ENTRY_INTERRUPT_SOFT(1, 0x101) /* IRQ Software/SBUS Level 1  */
-        TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2           */
-        TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3  */
-        TRAP_ENTRY_INTERRUPT_SOFT(4, 0x104) /* IRQ Software Level 4       */
-        TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5  */
-        TRAP_ENTRY_INTERRUPT_SOFT(6, 0x106) /* IRQ Software Level 6       */
-        TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5     */
-        TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6           */
-        TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7           */
-        TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1               */
-        TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.           */
-        TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip      */
-        TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.            */
-        TRAP_ENTRY_TIMER                    /* IRQ Timer #2 (one we use)  */
-        TRAP_ENTRY_INTERRUPT_NMI(15, linux_trap_nmi) /* Level 15 (nmi) */
-
-	TRAP_ENTRY(0x20, my_trap_handler)   /* General Register Access Error */
-	TRAP_ENTRY(0x21, my_trap_handler)   /* Instruction Access Error      */
-	TRAP_ENTRY(0x22, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x23, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x24, my_trap_handler)   /* Co-Processor Disabled         */
-	TRAP_ENTRY(0x25, my_trap_handler)   /* Unimplemented FLUSH inst.     */
-	TRAP_ENTRY(0x26, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x27, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x28, my_trap_handler)   /* Co-Processor Exception        */
-	TRAP_ENTRY(0x29, my_trap_handler)   /* Data Access Error             */
-	TRAP_ENTRY(0x2a, my_trap_handler)   /* Division by zero, you lose... */
-	TRAP_ENTRY(0x2b, my_trap_handler)   /* Data Store Error              */
-	TRAP_ENTRY(0x2c, my_trap_handler)   /* Data Access MMU-Miss          */
-	TRAP_ENTRY(0x2d, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x2e, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x2f, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x30, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x31, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x32, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x33, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x34, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x35, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x36, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x37, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x38, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x39, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x3a, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x3b, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x3c, my_trap_handler)   /* Instruction Access MMU-Miss   */
-	TRAP_ENTRY(0x3d, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x3e, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x3f, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x40, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x41, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x42, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x43, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x44, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x45, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x46, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x47, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x48, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x49, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x4a, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x4b, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x4c, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x4d, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x4e, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x4f, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x50, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x51, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x52, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x53, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x54, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x55, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x56, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x57, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x58, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x59, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x5a, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x5b, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x5c, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x5d, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x5e, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x5f, my_trap_handler)   /* Undefined...                  */
-	TRAP_ENTRY(0x60, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x61, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x62, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x63, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x64, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x65, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x66, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x67, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x68, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x69, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x6a, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x6b, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x6c, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x6d, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x6e, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x6f, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x70, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x71, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x72, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x73, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x74, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x75, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x76, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x77, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x78, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x79, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x7a, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x7b, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x7c, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x7d, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x7e, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x7f, my_trap_handler)   /* Impl-Dep Exception            */
-	TRAP_ENTRY(0x80, my_trap_handler)   /* SunOS System Call             */
-	TRAP_ENTRY(0x81, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x82, my_trap_handler)   /* Divide by zero trap XXX       */
-	TRAP_ENTRY(0x83, my_trap_handler)   /* Flush Windows Trap XXX        */
-	TRAP_ENTRY(0x84, my_trap_handler)   /* Clean Windows Trap XXX        */
-	TRAP_ENTRY(0x85, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x86, my_trap_handler)   /* Fix Unaligned Access Trap XXX */
-	TRAP_ENTRY(0x87, my_trap_handler)   /* Integer Overflow Trap XXX     */
-	TRAP_ENTRY(0x88, my_trap_handler)   /* Slowaris System Call          */
-	TRAP_ENTRY(0x89, my_trap_handler)   /* NetBSD System Call            */
-	TRAP_ENTRY(0x8a, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x8b, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x8c, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x8d, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x8e, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x8f, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x90, my_trap_handler)   /* SparcLinux System Call        */
-	TRAP_ENTRY(0x91, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x92, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x93, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x94, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x95, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x96, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x97, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x98, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x99, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x9a, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x9b, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x9c, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x9d, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x9e, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0x9f, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa0, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa1, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa2, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa3, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa4, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa5, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa6, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa7, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa8, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xa9, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xaa, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xab, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xac, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xad, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xae, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xaf, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb0, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb1, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb2, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb3, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb4, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb5, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb6, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb7, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb8, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xb9, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xba, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xbb, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xbc, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xbd, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xbe, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xbf, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc0, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc1, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc2, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc3, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc4, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc5, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc6, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc7, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc8, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xc9, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xca, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xcb, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xcc, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xcd, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xce, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xcf, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd0, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd1, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd2, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd3, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd4, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd5, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd6, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd7, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd8, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xd9, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xda, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xdb, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xdc, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xdd, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xde, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xdf, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe0, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe1, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe2, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe3, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe4, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe5, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe6, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe7, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe8, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xe9, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xea, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xeb, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xec, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xed, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xee, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xef, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf0, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf1, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf2, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf3, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf4, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf5, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf6, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf7, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf8, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xf9, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xfa, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xfb, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xfc, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xfd, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xfe, my_trap_handler)   /* Software Trap                 */
-	TRAP_ENTRY(0xff, my_trap_handler)   /* Software Trap                 */	
+		sethi	%hi(LOAD_ADDR), %g6
+		subcc	%g7, %g6, %g0
+		bne	remap_not_a_sun4	! This is not a Sun4
+		nop
 
-	.skip 4096
+		or	%g0, 0x1, %g1
+		lduba	[%g1] ASI_CONTROL, %g1	! Only safe to try on Sun4.
+		subcc	%g1, 0x24, %g0		! Is this a mutant Sun4/400???
+		be	sun4_mutant_remap	! Ugh, it is...
+		nop
 
-C_LABEL(msgbufmapped):
-        .word   1
+remap_not_a_sun4:
+		lda	[%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c
+		and	%g1, 0x1, %g1		! Test SRMMU Enable bit ;-)
+		subcc	%g1, 0x0, %g0
+		bz	sun4c_remap		! A sun4c MMU or normal Sun4
+		nop
+srmmu_remap:
+		/* First, check for a viking (TI) module. */
+		set	0x40000000, %g2
+		rd	%psr, %g3
+		and	%g2, %g3, %g3
+		subcc	%g3, 0x0, %g0
+		bz	srmmu_nviking
+		nop
+
+		/* Figure out what kind of viking we are on.
+		 * We need to know if we have to play with the
+		 * AC bit and disable traps or not.
+		 */
+
+		/* I've only seen MicroSparc's on SparcClassics with this
+		 * bit set.
+		 */
+		set	0x800, %g2
+		lda	[%g0] ASI_M_MMUREGS, %g3	! peek in the control reg
+		and	%g2, %g3, %g3
+		subcc	%g3, 0x0, %g0
+		bnz	srmmu_nviking			! is in mbus mode
+		nop
+		
+		rd	%psr, %g3			! DONT TOUCH %g3
+		andn	%g3, PSR_ET, %g2
+		wr	%g2, 0x0, %psr
+		WRITE_PAUSE
+		
+		/* Get context table pointer, then convert to
+		 * a physical address, which is 36 bits.
+		 */
+		set	AC_M_CTPR, %g4
+		lda	[%g4] ASI_M_MMUREGS, %g4
+		sll	%g4, 0x4, %g4			! We use this below
+							! DONT TOUCH %g4
+
+		/* Set the AC bit in the Viking's MMU control reg. */
+		lda	[%g0] ASI_M_MMUREGS, %g5	! DONT TOUCH %g5
+		set	0x8000, %g6			! AC bit mask
+		or	%g5, %g6, %g6			! Or it in...
+		sta	%g6, [%g0] ASI_M_MMUREGS	! Close your eyes...
+
+		/* Grrr, why does it seem like every other load/store
+		 * on the sun4m is in some ASI space...
+		 * Fine with me, let's get the pointer to the level 1
+		 * page table directory and fetch it's entry.
+		 */
+		lda	[%g4] ASI_M_BYPASS, %o1		! This is a level 1 ptr
+		srl	%o1, 0x4, %o1			! Clear low 4 bits
+		sll	%o1, 0x8, %o1			! Make physical
+		
+		/* Ok, pull in the PTD. */
+		lda	[%o1] ASI_M_BYPASS, %o2		! This is the 0x0 16MB pgd
+
+		/* Calculate to KERNBASE entry.
+		 *
+		 * XXX Should not use imperical constant, but Gas gets an  XXX
+		 * XXX upset stomach with the bitshift I would have to use XXX
+		 */
+		add	%o1, 0x3c0, %o3		
+
+		/* Poke the entry into the calculated address. */
+		sta	%o2, [%o3] ASI_M_BYPASS
+
+		/* I don't get it Sun, if you engineered all these
+		 * boot loaders and the PROM (thank you for the debugging
+		 * features btw) why did you not have them load kernel
+		 * images up in high address space, since this is necessary
+		 * for ABI compliance anyways?  Does this low-mapping provide
+		 * enhanced interoperability?
+		 *
+		 * "The PROM is the computer."
+		 */
 
+		/* Ok, restore the MMU control register we saved in %g5 */
+		sta	%g5, [%g0] ASI_M_MMUREGS	! POW... ouch
 
+		/* Turn traps back on.  We saved it in %g3 earlier. */
+		wr	%g3, 0x0, %psr			! tick tock, tick tock
 
-/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
-   %g7 and at _prom_vector_p. And also quickly check whether we are on
-   a v0 or v2 prom.
-*/
+		/* Now we burn precious CPU cycles due to bad engineering. */
+		WRITE_PAUSE
 
-gokernel:	or	%g0, %o0, %g7
-		sethi	%hi( C_LABEL(prom_vector_p) ), %g1
-		st	%o0, [%g1 + %lo( C_LABEL(prom_vector_p) )]   ! we will need it later
-		rd	%psr, %l2
-		rd	%wim, %l3
-		rd	%tbr, %l4
-		or	%g0, %o2, %l5		! could be prom magic value...
-	
-#if 0 /* You think I'm nutz? */
-		subcc	%l5, 0x0, %g0		! check for magic SMP pointer
-		bne	nosmp	
-		nop
-		call    %o2			! call smp prom setup 
+		/* Wow, all that just to move a 32-bit value from one
+		 * place to another...  Jump to high memory.
+		 */
+		b	go_to_highmem
+		nop
+
+		/* This works on viking's in Mbus mode and all
+		 * other MBUS modules.  It is virtually the same as
+		 * the above madness sans turning traps off and flipping
+		 * the AC bit.
+		 */
+srmmu_nviking:
+		set	AC_M_CTPR, %g1
+		lda	[%g1] ASI_M_MMUREGS, %g1	! get ctx table ptr
+		sll	%g1, 0x4, %g1			! make physical addr
+		lda	[%g1] ASI_M_BYPASS, %g1		! ptr to level 1 pg_table
+		srl	%g1, 0x4, %g1
+		sll	%g1, 0x8, %g1			! make phys addr for l1 tbl
+
+		lda	[%g1] ASI_M_BYPASS, %g2		! get level1 entry for 0x0
+		add	%g1, 0x3c0, %g3			! XXX AWAY WITH IMPERICALS
+		sta	%g2, [%g3] ASI_M_BYPASS		! place at KERNBASE entry
+		b	go_to_highmem
+		nop					! wheee....
+
+		/* This remaps the kernel on Sun4/4xx machines
+		 * that have the Sun Mutant Three Level MMU.
+		 * It's like a platypus, Sun didn't have the
+		 * SRMMU in conception so they kludged the three
+		 * level logic in the regular Sun4 MMU probably.
+		 *
+		 * Basically, you take each entry in the top level
+		 * directory that maps the low 3MB starting at
+		 * address zero and put the mapping in the KERNBASE
+		 * slots.  These top level pgd's are called regmaps.
+		 */
+sun4_mutant_remap:
+		or	%g0, %g0, %g3		! source base
+		sethi	%hi(KERNBASE), %g4	! destination base
+		or	%g4, %lo(KERNBASE), %g4
+		sethi	%hi(0x300000), %g5
+		or	%g5, %lo(0x300000), %g5	! upper bound 3MB
+		or	%g0, 0x1, %l6
+		sll	%l6, 24, %l6		! Regmap mapping size
+		add	%g3, 0x2, %g3		! Base magic
+		add	%g4, 0x2, %g4		! Base magic
+
+		/* Main remapping loop on Sun4-Mutant-MMU.
+		 * "I am not an animal..." -Famous Mutant Person
+		 */
+sun4_mutant_loop:
+		lduha	[%g3] ASI_REGMAP, %g2	! Get lower entry
+		stha	%g2, [%g4] ASI_REGMAP	! Store in high entry
+		add	%g4, %l6, %g4		! Move up high memory ptr
+		subcc	%g3, %g5, %g0		! Reached our limit?
+		blu	sun4_mutant_loop	! Nope, loop again
+		add	%g3, %l6, %g3		! delay, Move up low ptr
+		b	go_to_highmem		! Jump to high memory.
+		nop
+
+/* The following works for normal (ie. non Sun4/400) Sun4 MMU's */
+sun4c_remap:
+		or	%g0, %g0, %g3		! source base
+		sethi	%hi(KERNBASE), %g4	! destination base
+		or	%g4, %lo(KERNBASE), %g4
+		sethi	%hi(0x300000), %g5
+		or	%g5, %lo(0x300000), %g5	! upper bound 3MB
+		or	%g0, 0x1, %l6
+		sll	%l6, 18, %l6		! sun4c mmu segmap size
+sun4c_remap_loop:
+		lda	[%g3] ASI_SEGMAP, %g6	! load phys_seg
+		sta	%g6, [%g4] ASI_SEGMAP   ! store new virt mapping
+		add	%g3, %l6, %g3		! Increment source ptr
+		subcc	%g3, %g5, %g0		! Reached limit?
+		bl	sun4c_remap_loop	! Nope, loop again
+		add	%g4, %l6, %g4		! delay, Increment dest ptr
+
+/* Now do a non-relative jump so that PC is in high-memory */
+go_to_highmem:
+		set	execute_in_high_mem, %g1
+		jmp	%g1
 		nop
-#endif /* I will be soon... */
 
 /* Acquire boot time privileged register values, this will help debugging.
- * I figure out and store nwindows later on.
+ * I figure out and store nwindows and nwindowsm1 later on.
  */
+execute_in_high_mem:
+		or	%g0, %l0, %o0		! put back romvec
+		or	%g0, %l1, %o1		! and debug_vec
+
+		sethi	%hi( C_LABEL(prom_vector_p) ), %g1
+		st	%o0, [%g1 + %lo( C_LABEL(prom_vector_p) )]
 
-nosmp:		sethi	%hi( C_LABEL(boot_psr) ), %l1
-		st	%l2, [%l1 + %lo( C_LABEL(boot_psr) )]
-		sethi	%hi( C_LABEL(boot_wim) ), %l1
-		st	%l3, [%l1 + %lo( C_LABEL(boot_wim) )]
-		sethi	%hi( C_LABEL(boot_tbr) ), %l1
-		st	%l4, [%l1 + %lo( C_LABEL(boot_tbr) )]
-		sethi	%hi( C_LABEL(boot_smp_ptr) ), %l1
-		st	%l5, [%l1 + %lo( C_LABEL(boot_smp_ptr) )]
+		sethi	%hi( C_LABEL(linux_dbvec) ), %g1
+		st	%o1, [%g1 + %lo( C_LABEL(linux_dbvec) )]
 
-		or	%g0, %o0, %g7
-		sethi	%hi( C_LABEL(prom_vector_p) ), %g5
-		st	%o0, [%g5 + %lo( C_LABEL(prom_vector_p) )]   ! we will need it later
+		ld	[%o0 + 0x4], %o3
+		and	%o3, 0x3, %o5			! get the version
 
-		ld	[%g7 + 0x4], %o3
 		subcc	%o3, 0x2, %g0			! a v2 prom?
-		be	found_v2
+		be	found_version
 		nop
 
 		/* paul@sfe.com.au */
 		subcc	%o3, 0x3, %g0			! a v3 prom?
-		or	%g0, 0x3, %o5
-		sethi	%hi(C_LABEL(prom_iface_vers) ), %g1
-		st	%o5, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
-		be	not_v2
+		be	found_version
 		nop
 
-
 /* Old sun4's pass our load address into %o0 instead of the prom
-   pointer. On sun4's you have to hard code the romvec pointer into
-   your code. Sun probably still does that because they don't even
-   trust their own "OpenBoot" specifications.
-*/
+ * pointer. On sun4's you have to hard code the romvec pointer into
+ * your code. Sun probably still does that because they don't even
+ * trust their own "OpenBoot" specifications.
+ */
 
 		sethi	%hi(LOAD_ADDR), %g6
 		subcc	%o0, %g6, %g0		! an old sun4?
 		be	no_sun4_here
 		nop
 
-		sethi	%hi( C_LABEL(prom_iface_vers) ), %g1
-		st	%g0, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
-		b	not_v2
-		nop
-
-found_v2:
-		or	%g0, 0x2, %o5
-		sethi	%hi( C_LABEL(prom_iface_vers) ), %g1
-		st	%o5, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
-
-not_v2:
+found_version:
 
 /* Get the machine type via the mysterious romvec node operations.
- * Here we can find out whether we are on a sun4 sun4c, sun4m, or
- * a sun4m. The "nodes" are set up as a bunch of n-ary trees which
- * you can traverse to get information about devices and such. The
- * information acquisition happens via the node-ops which are defined
- * in the linux_openprom.h header file. Of particular interest is the
- * 'nextnode(int node)' function as it does the smart thing when
- * presented with a value of '0', it gives you the first node in the
+ * Here we can find out whether we are on a sun4, sun4c, sun4m, 
+ * sun4d, or a sun4e. The "nodes" are set up as a bunch of n-ary trees 
+ * which you can traverse to get information about devices and such.
+ * The information acquisition happens via the node-ops which are
+ * defined in the openprom.h header file. Of particular interest
+ * is the 'nextnode(int node)' function as it does the smart thing when
+ * presented with a value of '0', it gives you the root node in the
  * tree. These node integers probably offset into some internal prom
  * pointer table the openboot has. It's completely undocumented, so
  * I'm not about to go sifting through the prom address space, but may
@@ -593,8 +839,9 @@
 		ld	[%l0], %l0
 		call 	%l0
 		or	%g0, %g0, %o0		! next_node(0) = first_node
+		or	%o0, %g0, %g6
 
-		sethi	%hi( C_LABEL(cputypvar) ), %o1	! first node has cpu-arch
+		sethi	%hi( C_LABEL(cputypvar) ), %o1	! First node has cpu-arch
 		or	%o1, %lo( C_LABEL(cputypvar) ), %o1
 		sethi	%hi( C_LABEL(cputypval) ), %o2	! information, the string
 		or	%o2, %lo( C_LABEL(cputypval) ), %o2
@@ -605,235 +852,128 @@
 						! to a buf where above string
 						! will get stored by the prom.
 
-		sethi	%hi( C_LABEL(cputypval) ), %o2	! better safe than sorry
+		subcc	%o0, %g0, %g0
+		bpos	got_prop		! Got the property
+		nop
+
+		or	%g6, %g0, %o0
+		sethi	%hi( C_LABEL(cputypvar_sun4m) ), %o1
+		or	%o1, %lo( C_LABEL(cputypvar_sun4m) ), %o1
+		sethi	%hi( C_LABEL(cputypval) ), %o2
 		or	%o2, %lo( C_LABEL(cputypval) ), %o2
-		ldub	[%o2 + 0x4], %o0
-		subcc	%o0, 'c', %g0		! we already know we are not
-		be	is_sun4c		! on a plain sun4 because of
-		nop				! the check for 0x4000 in %o0
-		subcc	%o0, 'm', %g0		! at start:
-		be	is_sun4m
+		ld	[%l1], %l0
+		ld	[%l0 + 0xc], %l0
+		call	%l0
 		nop
-		b	no_sun4d_here		! god bless the person who
-		nop				! tried to run this on sun4d
 
-is_sun4m:
-is_sun4c:					! OK, this is a sun4c, yippie
-		or 	%g0, %g7, %g6		! load up the promvec offsets
-		sethi	%hi(prom_magic), %g5   	! magic mushroom :>
-		st	%g6, [%g5 + %lo(prom_magic)]
-		add	%g7, 0x4, %g6
-		sethi	%hi(prom_rom_vers), %g5
-		st	%g6, [%g5 + %lo(prom_rom_vers)]
-		add	%g7, 0x8, %g6
-		sethi	%hi(prom_pluginvers), %g5
-		st	%g6, [%g5 + %lo(prom_pluginvers)]
-		add	%g7, 0xc, %g6
-		sethi	%hi(prom_revision), %g5
-		st	%g6, [%g5 + %lo(prom_revision)]
-		add	%g7, 0x10, %g6
-		sethi	%hi(prom_v0mem_desc), %g5
-		st	%g6, [%g5 + %lo(prom_v0mem_desc)]
-		add	%g7, 0x1c, %g6
-		sethi	%hi(prom_nodefuncs), %g5
-		st	%g6, [%g5 + %lo(prom_nodefuncs)]
-		add	%g7, 0x68, %g6
-		sethi	%hi(prom_printf), %g5
-		st	%g6, [%g5 + %lo(prom_printf)]
-		add	%g7, 0x6c, %g6
-		sethi	%hi(prom_abort), %g5
-		st	%g6, [%g5 + %lo(prom_abort)]
-		add	%g7, 0x74, %g6
-		sethi	%hi(prom_halt), %g5
-		st	%g6, [%g5 + %lo(prom_halt)]
-		add	%g7, 0x78, %g6
-		sethi	%hi(prom_sync), %g5
-		st	%g6, [%g5 + %lo(prom_sync)]
-		add	%g7, 0x7c, %g6
-		sethi	%hi(prom_eval), %g5
-		st	%g6, [%g5 + %lo(prom_eval)]
-		add	%g7, 0x80, %g6
-		sethi	%hi(prom_v0bootline), %g6
-		st	%g6, [%g5 + %lo(prom_v0bootline)]
-
-
-/* That was easy, now lets try to print some message on the screen.
- * We don't have to worry about bad address translations when the prom
- * addresses our pointers because our pointers are at 0x0-kern_size
- * as the prom expects.
- */
+got_prop:
+		sethi	%hi( C_LABEL(cputypval) ), %o2
+		or	%o2, %lo( C_LABEL(cputypval) ), %o2
 
-/* paul@sfe.com.au */
-/* V3 doesn't have printf.. And I don't really feel like doing the formatting
- * myself.. So we miss out on some messages (for now).
- */
-		ld	[%g7 + 0x4], %o0
-		subcc	%o3, 0x3, %g0
-		be	v3_bootmsg
-		nop
-
-		sethi	%hi(boot_msg), %o0	
-		or	%o0, %lo(boot_msg), %o0
-		sethi	%hi(prom_printf), %o1
-		ld	[%o1 + %lo(prom_printf)], %o1
-		ld	[%o1], %o1
-		call	%o1  			! print boot message #1
-		nop
-
-		sethi	%hi(pstring1), %o0
-		or	%o0, %lo(pstring1), %o0
-		sethi	%hi(prom_printf), %o2
-		ld	[%o2 + %lo(prom_printf)], %o2
-		ld	[%o2], %o2
-		sethi	%hi(prom_magic), %o1
-		ld	[%o1 + %lo(prom_magic)], %o1
-		ld	[%o1], %o1
-		call	%o2
-		nop
-
-		sethi	%hi(pstring2), %o0
-		or	%o0, %lo(pstring2), %o0
-		sethi	%hi(prom_printf), %o2
-		ld	[%o2 + %lo(prom_printf)], %o2
-		ld	[%o2], %o2
-		sethi	%hi( C_LABEL(prom_iface_vers) ), %o1
-		ld	[%o1 + %lo( C_LABEL(prom_iface_vers) )], %o1
-		ld	[%o1], %o1
-		call 	%o2
-		nop
-
-		b	rest_of_boot
-		nop
-
-v3_bootmsg:
-		ld	[%g7 + 0x94], %o0
-		ld	[%o0], %o0
-		sethi	%hi(boot_msg), %o1
-		or	%o1, %lo(boot_msg), %o1
-		mov	BOOT_MSG_LEN, %o2
-		ld	[%g7 + 0xb8], %o4
-		call	%o4
-		nop
- 
-		ld	[%g7 + 0x94], %o0
-		ld	[%o0], %o0
-		sethi	%hi(boot_msg2), %o1
-		or	%o1, %lo(boot_msg2), %o1
-		mov	BOOT_MSG2_LEN, %o2
-		ld	[%g7 + 0xb8], %o4
-		call	%o4
-		nop
-		b	rest_of_boot
+		ldub	[%o2 + 0x4], %l1
+		subcc	%l1, 'c', %g0		! We already know we are not
+		be	1f			! on a plain sun4 because of
+		nop				! the check for 0x4000 in %o0
+		subcc	%l1, 'm', %g0		! at start
+		be	1f
 		nop
 
+		subcc	%l1, 'd', %g0
+		be	no_sun4d_here		! God bless the person who
+		nop				! tried to run this on sun4d.
+	
+		subcc	%l1, 'e', %g0
+		be	no_sun4e_here		! Could be a sun4e.
+		nop
 
-no_sun4_here:
-		ld	[%g7 + 0x68], %o1
-		set	sun4_notsup, %o0
-		call	%o1
+		b	no_sun4u_here		! AIEEE, a V9 sun4u...
 		nop
 
-rest_of_boot:
+
+1:
 		or	%g0, PAGE_SHIFT, %g5
 
+		sethi	%hi( C_LABEL(cputypval) ), %l1
+		or	%l1, %lo( C_LABEL(cputypval) ), %l1
+		ldub	[%l1 + 0x4], %l1
+		subcc	%l1, 'm', %g0           ! Test for sun4d, sun4e ?
+		be	sun4m_init
+		nop
+
 		sethi	%hi(AC_CONTEXT), %g1	! kernel context, safe now
 						! the only valid context
 						! until we call paging_init()
 		stba	%g0, [%g1] ASI_CONTROL
 
+		b	sun4c_continue_boot
+		nop
 
-/* I make the kernel image sit in memory relative to 0x0 with the text 
- * starting at 0x4000. Now it looks like the way memory is set in Linux
- * on an ix86.
- */
-
-/* Uh, oh, interrupt time. This crap is real confusing. What I want to do is
- * clear all interrupts, map the interrupt enable register which in effect
- * enables non-maskable interrupts (or NMI's). Actually we take no interrupts
- * until we frob with the %tbr (trap base register) which the prom has set 
- * to all its routines which allows some sanity during bootup.
+sun4m_init:
+/* P3: I just do not know what to do here. But I do know that ASI_CONTROL
+ * will not serve on sun4m. Also I do not want to smash the current MMU
+ * setup until we call paging_init().
  */
 
-		sethi	%hi(IE_reg_addr), %l0
-		or	%l0, %lo(IE_reg_addr), %l0
-
-		set	0xf4000000, %l3
-		sethi	%hi(INT_ENABLE_REG_PHYSADR), %l2
-		or	%l2, %lo(INT_ENABLE_REG_PHYSADR), %l2
-		srl	%l2, %g5, %l2
-		or	%l2, %l3, %l1		
-
-#ifndef CONFIG_SRMMU
-		sta	%l1, [%l0] ASI_PTE
-#endif
-	
-		or	%g0, 0x1, %l1
-		stb	%l1, [%l0]
-	
-
-/* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
- * show-time!
+/* Ok, the PROM could have done funny things and apple cider could still
+ * be sitting in the fault status/address registers.  Read them all to
+ * clear them so we don't get magic faults later on.
  */
+/* This sucks, aparently this makes Vikings call prom panic, will fix later */
 
-		sethi	%hi(1f), %g1
-		or	%g1, %lo(1f), %g1
-		jmp	%g1
+		set	(0x40000000), %o1
+		rd	%psr, %o0
+		andcc	%o0, %o1, %g0
+		bne	sun4c_continue_boot	! quick hack
 		nop
 
-		.align 4
-1:		sethi	%hi( C_LABEL(cputyp) ), %o0
-		st	%g4, [%o0 + %lo( C_LABEL(cputyp) )]
-
-		sethi	%hi( C_LABEL(pgshift) ), %o0
-		st	%g5, [%o0 + %lo( C_LABEL(pgshift) )]
-
-		mov	1, %o0
-		sll	%o0, %g5, %g5
-		sethi	%hi( C_LABEL(nbpg) ), %o0
-		st	%g5, [%o0 + %lo( C_LABEL(nbpg) )]
-
-		sub	%g5, 1, %g5
-		sethi	%hi( C_LABEL(pgofset) ), %o0
-		st	%g5, [%o0 + %lo( C_LABEL(pgofset) )]
-
-
-		rd	%psr, %g3
-		andn	%g3, PSR_ET, %g3
-		wr	%g3, 0x0, %psr		! make sure traps are off
-						! before we play around
-		WRITE_PAUSE			! no guarantees until 3 insns
+clr_srmmu_fregs:
+		set	AC_M_SFSR, %o0
+		lda	[%o0] ASI_M_MMUREGS, %g0
+		set	AC_M_SFAR, %o0
+		lda	[%o0] ASI_M_MMUREGS, %g0
+		set	AC_M_AFSR, %o0
+		lda	[%o0] ASI_M_MMUREGS, %g0
+		set	AC_M_AFAR, %o0
+		lda	[%o0] ASI_M_MMUREGS, %g0
+		nop
 
 
-		wr	%g0, 0x0, %wim		! magical invalid window reg
-		WRITE_PAUSE			! see above
+sun4c_continue_boot:
 
-/* I keep the timer interrupt on so that BogoMIPS works and the prom
- * keeps updating its "jiffies" counter. 100HZ clock on sparcstations.
- */	
 
-/* If gas wasn't so dumb, I could use or'd macros in this next
- * write. ;-( like this (PSR_PS | PSR_S | PSR_PIL)...
+/* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
+ * show-time!
  */
 
+		sethi	%hi( C_LABEL(cputyp) ), %o0
+		st	%g4, [%o0 + %lo( C_LABEL(cputyp) )]
+
+		/* Turn on PreviousSupervisor, Supervisor, EnableFloating,
+		 * and all the PIL bits.  Also puts us in register window
+		 * zero.
+		 */
 		sethi	%hi(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
 		or	%g2, %lo(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
 		wr	%g2, 0x0, %psr
 		WRITE_PAUSE
 
-		wr	%g0, 0x2, %wim		! window 1 invalid
+		wr	%g0, 0x2, %wim		! Make window 1 invalid.
 		WRITE_PAUSE
 
+		/* Initialize the WIM value for init_task. */
 		or	%g0, 0x1, %g1
 		sethi	%hi( C_LABEL(current) + THREAD_WIM), %g2
 		st	%g1, [%g2 + %lo( C_LABEL(current) + THREAD_WIM)]
 
 /* I want a kernel stack NOW! */
+/* Grrr, gotta be real careful about alignment here */
 
-		set	( C_LABEL(init_user_stack) + 4092 - 96 - 80), %fp	
-		set	( C_LABEL(init_user_stack) + 4092), %sp
-
-/* now out stack is set up similarly to the way it is on the i386 */
+		set	( C_LABEL(init_user_stack) + PAGE_SIZE - 96 - 96 - 80), %g1
+		andn	%g1, 0x7, %g1
+		or	%g1, 0x0, %fp
+		add	%fp, (96+80), %sp
 
+		/* Enable traps. */
 		rd	%psr, %l0
 		wr	%l0, PSR_ET, %psr
 		WRITE_PAUSE
@@ -843,26 +983,14 @@
  * don't know, do you?
  */
 
-		set	C_LABEL(edata) , %o0
-		set	C_LABEL(end) , %o1
-		sub	%o1, %o0, %g2
-		sethi	%hi( C_LABEL(kernel_bss_len) ), %g3
-		st	%g2, [%g3 + %lo( C_LABEL(kernel_bss_len) )]
-		sethi	%hi( C_LABEL(trapbase) ), %g3
-		or	%g3, %lo( C_LABEL(trapbase) ), %g3
-		sethi	%hi( C_LABEL(etext) ), %g4
-		or	%g4, %lo( C_LABEL(etext) ), %g4			
-		sub	%g4, %g3, %g2
-		sethi	%hi( C_LABEL(kernel_text_len) ), %g3
-		st	%g2, [%g3 + %lo( C_LABEL(kernel_text_len) )]
-		sethi	%hi( C_LABEL(etext) ), %g4
-		or	%g4, %lo( C_LABEL(etext) ), %g4
-		sethi	%hi( C_LABEL(edata) ), %g3
-		or	%g3, %lo( C_LABEL(edata) ), %g3
-		sub	%g3, %g4, %g2
-		sethi	%hi( C_LABEL(kernel_data_len) ), %g3
-		st	%g2, [%g3 + %lo( C_LABEL(kernel_data_len) )]
-		or	%g0, %g0, %g1
+		set	C_LABEL(edata) , %o0	! First address of BSS
+		set	C_LABEL(end) , %o1	! Last address of BSS
+
+		/* Argh, ELF gets me again... */
+		andn	%o0, 0x3, %o0
+		andn	%o1, 0x3, %o1
+
+/* Friggin' bzero() kludge. */
 
 1:	
 		st	%g0, [%o0]
@@ -872,55 +1000,102 @@
 		nop
 
 /* Compute NWINDOWS and stash it away. Now uses %wim trick explained
- * in the V8 manual. Ok, this method seems to work, sparc is cool...
+ * in the V8 manual. Ok, this method seems to work, Sparc is cool...
+ * No, it doesn't work, have to play the save/readCWP/restore trick.
  */
 
-		sethi	%hi(0xffffffff), %g1
-		rd	%wim, %g2			! save current value
-		or	%g1, %lo(0xffffffff), %g1
-		wr	%g1, 0x0, %wim
-		rd	%wim, %g1			! get remaining mask
-		wr	%g2, 0x0, %wim			! restore old value
+		rd	%wim, %g1
+		rd	%psr, %g2
+		wr	%g0, 0x0, %wim			! so we dont get a trap
+		andn	%g2, 0x1f, %g3
+		wr	%g3, 0x0, %psr
 		WRITE_PAUSE
+		save
+		rd	%psr, %g3
+		restore
+		and	%g3, 0x1f, %g3
+		add	%g3, 0x1, %g3
+		wr	%g2, 0x0, %psr
+		wr	%g1, 0x0, %wim
 
-		or	%g0, 0x0, %g3
+		cmp	%g3, 0x7
+		bne,a	2f
+		sethi	%hi( C_LABEL(nwindows) ), %g4
+
+
+		/* Nop out one save and one restore in the save state code
+		 * and system call entry if this is a seven window Sparc.
+		 */
+		sethi	%hi(nop7), %g5
+		or	%g5, %lo(nop7), %g5
+		sethi	%hi(NOP_INSN), %g6
+		or	%g6, %lo(NOP_INSN), %g6
+		/* patch 1 */
+		st	%g6, [%g5]
+		st	%g6, [%g5 + 0x4]
+		sethi	%hi(rnop7), %g5
+		or	%g5, %lo(rnop7), %g5
+		/* patch 2 */
+		st	%g6, [%g5]
+		st	%g6, [%g5 + 0x4]
 
-1:		srl	%g1, 0x1, %g1			! shift until highest
-		subcc	%g1, 0x0, %g0			! bit set
-		bne	1b
-		add	%g3, 0x1, %g3
 		sethi	%hi( C_LABEL(nwindows) ), %g4
+
+2:		
 		st	%g3, [%g4 + %lo( C_LABEL(nwindows) )]	! store final value
 		sub	%g3, 0x1, %g3
 		sethi	%hi( C_LABEL(nwindowsm1) ), %g4
 		st	%g3, [%g4 + %lo( C_LABEL(nwindowsm1) )]
 
+		/* Initialize lnx_winmask. */
+		set	lnx_winmask, %g4
+		or	%g0, 0x2, %g5
+		or	%g0, 0x0, %g6
+msk_loop:
+		stb	%g5, [%g4 + %g6]
+		add	%g6, 0x1, %g6
+		cmp	%g6, %g3
+		bl,a	msk_loop
+		sll	%g5, 0x1, %g5
+		or	%g0, 0x1, %g5
+		stb	%g5, [%g4 + %g3]
 
-/* Here we go */
-
-#ifndef CONFIG_SUN4M
-		/* paul@sfe.com.au */
-		/* Look into traps later :( */
+		/* Here we go */
 		set	C_LABEL(trapbase), %g3
 		wr	%g3, 0x0, %tbr
 		WRITE_PAUSE
-#endif
 
 
-/* First we call init_prom() to set up romvec, then off to start_kernel() */
-/* XXX put this in arch_init() */
+/* First we call prom_init() to set up PROMLIB, then off to start_kernel() */
+/* XXX put this in setup_arch() */
 
 		sethi	%hi( C_LABEL(prom_vector_p) ), %g5
-		call	C_LABEL(init_prom)
-		ld	[%g5 + %lo( C_LABEL(prom_vector_p) )], %o0   /* delay slot */
+		call	C_LABEL(prom_init)
+		ld	[%g5 + %lo( C_LABEL(prom_vector_p) )], %o0
+
+		subcc	%o0, 0x1, %g0
+		be	halt_me			! promlib init failed
+		nop
 
 		call 	C_LABEL(start_kernel)
 		nop
 	
+		/* We should not get here. */
 		call	halt_me
 		nop
 
-/* There, happy now adrian? */
+/* There, happy now Adrian? */
+
+		/* XXX Fix this... XXX */
+no_sun4_here:
+		sethi	%hi(SUN4_PROM_VECTOR+SUN4_PRINTF), %o1
+		ld	[%o1 + %lo(SUN4_PROM_VECTOR+SUN4_PRINTF)], %o1
+		set	sun4_notsup, %o0
+		call	%o1
+		nop
+1:
+		ba	1b			! Cannot exit into KMON
+		nop
 
 no_sun4d_here:
 		ld	[%g7 + 0x68], %o1
@@ -930,10 +1105,26 @@
 		b	halt_me
 		nop
 
+no_sun4e_here:
+		ld	[%g7 + 0x68], %o1
+		set	sun4e_notsup, %o0
+		call	%o1
+		nop
+		b	halt_me
+		nop
+
+no_sun4u_here:
+		ld	[%g7 + 0x68], %o1
+		set	sun4u_notsup, %o0
+		call	%o1
+		nop
+		b	halt_me
+		nop
+
 halt_me:
 		ld	[%g7 + 0x74], %o0
-		call	%o0			! get us out of here...
-		nop				! apparently solaris is better
+		call	%o0			! Get us out of here...
+		nop				! Apparently Solaris is better.
 
 	.data
 	.align 4
@@ -945,35 +1136,7 @@
  */
 
 			.globl C_LABEL(prom_vector_p)
-
 C_LABEL(prom_vector_p):	.skip 4
-prom_magic:  		.skip 4			! magic mushroom, beware...
-prom_rom_vers: 		.skip 4			! interface version (v0 or v2)
-prom_pluginvers:	.skip 4			! XXX help help help ???
-prom_revision:		.skip 4			! PROM revision (ie. 1.4)
-prom_halt:		.skip 4			! void halt(void)  solaris friend
-prom_eval:		.skip 4			! void eval(int len, char* string)
-prom_v0bootline:	.skip 4			! boot command line
-prom_v0mem_desc:	.skip 4			! V0 memory descriptor list ptr.
-prom_nodefuncs:		.skip 4			! Magical Node functions
-prom_printf:		.skip 4			! minimal printf()
-
-/* The prom_abort pointer MUST be mapped in all contexts, because if you
- * don't then if a user process is running when you press the abort key
- * sequence, all sorts of bad things can happen
- */
-
-prom_abort:		.skip 4		! L1-A magic cookie
-					! must be mapped in ALL contexts
-
-/* prom_sync is a place where the kernel should place a pointer to a kernel
- * function that when called will sync all pending information to the drives
- * and then promptly return. If the kernel gets aborted with 'L1-A' one can
- * give the 'sync' command to the boot prompt and this magic cookie gets
- * executed. Nice feature eh?
- */
-
-prom_sync:		.skip 4			! hook in prom for sync func
 
 	.align 4
 
@@ -987,59 +1150,15 @@
 C_LABEL(nwindowsm1):	.skip 4
 
 	.align 4
-/* Boot time privileged register values, plus magic %o2 value */
-
-	.globl C_LABEL(boot_wim)
-	.globl C_LABEL(boot_psr)
-	.globl C_LABEL(boot_tbr)
-	.globl C_LABEL(boot_smp_ptr)
-C_LABEL(boot_wim):		.skip 4
-C_LABEL(boot_psr):		.skip 4
-C_LABEL(boot_tbr):		.skip 4
-C_LABEL(boot_smp_ptr):		.skip 4
 
+/* Boot time debugger vector value.  We need this later on. */
 
-	.align 4
-/* Miscellaneous pieces of information saved at kernel startup. */
-	.globl C_LABEL(kernel_text_len)
-	.globl C_LABEL(kernel_data_len)
-	.globl C_LABEL(kernel_bss_len)
-C_LABEL(kernel_text_len):	.word 0
-C_LABEL(kernel_data_len):	.word 0
-C_LABEL(kernel_bss_len):	.word 0
-
-/* These are for page alignment/offset information as they change from
-   machine to machine.
-*/
-
-        .globl  C_LABEL(pgshift)
-	.globl 	C_LABEL(nbpg)
-	.globl	C_LABEL(pgofset)
+	.globl C_LABEL(linux_dbvec)
+C_LABEL(linux_dbvec):		.skip 4
 
 	.align 4
-C_LABEL(pgshift):
-        .word   1
-C_LABEL(nbpg):
-        .word   1
-C_LABEL(pgofset):
-        .word   1
 
 /* Just to get the kernel through the compiler for now */
-	.globl C_LABEL(swapper_pg_dir), C_LABEL(pg0)
-	.globl C_LABEL(empty_bad_page)
-	.globl C_LABEL(empty_bad_page_table)
-	.globl C_LABEL(empty_zero_page)
 	.globl C_LABEL(floppy_track_buffer)
 C_LABEL(floppy_track_buffer):
 	.fill 512*2*36,1,0
-
-	.align 4
-C_LABEL(swapper_pg_dir):		.skip 0x1000
-C_LABEL(pg0):				.skip 0x1000
-C_LABEL(empty_bad_page):		.skip 0x1000
-C_LABEL(empty_bad_page_table):		.skip 0x1000
-C_LABEL(empty_zero_page):		.skip 0x1000
-
-		.align 4
-diagstr:	.asciz	"DIAG\n"
-		.align 4
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/idprom.c linux/arch/sparc/kernel/idprom.c
--- v1.3.3/linux/arch/sparc/kernel/idprom.c	Sun Jan 22 23:02:31 1995
+++ linux/arch/sparc/kernel/idprom.c	Sat Jun 10 04:34:32 1995
@@ -1,31 +1,86 @@
 /* idprom.c: Routines to load the idprom into kernel addresses and
  *           interpret the data contained within.
  *
+ * Because they use the IDPROM's machine type field, some of the
+ * virtual address cache probings on the sun4c are done here.
+ *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/kernel.h>
 
 #include <asm/types.h>
-#include <asm/openprom.h>
+#include <asm/oplib.h>
 #include <asm/idprom.h>
+#include <asm/machines.h>  /* Fun with Sun released architectures. */
+#include <asm/system.h>    /* For halt() macro */
 
-struct idp_struct idprom;
-extern int num_segmaps, num_contexts;
+struct idp_struct *idprom;
+static struct idp_struct idprom_buff;
 
-void get_idprom(void)
+/* Here is the master table of Sun machines which use some implementation
+ * of the Sparc CPU and have a meaningful IDPROM machtype value that we
+ * know about.  See asm-sparc/machines.h for imperical constants.
+ */
+struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
+/* First, Sun4's */
+{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
+{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
+{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
+{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+/* Now, Sun4c's */
+{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
+{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
+{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
+{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
+{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
+{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
+{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
+/* Finally, early Sun4m's */
+{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
+{ "Sun4m SparcStation10", (SM_SUN4M | SM_4M_SS50) },
+{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
+/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
+{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
+
+void
+sparc_display_systype(unsigned char machtyp)
+{
+	char system_name[128];
+	int i;
+
+	for(i = 0; i<NUM_SUN_MACHINES; i++) {
+		if(Sun_Machines[i].id_machtype == machtyp) {
+			if(machtyp!=(SM_SUN4M_OBP | 0x0)) {
+				printk("TYPE: %s\n", Sun_Machines[i].name);
+				break;
+			} else {
+				prom_getproperty(prom_root_node, "banner-name",
+						 system_name, sizeof(system_name));
+				printk("TYPE: %s\n", system_name);
+				break;
+			}
+		}
+	}
+	if(i == NUM_SUN_MACHINES)
+		printk("Uh oh, IDPROM had bogus id_machtype value <%x>\n", machtyp);
+	return;
+}
+
+void
+get_idprom(void)
 {
-  char* idp_addr;
-  char* knl_idp_addr;
-  int i;
+	prom_getidp((char *) &idprom_buff, sizeof(idprom_buff));
+
+	idprom = &idprom_buff;
 
-  idp_addr = (char *)IDPROM_ADDR;
-  knl_idp_addr = (char *) &idprom;
+	sparc_display_systype(idprom->id_machtype);
 
-  for(i = 0; i<IDPROM_SIZE; i++)
-      *knl_idp_addr++ = *idp_addr++;
+	printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
+	       idprom->id_eaddr[0], idprom->id_eaddr[1], idprom->id_eaddr[2],
+	       idprom->id_eaddr[3], idprom->id_eaddr[4], idprom->id_eaddr[5]);
 
-  return;
+	return;
 }
 
 /* find_vac_size() returns the number of bytes in the VAC (virtual
@@ -35,37 +90,30 @@
 int
 find_vac_size(void)
 {
-  int vac_prop_len;
-  int vacsize = 0;
-  int node_root;
-
-  node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  vac_prop_len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-size");
-
-  if(vac_prop_len != -1)
-    {
-      (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-size", (char *) &vacsize);
-      return vacsize;
-    }
-  else
-    {
-
-  /* The prom node functions can't help, do it via idprom struct */
-      switch(idprom.id_machtype)
-	{
-	case 0x51:
-	case 0x52:
-	case 0x53:
-	case 0x54:
-	case 0x55:
-	case 0x56:
-	case 0x57:
-	  return 65536;
-	default:
-	  return -1;
-	}
-    };
+	int vac_prop_len;
+	int vacsize = 0;
+
+	vac_prop_len = prom_getproplen(prom_root_node, "vac-size");
+	if(vac_prop_len != -1) {
+		vacsize = prom_getint(prom_root_node, "vac-size");
+		return vacsize;
+	} else {
+		switch(idprom->id_machtype) {
+		case (SM_SUN4C | SM_4C_SS1):     /* SparcStation1 */
+		case (SM_SUN4C | SM_4C_IPC):     /* SparcStation IPX */
+		case (SM_SUN4C | SM_4C_SS1PLUS): /* SparcStation1+ */
+		case (SM_SUN4C | SM_4C_SLC):     /* SparcStation SLC */
+		case (SM_SUN4C | SM_4C_SS2):     /* SparcStation2 Cache-Chip BUG! */
+		case (SM_SUN4C | SM_4C_ELC):     /* SparcStation ELC */
+		case (SM_SUN4C | SM_4C_IPX):     /* SparcStation IPX */
+			return 65536;
+		default:
+			printk("find_vac_size: Can't determine size of VAC, bailing out...\n");
+			halt();
+			break;
+		};
+	};
+	return -1;
 }
 
 /* find_vac_linesize() returns the size in bytes of the VAC linesize */ 
@@ -73,111 +121,49 @@
 int
 find_vac_linesize(void)
 {
-  int vac_prop_len;
-  int vaclinesize = 0;
-  int node_root;
-
-  node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  vac_prop_len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-linesize");
-
-  if(vac_prop_len != -1)
-    {
-      (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-linesize",
-				      (char *) &vaclinesize);
-      return vaclinesize;
-    }
-  else
-    {
-
-  /* The prom node functions can't help, do it via idprom struct */
-      switch(idprom.id_machtype)
-	{
-	case 0x51:
-	case 0x52:
-	case 0x53:
-	case 0x54:
-	  return 16;
-	case 0x55:
-	case 0x56:
-	case 0x57:
-	  return 32;
-	default:
-	  return -1;
-	}
-    };
-}
-
-int
-find_vac_hwflushes(void)
-{
-  register int len, node_root;
-  int tmp1, tmp2;
-
-  node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac_hwflush");
-
-#ifdef DEBUG_IDPROM
-  printf("DEBUG: find_vac_hwflushes: proplen vac_hwflush=0x%x\n", len);
-#endif
-
-  /* Sun 4/75 has typo in prom_node, it's a dash instead of an underscore
-   * in the property name. :-(
-   */
-  len |= (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-hwflush");
-
-#ifdef DEBUG_IDPROM
-  printf("DEBUG: find_vac_hwflushes: proplen vac-hwflush=0x%x\n", len);
-#endif
-
-  len = (*(romvec->pv_nodeops->no_getprop))(node_root,"vac_hwflush", 
-					    (char *) &tmp1);
-  if(len != 4) tmp1=0;
-
-  len = (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-hwflush",
-					    (char *) &tmp2);
-  if(len != 4) tmp2=0;
-
-
-  return (tmp1|tmp2);
-}
-
-void
-find_mmu_num_segmaps(void)
-{
-  register int root_node, len;
-
-  root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  len = (*(romvec->pv_nodeops->no_getprop))(root_node, "mmu-npmg", 
-					    (char *) &num_segmaps);
+	int vac_prop_len;
 
-#ifdef DEBUG_MMU
-  printf("find_mmu_num_segmaps: property length = %d\n", len);
-#endif
+	vac_prop_len = prom_getproplen(prom_root_node, "vac-linesize");
 
-  if(len != 4) num_segmaps = 128;
-
-  return;
+	if(vac_prop_len != -1)
+		return prom_getint(prom_root_node, "vac-linesize");
+	else {
+		switch(idprom->id_machtype) {
+		case (SM_SUN4C | SM_4C_SS1):     /* SparcStation1 */
+		case (SM_SUN4C | SM_4C_IPC):     /* SparcStation IPC */
+		case (SM_SUN4C | SM_4C_SS1PLUS): /* SparcStation1+ */
+		case (SM_SUN4C | SM_4C_SLC):     /* SparcStation SLC */
+			return 16;
+		case (SM_SUN4C | SM_4C_SS2):     /* SparcStation2 Cache-Chip BUG! */
+		case (SM_SUN4C | SM_4C_ELC):     /* SparcStation ELC */
+		case (SM_SUN4C | SM_4C_IPX):     /* SparcStation IPX */
+			return 32;
+		default:
+			printk("find_vac_linesize: Can't determine VAC linesize, bailing out...\n");
+			halt();
+			break;
+		};
+	};
+	return -1;
 }
 
-void
-find_mmu_num_contexts(void)
+int
+find_vac_hwflushes(void)
 {
-  register int root_node, len;
-
-  root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
-
-  len = (*(romvec->pv_nodeops->no_getprop))(root_node, "mmu-nctx", 
-					    (char *) &num_contexts);
-
-#ifdef DEBUG_MMU
-  printf("find_mmu_num_contexts: property length = %d\n", len);
-#endif
+	register int len;
+	int tmp1, tmp2;
 
-  if(len != 4) num_contexts = 8;
+	/* Sun 4/75 has typo in prom_node, it's a dash instead of an underscore
+	 * in the property name. :-(
+	 */
+	len = prom_getproperty(prom_root_node, "vac_hwflush",
+			       (char *) &tmp1, sizeof(int));
+	if(len != 4) tmp1=0;
+
+	len = prom_getproperty(prom_root_node, "vac-hwflush",
+			       (char *) &tmp2, sizeof(int));
+	if(len != 4) tmp2=0;
 
-  return;
+	return (tmp1|tmp2);
 }
 
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v1.3.3/linux/arch/sparc/kernel/ioport.c	Mon Feb 20 08:59:51 1995
+++ linux/arch/sparc/kernel/ioport.c	Sun Jun 11 01:51:31 1995
@@ -1,8 +1,15 @@
-/* ioport.c:  I/O access on the Sparc. Work in progress.. Most of the things
- *            in this file are for the sole purpose of getting the kernel
- *            through the compiler. :-)
+/* ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * The routines in this file should be changed for a memory allocator
+ * that would be setup just like NetBSD does : you create regions that
+ * are administered by a general purpose allocator, and then you call
+ * that allocator with your handle and the block size instead of this
+ * weak stuff.
+ *
+ * XXX No joke, this needs to be rewritten badly. XXX
  */
 
 #include <linux/sched.h>
@@ -10,3 +17,95 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/vaddrs.h>
+#include <asm/oplib.h>
+
+/* This points to the next to use virtual memory for io mappings */
+static long next_free_region = IOBASE_VADDR;
+static long dvma_next_free   = DVMA_VADDR;
+
+/*
+ * sparc_alloc_dev:
+ * Map and allocates an obio device.
+ * Implements a simple linear allocator, you can force the function
+ * to use your own mapping, but in practice this should not be used.
+ *
+ * Input:
+ *  address: the obio address to map
+ *  virtual: if non zero, specifies a fixed virtual address where
+ *           the mapping should take place.
+ *  len:     the length of the mapping
+ *  bus_type: The bus on which this io area sits.
+ *
+ * Returns:
+ *  The virtual address where the mapping actually took place.
+ */
+
+void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
+		      int bus_type, int rdonly)
+{
+	unsigned long vaddr, base_address;
+	unsigned long addr = (unsigned long) address;
+
+
+	if (virtual){
+		vaddr = (unsigned long) virtual;
+	} else {
+		vaddr = next_free_region;
+	}
+	
+	if (((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)){
+		printk ("alloc_io: Mapping ouside IOBASE area\n");
+		prom_halt ();
+	}
+	if (check_region (vaddr, len)){
+		printk ("alloc_io: 0x%lx is already in use\n", vaddr);
+		prom_halt ();
+	}
+
+	/* Tell Linux resource manager about the mapping */
+	request_region (vaddr, len, name);
+
+	base_address = vaddr;
+	/* Do the actual mapping */
+	for (; len > 0; len -= PAGE_SIZE){
+		mapioaddr (addr, vaddr, bus_type, rdonly);
+		vaddr += PAGE_SIZE;
+		addr  += PAGE_SIZE;
+		if (!virtual)
+			next_free_region += PAGE_SIZE;
+	}
+	return (void *) base_address;
+}
+
+/* Does DVMA allocations with PAGE_SIZE granulatity */
+void *sparc_dvma_malloc (int len, char *name)
+{
+	unsigned long vaddr, base_address;
+
+	vaddr = dvma_next_free;
+	if (check_region (vaddr, len)){
+		printk ("alloc_dma: 0x%lx is already in use\n", vaddr);
+		prom_halt ();
+	}
+	if (vaddr + len > (DVMA_VADDR + DVMA_LEN)){
+		printk ("alloc_dvma: out of dvma memory\n");
+		prom_halt ();
+	}
+
+	/* Tell Linux resource manager about the mapping */
+	request_region (vaddr, len, name);
+
+	base_address = vaddr;
+	/* Assign the memory area and remove the cache bit */
+	/* XXX EWWWWEE!!  Sun4c specific, fix now! XXX */
+	for (; len > 0; len -= PAGE_SIZE){
+		printk ("Len=%d\n", len);
+		put_pte (vaddr, get_pte (vaddr) | PTE_NC);
+		vaddr += PAGE_SIZE;
+		dvma_next_free += PAGE_SIZE;
+	}
+	return (void *) base_address;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v1.3.3/linux/arch/sparc/kernel/irq.c	Mon Feb 20 08:59:52 1995
+++ linux/arch/sparc/kernel/irq.c	Sun Jun 25 11:57:03 1995
@@ -3,8 +3,9 @@
  *                            and you are supposed to probe the prom's device
  *                            node trees to find out who's got which IRQ.
  *
- *  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
- *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@jamica.lab.ipmce.su)
  */
 
 /*
@@ -27,116 +28,126 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+
 #include <asm/ptrace.h>
+#include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/psr.h>
 #include <asm/vaddrs.h>
-#include <asm/clock.h>
+#include <asm/timer.h>
 #include <asm/openprom.h>
-
-#define DEBUG_IRQ
-
-void disable_irq(unsigned int irq_nr)
-{
-  unsigned long flags;
-  unsigned char *int_reg;
-  
-  save_flags(flags);
-  cli();
-
-  /* We have mapped the irq enable register in head.S and all we
-   * have to do here is frob the bits.
-   */
-
-  int_reg = (unsigned char *) IRQ_ENA_ADR;
-
-  switch(irq_nr)
-    {
-    case 1:
-      *int_reg = ((*int_reg) & (~(0x02)));
-      break;
-    case 4:
-      *int_reg = ((*int_reg) & (~(0x04)));
-      break;
-    case 6:
-      *int_reg = ((*int_reg) & (~(0x08)));
-      break;      
-    case 8:
-      *int_reg = ((*int_reg) & (~(0x10)));
-      break;      
-    case 10:
-      *int_reg = ((*int_reg) & (~(0x20)));
-      break;      
-    case 14:
-      *int_reg = ((*int_reg) & (~(0x80)));
-      break;      
-    default:
-      printk("AIEEE, Illegal interrupt disable requested irq=%d\n", 
-	     (int) irq_nr);
-      break;
-    };
+#include <asm/oplib.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+/* Pointer to the interrupt enable byte */
+/* XXX Ugh, this is so sun4c specific it's driving me nuts. XXX */
+unsigned char *interrupt_enable = 0;
+struct sun4m_intregs *sun4m_interrupts;
+
+/* XXX Needs to handle Sun4m semantics XXX */
+void
+disable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+	unsigned char current_mask, new_mask;
+
+	if(sparc_cpu_model != sun4c) return;
+
+	save_flags(flags);
+	cli();
+
+	current_mask = *interrupt_enable;
+
+	switch(irq_nr) {
+	case 1:
+		new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
+		break;
+	case 4:
+		new_mask = ((current_mask) & (~(SUN4C_INT_E4)));
+		break;
+	case 6:
+		new_mask = ((current_mask) & (~(SUN4C_INT_E6)));
+		break;
+	case 8:
+		new_mask = ((current_mask) & (~(SUN4C_INT_E8)));
+		break;
+	case 10:
+		new_mask = ((current_mask) & (~(SUN4C_INT_E10)));
+		break;
+	case 14:
+		new_mask = ((current_mask) & (~(SUN4C_INT_E14)));
+		break;
+	default:
+#if 0 /* Actually this is safe, as the floppy driver needs this */
+		printk("AIEEE, Illegal interrupt disable requested irq=%d\n", 
+		       (int) irq_nr);
+		prom_halt();
+#endif
+		break;
+	};
   
-  restore_flags(flags);
-  return;
+	restore_flags(flags);
+	return;
 }
 
-void enable_irq(unsigned int irq_nr)
-{
-  unsigned long flags;
-  unsigned char *int_reg;
-  
-  save_flags(flags);
-  cli();
-
-  /* We have mapped the irq enable register in head.S and all we
-   * have to do here is frob the bits.
-   */
-
-  int_reg = (unsigned char *) IRQ_ENA_ADR;
-  
-#ifdef DEBUG_IRQ
-  printk(" --- Enabling IRQ level %d ---\n", irq_nr);
+/* XXX Needs to handle sun4m semantics XXX */
+void
+enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+	unsigned char current_mask, new_mask;
+
+	if(sparc_cpu_model != sun4c) return;
+
+	save_flags(flags);
+	cli();
+
+	current_mask = *interrupt_enable;
+
+	switch(irq_nr) {
+	case 1:
+		new_mask = ((current_mask) | SUN4C_INT_E1);
+		break;
+	case 4:
+		new_mask = ((current_mask) | SUN4C_INT_E4);
+		break;
+	case 6:
+		new_mask = ((current_mask) | SUN4C_INT_E6);
+		break;
+	case 8:
+		new_mask = ((current_mask) | SUN4C_INT_E8);
+		break;
+	case 10:
+		new_mask = ((current_mask) | SUN4C_INT_E10);
+		break;
+	case 14:
+		new_mask = ((current_mask) | SUN4C_INT_E14);
+		break;
+	default:
+#if 0  /* Floppy driver does this on sun4c's anyhow */
+		printk ("Interrupt does not need to enable IE\n");
+		return;
 #endif
+		restore_flags(flags);
+		return;
+	};
 
-  switch(irq_nr)
-    {
-    case 1:
-      *int_reg = ((*int_reg) | 0x02);
-      break;
-    case 4:
-      *int_reg = ((*int_reg) | 0x04);
-      break;
-    case 6:
-      *int_reg = ((*int_reg) | 0x08);
-      break;      
-    case 8:
-      *int_reg = ((*int_reg) | 0x10);
-      break;      
-    case 10:
-      *int_reg = ((*int_reg) | 0x20);
-      break;      
-    case 14:
-      *int_reg = ((*int_reg) | 0x80);
-      break;      
-    default:
-      printk("AIEEE, Illegal interrupt enable requested irq=%d\n", 
-	     (int) irq_nr);
-      break;
-    };
+	*interrupt_enable = new_mask;
 
-  restore_flags(flags);
+	restore_flags(flags);
 
-  return;
+	return;
 }
 
 /*
  * Initial irq handlers.
  */
 struct irqaction {
-  void (*handler)(int, struct pt_regs *);
-  unsigned long flags;
-  unsigned long mask;
-  const char *name;
+	void (*handler)(int, struct pt_regs *);
+	unsigned long flags;
+	unsigned long mask;
+	const char *name;
 };
 
 static struct irqaction irq_action[16] = {
@@ -151,29 +162,31 @@
 };
 
 
-int get_irq_list(char *buf)
+int
+get_irq_list(char *buf)
 {
-  int i, len = 0;
-  struct irqaction * action = irq_action;
-  
-  for (i = 0 ; i < 16 ; i++, action++) {
-    if (!action->handler)
-      continue;
-    len += sprintf(buf+len, "%2d: %8d %c %s\n",
-		   i, kstat.interrupts[i],
-		   (action->flags & SA_INTERRUPT) ? '+' : ' ',
-		   action->name);
-  }
-  return len;
+	int i, len = 0;
+	struct irqaction * action = irq_action;
+
+	for (i = 0 ; i < 16 ; i++, action++) {
+		if (!action->handler)
+			continue;
+		len += sprintf(buf+len, "%2d: %8d %c %s\n",
+			       i, kstat.interrupts[i],
+			       (action->flags & SA_INTERRUPT) ? '+' : ' ',
+			       action->name);
+	}
+	return len;
 }
 
-void free_irq(unsigned int irq)
+void
+free_irq(unsigned int irq)
 {
         struct irqaction * action = irq + irq_action;
         unsigned long flags;
 
         if (irq > 14) {  /* 14 irq levels on the sparc */
-                printk("Trying to free IRQ %d\n", irq);
+                printk("Trying to free bogus IRQ %d\n", irq);
                 return;
         }
         if (!action->handler) {
@@ -190,37 +203,33 @@
         restore_flags(flags);
 }
 
-#if 0
-static void handle_nmi(struct pt_regs * regs)
-{
-  printk("NMI, probably due to bus-parity error.\n");
-  printk("PC=%08lx, SP=%08lx\n", regs->pc, regs->sp);
-}
-#endif
-
-void unexpected_irq(int irq, struct pt_regs * regs)
+void
+unexpected_irq(int irq, struct pt_regs * regs)
 {
         int i;
 
         printk("IO device interrupt, irq = %d\n", irq);
-        printk("PC = %08lx NPC = %08lx SP=%08lx\n", regs->pc, 
-	       regs->npc, regs->sp);
+        printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
+	       regs->npc, regs->u_regs[14]);
         printk("Expecting: ");
         for (i = 0; i < 16; i++)
                 if (irq_action[i].handler)
-                        printk("[%s:%d] ", irq_action[i].name, i);
+                        printk("[%s:%d:0x%x] ", irq_action[i].name, (int) i,
+			       (unsigned int) irq_action[i].handler);
         printk("AIEEE\n");
+	prom_halt();
 }
 
-static inline void handler_irq(int irq, struct pt_regs * regs)
+void
+handler_irq(int irq, struct pt_regs * regs)
 {
-  struct irqaction * action = irq + irq_action;
+	struct irqaction * action = irq_action + irq;
 
-  if (!action->handler) {
-    unexpected_irq(irq, regs);
-    return;
-  }
-  action->handler(irq, regs);
+	if (!action->handler) {
+		unexpected_irq(irq, regs);
+		return;
+	}
+	action->handler(irq, regs);
 }
 
 /*
@@ -230,35 +239,14 @@
  * IRQ's should use this format: notably the keyboard/timer
  * routines.
  */
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void
+do_IRQ(int irq, struct pt_regs * regs)
 {
-  struct irqaction *action = irq + irq_action;
+	struct irqaction *action = irq + irq_action;
 
-  kstat.interrupts[irq]++;
-  action->handler(irq, regs);
-  return;
-}
-
-/*
- * Since we need to special things to clear up the clock chip around
- * the do_timer() call we have a special version of do_IRQ for the
- * level 14 interrupt which does these things.
- */
-
-asmlinkage void do_sparc_timer(int irq, struct pt_regs * regs)
-{
-  struct irqaction *action = irq + irq_action;
-  register volatile int clear;
-
-  kstat.interrupts[irq]++;
-
-  /* I do the following already in the entry code, better safe than
-   * sorry for now. Reading the limit register clears the interrupt.
-   */
-  clear = TIMER_STRUCT->timer_limit14;
-
-  action->handler(irq, regs);
-  return;
+	kstat.interrupts[irq]++;
+	action->handler(irq, regs);
+	return;
 }
 
 /*
@@ -266,70 +254,162 @@
  * stuff - the handler is also running with interrupts disabled unless
  * it explicitly enables them later.
  */
-asmlinkage void do_fast_IRQ(int irq)
+asmlinkage void
+do_fast_IRQ(int irq)
 {
-  kstat.interrupts[irq]++;
-  printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
-  return;
+	kstat.interrupts[irq]++;
+	printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
+	return;
 }
 
-extern int first_descent;
-extern void probe_clock(int);
+extern void probe_clock(void);
 		
-int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
-	unsigned long irqflags, const char * devname)
+int
+request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
+	    unsigned long irqflags, const char * devname)
 {
-  struct irqaction *action;
-  unsigned long flags;
+	struct irqaction *action;
+	unsigned long flags;
+
+	if(irq > 14)  /* Only levels 1-14 are valid on the Sparc. */
+		return -EINVAL;
 
-  if(irq > 14)  /* Only levels 1-14 are valid on the Sparc. */
-    return -EINVAL;
+	/* i386 keyboard interrupt request, just return */
+	if(irq == 1) return 0;
 
-  if(irq == 0)  /* sched_init() requesting the timer IRQ */
-    {
-      irq = 14;
-      probe_clock(first_descent);
-    }
+	/* sched_init() requesting the timer IRQ */
+	if(irq == 0) {
+		irq = 10;
+	}
 
-  action = irq + irq_action;
+	action = irq + irq_action;
 
-  if(action->handler)
-    return -EBUSY;
+	if(action->handler)
+		return -EBUSY;
 
-  if(!handler)
-    return -EINVAL;
+	if(!handler)
+		return -EINVAL;
 
-  save_flags(flags);
+	save_flags(flags);
 
-  cli();
+	cli();
 
-  action->handler = handler;
-  action->flags = irqflags;
-  action->mask = 0;
-  action->name = devname;
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
 
-  enable_irq(irq);
+	enable_irq(irq);
 
-  restore_flags(flags);
+	/* Init the timer/clocks if necessary. */
+	if(irq == 10) probe_clock();
 
-  return 0;
+	restore_flags(flags);
+
+	return 0;
 }
 
-unsigned int probe_irq_on (void)
+void
+sun4c_init_IRQ(void)
 {
-  unsigned int irqs = 0;
+	struct linux_prom_registers int_regs[2];
+	int ie_node;
+
+	ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
+				       "interrupt-enable");
+	if(ie_node == 0) {
+		printk("Cannot find /interrupt-enable node\n");
+		prom_halt();
+	}
+	/* Depending on the "address" property is bad news... */
+	prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
+	sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
+		       int_regs[0].reg_size, "sun4c_interrupts",
+		       int_regs[0].which_io, 0x0);
+
+	interrupt_enable = (char *) INTREG_VADDR;
 
-  return irqs;
+	/* Default value, accept interrupts, but no one is actually active */
+	/* We also turn on level14 interrupts so PROM can run the console. */
+	*interrupt_enable = (SUN4C_INT_ENABLE | SUN4C_INT_E14);
+	sti(); /* As of NOW, L1-A works.  Turn irq's on full-blast. */
+	return;
 }
 
-int probe_irq_off (unsigned int irqs)
+void
+sun4m_init_IRQ(void)
 {
-  unsigned int i = 0;
+	int ie_node, i;
+
+	struct linux_prom_registers int_regs[PROMREG_MAX];
+	int num_regs;
+
+	cli();
+
+	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
+	   (ie_node = prom_getchild (ie_node)) == 0 ||
+	   (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
+	{
+		printk("Cannot find /obio/interrupt node\n");
+		prom_halt();
+	}
+	num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
+				    sizeof(int_regs));
+	num_regs = (num_regs/sizeof(struct linux_prom_registers));
 
-  return i;
+	/* Apply the obio ranges to these registers. */
+	prom_apply_obio_ranges(int_regs, num_regs);
+
+	/* Map the interrupt registers for all possible cpus. */
+	sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
+		       PAGE_SIZE*NCPUS, "interrupts_percpu",
+		       int_regs[0].which_io, 0x0);
+
+	/* Map the system interrupt control registers. */
+	sparc_alloc_io(int_regs[num_regs-1].phys_addr,
+		       (void *) INTREG_VADDR+(NCPUS*PAGE_SIZE),
+		       int_regs[num_regs-1].reg_size, "interrupts_system",
+		       int_regs[num_regs-1].which_io, 0x0);
+
+	sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR;
+
+#if 0
+	printk("Interrupt register dump...\n");
+
+	for(i=0; i<NCPUS; i++)
+		printk("cpu%d: tbt %08x\n", i,
+		       sun4m_interrupts->cpu_intregs[i].tbt);
+
+	printk("Master tbt %08x\n", sun4m_interrupts->tbt);
+	printk("Master irqs %08x\n", sun4m_interrupts->irqs);
+	printk("Master set %08x\n", sun4m_interrupts->set);
+	printk("Master clear %08x\n", sun4m_interrupts->clear);
+	printk("Undirected ints taken by: %08x\n",
+	       sun4m_interrupts->undirected_target);
+
+	prom_halt();
+#endif
+
+	sti();
+
+	return;
 }
 
-void init_IRQ(void)
+void
+init_IRQ(void)
 {
-  return;
+	switch(sparc_cpu_model) {
+	case sun4c:
+		sun4c_init_IRQ();
+		break;
+	case sun4m:
+		sun4m_init_IRQ();
+		break;
+	default:
+		printk("Cannot initialize IRQ's on this Sun machine...\n");
+		halt();
+		break;
+	};
+
+	return;
 }
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/mp.S linux/arch/sparc/kernel/mp.S
--- v1.3.3/linux/arch/sparc/kernel/mp.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/mp.S	Tue Jun 13 10:34:30 1995
@@ -0,0 +1,91 @@
+/* mp.S:  Multiprocessor low-level routines on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/vaddrs.h>
+#include <asm/contregs.h>
+
+
+	.text
+	.align 4
+
+/* When we start up a cpu for the first time it enters this routine.
+ * This initializes the chip from whatever state the prom left it
+ * in and sets PIL in %psr to 15, no irqs.
+ */
+
+	.globl C_LABEL(sparc_cpu_startup)
+C_LABEL(sparc_cpu_startup):
+	/* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
+	set	(PSR_PIL | PSR_S | PSR_PS), %g1
+	wr	%g1, 0x0, %psr		! traps off though
+	WRITE_PAUSE
+
+	/* Our %wim is one behind CWP */
+	wr	%g0, 0x2, %wim
+
+	rd	%tbr, %g4
+	or	%g0, 0x3, %g5
+	sll	%g5, 20, %g5
+	and	%g4, %g5, %g4		! Mask cpu-id bits
+
+	/* Give ourselves a stack. */
+	set	PERCPU_VADDR, %g1
+	add	%g1, %g4, %g1
+	set	PERCPU_KSTACK_OFFSET, %g5
+	add	%g1, %g5, %g1
+	set	0x1000, %g5
+	add	%g1, %g5, %g1		! end of stack
+	sub	%g1, (96+96+80), %g1	! set up a frame
+	andn	%g1, 0x7, %g1
+	or	%g1, 0x0, %fp		! bottom of frame
+	add	%fp, (96+80), %sp	! top of frame
+
+	/* Set up per-cpu trap table pointer.  In actuality, the virtual
+	 * address for the trap table on every cpu points to the same
+	 * physical address, this virtual address is only used for cpu
+	 * identification purposes.
+	 */
+#if 0
+/*	set	PERCPU_VADDR, %g1 */
+/*	add	%g1, %g4, %g1 */
+/*	add	%g1, PERCPU_TBR_OFFSET, %g1 */
+	set	C_LABEL(thiscpus_tbr), %g1
+	ld	[%g1], %g1
+	wr	%g1, 0x0, %tbr
+	WRITE_PAUSE
+#else
+	set	C_LABEL(trapbase), %g3
+	wr	%g3, 0x0, %tbr
+	WRITE_PAUSE
+#endif
+
+	/* Turn on traps (PSR_ET). */
+	rd	%psr, %g1
+	wr	%g1, PSR_ET, %psr	! traps on
+
+#if 0
+1:	nop
+	b	1b
+	nop
+#endif
+
+	/* Call C-code to do the rest of the real work. */
+	call	C_LABEL(sparc_cpu_init)
+	nop
+
+	/* Call cpu-idle routine so we can start it up later on. */
+	call	C_LABEL(sparc_cpu_idle)
+	nop
+
+	/* Done... This cpu should me spinning in a test loop.
+	 * If execution gets here, something really bad happened.
+	 */
+	call	C_LABEL(prom_halt)	! Seems reasonable...
+	nop
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c
--- v1.3.3/linux/arch/sparc/kernel/probe.c	Wed Mar  1 09:12:33 1995
+++ linux/arch/sparc/kernel/probe.c	Mon Jun 26 11:19:36 1995
@@ -1,35 +1,41 @@
 /* probe.c: Preliminary device tree probing routines...
-
-   Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 #include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/string.h>
+
+#include <asm/oplib.h>
 #include <asm/vac-ops.h>
+#include <asm/idprom.h>
 #include <asm/io.h>
 #include <asm/vaddrs.h>
 #include <asm/param.h>
-#include <asm/clock.h>
+#include <asm/timer.h>
+#include <asm/mostek.h>
+#include <asm/auxio.h>
 #include <asm/system.h>
+#include <asm/mp.h>
+#include <asm/mbus.h>
 
 /* #define DEBUG_PROBING */
 
-char promstr_buf[64];         /* overkill */
-unsigned int promint_buf[1];
-
-extern int prom_node_root;
-extern int num_segmaps, num_contexts;
-
-extern int node_get_sibling(int node);
-extern int node_get_child(int node);
-extern char* get_str_from_prom(int node, char* name, char* value);
-extern unsigned int* get_int_from_prom(int node, char* name, unsigned int *value);
+/* XXX Grrr, this stuff should have it's own file, only generic stuff goes
+ * XXX here.  Possibly clock.c and timer.c?
+ */
+enum sparc_clock_type sp_clock_typ;
+struct mostek48t02 *mstk48t02_regs;
+struct mostek48t08 *mstk48t08_regs;
+volatile unsigned int *master_l10_limit = 0;
+struct sun4m_timer_regs *sun4m_timers;
 
-int first_descent;
+static char node_str[128];
 
 /* Cpu-type information and manufacturer strings */
 
-
 struct cpu_iu_info {
   int psr_impl;
   int psr_vers;
@@ -42,19 +48,24 @@
   char* fp_name;
 };
 
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too.  I will fix this.
+ */
 struct cpu_fp_info linux_sparc_fpu[] = {
   { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
-  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5"},
+  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
   { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+  /* SparcStation SLC, SparcStation1 */
   { 0, 3, "Weitek WTL3170/2"},
-  { 0, 4, "Lsi Logic/Meiko L64804"},
+  /* SPARCstation-5 */
+  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
   { 0, 5, "reserved"},
   { 0, 6, "reserved"},
   { 0, 7, "No FPU"},
-  { 1, 0, "Lsi Logic L64812 or Texas Instruments ACT8847"},
+  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
   { 1, 1, "Lsi Logic L64814"},
   { 1, 2, "Texas Instruments TMS390-C602A"},
-  { 1, 3, "Weitek WTL3171"},
+  { 1, 3, "Cypress CY7C602 FPU"},
   { 1, 4, "reserved"},
   { 1, 5, "reserved"},
   { 1, 6, "reserved"},
@@ -63,10 +74,14 @@
   { 2, 1, "reserved"},
   { 2, 2, "reserved"},
   { 2, 3, "reserved"},
-  { 2, 4,  "reserved"},
+  { 2, 4, "reserved"},
   { 2, 5, "reserved"},
   { 2, 6, "reserved"},
   { 2, 7, "No FPU"},
+  /* SuperSparc 50 module */
+  { 4, 0, "SuperSparc on-chip FPU"},
+  /* SparcClassic */
+  { 4, 4, "TI MicroSparc on chip FPU"},
   { 5, 0, "Matsushita MN10501"},
   { 5, 1, "reserved"},
   { 5, 2, "reserved"},
@@ -77,22 +92,37 @@
   { 5, 7, "No FPU"},
 };
 
+#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
 struct cpu_iu_info linux_sparc_chips[] = {
-  { 0, 0, "Fujitsu Microelectronics, Inc. - MB86900/1A"},
-  { 1, 0, "Cypress CY7C601"},
-  { 1, 1, "LSI Logic Corporation - L64811"},
-  { 1, 3, "Cypress CY7C611"},
+  /* Sun4/100, 4/200, SLC */
+  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
+  /* borned STP1012PGA */
+  { 0, 4, "Fujitsu  MB86904"},
+  /* SparcStation2, SparcServer 490 & 690 */
+  { 1, 0, "LSI Logic Corporation - L64811"},
+  /* SparcStation2 */
+  { 1, 1, "Cypress/ROSS CY7C601"},
+  /* Embedded controller */
+  { 1, 3, "Cypress/ROSS CY7C611"},
+  /* Ross Technologies HyperSparc */
+  { 1, 0xf, "ROSS HyperSparc RT620"},
+  { 1, 0xe, "ROSS HyperSparc RT625"},
+  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+  /* Someone please write the code to support this beast! ;) */
   { 2, 0, "Bipolar Integrated Technology - B5010"},
   { 3, 0, "LSI Logic Corporation - unknown-type"},
-  { 4, 0, "Texas Instruments, Inc. - unknown"},
-  { 4, 1, "Texas Instruments, Inc. - Sparc Classic"},
-  { 4, 2, "Texas Instruments, Inc. - unknown"},
-  { 4, 3, "Texas Instruments, Inc. - unknown"},
-  { 4, 4, "Texas Instruments, Inc. - unknown"},
+  { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"},
+  /* SparcClassic  --  borned STP1010TAB-50*/
+  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
+  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
+  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
+  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
   { 4, 5, "Texas Instruments, Inc. - unknown"},
   { 5, 0, "Matsushita - MN10501"},
   { 6, 0, "Philips Corporation - unknown"},
   { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
   { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
   { 9, 0, "UNKNOWN CPU-VENDOR/TYPE"},
   { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
@@ -103,8 +133,10 @@
   { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
 };
 
-char *sparc_cpu_type = "cpu-oops";
-char *sparc_fpu_type = "fpu-oops";
+#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+
+char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
 
 /* various Virtual Address Cache parameters we find at boot time... */
 
@@ -115,82 +147,72 @@
 extern int find_vac_size(void);
 extern int find_vac_linesize(void);
 extern int find_vac_hwflushes(void);
-extern void find_mmu_num_segmaps(void);
-extern void find_mmu_num_contexts(void);
+
+static inline int find_mmu_num_contexts(int cpu)
+{
+	return prom_getintdefault(cpu, "mmu-nctx", 0x8);
+}
+
+unsigned int fsr_storage;
 
 void
 probe_cpu(void)
 {
-  register int psr_impl=0;
-  register int psr_vers = 0;
-  register int fpu_vers = 0;
-  register int i = 0;
-  unsigned int tmp_fsr;
-
-  &tmp_fsr;   /* GCC grrr... */
-
-  __asm__("rd %%psr, %0\n\t"
-	  "mov %0, %1\n\t"
-	  "srl %0, 28, %0\n\t"
-	  "srl %1, 24, %1\n\t"
-	  "and %0, 0xf, %0\n\t"
-	  "and %1, 0xf, %1\n\t" :
-	  "=r" (psr_impl),
-	  "=r" (psr_vers) :
-	  "0" (psr_impl),
-	  "1" (psr_vers));
-
-
-  __asm__("st %%fsr, %1\n\t"
-	  "ld %1, %0\n\t"
-	  "srl %0, 17, %0\n\t"
-	  "and %0, 0x7, %0\n\t" :
-	  "=r" (fpu_vers),
-	  "=m" (tmp_fsr) :
-	  "0" (fpu_vers),
-	  "1" (tmp_fsr));
-
-  printk("fpu_vers: %d ", fpu_vers);
-  printk("psr_impl: %d ", psr_impl);
-  printk("psr_vers: %d \n\n", psr_vers);
+  int psr_impl, psr_vers, fpu_vers;
+  int i, cpuid;
+
+  cpuid = get_cpuid();
+
+  psr_impl = ((get_psr()>>28)&0xf);
+  psr_vers = ((get_psr()>>24)&0xf);
+
+  fpu_vers = ((get_fsr()>>17)&0x7);
 
-  for(i = 0; i<23; i++)
+  for(i = 0; i<NSPARCCHIPS; i++)
     {
       if(linux_sparc_chips[i].psr_impl == psr_impl)
 	if(linux_sparc_chips[i].psr_vers == psr_vers)
 	  {
-	    sparc_cpu_type = linux_sparc_chips[i].cpu_name;
+	    sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
 	    break;
 	  }
     }
 
-  if(i==23)
+  if(i==NSPARCCHIPS)
     {
       printk("No CPU type! You lose\n");
       printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
 	     psr_vers);
-      return;
+      printk("Send this information and the type of SUN and CPU/FPU type you have\n");
+      printk("to davem@caip.rutgers.edu so that this can be fixed.\n");
+      printk("halting...\n\r\n");
+      /* If I don't know about this CPU, I don't want people running on it
+       * until I do.....
+       */
+      halt();
     }
 
-  for(i = 0; i<32; i++)
+  for(i = 0; i<NSPARCFPU; i++)
     {
       if(linux_sparc_fpu[i].psr_impl == psr_impl)
 	if(linux_sparc_fpu[i].fp_vers == fpu_vers)
 	  {
-	    sparc_fpu_type = linux_sparc_fpu[i].fp_name;
+	    sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
 	    break;
 	  }
     }
 
-  if(i == 32)
+  if(i == NSPARCFPU)
     {
       printk("No FPU type! You don't completely lose though...\n");
       printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl, fpu_vers);
-      sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+      printk("Send this information and the type of SUN and CPU/FPU type you have\n");
+      printk("to davem@caip.rutgers.edu so that this can be fixed.\n");
+      sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
     }
 
-  printk("CPU: %s \n", sparc_cpu_type);
-  printk("FPU: %s \n", sparc_fpu_type);
+  printk("cpu%d CPU: %s \n", cpuid, sparc_cpu_type[cpuid]);
+  printk("cpu%d FPU: %s \n", cpuid, sparc_fpu_type[cpuid]);
 
   return;
 }
@@ -198,205 +220,295 @@
 void
 probe_vac(void)
 {
-  register unsigned int x,y;
-
-#ifndef CONFIG_SRMMU
-  vac_size = find_vac_size();
-  vac_linesize = find_vac_linesize();
-  vac_do_hw_vac_flushes = find_vac_hwflushes();
-
-  /* Calculate various constants that make the cache-flushing code
-   * mode speedy.
-   */
-
-  vac_entries_per_segment = vac_entries_per_context = vac_size >> 12;
-
-  for(x=0,y=vac_linesize; ((1<<x)<y); x++);
-  if((1<<x) != vac_linesize) printk("Warning BOGUS VAC linesize 0x%x",
-				    vac_size);
-
-  vac_entries_per_page = x;
+	unsigned int x,y;
 
-  printk("Sparc VAC cache: Size=%d bytes  Line-Size=%d bytes ... ", vac_size,
-	 vac_linesize);
-
-  /* Here we want to 'invalidate' all the software VAC "tags"
-   * just in case there is garbage in there. Then we enable it.
-   */
-
-  for(x=0x80000000, y=(x+vac_size); x<y; x+=vac_linesize)
-    __asm__("sta %0, [%1] %2" : : "r" (0), "r" (x), "n" (0x2));
-
-  x=enable_vac();
-  printk("ENABLED\n");
-#endif
-
-  return;
+	vac_size = find_vac_size();
+	vac_linesize = find_vac_linesize();
+	vac_do_hw_vac_flushes = find_vac_hwflushes();
+
+	/* Calculate various constants that make the cache-flushing code
+	 * mode speedy.
+	 */
+
+	vac_entries_per_segment = vac_entries_per_context = vac_size >> 12;
+	for(x=0,y=vac_linesize; ((1<<x)<y); x++);
+	if((1<<x) != vac_linesize) printk("Warning BOGUS VAC linesize 0x%x",
+					  vac_size);
+	vac_entries_per_page = x;
+
+	/* Here we want to 'invalidate' all the software VAC "tags"
+	 * just in case there is garbage in there. Then we enable it.
+	 */
+
+	/* flush flush flush */
+	for(x=AC_CACHETAGS; x<(AC_CACHETAGS+vac_size); x+=vac_linesize)
+		__asm__("sta %%g0, [%0] %1" : : "r" (x), "i" (0x2));
+	x=enable_vac();
+	return;
 }
 
+extern int num_segmaps, num_contexts;
+
 void
-probe_mmu(void)
+probe_mmu(int prom_node_cpu)
 {
-  find_mmu_num_segmaps();
-  find_mmu_num_contexts();
+	int cpuid;
 
-  printk("MMU segmaps: %d     MMU contexts: %d\n", num_segmaps, 
-	 num_contexts);
+	/* who are we? */
+	cpuid = get_cpuid();
+	switch(sparc_cpu_model) {
+	case sun4:
+		break;
+	case sun4c:
+		/* A sun4, sun4c. */
+		num_segmaps = prom_getintdefault(prom_node_cpu, "mmu-npmg", 128);
+		num_contexts = find_mmu_num_contexts(prom_node_cpu);
+
+		printk("cpu%d MMU segmaps: %d     MMU contexts: %d\n", cpuid,
+		       num_segmaps, num_contexts);
+		break;
+	case sun4m:
+	case sun4d:
+	case sun4e:
+		/* Any Reference MMU derivate should be handled here, hopefuly. */
+		num_segmaps = 0;
+		num_contexts = find_mmu_num_contexts(prom_node_cpu);
+		vac_linesize = prom_getint(prom_node_cpu, "cache-line-size");
+		vac_size = (prom_getint(prom_node_cpu, "cache-nlines")*vac_linesize);
+		printk("cpu%d MMU contexts: %d\n", cpuid, num_contexts);
+		printk("cpu%d CACHE linesize %d total size %d\n", cpuid, vac_linesize,
+		       vac_size);
+		break;
+	default:
+		printk("cpu%d probe_mmu: sparc_cpu_model botch\n", cpuid);
+		break;
+	};
 
-  return;
+	return;
 }
 
+/* Clock probing, we probe the timers here also. */
+/* #define DEBUG_PROBE_CLOCK */
+volatile unsigned int foo_limit;
+
 void
 probe_clock(int fchild)
 {
   register int node, type;
-  register char *node_str;
+  struct linux_prom_registers clk_reg[2];
 
   /* This will basically traverse the node-tree of the prom to see
    * which timer chip is on this machine.
    */
 
-  printk("Probing timer chip... ");
-
-  type = 0;
-  for(node = fchild ; ; )
-    {
-      node_str = get_str_from_prom(node, "model", promstr_buf);
-      if(strcmp(node_str, "mk48t02") == 0)
-	{
-	  type = 2;
-	  break;
-	}
-
-      if(strcmp(node_str, "mk48t08") == 0)
-	{
-	  type = 8;
-	  break;
-	}
-
-      node = node_get_sibling(node);
-      if(node == fchild)
-	{
-	  printk("Aieee, could not find timer chip type\n");
+  node = 0;
+  if(sparc_cpu_model == sun4) {
+	  printk("probe_clock: No SUN4 Clock/Timer support yet...\n");
 	  return;
-	}
-    }
-
-  printk("Mostek %s\n", node_str);
-  printk("At OBIO address: 0x%x Virtual address: 0x%x\n",
-	 (unsigned int) TIMER_PHYSADDR, (unsigned int) TIMER_STRUCT);
-
-  mapioaddr((unsigned long) TIMER_PHYSADDR,
-	    (unsigned long) TIMER_STRUCT);
+  }
+  if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node);
+  else
+	  if(sparc_cpu_model == sun4m)
+		  node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio"));
+  type = 0;
+  sp_clock_typ = MSTK_INVALID;
+  for(;;) {
+	  prom_getstring(node, "model", node_str, sizeof(node_str));
+	  if(strcmp(node_str, "mk48t02") == 0) {
+		  sp_clock_typ = MSTK48T02;
+		  if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
+			  printk("probe_clock: FAILED!\n");
+			  halt();
+		  }
+		  prom_apply_obio_ranges(clk_reg, 1);
+		  /* Map the clock register io area read-only */
+		  mstk48t02_regs = (struct mostek48t02 *) 
+			  sparc_alloc_io((void *) clk_reg[0].phys_addr,
+					 (void *) 0, sizeof(*mstk48t02_regs),
+					 "clock", 0x0, 0x1);
+		  mstk48t08_regs = 0;  /* To catch weirdness */
+		  break;
+	  }
 
-  TIMER_STRUCT->timer_limit14=(((1000000/HZ) << 10) | 0x80000000);
+	  if(strcmp(node_str, "mk48t08") == 0) {
+		  sp_clock_typ = MSTK48T08;
+		  if(prom_getproperty(node, "reg", (char *) clk_reg,
+				      sizeof(clk_reg)) == -1) {
+			  printk("probe_clock: FAILED!\n");
+			  halt();
+		  }
+		  prom_apply_obio_ranges(clk_reg, 1);
+		  /* Map the clock register io area read-only */
+		  mstk48t08_regs = (struct mostek48t08 *)
+			  sparc_alloc_io((void *) clk_reg[0].phys_addr,
+					 (void *) 0, sizeof(*mstk48t08_regs),
+					 "clock", 0x0, 0x1);
 
-  return;
-}
+		  mstk48t02_regs = &mstk48t08_regs->regs;
+		  break;
+	  }
 
+	  node = prom_getsibling(node);
+	  if(node == 0) {
+		  printk("Aieee, could not find timer chip type\n");
+		  return;
+	  }
+  }
 
-void
-probe_esp(register int esp_node)
-{
-  register int nd;
-  register char* lbuf;
+  if(sparc_cpu_model == sun4c) {
 
-  nd = node_get_child(esp_node);
+  /* Map the Timer chip, this is implemented in hardware inside
+   * the cache chip on the sun4c.
+   */
+  sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, (void *) TIMER_VADDR,
+		  sizeof (*SUN4C_TIMER_STRUCT), "timer", 0x0, 0x0);
 
-  printk("\nProbing ESP:\n");
-  lbuf = get_str_from_prom(nd, "name", promstr_buf);
+  /* Have the level 10 timer tick at 100HZ.  We don't touch the
+   * level 14 timer limit since we are letting the prom handle
+   * them until we have a real console driver so L1-A works.
+   */
+  SUN4C_TIMER_STRUCT->timer_limit10 = (((1000000/HZ) + 1) << 10);
+  master_l10_limit = &(SUN4C_TIMER_STRUCT->timer_limit10);
 
-  if(*get_int_from_prom(nd, "name", promint_buf) != 0)
-  printk("Node: 0x%x Name: %s\n", nd, lbuf);
+  } else {
+	  int reg_count;
+	  struct linux_prom_registers cnt_regs[PROMREG_MAX];
+	  int obio_node, cnt_node;
+
+	  cnt_node = 0;
+	  if((obio_node =
+	      prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
+	     (obio_node = prom_getchild (obio_node)) == 0 ||
+	     (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
+		  printk ("Cannot find /obio/counter node\n");
+		  prom_halt ();
+	  }
+	  reg_count = prom_getproperty(cnt_node, "reg",
+				       (void *) cnt_regs, sizeof(cnt_regs));
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    lbuf = get_str_from_prom(nd, "name", promstr_buf);
-    printk("Node: 0x%x Name: %s\n", nd, lbuf);
-  }
+	  reg_count = (reg_count/sizeof(struct linux_prom_registers));
 
-  printk("\n");
+	  /* Apply the obio ranges to the timer registers. */
+	  prom_apply_obio_ranges(cnt_regs, reg_count);
 
-  return;
-}
+	  /* Map the per-cpu Counter registers. */
+	  sparc_alloc_io(cnt_regs[0].phys_addr, (void *) TIMER_VADDR,
+			 PAGE_SIZE*NCPUS, "counters_percpu", cnt_regs[0].which_io, 0x0);
 
-void
-probe_sbus(register int cpu_child_node)
-{
-  register int nd, savend;
-  register char* lbuf;
+	  /* Map the system Counter register. */
+	  sparc_alloc_io(cnt_regs[reg_count-1].phys_addr,
+			 (void *) TIMER_VADDR+(NCPUS*PAGE_SIZE),
+			 cnt_regs[reg_count-1].reg_size,
+			 "counters_system", cnt_regs[reg_count-1].which_io, 0x0);
 
-  nd = cpu_child_node;
 
-  lbuf = (char *) 0;
+	  sun4m_timers = (struct sun4m_timer_regs *) TIMER_VADDR;
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    lbuf = get_str_from_prom(nd, "name", promstr_buf);
-    if(strcmp(lbuf, "sbus") == 0)
-      break;
-  };
+	  foo_limit = (volatile) sun4m_timers->l10_timer_limit;
 
-  nd = node_get_child(nd);
+/*	  printk("Timer register dump:\n"); */
+#if 0
+	  printk("cpu0: l14limit %08x l14curcount %08x\n",
+		 sun4m_timers->cpu_timers[0].l14_timer_limit,
+		 sun4m_timers->cpu_timers[0].l14_cur_count);
+#endif
+#if 0
+	  printk("sys: l10limit %08x l10curcount %08x\n",
+		 sun4m_timers->l10_timer_limit,
+		 sun4m_timers->l10_cur_count);
+#endif
 
-  printk("Node: 0x%x Name: %s\n", nd,
-	 get_str_from_prom(nd, "name", promstr_buf));
+	  /* Must set the master pointer first or we will lose badly. */
+	  master_l10_limit =
+		  &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit);
 
-  if(strcmp(lbuf, "esp") == 0) {
-    probe_esp(nd);
-  };
+          ((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit =
+		  (((1000000/HZ) + 1) << 10);   /* 0x9c4000 */
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    printk("Node: 0x%x Name: %s\n", nd,
-	   lbuf = get_str_from_prom(nd, "name", promstr_buf));
-    
-    if(strcmp(lbuf, "esp") == 0) {
-      savend = nd;
-      probe_esp(nd);
-      nd = savend;
-    };
-  };
+	  /* We should be getting level 10 interrupts now. */
+  }
 
-  printk("\n");
   return;
 }
 
-extern unsigned long probe_memory(void);
-extern struct sparc_phys_banks sp_banks[14];
-unsigned int phys_bytes_of_ram, end_of_phys_memory;
-
+/* Probe and map in the Auxiliaary I/O register */
 void
-probe_devices(void)
+probe_auxio(void)
 {
-  register int nd, i;
-  register char* str;
+	int node, auxio_nd;
+	struct linux_prom_registers auxregs[1];
+
+	node = prom_getchild(prom_root_node);
+	auxio_nd = prom_searchsiblings(node, "auxiliary-io");
+	if(!auxio_nd) {
+		node = prom_searchsiblings(node, "obio");
+		node = prom_getchild(node);
+		auxio_nd = prom_searchsiblings(node, "auxio");
+		if(!auxio_nd) {
+			printk("Cannot find auxio node, cannot continue...\n");
+			prom_halt();
+		}
+	}
+	prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
+	prom_apply_obio_ranges(auxregs, 0x1);
+	/* Map the register both read and write */
+	sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR,
+		       auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0);
+	printk("Mapped AUXIO at paddr %08lx vaddr %08lx\n",
+	       (unsigned long) auxregs[0].phys_addr,
+	       (unsigned long) AUXIO_VADDR);
+	return;
+}
 
-  nd = prom_node_root;
+extern unsigned long probe_memory(void);
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
+extern unsigned long probe_sbus(int, unsigned long);
+extern void probe_mbus(void);
 
-  printk("PROBING DEVICES:\n");
+/* #define DEBUG_PROBE_DEVICES */
+struct prom_cpuinfo linux_cpus[NCPUS];
+int linux_num_cpus;
 
-  str = get_str_from_prom(nd, "device_type", promstr_buf);
-  if(strcmp(str, "cpu") == 0) {
-    printk("Found CPU root prom device tree node.\n");
+unsigned long
+probe_devices(unsigned long mem_start)
+{
+  int nd, i, prom_node_cpu, thismid;
+  int cpu_nds[NCPUS];  /* One node for each cpu */
+  int cpu_ctr = 0;
+
+  prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+  if(strcmp(node_str, "cpu") == 0) {
+    cpu_nds[0] = prom_root_node;
+    cpu_ctr++;
   } else {
-    printk("Root node in device tree was not 'cpu' cannot continue.\n");
-    halt();
+    int scan;
+    scan = prom_getchild(prom_root_node);
+    nd = 0;
+    while((scan = prom_getsibling(scan)) != 0) {
+      prom_getstring(scan, "device_type", node_str, sizeof(node_str));
+      if(strcmp(node_str, "cpu") == 0) {
+	      cpu_nds[cpu_ctr] = scan;
+	      linux_cpus[cpu_ctr].prom_node = scan;
+	      prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+	      linux_cpus[cpu_ctr].mid = thismid;
+	      cpu_ctr++;
+      }
+    };
+    if(cpu_ctr == 0) {
+      printk("No CPU nodes found, cannot continue.\n");
+      /* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */
+      halt();
+    }
+    printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
   };
+  prom_node_cpu = cpu_nds[0];
 
-#ifdef DEBUG_PROBING
-  printk("String address for d_type: 0x%x\n", (unsigned int) str);
-  printk("str[0] = %c  str[1] = %c  str[2] = %c \n", str[0], str[1], str[2]);
-#endif
-
-  str = get_str_from_prom(nd, "name", promstr_buf);
-
-#ifdef DEBUG_PROBING
-  printk("String address for name: 0x%x\n", (unsigned int) str);
-  printk("str[0] = %c  str[1] = %c  str[2] = %c \n", str[0], str[1], str[2]);
-#endif
-
-  printk("Name: %s \n", str);
-
-  first_descent = nd = node_get_child(nd);
-
+  linux_num_cpus = cpu_ctr;
+  for(i=0; i<cpu_ctr; i++) {
+	  prom_getstring(cpu_nds[i], "name", node_str, sizeof(node_str));
+	  printk("cpu%d: %s \n", i, node_str);
+  }
 
 /* Ok, here will go a call to each specific device probe. We can
  * call these now that we have the 'root' node and the child of
@@ -404,29 +516,11 @@
  */
 
   probe_cpu();
-  probe_vac();
-  probe_mmu();
-  phys_bytes_of_ram = probe_memory();
-
-  printk("Physical Memory: %d bytes\n", (int) phys_bytes_of_ram);
-  for(i=0; sp_banks[i].num_bytes != 0; i++) {
-    printk("Bank %d:  base 0x%x  bytes %d\n", i,
-	   (unsigned int) sp_banks[i].base_addr, 
-	   (int) sp_banks[i].num_bytes);
-    end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes;
-  }
-
-  printk("PROM Root Child Node: 0x%x Name: %s \n", nd,
-	 get_str_from_prom(nd, "name", promstr_buf));
+  probe_auxio();
+  if(sparc_cpu_model == sun4c) probe_vac();
+  if(sparc_cpu_model != sun4c) probe_mbus(); /* Are MBUS's relevant on sun4c's? */
 
-  while((nd = node_get_sibling(nd)) != 0) {
-    printk("Node: 0x%x Name: %s", nd,
-	   get_str_from_prom(nd, "name", promstr_buf));
-    printk("\n");
-  };
-
-  printk("\nProbing SBUS:\n");
-  probe_sbus(first_descent);
+  mem_start = probe_sbus(prom_getchild(prom_root_node), mem_start);
 
-  return;
+  return mem_start;
 }
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v1.3.3/linux/arch/sparc/kernel/process.c	Sun Feb 26 20:46:20 1995
+++ linux/arch/sparc/kernel/process.c	Sat Jun 10 09:07:20 1995
@@ -1,7 +1,7 @@
 /*
- *  linux/arch/i386/kernel/process.c
+ *  linux/arch/sparc/kernel/process.c
  *
- *  Copyright (C) 1995  Linus Torvalds
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 /*
@@ -20,47 +20,43 @@
 #include <linux/user.h>
 #include <linux/a.out.h>
 
+#include <asm/oplib.h>
 #include <asm/segment.h>
 #include <asm/system.h>
-
-void ret_from_sys_call(void) { __asm__("nop"); }
+#include <asm/processor.h>
 
 /*
- * The idle loop on a i386..
+ * The idle loop on a sparc... ;)
  */
 asmlinkage int sys_idle(void)
 {
+
 	if (current->pid != 0)
 		return -EPERM;
 
+	printk("in sys_idle...\n");
 	/* Map out the low memory: it's no longer needed */
 	/* Sparc version RSN */
 
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
-		schedule();
+	  printk("calling schedule() aieee!\n");
+	  schedule();
+	  printk("schedule() returned, halting...\n");
+	  halt();
 	}
 }
 
 void hard_reset_now(void)
 {
-	halt();
+	prom_reboot("boot vmlinux");
 }
 
 void show_regs(struct pt_regs * regs)
 {
-        printk("\nSP: %08lx PC: %08lx NPC: %08lx\n", regs->sp, regs->pc,
-	       regs->npc);
-}
-
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-void start_thread(struct pt_regs * regs, unsigned long sp, unsigned long fp)
-{
-	regs->sp = sp;
-	regs->fp = fp;
+        printk("\nFP: %08lx PC: %08lx NPC: %08lx\n", regs->u_regs[14],
+	       regs->pc, regs->npc);
 }
 
 /*
@@ -76,15 +72,60 @@
   halt();
 }
 
-void copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct * p, struct pt_regs * regs)
+extern void ret_sys_call(void);
+
+/*
+ * Copy a Sparc thread.  The context of a process on the Sparc is
+ * composed of the following:
+ *  1) status registers  %psr (for condition codes + CWP) and %wim
+ *  2) current register window (in's and global registers)
+ *  3) the current live stack frame, it contains the register
+ *     windows the child may 'restore' into, this is important
+ *  4) kernel stack pointer, user stack pointer (which is %i6)
+ *  5) The pc and npc the child returns to during a switch
+ */
+
+void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+		 struct task_struct * p, struct pt_regs * regs)
 {
-	struct pt_regs * childregs;
+	struct pt_regs *childregs;
+	unsigned char *old_stack;
+	unsigned char *new_stack;
+	int i;
+
+	/* This process has no context yet. */
+	p->tss.context = -1;
+
+	/* Grrr, Sparc stack alignment restrictions make things difficult. */
+	childregs = ((struct pt_regs *) 
+		     ((p->kernel_stack_page + PAGE_SIZE - 80)&(~7)));
 
-	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
-	p->tss.usp = (unsigned long) childregs;
 	*childregs = *regs;
-	childregs->sp = sp;
-	p->tss.psr = regs->psr; /* for condition codes */
+
+	p->tss.usp = sp;    /* both processes have the same user stack */
+	/* See entry.S */
+
+	/* Allocate new processes kernel stack right under pt_regs.
+	 * Hopefully this should align things the right way.
+	 */
+	p->tss.ksp = (unsigned long) ((p->kernel_stack_page + PAGE_SIZE - 80 - 96)&(~7));
+	new_stack = (unsigned char *) (p->tss.ksp);
+	old_stack = (unsigned char *) (((unsigned long) regs) - 96);
+
+	/* Copy c-stack. */
+	for(i=0; i<96; i++) *new_stack++ = *old_stack++;
+
+	/* These pc values are only used when we switch to the child for
+	 * the first time, it jumps the child to ret_sys_call in entry.S
+	 * so that the child returns from the sys_call just like parent.
+	 */
+	p->tss.pc = (((unsigned long) ret_sys_call) - 8);
+	p->tss.npc = p->tss.pc+4;
+
+	/* Set the return values for both the parent and the child */
+	regs->u_regs[8] = p->pid;
+	childregs->u_regs[8] = 0;
+
 	return;
 }
 
@@ -96,9 +137,9 @@
   return; /* solaris does this enough */
 }
 
-asmlinkage int sys_fork(struct pt_regs regs)
+asmlinkage int sys_fork(struct pt_regs *regs)
 {
-	return do_fork(COPYVM | SIGCHLD, regs.sp, &regs);
+  return do_fork(COPYVM | SIGCHLD, regs->u_regs[14], regs);
 }
 
 /*
@@ -106,6 +147,7 @@
  */
 asmlinkage int sys_execve(struct pt_regs regs)
 {
+  printk("sys_execve()... halting\n");
   halt();
   return 0;
 }
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v1.3.3/linux/arch/sparc/kernel/setup.c	Mon Mar  6 11:22:09 1995
+++ linux/arch/sparc/kernel/setup.c	Sat Jun 17 08:06:01 1995
@@ -24,10 +24,15 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/openprom.h>   /* for console registration + cheese */
+#include <asm/processor.h>
+#include <asm/oplib.h>    /* The PROM is your friend... */
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/vaddrs.h>
+#include <asm/kdebug.h>
 
-extern void get_idprom(void);
-extern void probe_devices(void);
+extern unsigned long probe_devices(unsigned long);
 
 /*
  * Gcc is hard to keep happy ;-)
@@ -42,9 +47,7 @@
 	25			/* orig-video-lines */
 };
 
-/* At least I hide the sneaky floppy_track_buffer in my dirty assembly
- * code. ;-)
- */
+char wp_works_ok = 0;
 
 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 {
@@ -52,8 +55,8 @@
 }
 
 /* Lame prom console routines, gets registered below. Thanks for the
- * tip Linus.  First comes the V0 prom routine, then the V3 version
- * written by Paul Hatchman (paul@sfe.com.au).
+ * tip Linus.  We now use a generic putchar prom routine through the
+ * linux prom library.
  */
 
 void sparc_console_print(const char * p)
@@ -62,32 +65,67 @@
 
 	while ((c = *(p++)) != 0)
 	  {
-	    if (c == '\n') romvec->pv_putchar('\r');
-	    (*(romvec->pv_putchar))(c);
+	    if (c == '\n')
+	      prom_putchar('\r');
+	    prom_putchar(c);
 	  }
 
   return;
 
 }
 
-/* paul@sfe.com.au */
-/* V3 prom console printing routines */
-void sparc_console_print_v3 (const char *p)
+/* Typing sync at the prom promptcalls the function pointed to by
+ * romvec->pv_synchook which I set to the following function.
+ * This should sync all filesystems and return, for now it just
+ * prints out pretty messages and returns.
+ */
+void prom_sync_me(void)
 {
-       unsigned char c;
+	printk("PROM SYNC COMMAND...\n");
+	show_free_areas();
+	printk("Returning to prom\n");
+	return;
+}
 
-       while ((c = *(p++)) != 0)
-       {
-               if (c == '\n') romvec->pv_v2devops.v2_dev_write 
-                       ((*romvec->pv_v2bootargs.fd_stdout), "\r", 1);
-               romvec->pv_v2devops.v2_dev_write 
-                       ((*romvec->pv_v2bootargs.fd_stdout), &c, 1);
-       }
+unsigned int boot_flags;
+#define BOOTME_DEBUG  0x1
+#define BOOTME_SINGLE 0x2
+#define BOOTME_KGDB   0x3
+
+/* This routine does no error checking, make sure your string is sane
+ * before calling this!
+ * XXX This is cheese, make generic and better.
+ */
+void
+boot_flags_init(char *commands)
+{
+	int i;
+	for(i=0; i<strlen(commands); i++)
+		if(commands[i]=='-')
+			switch(commands[i+1]) {
+			case 'd':
+				boot_flags |= BOOTME_DEBUG;
+				break;
+			case 's':
+				boot_flags |= BOOTME_SINGLE;
+				break;
+			case 'h':
+				printk("boot_flags_init: Found halt flag, doing so now...\n");
+				halt();
+				break;
+			case 'k':
+				printk("Found KGDB boot flag...\n");
+				boot_flags |= BOOTME_KGDB;
+				break;
+			default:
+				printk("boot_flags_init: Unknown boot arg (-%c)\n",
+				       commands[i+1]);
+				break;
+			};
 
-       return;
+	return;
 }
 
-
 /* This routine will in the future do all the nasty prom stuff
  * to probe for the mmu type and its parameters, etc. This will
  * also be where SMP things happen plus the Sparc specific memory
@@ -95,23 +133,133 @@
  */
 
 extern void register_console(void (*proc)(const char *));
-extern unsigned int prom_iface_vers, end_of_phys_memory;
+extern void load_mmu(void);
+extern int prom_probe_memory(void);
+extern void probe_mmu(int node);
+extern void get_idprom(void);
+extern void srmmu_patch_fhandlers(void);
+extern unsigned int prom_iface_vers, end_of_phys_memory, phys_bytes_of_ram;
+extern char cputypval;
+extern unsigned long start;
+char sparc_command_line[256];  /* Should be enough */
+enum sparc_cpu sparc_cpu_model;
+
+struct tt_entry *sparc_ttable;
+
+/* #define DEBUG_CMDLINE */
 
 void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
-	if(romvec->pv_romvers == 0) {
-	  register_console(sparc_console_print);
-	} else {
-	  register_console(sparc_console_print_v3);
-	};
-
-	printk("Sparc PROM-Console registered...\n");
-	get_idprom();     /* probe_devices expects this to be done */
-	probe_devices();  /* cpu/fpu, mmu probes */
+	int counter, total, i, node;
+	char devtype[64];
 
+	sparc_ttable = (struct tt_entry *) &start;
+
+	register_console(sparc_console_print);
+
+	/* Initialize PROM console and command line. */
+	*cmdline_p = prom_getbootargs();
+	boot_flags_init(*cmdline_p);
+
+	/* Synchronize with debugger if necessary.  Grrr, have to check
+	 * the boot flags too. ;(
+	 */
+	if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
+	   ((*(short *)linux_dbvec) != -1)) {
+		printk("Booted under debugger. Syncing up trap table.\n");
+		/* Sync us up... */
+		(*(linux_dbvec->teach_debugger))();
+
+		SP_ENTER_DEBUGGER;
+	}
+
+	/* Set sparc_cpu_model */
+	sparc_cpu_model = sun_unknown;
+	if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
+	if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
+	if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
+	if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
+	if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
+	printk("ARCH: ");
+	switch(sparc_cpu_model)
+	  {
+	  case sun4c:
+		  memset(phys_seg_map, 0x0, sizeof(phys_seg_map[PSEG_ENTRIES]));
+		  put_segmap(IOBASE_VADDR, IOBASE_SUN4C_SEGMAP);
+		  phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV;
+		  node = prom_root_node;
+
+		  printk("SUN4C\n");
+		  break;
+          case sun4m:
+		  node = prom_getchild(prom_root_node);
+		  prom_getproperty(node, "device_type", devtype, sizeof(devtype));
+		  while(strcmp(devtype, "cpu") != 0) {
+			  node = prom_getsibling(node);
+			  prom_getproperty(node, "device_type", devtype,
+					   sizeof(devtype));
+		  }
+		  /* Patch trap table. */
+		  srmmu_patch_fhandlers();
+		  printk("SUN4M\n");
+		  break;
+	  case sun4d:
+		  printk("SUN4D\n");
+		  break;
+	  case sun4e:
+		  printk("SUN4E\n");
+		  break;
+	  case sun4u:
+		  printk("SUN4U\n");
+		  break;
+	  default:
+		  printk("UNKNOWN!\n");
+		  break;
+	  };
+
+	/* probe_devices() expects this to be done. */
+	get_idprom();
+
+	/* Probe the mmu constants. */
+	probe_mmu(node);
+
+	/* Set pointers to memory management routines. */
+	load_mmu();
+
+	/* Probe for memory. */
+	total = prom_probe_memory();
 	*memory_start_p = (((unsigned long) &end));
-	*memory_end_p = (((unsigned long) end_of_phys_memory));
+
+	printk("Physical Memory: %d bytes (in hex %08lx)\n", (int) total,
+	       (unsigned long) total);
+
+	for(i=0; sp_banks[i].num_bytes != 0; i++) {
+#if 0
+		printk("Bank %d:  base 0x%x  bytes %d\n", i,
+		       (unsigned int) sp_banks[i].base_addr, 
+		       (int) sp_banks[i].num_bytes);
+#endif
+		end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes;
+	}
+
+	/* Set prom sync hook pointer */
+	prom_setsync(prom_sync_me);
+
+	init_task.mm->start_code = PAGE_OFFSET;
+	init_task.mm->end_code = PAGE_OFFSET + (unsigned long) &etext;
+	init_task.mm->end_data = PAGE_OFFSET + (unsigned long) &edata;
+	init_task.mm->brk = PAGE_OFFSET + (unsigned long) &end;
+	init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
+
+	/* Grrr, wish I knew why I have to do this ;-( */
+	for(counter=1; counter<NR_TASKS; counter++) {
+		task[counter] = NULL;
+	}
+
+	*memory_end_p = (((unsigned long) (total) + PAGE_OFFSET));
+
+	return;
 }
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v1.3.3/linux/arch/sparc/kernel/traps.c	Thu Feb  2 08:45:28 1995
+++ linux/arch/sparc/kernel/traps.c	Thu Jun 15 06:05:18 1995
@@ -1,7 +1,7 @@
 /*
  * arch/sparc/kernel/traps.c
  *
- * Copyright 1994 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 /*
@@ -11,37 +11,274 @@
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
 
-void do_hw_interrupt(unsigned long type, unsigned long vector)
-{
-  if (vector == 14) {
-    jiffies++;
-    return;
-  }
+#include <asm/delay.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mp.h>
+#include <asm/kdebug.h>
 
-  /* Just print garbage for everything else for now. */
+void
+do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
+{
 
-  printk("Unimplemented Sparc TRAP, vector = %lx type = %lx\n", vector, type);
+  printk("Unimplemented Sparc TRAP, type = %02lx psr = %08lx pc = %08lx\n",
+	 type, psr, pc);
+  halt();
 
   return;
 }
 
-extern unsigned long *trapbase;
+void
+do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Illegal instruction at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Privileged instruction at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Unaligned memory access at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Floating Point Disabled trap at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Floating Point Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Tag overflow trap at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_iacc_error(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Instruction Access Error at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Co-Processor disabled trap at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_dacc_error(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Data Access Error at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Divide By Zero Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_dstore_error(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Data Store Error at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+void
+handle_dacc_mmu_miss(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
+{
+	printk("Data Access MMU-Miss Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
 
-void trap_init(void)
+void
+handle_iacc_mmu_miss(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		       unsigned long psr)
 {
+	printk("Instruction Access MMU-Miss Exception at PC %08lx NPC %08lx PSR %08lx\n",
+	       pc, npc, psr);
+	halt();
+	return;
+}
+
+/* Since we have our mappings set up, on multiprocessors we can spin them
+ * up here so that timer interrupts work during initialization.
+ */
+
+extern void sparc_cpu_startup(void);
 
-  /* load up the trap table */
+extern int linux_num_cpus;
+extern pgd_t *lnx_root;
 
-#if 0 /* not yet */
-  __asm__("wr %0, 0x0, %%tbr\n\t"
-	  "nop; nop; nop\n\t" : :
-	  "r" (trapbase));
+int linux_smp_still_initting;
+unsigned int thiscpus_tbr;
+int thiscpus_mid;
+
+/* #define SMP_TESTING */
+
+void
+trap_init(void)
+{
+	struct linux_prom_registers ctx_reg;
+	int i;
+
+	if(linux_num_cpus == 1) {
+		printk("trap_init: Uniprocessor detected.\n");
+		return;
+	}
+	if(sparc_cpu_model != sun4m) {
+		printk("trap_init: Multiprocessor on a non-sun4m! Aieee...\n");
+		printk("trap_init: Cannot continue, bailing out.\n");
+		prom_halt();
+	}
+	/* Ok, we are on a sun4m with multiple cpu's */
+	printk("trap_init: Multiprocessor detected, initiating CPU-startup. cpus=%d\n",
+	       linux_num_cpus);
+	linux_smp_still_initting = 1;
+	ctx_reg.which_io = 0x0;  /* real ram */
+	ctx_reg.phys_addr = (char *) (((unsigned long) lnx_root) - PAGE_OFFSET);
+	ctx_reg.reg_size = 0x0;
+	/* This basically takes every cpu, loads up our Linux context table
+	 * into it's context table pointer register, inits it at the low level
+	 * and then makes it spin in an endless loop...
+	 */
+	for(i=0; i<linux_num_cpus; i++) {
+		if((linux_cpus[i].mid & (~8)) != 0x0) {
+			static int cpuid = 0;
+			cpuid = (linux_cpus[i].mid & (~8));
+			percpu_table[cpuid].cpu_is_alive = 0;
+			thiscpus_mid = linux_cpus[i].mid;
+			thiscpus_tbr = (unsigned int)
+				percpu_table[cpuid].trap_table;
+#ifdef SMP_TESTING
+			printk("thiscpus_tbr = %08x\n", thiscpus_tbr);
+			printk("About to fire up cpu %d mid %d cpuid %d\n", i,
+			       linux_cpus[i].mid, cpuid);
 #endif
+			prom_startcpu(linux_cpus[i].prom_node, &ctx_reg, 0x0,
+				      (char *) sparc_cpu_startup);
+			printk("Waiting for cpu %d to start up...\n", i);
+			while(percpu_table[cpuid].cpu_is_alive == 0) {
+				static int counter = 0;
+				counter++;
+				if(counter>200) {
+#ifdef SMP_TESTING
+					printk("UGH, CPU would not start up ;-( \n");
+#endif
+					break;
+				}
+				__delay(200000);
+			}
+		}
+	}
 
-  return;
+	linux_smp_still_initting = 1;
+
+	return;
 }
 
-void die_if_kernel(char * str, struct pt_regs * regs, long err)
+void
+die_if_kernel(char * str, struct pt_regs * regs, long err)
 {
   return;
 }
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v1.3.3/linux/arch/sparc/mm/Makefile	Sun Jan 22 23:02:47 1995
+++ linux/arch/sparc/mm/Makefile	Thu Jun  8 23:52:15 1995
@@ -14,7 +14,7 @@
 .c.s:
 	$(CC) $(CFLAGS) -S $<
 
-OBJS	= fault.o vac-flush.o init.o
+OBJS	= fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o
 
 mm.o: $(OBJS)
 	$(LD) -r -o mm.o $(OBJS)
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v1.3.3/linux/arch/sparc/mm/fault.c	Sun Feb 26 20:46:20 1995
+++ linux/arch/sparc/mm/fault.c	Sun Jun 25 07:06:31 1995
@@ -1,3 +1,8 @@
+/* fault.c:  Page fault handlers for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
@@ -8,11 +13,18 @@
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <asm/openprom.h>
+#include <asm/idprom.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/memreg.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/kdebug.h>
 
-extern unsigned long pg0[1024];		/* page table for 0-4MB for everybody */
-extern struct sparc_phys_banks sp_banks[14];
+#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
+
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+extern int prom_node_root;
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
@@ -42,46 +54,37 @@
  */
 #undef CONFIG_TEST_VERIFY_AREA
 
-/* Traverse the memory lists in the prom to see how much physical we
- * have.
- */
-
-unsigned long
-probe_memory(void)
+/* Nice, simple, prom library does all the sweating for us. ;) */
+int prom_probe_memory (void)
 {
-  register struct linux_romvec *lprom;
   register struct linux_mlist_v0 *mlist;
   register unsigned long bytes, base_paddr, tally;
   register int i;
 
-  bytes = tally = 0;
-  base_paddr = 0;
-  i=0;
-  lprom = romvec;
-  switch(lprom->pv_romvers)
-    {
-    case 0:
-      mlist=(*(lprom->pv_v0mem.v0_totphys));
-      bytes = tally = mlist->num_bytes;
-      base_paddr = (unsigned long) mlist->start_adr;
-
-      sp_banks[0].base_addr = base_paddr;
-      sp_banks[0].num_bytes = bytes;
-
-      if(mlist->theres_more != (void *)0) {
-	  i++;
-	  mlist=mlist->theres_more;
-	  bytes=mlist->num_bytes;
-	  tally += bytes;
-	  sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
-	  sp_banks[i].num_bytes = mlist->num_bytes;
-	}
-      break;
-    case 2:
-      printk("no v2 memory probe support yet.\n");
-      (*(lprom->pv_halt))();
+  i = 0;
+  mlist= *prom_meminfo()->v0_available;
+  bytes = tally = mlist->num_bytes;
+  base_paddr = (unsigned long) mlist->start_adr;
+  
+  sp_banks[0].base_addr = base_paddr;
+  sp_banks[0].num_bytes = bytes;
+
+  while (mlist->theres_more != (void *) 0){
+    i++;
+    mlist = mlist->theres_more;
+    bytes = mlist->num_bytes;
+    tally += bytes;
+    if (i >= SPARC_PHYS_BANKS-1) {
+      printk ("The machine has more banks that this kernel can support\n"
+	      "Increase the SPARC_PHYS_BANKS setting (currently %d)\n",
+	      SPARC_PHYS_BANKS);
+      i = SPARC_PHYS_BANKS-1;
       break;
     }
+    
+    sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
+    sp_banks[i].num_bytes = mlist->num_bytes;
+  }
 
   i++;
   sp_banks[i].base_addr = 0xdeadbeef;
@@ -90,84 +93,464 @@
   return tally;
 }
 
-/* Sparc routine to reserve the mapping of the open boot prom */
+/* Traverse the memory lists in the prom to see how much physical we
+ * have.
+ */
+unsigned long
+probe_memory(void)
+{
+	int total;
+
+	total = prom_probe_memory();
 
-/* uncomment this for FAME and FORTUNE! */
-/* #define DEBUG_MAP_PROM */
+	/* Oh man, much nicer, keep the dirt in promlib. */
+	return total;
+}
 
-int
-map_the_prom(int curr_num_segs)
+asmlinkage void sparc_txtmem_error(int type, unsigned long sync_err_reg,
+				   unsigned long sync_vaddr,
+				   unsigned long async_err_reg,
+				   unsigned long async_vaddr)
 {
-  register unsigned long prom_va_begin;
-  register unsigned long prom_va_end;
-  register int segmap_entry, i;
+  printk("Aieee, sparc text page access error, halting\n");
+  printk("type = %d  sync_err_reg = 0x%x  sync_vaddr = 0x%x\n",
+	 type, (unsigned int) sync_err_reg, (unsigned int) sync_vaddr);
+  printk("async_err_reg = 0x%x  async_vaddr = 0x%x\n",
+	 (unsigned int) async_err_reg, (unsigned int) async_vaddr);
+  halt();
+}
 
-  prom_va_begin = LINUX_OPPROM_BEGVM;
-  prom_va_end   = LINUX_OPPROM_ENDVM;
+/* #define DEBUG_SPARC_TEXT_ACCESS_FAULT */
 
-#ifdef DEBUG_MAP_PROM
-  printk("\ncurr_num_segs = 0x%x\n", curr_num_segs);
+asmlinkage void sparc_text_access_fault(int type, unsigned long sync_err_reg,
+					unsigned long sync_vaddr,
+					unsigned long pc, unsigned long psr,
+					struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address;
+
+  address = sync_vaddr;
+#ifdef DEBUG_SPARC_TEXT_ACCESS_FAULT
+  printk("Text FAULT: address = %08lx  code = %08lx\n",
+	 (unsigned long) address, (unsigned long) sync_err_reg);
+  printk("PC = %08lx\n", (unsigned long) regs->pc);
+  SP_ENTER_DEBUGGER;
+  halt();
 #endif
+  vma = find_vma(current, address);
+  if(!vma) {
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+  goto bad_area;
 
-  while( prom_va_begin < prom_va_end)
-    {
-      segmap_entry=get_segmap(prom_va_begin);
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+  handle_mm_fault(vma, address, 0);
+  return;
 
-      curr_num_segs = ((segmap_entry<curr_num_segs) 
-		       ? segmap_entry : curr_num_segs);
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+	 (unsigned long) current->tss.pgd_ptr);
+  halt();
+}
 
-      for(i = num_contexts; --i > 0;)
-	  (*romvec->pv_setctxt)(i, (char *) prom_va_begin,
-				segmap_entry);
+asmlinkage void sparc_datamem_error(int type, unsigned long sync_err_reg,
+				    unsigned long sync_vaddr,
+				    unsigned long async_err_reg,
+				    unsigned long async_vaddr)
+{
+  printk("Aieee, sparc data page access error, halting\n");
+  printk("type = %d  sync_err_reg = 0x%x  sync_vaddr = 0x%x\n",
+	 type, (unsigned int) sync_err_reg, (unsigned int) sync_vaddr);
+  printk("async_err_reg = 0x%x  async_vaddr = 0x%x\n",
+	 (unsigned int) async_err_reg, (unsigned int) async_vaddr);
+  printk("SYNC PAGE has MMU entry %08lx\n",
+	 (unsigned long) get_pte(sync_vaddr));
+  halt();
+}
 
-      if(segmap_entry == invalid_segment)
-	{
+/* #define DEBUG_SPARC_DATA_ACCESS_FAULT */
 
-#ifdef DEBUG_MAP_PROM
-	  printk("invalid_segments, virt_addr 0x%x\n", prom_va_begin);
+asmlinkage void sparc_data_access_fault(int type, unsigned long sync_err_reg,
+					unsigned long sync_vaddr,
+					unsigned long pc, unsigned long psr,
+					struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address;
+  int error_code;
+
+  address = sync_vaddr;
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+  printk("Data FAULT: address = %08lx  code = %08lx\n",
+	 (unsigned long) address, (unsigned long) sync_err_reg);
+  printk("PC = %08lx\n", (unsigned long) regs->pc);
+  printk("PTE = %08lx\n", (unsigned long) get_pte(address));
 #endif
+  vma = find_vma(current, address);
+  if(!vma) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+    printk("NULL VMA\n");
+#endif
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+
+  if(!(vma->vm_flags & VM_GROWSDOWN)) {
+    goto bad_area;
+  }
+  if(vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) {
+    goto bad_area;
+  }
 
-	  prom_va_begin += 0x40000;  /* num bytes per segment entry */
-	  continue;
-	}
+  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
+  vma->vm_start = (address & PAGE_MASK);
 
-      /* DUH, prom maps itself so that users can access it. This is
-       * broken.
-       */
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+  printk("Found good_area\n");
+#endif
+  if((sync_err_reg & SUN4C_SYNC_BADWRITE) &&
+     (sync_err_reg & SUN4C_SYNC_NPRESENT)) {
+    if(!(vma->vm_flags & VM_WRITE)) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+      printk("oops, vma not writable\n");
+#endif
+      goto bad_area;
+    }
+  } else {
+    if(sync_err_reg & SUN4C_SYNC_PROT) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+      printk("PROT violation\n");
+#endif
+      goto bad_area;
+    }
+    if(!(vma->vm_flags & (VM_READ | VM_EXEC))) {
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+      printk("vma not readable nor executable\n");
+#endif
+      goto bad_area;
+    }
+  }
 
-#ifdef DEBUG_MAP_PROM
-      printk("making segmap for prom privileged, va = 0x%x\n",
-	     prom_va_begin);
+  if(sync_err_reg & SUN4C_SYNC_BADWRITE)
+    error_code = 0x2;
+  else
+    error_code = 0x0;
+
+#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT 
+  printk("calling handle_mm_fault vma=%08lx addr=%08lx code=%d\n",
+	 (unsigned long) vma, (unsigned long) address,
+	 (int) error_code);
 #endif
+  handle_mm_fault(vma, address, error_code);
+  return;
 
-      for(i = 0x40; --i >= 0; prom_va_begin+=4096)
-	{
-	  put_pte(prom_va_begin, get_pte(prom_va_begin) | 0x20000000);
-	}
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if (wp_works_ok < 0 && address == 0x0) {
+	  wp_works_ok = 1;
+	  pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_SHARED));
+	  put_pte((unsigned long) 0x0, pg0[0]);
+	  printk("This Sparc honours the WP bit even when in supervisor mode. Good.\n");
+	  return;
+  }
+
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+	 (unsigned long) current->tss.pgd_ptr);
+  halt();
+}
 
-    }
+/* Dump the contents of the SRMMU fsr in a human readable format. */
+void
+dump_srmmu_fsr(unsigned long fsr)
+{
+	unsigned long ebe, l, at, ft, fav, ow;
 
-  printk("Mapped the PROM in all contexts...\n");
+	ebe = (fsr&SRMMU_FSR_EBE_MASK)>>10;
+	l = (fsr&SRMMU_FSR_L_MASK)>>8;
+	at = (fsr&SRMMU_FSR_AT_MASK)>>5;
+	ft = (fsr&SRMMU_FSR_FT_MASK)>>2;
+	fav = (fsr&SRMMU_FSR_FAV_MASK)>>1;
+	ow = (fsr&SRMMU_FSR_OW_MASK);
+
+	printk("FSR %08lx: ", fsr);
+
+	/* Ugh, the ebe is arch-dep, have to find out the meanings. */
+	printk("EBE<%s> ", (ebe == 0 ? "none" : (ebe == 1 ? "bus err" :
+						 (ebe == 2 ? "bus timeout" :
+						  (ebe == 4 ? "uncorrectable err" :
+						   (ebe == 8 ? "undefined err" :
+						    (ebe == 16 ? "parity err" :
+						     (ebe == 24 ? "tsunami parity err" :
+						      (ebe == 32 ? "store buf err" :
+						       (ebe == 64 ? "control space err" :
+							"VIKING emergency response team"))))))))));
+	printk("L<%s> ", (l == 0 ? "context table" : (l == 1 ? "level1" :
+						      (l == 2 ? "level2" :
+						       "level3"))));
+	printk("AT<%s> ", (at == 0 ? "user load" :
+			   (at == 1 ? "priv load" :
+			    (at == 2 ? "user rd/exec" :
+			     (at == 3 ? "priv rd/exec" :
+			      (at == 4 ? "user store data" :
+			       (at == 5 ? "priv store data" :
+				(at == 6 ? "user store inst" :
+				 "priv store inst"))))))));
+
+	printk("FT<%s> ", (ft == 0 ? "none" :
+			   (ft == 1 ? "invalid address" :
+			    (ft == 2 ? "prot violation" :
+			     (ft == 3 ? "priv violation" :
+			      (ft == 4 ? "translation error" :
+			       (ft == 5 ? "bus acc error" :
+				(ft == 6 ? "internal error" :
+				 "reserved"))))))));
 
-#ifdef DEBUG_MAP_PROM
-  printk("curr_num_segs = 0x%x\n", curr_num_segs);
-#endif
+	printk("FAV<%s> ", (fav == 0 ? "faddr invalid" : "faddr valid"));
+	printk("OW<%s>\n", (ow == 0 ? "fsr not overwritten" : "fsr overwritten"));
+
+	return;
+}
 
-  return curr_num_segs;
+/* #define DEBUG_SRMMU_TEXT_ACCESS_FAULT */
 
+void
+really_bad_srmmu_fault(int type, unsigned long fstatus, unsigned long faddr)
+{
+	/* Learn how to handle these later... */
+	printk("REALLY BAD SRMMU FAULT DETECTED\n");
+	printk("Bailing out...\n");
+	dump_srmmu_fsr(fstatus);
+	prom_halt();
+	return;
 }
 
+asmlinkage void srmmu_text_access_fault(int type, unsigned long fstatus,
+					unsigned long faddr,
+					unsigned long pc, unsigned long psr,
+					struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address;
+
+  /* Check for external bus errors and uncorrectable errors */
+  if(fstatus&SRMMU_FSR_EBE_MASK)
+	  printk("External Bus Error detected during a text fault.\n");
+
+  /* Check for multiple faults... */
+  if(fstatus&SRMMU_FSR_OW_MASK && (fstatus&SRMMU_FSR_FT_TRANS)) {
+	  printk("Multiple faults detected in text fault handler\n");
+	  printk("Fault number one: Text fault at addr %08lx", faddr);
+	  printk("Fault number two: Translation Error\n");
+	  printk("Giving up...\n");
+	  prom_halt();
+  }
+	  
+  if(fstatus&(SRMMU_FSR_EBE_BERR | SRMMU_FSR_EBE_BTIMEO | SRMMU_FSR_EBE_UNCOR))
+	  really_bad_srmmu_fault(type, fstatus, faddr);
+
+  /* Ok, we should be able to handle it at this point. */
+
+  address = faddr;
+#ifdef DEBUG_SRMMU_TEXT_ACCESS_FAULT
+  printk("Text FAULT: address = %08lx  code = %08lx\n",
+	 (unsigned long) address, (unsigned long) fstatus);
+  printk("PC = %08lx\n", (unsigned long) regs->pc);
+  dump_srmmu_fsr(fstatus);
+  halt();
+#endif
+
+  /* Ugh, how often does this happen? ;-( */
+  if(!(fstatus&SRMMU_FSR_FAV_MASK)) {
+	  printk("Fault address register is INVALID!  Since this is a text\n");
+	  printk("fault I'll use the value of the trapped PC instead...\n");
+	  address = regs->pc;
+  }
+
+  /* Ugh, I don't wanna know... */
+
+  vma = find_vma(current, address);
+  if(!vma) {
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+  goto bad_area;
+
 /*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
-{
-	die_if_kernel("Oops", regs, error_code);
-	do_exit(SIGKILL);
+good_area:
+  do_no_page(vma, address, 0);
+  return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+	 (unsigned long) current->tss.pgd_ptr);
+  halt();
 }
 
+/* #define DEBUG_SRMMU_DATA_ACCESS_FAULT */
 
+asmlinkage void srmmu_data_access_fault(int type, unsigned long fstatus,
+					unsigned long faddr,
+					unsigned long afstatus,
+					unsigned long afaddr,
+					struct pt_regs *regs)
+{
+  struct vm_area_struct *vma;
+  unsigned long address, pc, psr;
+  int error_code;
+
+  pc = regs->pc;
+  psr= regs->psr;
+  address = faddr;
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+  printk("Data FAULT: address = %08lx  code = %08lx\n",
+	 (unsigned long) address, (unsigned long) fstatus);
+  printk("PC = %08lx\n", (unsigned long) pc);
+  printk("afsr = %08lx afaddr = %08lx\n", afstatus, afaddr);
+  dump_srmmu_fsr(fstatus);
+#endif
 
+  /* I figure if I make the panic's look like they came from SunOS or Solaris
+   * my life will be a lot easier ;-)
+   */
+  if(!(fstatus&SRMMU_FSR_FAV_MASK)) {
+	  dump_srmmu_fsr(fstatus);
+	  panic("hat_pteload: Fault address is invalid on a data fault, I'm confused...\n");
+  }
+
+#if 0 /* I see this all the time on supersparcs ;-( */
+  if(fstatus&SRMMU_FSR_OW_MASK) {
+	  dump_srmmu_fsr(fstatus);
+	  panic("hat_pteload: Multiple faults at once, giving up...\n");
+  }
+#endif
+
+  vma = find_vma(current, address);
+  if(!vma) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+    printk("NULL VMA\n");
+#endif
+    goto bad_area;
+  }
+  if(vma->vm_start <= address)
+    goto good_area;
+
+  if(!(vma->vm_flags & VM_GROWSDOWN)) {
+    goto bad_area;
+  }
+  if(vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) {
+    goto bad_area;
+  }
 
+  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
+  vma->vm_start = (address & PAGE_MASK);
+
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+  printk("Found good_area\n");
+#endif
+  if((fstatus & SUN4C_SYNC_BADWRITE) &&
+     (fstatus & SUN4C_SYNC_NPRESENT)) {
+    if(!(vma->vm_flags & VM_WRITE)) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+      printk("oops, vma not writable\n");
+#endif
+      goto bad_area;
+    }
+  } else {
+    if(fstatus & SUN4C_SYNC_PROT) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+      printk("PROT violation\n");
+#endif
+      goto bad_area;
+    }
+    if(!(vma->vm_flags & (VM_READ | VM_EXEC))) {
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+      printk("vma not readable nor executable\n");
+#endif
+      goto bad_area;
+    }
+  }
+
+  if(fstatus & SUN4C_SYNC_BADWRITE)
+    error_code = 0x2;
+  else
+    error_code = 0x0;
+
+#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT 
+  printk("calling do_no_page vma=%08lx addr=%08lx code=%d\n",
+	 (unsigned long) vma, (unsigned long) address,
+	 (int) error_code);
+#endif
+  do_no_page(vma, address, error_code);
+  return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+  if (wp_works_ok < 0 && address == 0x0) {
+	  wp_works_ok = 1;
+	  /* Advance the PC and NPC over the test store. */
+	  regs->pc = regs->npc;
+	  regs->npc += 4;
+	  printk("This Sparc honours the WP bit even when in supervisor mode. Good.\n");
+	  return;
+  }
+
+  if((unsigned long) address < PAGE_SIZE) {
+    printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+  } else
+    printk(KERN_ALERT "Unable to handle kernel paging request");
+  printk(" at virtual address %08lx\n",address);
+  printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
+	 (unsigned long) current->tss.pgd_ptr);
+  halt();
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.3.3/linux/arch/sparc/mm/init.c	Wed Mar  1 09:12:33 1995
+++ linux/arch/sparc/mm/init.c	Sun Jun 11 05:46:13 1995
@@ -21,16 +21,29 @@
 #include <asm/vac-ops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/vaddrs.h>
 
 extern void scsi_mem_init(unsigned long);
 extern void sound_mem_init(void);
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
-extern int map_the_prom(int);
+struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+
+/* The following number keeps track of which page table is to
+ * next be allocated in a page.  This is necessary since there
+ * are 16 page tables per page on the space.
+ */
+unsigned long ptr_in_current_pgd;
+
+/* This keeps track of which physical segments are in use right now. */
+unsigned int phys_seg_map[PSEG_ENTRIES];
+unsigned int phys_seg_life[PSEG_ENTRIES];
+
+/* Context allocation. */
+struct task_struct *ctx_tasks[MAX_CTXS];
+int ctx_tasks_last_frd;
 
-struct sparc_phys_banks sp_banks[14];
-unsigned long *sun4c_mmu_table;
 extern int invalid_segment, num_segmaps, num_contexts;
 
 /*
@@ -61,7 +74,7 @@
 unsigned long __zero_page(void)
 {
 	memset((void *) ZERO_PGE, 0, PAGE_SIZE);
-	return ZERO_PGE;
+	return (unsigned long) ZERO_PGE;
 }
 
 void show_mem(void)
@@ -93,252 +106,140 @@
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
+extern pgprot_t protection_map[16];
 
 /*
- * paging_init() sets up the page tables: in the alpha version this actually
- * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
+ * paging_init() sets up the page tables: We call the MMU specific
+ * init routine based upon the Sun model type on the Sparc.
  *
- * The bootup sequence put the virtual page table into high memory: that
- * means that we can change the L1 page table by just using VL1p below.
  */
+extern unsigned long sun4c_paging_init(unsigned long, unsigned long);
+extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
+extern unsigned long probe_devices(unsigned long);
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-	unsigned long i, a, b, mask=0;
-	unsigned long curseg, curpte, num_inval;
-	unsigned long address;
-	pte_t *pg_table;
-
-	register int num_segs, num_ctx;
-	register char * c;
-
-	num_segs = num_segmaps;
-	num_ctx = num_contexts;
-
-	num_segs -= 1;
-	invalid_segment = num_segs;
-
-	start_mem = free_area_init(start_mem, end_mem);
-
-/* On the sparc we first need to allocate the segmaps for the
- * PROM's virtual space, and make those segmaps unusable. We
- * map the PROM in ALL contexts therefore the break key and the
- * sync command work no matter what state you took the machine
- * out of
- */
-
-	printk("mapping the prom...\n");
-	num_segs = map_the_prom(num_segs);
-
-	start_mem = PAGE_ALIGN(start_mem);
+	int i;
 
-	/* Set up static page tables in kernel space, this will be used
-	 * so that the low-level page fault handler can fill in missing
-	 * TLB entries since all mmu entries cannot be loaded at once
-	 * on the sun4c.
-	 */
-
-#if 0
-	/* ugly debugging code */
-	for(i=0; i<40960; i+=PAGE_SIZE)
-	  printk("address=0x%x  vseg=%d  pte=0x%x\n", (unsigned int) i,
-		 (int) get_segmap(i), (unsigned int) get_pte(i));
-#endif
+	switch(sparc_cpu_model) {
+	case sun4c:
+		start_mem = sun4c_paging_init(start_mem, end_mem);
+		break;
+	case sun4m:
+	case sun4d:
+	case sun4e:
+		start_mem = srmmu_paging_init(start_mem, end_mem);
+		break;
+	default:
+		printk("paging_init: Cannot init paging on this Sparc\n");
+		printk("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+		printk("paging_init: Halting...\n");
+		halt();
+	};
+
+	/* Initialize context map. */
+	for(i=0; i<MAX_CTXS; i++) ctx_tasks[i] = NULL;
+
+	/* Initialize the protection map */
+	protection_map[0] = __P000;
+	protection_map[1] = __P001;
+	protection_map[2] = __P010;
+	protection_map[3] = __P011;
+	protection_map[4] = __P100;
+	protection_map[5] = __P101;
+	protection_map[6] = __P110;
+	protection_map[7] = __P111;
+	protection_map[8] = __S000;
+	protection_map[9] = __S001;
+	protection_map[10] = __S010;
+	protection_map[11] = __S011;
+	protection_map[12] = __S100;
+	protection_map[13] = __S101;
+	protection_map[14] = __S110;
+	protection_map[15] = __S111;
 
-	printk("Setting up kernel static mmu table... bounce bounce\n");
+	start_mem = probe_devices(start_mem);
 
-	address = 0; /* ((unsigned long) &end) + 524288; */
-	sun4c_mmu_table = (unsigned long *) start_mem;
-	pg_table = (pte_t *) start_mem;
-	curseg = curpte = num_inval = 0;
-	while(address < end_mem) {
-	  if(curpte == 0)
-	    put_segmap((address&PGDIR_MASK), curseg);
-	  for(i=0; sp_banks[i].num_bytes != 0; i++)
-	    if((address >= sp_banks[i].base_addr) && 
-	       (address <= (sp_banks[i].base_addr + sp_banks[i].num_bytes)))
-	      goto good_address;
-	  /* No physical memory here, so set the virtual segment to
-	   * the invalid one, and put an invalid pte in the static
-	   * kernel table.
-	   */
-	  *pg_table = mk_pte((address >> PAGE_SHIFT), PAGE_INVALID);
-	  pg_table++; curpte++; num_inval++;
-	  if(curpte > 63) {
-	    if(curpte == num_inval) {
-	      put_segmap((address&PGDIR_MASK), invalid_segment);
-	    } else {
-	      put_segmap((address&PGDIR_MASK), curseg);
-	      curseg++;
-	    }
-	    curpte = num_inval = 0;
-	  }
-	  address += PAGE_SIZE;
-	  continue;
-
-	  good_address:
-	  /* create pte entry */
-	  if(address < (((unsigned long) &end) + 524288)) {
-	    pte_val(*pg_table) = get_pte(address);
-	  } else {
-	    *pg_table = mk_pte((address >> PAGE_SHIFT), PAGE_KERNEL);
-	    put_pte(address, pte_val(*pg_table));
-	  }
-
-	  pg_table++; curpte++;
-	  if(curpte > 63) {
-	    put_segmap((address&PGDIR_MASK), curseg);
-	    curpte = num_inval = 0;
-	    curseg++;
-	  }
-	  address += PAGE_SIZE;
-	}	  
-
-	start_mem = (unsigned long) pg_table;
-	/* ok, allocate the kernel pages, map them in all contexts
-	 * (with help from the prom), and lock them. Isn't the sparc
-	 * fun kiddies? TODO
-	 */
-
-#if 0
-	/* ugly debugging code */
-	for(i=0x1a3000; i<(0x1a3000+40960); i+=PAGE_SIZE)
-	  printk("address=0x%x  vseg=%d  pte=0x%x\n", (unsigned int) i,
-		 (int) get_segmap(i), (unsigned int) get_pte(i));
-	halt();
-#endif
+	return start_mem;
+}
 
-	b=PGDIR_ALIGN(start_mem)>>18;
-	c= (char *)0x0;
+extern unsigned long sun4c_test_wp(unsigned long);
+extern void srmmu_test_wp(void);
 
-	printk("mapping kernel in all contexts...\n");
+void mem_init(unsigned long start_mem, unsigned long end_mem)
+{
+	int codepages = 0;
+	int reservedpages = 0;
+	int datapages = 0;
+	unsigned long tmp2, addr;
+	extern char etext;
 
-	for(a=0; a<b; a++)
-	  {
-	    for(i=0; i<num_contexts; i++)
-	      {
-		/* map the kernel virt_addrs */
-		(*(romvec->pv_setctxt))(i, (char *) c, a);
-	      }
-	    c += 0x40000;
-	  }
-
-	/* Ok, since now mapped in all contexts, we can free up
-	 * context zero to be used amongst user processes.
-	 */
-
-	/* free context 0 here TODO */
-
-	/* invalidate all user pages and initialize the pte struct 
-	 * for userland. TODO
-	 */
-
-	/* Make the kernel text unwritable and cacheable, the prom
-	 * loaded our text as writable, only sneaky sunos kernels need
-	 * self-modifying code.
-	 */
-
-	a= (unsigned long) &etext;
-	mask=~(PTE_NC|PTE_W);    /* make cacheable + not writable */
-
-	/* must do for every segment since kernel uses all contexts
-	 * and unlike some sun kernels I know of, we can't hard wire
-	 * context 0 just for the kernel, that is unnecessary.
-	 */
-
-	for(i=0; i<8; i++)
-	  {
-	    b=PAGE_ALIGN((unsigned long) &trapbase);
-
-	    switch_to_context(i);
-
-	    for(;b<a; b+=4096)
-	      {
-		put_pte(b, (get_pte(b) & mask));
-	      }
-	  }
-
-	invalidate(); /* flush the virtual address cache */
-
-	printk("\nCurrently in context - ");
-	for(i=0; i<num_contexts; i++)
-	  {
-	    switch_to_context(i);
-	    printk("%d ", (int) i);
-	  }
-	printk("\n");
+	end_mem &= PAGE_MASK;
+	high_memory = end_mem;
 
-	switch_to_context(0);
+	start_mem = PAGE_ALIGN(start_mem);
 
-	invalidate();
-	return start_mem;
-}
+	addr = PAGE_OFFSET;
+	while(addr < start_mem) {
+		mem_map[MAP_NR(addr)] = MAP_PAGE_RESERVED;
+		addr += PAGE_SIZE;
+	}
 
-void mem_init(unsigned long start_mem, unsigned long end_mem)
-{
-  unsigned long start_low_mem = PAGE_SIZE;
-  int codepages = 0;
-  int reservedpages = 0;
-  int datapages = 0;
-  int i = 0;
-  unsigned long tmp, limit, tmp2, addr;
-  extern char etext;
-
-  end_mem &= PAGE_MASK;
-  high_memory = end_mem;
-
-  start_low_mem = PAGE_ALIGN(start_low_mem);
-  start_mem = PAGE_ALIGN(start_mem);
-
-  for(i = 0; sp_banks[i].num_bytes != 0; i++) {
-    tmp = sp_banks[i].base_addr;
-    limit = (sp_banks[i].base_addr + sp_banks[i].num_bytes);
-    if(tmp<start_mem) {
-      if(limit>start_mem)
-	tmp = start_mem;
-      else continue;
-    }
-
-    while(tmp<limit) {
-      mem_map[MAP_NR(tmp)] = 0;
-      tmp += PAGE_SIZE;
-    }
-    if(sp_banks[i+1].num_bytes != 0)
-      while(tmp < sp_banks[i+1].base_addr) {
-	mem_map[MAP_NR(tmp)] = MAP_PAGE_RESERVED;
-	tmp += PAGE_SIZE;
-      }
-  }
+	for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE)
+			mem_map[MAP_NR(addr)] = 0;
 
 #ifdef CONFIG_SCSI
-  scsi_mem_init(high_memory);
+	scsi_mem_init(high_memory);
 #endif
 
-  for (addr = 0; addr < high_memory; addr += PAGE_SIZE) {
-    if(mem_map[MAP_NR(addr)]) {
-      if (addr < (unsigned long) &etext)
-	codepages++;
-      else if(addr < start_mem)
-	datapages++;
-      else
-	reservedpages++;
-      continue;
-    }
-    mem_map[MAP_NR(addr)] = 1;
-    free_page(addr);
-  }
-
-  tmp2 = nr_free_pages << PAGE_SHIFT;
-
-  printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
-	 tmp2 >> 10,
-	 high_memory >> 10,
-	 codepages << (PAGE_SHIFT-10),
-	 reservedpages << (PAGE_SHIFT-10),
-	 datapages << (PAGE_SHIFT-10));
+	for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+		if(mem_map[MAP_NR(addr)]) {
+			if (addr < (unsigned long) &etext)
+				codepages++;
+			else if(addr < start_mem)
+				datapages++;
+			else
+				reservedpages++;
+			continue;
+		}
+		mem_map[MAP_NR(addr)] = 1;
+		free_page(addr);
+	}
+
+	tmp2 = nr_free_pages << PAGE_SHIFT;
+
+	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
+	       tmp2 >> 10,
+	       (high_memory - PAGE_OFFSET) >> 10,
+	       codepages << (PAGE_SHIFT-10),
+	       reservedpages << (PAGE_SHIFT-10),
+	       datapages << (PAGE_SHIFT-10));
+
+/* Heh, test write protection just like the i386, this is bogus but it is
+ * fun to do ;)
+ */
+	switch(sparc_cpu_model) {
+	case sun4c:
+		start_mem = sun4c_test_wp(start_mem);
+		break;
+	case sun4m:
+	case sun4d:
+	case sun4e:
+		srmmu_test_wp();
+		break;
+	default:
+		printk("mem_init: Could not test WP bit on this machine.\n");
+		printk("mem_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+		printk("mem_init: Halting...\n");
+		halt();
+	};
+
+#ifdef DEBUG_MEMINIT
+	printk("Breaker breaker...Roger roger.... Over and out...\n");
+#endif
+	invalidate();
 
-  invalidate();
-  return;
+	return;
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c
--- v1.3.3/linux/arch/sparc/mm/loadmmu.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/loadmmu.c	Thu Jun  8 23:52:59 1995
@@ -0,0 +1,118 @@
+/* loadmmu.c:  This code loads up all the mm function pointers once the
+ *             machine type has been determined.  It also sets the static
+ *             mmu values such as PAGE_NONE, etc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+void (*invalidate)(void);
+
+unsigned int pmd_shift, pmd_size, pmd_mask;
+unsigned int (*pmd_align)(unsigned int);
+unsigned int pgdir_shift, pgdir_size, pgdir_mask;
+unsigned int (*pgdir_align)(unsigned int);
+unsigned int ptrs_per_pte, ptrs_per_pmd, ptrs_per_pgd;
+
+pgprot_t page_none, page_shared, page_copy, page_readonly, page_kernel;
+pgprot_t page_invalid;
+
+/* Grrr... function pointers galore... */
+unsigned long (*pte_page)(pte_t);
+unsigned long (*pmd_page)(pmd_t);
+unsigned long (*pgd_page)(pgd_t);
+
+void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
+unsigned long (*(vmalloc_start))(void);
+void (*switch_to_context)(int);
+
+int (*pte_none)(pte_t);
+int (*pte_present)(pte_t);
+int (*pte_inuse)(pte_t *);
+void (*pte_clear)(pte_t *);
+void (*pte_reuse)(pte_t *);
+
+int (*pmd_none)(pmd_t);
+int (*pmd_bad)(pmd_t);
+int (*pmd_present)(pmd_t);
+int (*pmd_inuse)(pmd_t *);
+void (*pmd_clear)(pmd_t *);
+void (*pmd_reuse)(pmd_t *);
+
+int (*pgd_none)(pgd_t);
+int (*pgd_bad)(pgd_t);
+int (*pgd_present)(pgd_t);
+int (*pgd_inuse)(pgd_t *);
+void (*pgd_clear)(pgd_t *);
+void (*pgd_reuse)(pgd_t *);
+
+pte_t (*mk_pte)(unsigned long, pgprot_t);
+void (*pgd_set)(pgd_t *, pte_t *);
+pte_t (*pte_modify)(pte_t, pgprot_t);
+pgd_t * (*pgd_offset)(struct task_struct *, unsigned long);
+pmd_t * (*pmd_offset)(pgd_t *, unsigned long);
+pte_t * (*pte_offset)(pmd_t *, unsigned long);
+void (*pte_free_kernel)(pte_t *);
+pte_t * (*pte_alloc_kernel)(pmd_t *, unsigned long);
+
+void (*pmd_free_kernel)(pmd_t *);
+pmd_t * (*pmd_alloc_kernel)(pgd_t *, unsigned long);
+void (*pte_free)(pte_t *);
+pte_t * (*pte_alloc)(pmd_t *, unsigned long);
+
+void (*pmd_free)(pmd_t *);
+pmd_t * (*pmd_alloc)(pgd_t *, unsigned long);
+void (*pgd_free)(pgd_t *);
+
+pgd_t * (*pgd_alloc)(void);
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+int (*pte_read)(pte_t);
+int (*pte_write)(pte_t);
+int (*pte_exec)(pte_t);
+int (*pte_dirty)(pte_t);
+int (*pte_young)(pte_t);
+int (*pte_cow)(pte_t);
+
+pte_t (*pte_wrprotect)(pte_t);
+pte_t (*pte_rdprotect)(pte_t);
+pte_t (*pte_exprotect)(pte_t);
+pte_t (*pte_mkclean)(pte_t);
+pte_t (*pte_mkold)(pte_t);
+pte_t (*pte_uncow)(pte_t);
+pte_t (*pte_mkwrite)(pte_t);
+pte_t (*pte_mkread)(pte_t);
+pte_t (*pte_mkexec)(pte_t);
+pte_t (*pte_mkdirty)(pte_t);
+pte_t (*pte_mkyoung)(pte_t);
+pte_t (*pte_mkcow)(pte_t);
+
+extern void ld_mmu_sun4c(void);
+extern void ld_mmu_srmmu(void);
+
+void
+load_mmu(void)
+{
+	switch(sparc_cpu_model) {
+	case sun4c:
+		ld_mmu_sun4c();
+		break;
+	case sun4m:
+	case sun4d:
+	case sun4e:
+		ld_mmu_srmmu();
+		break;
+	default:
+		printk("load_mmu:  MMU support not available for this architecture\n");
+		printk("load_mmu:  sparc_cpu_model = %d\n", (int) sparc_cpu_model);
+		printk("load_mmu:  Halting...\n");
+		halt();
+	};
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v1.3.3/linux/arch/sparc/mm/srmmu.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/srmmu.c	Sun Jun 25 07:01:37 1995
@@ -0,0 +1,912 @@
+/* srmmu.c:  SRMMU specific routines for memory management.
+ *
+ * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@lab.ipmce.su)
+ */
+
+#include <linux/kernel.h>  /* for printk */
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/kdebug.h>
+#include <asm/vaddrs.h>
+#include <asm/traps.h>
+#include <asm/mp.h>
+#include <asm/cache.h>
+#include <asm/oplib.h>
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
+unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
+
+/* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job.
+ * Many of the page table/directory functions on the SRMMU use this
+ * routine.
+ *
+ * Having a complete physical ram structure walk happen for each
+ * invocation is quite costly.  However, this does do some nice
+ * sanity checking and we'll see when our maps don't match.  Eventually
+ * when I trust my code I will just do a direct mmu probe in mk_pte().
+ */
+static inline unsigned int
+srmmu_virt_to_phys(unsigned int vaddr)
+{
+	unsigned int paddr = 0;
+	unsigned int voff = (vaddr - PAGE_OFFSET);
+	int i;
+
+	for(i=0; sp_banks[i].num_bytes != 0; i++) {
+		if(voff < paddr + sp_banks[i].num_bytes) {
+			/* This matches. */
+			return sp_banks[i].base_addr + voff - paddr;
+		} else
+			paddr += sp_banks[i].num_bytes;
+	}
+	/* Shit, gotta consult the MMU, this shouldn't happen... */
+	printk("srmmu_virt_to_phys: SRMMU virt to phys translation failed, halting\n");
+	halt();
+}		
+
+static inline unsigned long
+srmmu_phys_to_virt(unsigned long paddr)
+{
+        int i;
+        unsigned long offset = PAGE_OFFSET;
+
+        for (i=0; sp_banks[i].num_bytes != 0; i++)
+        {
+                if (paddr >= sp_banks[i].base_addr &&
+                    paddr < (sp_banks[i].base_addr
+                             + sp_banks[i].num_bytes)) {
+                        return (paddr - sp_banks[i].base_addr) + offset;
+                } else
+                        offset += sp_banks[i].num_bytes;
+        }
+	printk("srmmu_phys_to_virt: Could not make translation, halting...\n");
+	halt();
+}
+
+unsigned long
+srmmu_vmalloc_start(void)
+{
+	return ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1));
+}
+
+unsigned long 
+srmmu_pmd_page(pmd_t pmd)
+{
+	unsigned long page;
+
+	page = (pmd_val(pmd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
+	return srmmu_phys_to_virt(page);
+}
+
+unsigned long
+srmmu_pgd_page(pgd_t pgd)
+{
+	unsigned long page;
+
+	page = (pgd_val(pgd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
+	return srmmu_phys_to_virt(page);
+}
+
+unsigned long 
+srmmu_pte_page(pte_t pte)
+{
+	unsigned long page;
+
+	page = (pte_val(pte) & (SRMMU_PTE_PPN_MASK)) << SRMMU_PTE_PPN_PADDR_SHIFT;
+	printk("srmmu_pte_page: page = %08lx\n", page);
+	return srmmu_phys_to_virt(page);
+}
+
+int srmmu_pte_none(pte_t pte)		{ return !pte_val(pte); }
+int srmmu_pte_present(pte_t pte)	{ return pte_val(pte) & SRMMU_ET_PTE; }
+int srmmu_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] != 1; }
+void srmmu_pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+void srmmu_pte_reuse(pte_t *ptep)
+{
+  if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(ptep)]++;
+}
+
+int srmmu_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+int srmmu_pmd_bad(pmd_t pmd)
+{
+	return ((pmd_val(pmd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
+		(srmmu_pmd_page(pmd) > high_memory);
+}
+
+int srmmu_pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & SRMMU_ET_PTD; }
+int srmmu_pmd_inuse(pmd_t *pmdp)        { return mem_map[MAP_NR(pmdp)] != 1; }
+void srmmu_pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
+void srmmu_pmd_reuse(pmd_t * pmdp)
+{
+        if (!(mem_map[MAP_NR(pmdp)] & MAP_PAGE_RESERVED))
+                mem_map[MAP_NR(pmdp)]++;
+}
+
+int srmmu_pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+int srmmu_pgd_bad(pgd_t pgd)
+{
+	return ((pgd_val(pgd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
+		(srmmu_pgd_page(pgd) > high_memory);
+}
+int srmmu_pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & SRMMU_ET_PTD; }
+int srmmu_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] != 1; }
+void srmmu_pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+void srmmu_pgd_reuse(pgd_t *pgdp)
+{
+  if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(pgdp)]++;
+}
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+int srmmu_pte_read(pte_t pte)		{ return (pte_val(pte) & _SRMMU_PAGE_RDONLY) || (pte_val(pte) & _SRMMU_PAGE_WRITE_USR); }
+int srmmu_pte_write(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_WRITE_USR; }
+int srmmu_pte_exec(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_EXEC; }
+int srmmu_pte_dirty(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_DIRTY; }
+int srmmu_pte_young(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_REF; }
+int srmmu_pte_cow(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_COW; }
+
+/* When we change permissions, we first clear all bits in the ACCESS field
+ * then apply the wanted bits.
+ */
+pte_t srmmu_pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
+pte_t srmmu_pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_NOREAD; return pte; }
+pte_t srmmu_pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
+pte_t srmmu_pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_SRMMU_PAGE_DIRTY; return pte; }
+pte_t srmmu_pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_SRMMU_PAGE_REF; return pte; }
+pte_t srmmu_pte_uncow(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_UNCOW; return pte; }
+pte_t srmmu_pte_mkwrite(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
+pte_t srmmu_pte_mkread(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_RDONLY; return pte; }
+pte_t srmmu_pte_mkexec(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
+pte_t srmmu_pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _SRMMU_PAGE_DIRTY; return pte; }
+pte_t srmmu_pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _SRMMU_PAGE_REF; return pte; }
+pte_t srmmu_pte_mkcow(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_COW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+pte_t
+srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
+{
+	pte_t pte;
+
+	if(page & (~PAGE_MASK)) panic("srmmu_mk_pte() called with unaligned page");
+	page = (srmmu_virt_to_phys(page) >> SRMMU_PTE_PPN_PADDR_SHIFT);
+	pte_val(pte) = (page & SRMMU_PTE_PPN_MASK);
+	pte_val(pte) |= pgprot_val(pgprot);
+	return pte;
+}
+
+void
+srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+	unsigned long page = (unsigned long) pmdp;
+
+	page = (srmmu_virt_to_phys(page) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+
+	pgd_val(*pgdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
+}
+
+void
+srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+	unsigned long page = (unsigned long) ptep;
+
+	page = (srmmu_virt_to_phys(page) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+
+	pmd_val(*pmdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
+}
+
+pte_t
+srmmu_pte_modify(pte_t pte, pgprot_t newprot)
+{
+	pte_val(pte) = (pte_val(pte) & (~SRMMU_PTE_ACC_MASK)) | pgprot_val(newprot);
+	return pte;
+}
+
+/* to find an entry in a top-level page table... */
+pgd_t *
+srmmu_pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+	return ((pgd_t *) tsk->tss.pgd_ptr) +
+		((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1));
+}
+
+/* Find an entry in the second-level page table.. */
+pmd_t *
+srmmu_pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return ((pmd_t *) pgd_page(*dir)) +
+		((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+}
+
+/* Find an entry in the third-level page table.. */ 
+pte_t *
+srmmu_pte_offset(pmd_t * dir, unsigned long address)
+{
+	return ((pte_t *) pmd_page(*dir)) +
+		((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+}
+
+/* This must update the context register for this process. */
+void
+srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) 
+{
+	/* See if this process has a context entry already, like after execve() */
+	if(tsk->tss.context != -1) {
+		pgd_t *ctable_ptr = 0;
+		ctable_ptr = (pgd_t *) srmmu_phys_to_virt(srmmu_get_ctable_ptr());
+		ctable_ptr += tsk->tss.context;
+		srmmu_pgd_set(ctable_ptr, (pmd_t *) pgdir);
+		/* Should flush caches here too... */
+		srmmu_flush_whole_tlb();
+	}
+
+	tsk->tss.pgd_ptr = (unsigned long) pgdir;
+
+	return;
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+void
+srmmu_pte_free_kernel(pte_t *pte)
+{
+	mem_map[MAP_NR(pte)] = 1;
+	free_page((unsigned long) pte);
+}
+
+pte_t *
+srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+	pte_t *page;
+
+	address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
+	if (srmmu_pmd_none(*pmd)) {
+		page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (srmmu_pmd_none(*pmd)) {
+			if (page) {
+				srmmu_pmd_set(pmd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (srmmu_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+		srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+		return NULL;
+	}
+	return (pte_t *) srmmu_pmd_page(*pmd) + address;
+}
+
+/* Full three level on SRMMU */
+void
+srmmu_pmd_free_kernel(pmd_t *pmd)
+{
+	mem_map[MAP_NR(pmd)] = 1;
+	free_page((unsigned long) pmd);
+}
+
+pmd_t *
+srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+	pmd_t *page;
+
+	address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
+	if (srmmu_pgd_none(*pgd)) {
+		page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if (srmmu_pgd_none(*pgd)) {
+			if (page) {
+				srmmu_pgd_set(pgd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (srmmu_pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+		srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+		return NULL;
+	}
+	return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+}
+
+void
+srmmu_pte_free(pte_t *pte)
+{
+	free_page((unsigned long) pte);
+}
+
+pte_t *
+srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	pte_t *page;
+
+	address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
+	if (srmmu_pmd_none(*pmd)) {
+		page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (srmmu_pmd_none(*pmd)) {
+			if (page) {
+				srmmu_pmd_set(pmd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (srmmu_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+		srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+		return NULL;
+	}
+	return (pte_t *) srmmu_pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+void 
+srmmu_pmd_free(pmd_t * pmd)
+{
+	free_page((unsigned long) pmd);
+}
+
+pmd_t *
+srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	pmd_t *page;
+
+	address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
+	if (srmmu_pgd_none(*pgd)) {
+		page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if (srmmu_pgd_none(*pgd)) {
+			if (page) {
+				srmmu_pgd_set(pgd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (srmmu_pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+		srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+		return NULL;
+	}
+	return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+}
+
+void
+srmmu_pgd_free(pgd_t *pgd)
+{
+	free_page((unsigned long) pgd);
+}
+
+/* A page directory on the srmmu needs 1k, but for now to simplify the
+ * alignment constraints and allocation we just grab a whole page.
+ */
+
+pgd_t *
+srmmu_pgd_alloc(void)
+{
+	return (pgd_t *) get_free_page(GFP_KERNEL);
+}
+
+/* Just flush the whole thing for now. We will need module
+ * specific invalidate routines in certain circumstances,
+ * because of different flushing facilities and hardware
+ * bugs.
+ */
+void
+srmmu_invalidate(void)
+{
+	srmmu_flush_whole_tlb();
+	return;
+}
+
+/* XXX Needs to be written */
+void
+srmmu_switch_to_context(int context)
+{
+	printk("switching to context %d\n", context);
+
+	return;
+}
+
+/* Low level IO area allocation on the SRMMU.
+ *
+ * I think we can get away with just using a regular page translation,
+ * just making sure the cacheable bit is off.  I would like to avoid
+ * having to mess with the IOMMU if at all possible at first.
+ *
+ * Aparently IOMMU is only necessary for SBus devices, maybe VME too.
+ * We'll see...
+ */
+void
+srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+		int bus_type, int rdonly)
+{
+  pgd_t *pgdp;
+  pmd_t *pmdp;
+  pte_t *ptep;
+
+  pgdp = srmmu_pgd_offset(&init_task, virt_addr);
+  pmdp = srmmu_pmd_offset(pgdp, virt_addr);
+  ptep = srmmu_pte_offset(pmdp, virt_addr);
+  pte_val(*ptep) = (physaddr >> SRMMU_PTE_PPN_PADDR_SHIFT) & SRMMU_PTE_PPN_MASK;
+
+  if(!rdonly)
+	  pte_val(*ptep) |= (SRMMU_ACC_S_RDWREXEC | SRMMU_ET_PTE);
+  else
+	  pte_val(*ptep) |= (SRMMU_ACC_S_RDEXEC | SRMMU_ET_PTE);
+
+  pte_val(*ptep) |= (bus_type << 28);
+  pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK); /* Make sure cacheable bit is off. */
+  srmmu_flush_whole_tlb();
+  flush_ei_ctx(0x0);
+
+  return;
+}
+
+/* Perfom a some soft of MMU tablewalk.
+ * Long contiguous mappings are not supported (yet ?).
+ *
+ * Origionally written by Peter Zaitcev, modified by David S.
+ * Miller.  This is only used to copy over the PROM/KADB mappings
+ * in srmmu_paging_init().
+ *
+ * The return value encodes at what level the entry was found,
+ * basically this is found in the lower 2 bits of the return
+ * value.  If the return value is zero, there was no valid mapping
+ * found at all, the low bits for a non-zero return value
+ * are:
+ *         0 -- Level 1 PTE
+ *         1 -- Level 2 PTE
+ *         2 -- Normal level 3 PTE
+ *         3 -- Context Table PTE (unlikely, but still)
+ * 
+ * Also note that this is called before the context table pointer
+ * register is changed, so the PROMs entry is still in there.  Also,
+ * it is safe to assume that the context 0 contains the mappings.
+ */
+/* TODO chop out 'trace' when stable */
+unsigned int
+srmmu_init_twalk(unsigned virt, int trace)
+{
+	unsigned int wh, root;
+
+	root = (unsigned int) srmmu_get_ctable_ptr();
+	if(trace) printk(":0x%x >> ", virt);
+
+	if(trace) printk(" 0x%x :", root);
+	wh = ldw_sun4m_bypass(root);
+	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+		if(trace) printk("\n");
+		return 0;
+	}
+	if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
+		wh &= ~SRMMU_PTE_ET_MASK;
+		wh |= 0x3;
+		if(trace) printk("\n");
+		printk("AIEEE context table level pte prom mapping!\n");
+		prom_halt();
+		return 0;
+	}
+		
+	if(trace) printk(" 0x%x .", wh);
+	wh = ldw_sun4m_bypass(
+			      ((wh & SRMMU_PTD_PTP_MASK) << 4)
+			      + ((virt & SRMMU_IDX1_MASK) >> SRMMU_IDX1_SHIFT)*sizeof(pte_t));
+
+	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+		if(trace) printk("\n");
+		return 0;
+	}
+	if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
+		wh &= ~SRMMU_PTE_ET_MASK;
+		if(trace) printk("\n");
+		return wh;
+	}
+
+	if(trace) printk(" 0x%x .", wh);
+	wh = ldw_sun4m_bypass(
+			      ((wh & SRMMU_PTD_PTP_MASK) << 4)
+			      + ((virt & SRMMU_IDX2_MASK) >> SRMMU_IDX2_SHIFT)*sizeof(pte_t));
+	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+		if(trace) printk("\n");
+		return 0;
+	}
+	if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
+		wh &= ~SRMMU_PTE_ET_MASK;
+		wh |= 0x1;
+		if(trace) printk("\n");
+		return wh;
+	}
+
+	if(trace) printk(" 0x%x .", wh);
+	wh = ldw_sun4m_bypass(
+			      ((wh & SRMMU_PTD_PTP_MASK) << 4)
+			      + ((virt & SRMMU_IDX3_MASK) >> SRMMU_IDX3_SHIFT)*sizeof(pte_t));
+	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
+		if(trace) printk("\n");
+		return 0;
+	}
+	if(trace) printk(" 0x%x\n", wh);
+	return wh;
+}
+
+
+/* Allocate a block of RAM which is aligned to its size.
+ * This procedure can be used until the call to mem_init().
+ *
+ * To get around the elf bootloader nastyness we have a
+ * early-on page table pool allocation area starting at
+ * C_LABEL(pg0) which is 256k, this should be enough for now.
+ */
+static void *
+srmmu_init_alloc(unsigned long *kbrk, unsigned size)
+{
+	register unsigned mask = size - 1;
+	register unsigned long ret;
+
+	if(size==0) return 0x0;
+	if(size & mask) {
+		printk("panic: srmmu_init_alloc botch\n");
+		prom_halt();
+	}
+	ret = (*kbrk + mask) & ~mask;
+	*kbrk = ret + size;
+	memset((void*) ret, 0, size);
+	return (void*) ret;
+}
+
+extern unsigned long srmmu_data_fault, srmmu_text_fault;
+
+/* Patch in the SRMMU fault handlers for the trap table. */
+void
+srmmu_patch_fhandlers(void)
+{
+	/* Say the following ten times fast... */
+	sparc_ttable[SP_TRAP_TFLT].inst_one = SPARC_MOV_CONST_L3(0x1);
+	sparc_ttable[SP_TRAP_TFLT].inst_two =
+		SPARC_BRANCH((unsigned long) &srmmu_text_fault, 
+			     (unsigned long) &sparc_ttable[SP_TRAP_TFLT].inst_two);
+	sparc_ttable[SP_TRAP_TFLT].inst_three = SPARC_RD_PSR_L0;
+	sparc_ttable[SP_TRAP_TFLT].inst_four = SPARC_NOP;
+
+	sparc_ttable[SP_TRAP_DFLT].inst_one = SPARC_MOV_CONST_L3(0x9);
+	sparc_ttable[SP_TRAP_DFLT].inst_two =
+		SPARC_BRANCH((unsigned long) &srmmu_data_fault,
+			     (unsigned long) &sparc_ttable[SP_TRAP_DFLT].inst_two);
+	sparc_ttable[SP_TRAP_DFLT].inst_three = SPARC_RD_PSR_L0;
+	sparc_ttable[SP_TRAP_DFLT].inst_four = SPARC_NOP;
+
+	return;
+}
+
+/* Paging initialization on the Sparc Reference MMU. */
+
+/* This is all poorly designed, we cannot assume any pages are valid
+ * past _end until *after* this routine runs, thus we can't use the
+ * start_mem mechanism during initialization...
+ */
+static unsigned long mempool;
+
+/* The following is global because trap_init needs it to fire up
+ * the other cpu's on multiprocessors.
+ */
+pgd_t *lnx_root;      /* Pointer to the new root table */
+
+extern char start[];
+
+unsigned long
+srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+	unsigned long vaddr;  /* Virtual counter */
+	int i;
+
+	pte_t *ptep = 0;
+	pmd_t *pmdp = 0;
+	pgd_t *pgdp = 0;
+
+	mempool = start_mem;
+	lnx_root = srmmu_init_alloc(&mempool, num_contexts*sizeof(pgd_t));
+
+	memset(swapper_pg_dir, 0, PAGE_SIZE);
+
+	/* For every entry in the new Linux context table, put in
+	 * an entry which points to swapper_pg_dir .
+	 */
+	pmdp = (pmd_t *) swapper_pg_dir;
+	for(i = 0; i < num_contexts; i++)
+		srmmu_pgd_set(&lnx_root[i], pmdp);
+
+	/* Make Linux physical page tables. */
+	for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
+		pgdp = srmmu_pgd_offset(&init_task, vaddr);
+		if(srmmu_pgd_none(*pgdp)) {
+			pmdp = srmmu_init_alloc(&mempool,
+						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+			srmmu_pgd_set(pgdp, pmdp);
+		}
+
+		pmdp = srmmu_pmd_offset(pgdp, vaddr);
+		if(srmmu_pmd_none(*pmdp)) {
+			ptep = srmmu_init_alloc(&mempool,
+						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+			srmmu_pmd_set(pmdp, ptep);
+		}
+
+		ptep = srmmu_pte_offset(pmdp, vaddr);
+		*ptep = srmmu_mk_pte(vaddr, SRMMU_PAGE_KERNEL);
+	}
+
+	/* Map IO areas. */
+	for(vaddr = IOBASE_VADDR; vaddr < (IOBASE_VADDR+IOBASE_LEN);
+	    vaddr += SRMMU_PMD_SIZE) {
+		pgdp = srmmu_pgd_offset(&init_task, vaddr);
+		if(srmmu_pgd_none(*pgdp)) {
+			pmdp = srmmu_init_alloc(&mempool,
+						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+			srmmu_pgd_set(pgdp, pmdp);
+		}
+		pmdp = srmmu_pmd_offset(pgdp, vaddr);
+		if(srmmu_pmd_none(*pmdp)) {
+			ptep = srmmu_init_alloc(&mempool,
+						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+			srmmu_pmd_set(pmdp, ptep);
+		}
+	}
+
+	/* Map in the PERCPU areas in virtual address space. */
+	printk("PERCPU_VADDR + PERCPU_LEN = %08lx\n",
+	       (PERCPU_VADDR + PERCPU_LEN));
+	for(vaddr = PERCPU_VADDR; vaddr < (PERCPU_VADDR + PERCPU_LEN);
+	    vaddr += PERCPU_ENTSIZE) {
+		pgdp = srmmu_pgd_offset(&init_task, vaddr);
+		if(srmmu_pgd_none(*pgdp)) {
+			pmdp = srmmu_init_alloc(&mempool,
+						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+			srmmu_pgd_set(pgdp, pmdp);
+		}
+		pmdp = srmmu_pmd_offset(pgdp, vaddr);
+		if(srmmu_pmd_none(*pmdp)) {
+			ptep = srmmu_init_alloc(&mempool,
+						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+			srmmu_pmd_set(pmdp, ptep);
+		}
+		ptep = srmmu_pte_offset(pmdp, vaddr);
+		/* Per-cpu trap table page. */
+		*ptep++ = srmmu_mk_pte((unsigned int) start, SRMMU_PAGE_KERNEL);
+		/* Per-cpu kernel stack page. */
+		*ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
+				       SRMMU_PAGE_KERNEL);
+		/* Per-cpu Prom MBox. */
+		*ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
+				       SRMMU_PAGE_KERNEL);
+		/* Per-cpu state variables. */
+		*ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
+				     SRMMU_PAGE_KERNEL);
+	}
+	percpu_table = (struct sparc_percpu *) PERCPU_VADDR;
+
+	/* Ugh, have to map DVMA that the prom has mapped too or else
+	 * you will lose with video cards when we take over the ctx table.
+	 * Also, must take into consideration that prom might be using level
+	 * two or one PTE's. TODO
+	 */
+	for(vaddr = KADB_DEBUGGER_BEGVM; vaddr != 0x0;) {
+		unsigned int prom_pte;
+
+		prom_pte = srmmu_init_twalk(vaddr, 0);
+
+		if(prom_pte) {
+			pgdp = srmmu_pgd_offset(&init_task, vaddr);
+			if((prom_pte&0x3) == 0x0) {
+				prom_pte &= ~0x3;
+				prom_pte |= SRMMU_ET_PTE;
+				pgd_val(*pgdp) = prom_pte;
+				vaddr = SRMMU_PGDIR_ALIGN(vaddr+1);
+				continue;
+			}
+			if(srmmu_pgd_none(*pgdp)) {
+				pmdp = srmmu_init_alloc(&mempool,
+							SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+				srmmu_pgd_set(pgdp, pmdp);
+			}
+
+			pmdp = srmmu_pmd_offset(pgdp, vaddr);
+			if((prom_pte&0x3) == 0x1) {
+				prom_pte &= ~0x3;
+				prom_pte |= SRMMU_ET_PTE;
+				pgd_val(*pgdp) = prom_pte;
+				vaddr = SRMMU_PMD_ALIGN(vaddr+1);
+				continue;
+			}
+			if(srmmu_pmd_none(*pmdp)) {
+				ptep = srmmu_init_alloc(&mempool,
+							SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+				srmmu_pmd_set(pmdp, ptep);
+			}
+			/* A normal 3rd level PTE, no need to change ET bits. */
+			ptep = srmmu_pte_offset(pmdp, vaddr);
+			pte_val(*ptep) = prom_pte;
+
+		}
+		vaddr += PAGE_SIZE;
+	}
+
+	/* I believe I do not need to flush VAC here since my stores  */
+        /* probably already reached the physical RAM.             --P3 */
+
+	/* We probably do, and should do it just to be safe... -Davem */
+
+	/* Take the MMU over from the PROM */
+	printk("Taking over MMU from PROM.\n");
+
+	srmmu_set_ctable_ptr(srmmu_virt_to_phys((unsigned)lnx_root));
+
+	srmmu_flush_whole_tlb();
+
+	/* Now it is ok to use memory at start_mem. */
+	start_mem = PAGE_ALIGN(mempool);
+	start_mem = free_area_init(start_mem, end_mem);
+	start_mem = PAGE_ALIGN(start_mem);
+
+#if 0
+	printk("Testing context switches...\n");
+	for(i=0; i<num_contexts; i++)
+		srmmu_set_context(i);
+	printk("done...\n");
+	srmmu_set_context(0);
+#endif
+
+	printk("survived...\n");
+	return start_mem;
+}
+
+/* Test the WP bit on the Sparc Reference MMU. */
+void
+srmmu_test_wp(void)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	
+	wp_works_ok = -1;
+	/* We mapped page zero as a read-only page in paging_init()
+	 * So fire up the test, then invalidate the pgd for page zero.
+	 * It is no longer needed.
+	 */
+
+	/* Let it rip... */
+	__asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
+	if (wp_works_ok < 0)
+		wp_works_ok = 0;
+
+	pgdp = srmmu_pgd_offset(&init_task, 0x0);
+	pgd_val(*pgdp) = 0x0;
+
+	return;
+}
+
+/* Load up routines and constants for sun4m mmu */
+void
+ld_mmu_srmmu(void)
+{
+	printk("Loading srmmu MMU routines\n");
+
+	/* First the constants */
+	pmd_shift = SRMMU_PMD_SHIFT;
+	pmd_size = SRMMU_PMD_SIZE;
+	pmd_mask = SRMMU_PMD_MASK;
+	pgdir_shift = SRMMU_PGDIR_SHIFT;
+	pgdir_size = SRMMU_PGDIR_SIZE;
+	pgdir_mask = SRMMU_PGDIR_MASK;
+
+	ptrs_per_pte = SRMMU_PTRS_PER_PTE;
+	ptrs_per_pmd = SRMMU_PTRS_PER_PMD;
+	ptrs_per_pgd = SRMMU_PTRS_PER_PGD;
+
+	page_none = SRMMU_PAGE_NONE;
+	page_shared = SRMMU_PAGE_SHARED;
+	page_copy = SRMMU_PAGE_COPY;
+	page_readonly = SRMMU_PAGE_READONLY;
+	page_kernel = SRMMU_PAGE_KERNEL;
+	page_invalid = SRMMU_PAGE_INVALID;
+	
+	/* Functions */
+	invalidate = srmmu_invalidate;
+	switch_to_context = srmmu_switch_to_context;
+	pmd_align = srmmu_pmd_align;
+	pgdir_align = srmmu_pgdir_align;
+	vmalloc_start = srmmu_vmalloc_start;
+
+	pte_page = srmmu_pte_page;
+	pmd_page = srmmu_pmd_page;
+	pgd_page = srmmu_pgd_page;
+
+	sparc_update_rootmmu_dir = srmmu_update_rootmmu_dir;
+
+	pte_none = srmmu_pte_none;
+	pte_present = srmmu_pte_present;
+	pte_inuse = srmmu_pte_inuse;
+	pte_clear = srmmu_pte_clear;
+	pte_reuse = srmmu_pte_reuse;
+
+	pmd_none = srmmu_pmd_none;
+	pmd_bad = srmmu_pmd_bad;
+	pmd_present = srmmu_pmd_present;
+	pmd_inuse = srmmu_pmd_inuse;
+	pmd_clear = srmmu_pmd_clear;
+	pmd_reuse = srmmu_pmd_reuse;
+
+	pgd_none = srmmu_pgd_none;
+	pgd_bad = srmmu_pgd_bad;
+	pgd_present = srmmu_pgd_present;
+	pgd_inuse = srmmu_pgd_inuse;
+	pgd_clear = srmmu_pgd_clear;
+	pgd_reuse = srmmu_pgd_reuse;
+
+	mk_pte = srmmu_mk_pte;
+	pgd_set = srmmu_pgd_set;  /* XXX needs a cast */
+	pte_modify = srmmu_pte_modify;
+	pgd_offset = srmmu_pgd_offset;
+	pmd_offset = srmmu_pmd_offset;
+	pte_offset = srmmu_pte_offset;
+	pte_free_kernel = srmmu_pte_free_kernel;
+	pmd_free_kernel = srmmu_pmd_free_kernel;
+	pte_alloc_kernel = srmmu_pte_alloc_kernel;
+	pmd_alloc_kernel = srmmu_pmd_alloc_kernel;
+	pte_free = srmmu_pte_free;
+	pte_alloc = srmmu_pte_alloc;
+	pmd_free = srmmu_pmd_free;
+	pmd_alloc = srmmu_pmd_alloc;
+	pgd_free = srmmu_pgd_free;
+	pgd_alloc = srmmu_pgd_alloc;
+
+	pte_read = srmmu_pte_read;
+	pte_write = srmmu_pte_write;
+	pte_exec = srmmu_pte_exec;
+	pte_dirty = srmmu_pte_dirty;
+	pte_young = srmmu_pte_young;
+	pte_cow = srmmu_pte_cow;
+	pte_wrprotect = srmmu_pte_wrprotect;
+	pte_rdprotect = srmmu_pte_rdprotect;
+	pte_exprotect = srmmu_pte_exprotect;
+	pte_mkclean = srmmu_pte_mkclean;
+	pte_mkold = srmmu_pte_mkold;
+	pte_uncow = srmmu_pte_uncow;
+	pte_mkwrite = srmmu_pte_mkwrite;
+	pte_mkread = srmmu_pte_mkread;
+	pte_mkexec = srmmu_pte_mkexec;
+	pte_mkdirty = srmmu_pte_mkdirty;
+	pte_mkyoung = srmmu_pte_mkyoung;
+	pte_mkcow = srmmu_pte_mkcow;
+
+	return;
+}
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/srmmuinv.c linux/arch/sparc/mm/srmmuinv.c
--- v1.3.3/linux/arch/sparc/mm/srmmuinv.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/srmmuinv.c	Sat Jun 24 14:18:39 1995
@@ -0,0 +1,168 @@
+/* srmmuinv.c:  Invalidate routines for the various different
+ *              SRMMU implementations.
+ *
+ * Copyright (C) 1995 David S. Miller
+ */
+
+/* HyperSparc */
+hyper_invalidate(void)
+{
+	volatile unsigned int sfsr_clear;
+
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	/* Flush ICACHE */
+	flush_whole_icache();
+	sfsr_clear = srmmu_get_fstatus();
+	return;
+}
+
+hyper_invalidate_mp(void)
+{
+	volatile unsigned int sfsr_clear;
+
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	/* Flush ICACHE */
+	flush_whole_icache();
+
+	sfsr_clear = srmmu_get_fstatus();
+
+	/* Tell other CPUS to each call the Uniprocessor
+	 * invalidate routine.
+	 */
+
+	return;
+}
+
+/* Cypress */
+void
+cypress_invalidate(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	return;
+}
+
+void
+cypress_invalidate_mp(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	/* Tell other CPUS to call the UP version */
+
+	return;
+}
+
+void
+cypress_invalidate_asibad(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache w/o using ASIs */
+
+	return;
+}
+
+void
+cypress_invalidate_asibad_mp(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache w/o using ASIs */
+
+	/* Tell other CPUS to call the UP version */
+
+	return;
+}
+
+/* Swift */
+void
+swift_invalidate(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	return;
+}
+
+void
+swift_invalidate_poke_kernel_pageperms(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	return;
+}
+
+void
+swift_invalidate_poke_kernel_pte_cbits(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	return;
+}
+
+void
+swift_invalidate_poke_everything(void)
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	return;
+}
+
+/* Tsunami */
+tsunami_invalidate()
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Flush Virtual Address Cache */
+
+	return;
+}
+
+/* Viking */
+viking_invalidate()
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	return;
+}
+
+viking_invalidate_mp()
+{
+	/* Flush TLB */
+	srmmu_flush_whole_tlb();
+
+	/* Make other CPUS call UP routine. */
+
+	return;
+}
+
+/* That should be it */
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v1.3.3/linux/arch/sparc/mm/sun4c.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/sun4c.c	Mon Jun 12 02:54:47 1995
@@ -0,0 +1,701 @@
+/* sun4c.c:  Sun4C specific mm routines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* The SUN4C has an MMU based upon a Translation Lookaside Buffer scheme
+ * where only so many translations can be loaded at once.  As Linus said
+ * in Boston, this is a broken way of doing things.
+ *
+ * NOTE:  Free page pool and tables now live in high memory, see
+ *        asm-sparc/pgtsun4c.c and asm-sparc/page.h for details.
+ */
+
+#include <linux/kernel.h>  /* for printk */
+#include <linux/sched.h>
+
+#include <asm/processor.h> /* for wp_works_ok */
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/vac-ops.h>
+#include <asm/vaddrs.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
+#include <asm/kdebug.h>
+
+unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
+unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+
+extern int num_segmaps, num_contexts;
+
+/* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job.
+ * The only function that actually uses this is sun4c_mk_pte() and
+ * to have a complete physical ram structure walk happen for each
+ * invocation is quite costly.  However, this does do some nice
+ * sanity checking and we'll see when our maps don't match.  Eventually
+ * when I trust my code I will just do a direct mmu probe in mk_pte().
+ */
+static inline unsigned int sun4c_virt_to_phys(unsigned int vaddr)
+{
+	unsigned int paddr = 0;
+	unsigned int voff = (vaddr - PAGE_OFFSET);
+	int i;
+
+	for(i=0; sp_banks[i].num_bytes != 0; i++) {
+		if(voff < paddr + sp_banks[i].num_bytes) {
+			/* This matches. */
+			return sp_banks[i].base_addr + voff - paddr;
+		} else
+			paddr += sp_banks[i].num_bytes;
+	}
+	/* Shit, gotta consult the MMU, this shouldn't happen... */
+	printk("sun4c_virt_to_phys: Could not make translation for vaddr %08lx\n", (unsigned long) vaddr);
+	SP_ENTER_DEBUGGER;
+}		
+
+static inline unsigned long
+sun4c_phys_to_virt(unsigned long paddr)
+{
+        int i;
+        unsigned long offset = PAGE_OFFSET;
+
+        for (i=0; sp_banks[i].num_bytes != 0; i++)
+        {
+                if (paddr >= sp_banks[i].base_addr &&
+                    paddr < (sp_banks[i].base_addr
+                             + sp_banks[i].num_bytes)) {
+                        return (paddr - sp_banks[i].base_addr) + offset;
+                } else
+                        offset += sp_banks[i].num_bytes;
+        }
+	printk("sun4c_phys_to_virt: Could not make translation for paddr %08lx\n", (unsigned long) paddr);
+	SP_ENTER_DEBUGGER;
+}
+
+unsigned long
+sun4c_vmalloc_start(void)
+{
+	return ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1));
+}
+
+/* Note that I have 16 page tables per page, thus four less
+ * bits of shifting than normal.
+ */
+
+unsigned long
+sun4c_pte_page(pte_t pte)
+{
+	unsigned long page;
+
+	page = ((pte_val(pte) & _SUN4C_PFN_MASK) << (PAGE_SHIFT));
+	return sun4c_phys_to_virt(page);
+}
+
+unsigned long 
+sun4c_pmd_page(pmd_t pmd)
+{
+	return ((pmd_val(pmd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT));
+}
+
+unsigned long
+sun4c_pgd_page(pgd_t pgd)
+{
+	return ((pgd_val(pgd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT));
+}
+
+/* Update the root mmu directory on the sun4c mmu. */
+void
+sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
+{
+	(tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
+
+	/* May have to do some flushing here. */
+
+	return;
+}
+
+int sun4c_pte_none(pte_t pte)		{ return !pte_val(pte); }
+int sun4c_pte_present(pte_t pte)	{ return pte_val(pte) & _SUN4C_PAGE_VALID; }
+int sun4c_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] != 1; }
+void sun4c_pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+void sun4c_pte_reuse(pte_t *ptep)
+{
+  if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(ptep)]++;
+}
+
+int sun4c_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+int sun4c_pmd_bad(pmd_t pmd)
+{
+	return ((pmd_val(pmd) & _SUN4C_PGD_MMU_MASK) != _SUN4C_PAGE_TABLE);
+}
+
+int sun4c_pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _SUN4C_PAGE_VALID; }
+int sun4c_pmd_inuse(pmd_t *pmdp)        { return 0; }
+void sun4c_pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
+void sun4c_pmd_reuse(pmd_t * pmdp)      { }
+
+int sun4c_pgd_none(pgd_t pgd)		{ return 0; }
+int sun4c_pgd_bad(pgd_t pgd)		{ return 0; }
+int sun4c_pgd_present(pgd_t pgd)	{ return 1; }
+int sun4c_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] != 1; }
+void sun4c_pgd_clear(pgd_t * pgdp)	{ }
+void sun4c_pgd_reuse(pgd_t *pgdp)
+{
+  if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
+    mem_map[MAP_NR(pgdp)]++;
+}
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+int sun4c_pte_read(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_VALID; }
+int sun4c_pte_write(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_WRITE; }
+int sun4c_pte_exec(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_VALID; }
+int sun4c_pte_dirty(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
+int sun4c_pte_young(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_REF; }
+int sun4c_pte_cow(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_COW; }
+
+pte_t sun4c_pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
+pte_t sun4c_pte_rdprotect(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_exprotect(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
+pte_t sun4c_pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
+pte_t sun4c_pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
+pte_t sun4c_pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
+pte_t sun4c_pte_mkread(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_mkexec(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
+pte_t sun4c_pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
+pte_t sun4c_pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
+pte_t sun4c_pte_mkcow(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+pte_t
+sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
+{
+	pte_t pte;
+
+	if(page & (~PAGE_MASK)) panic("sun4c_mk_pte() called with unaligned page");
+	page = sun4c_virt_to_phys(page);
+	pte_val(pte) = ((page>>PAGE_SHIFT)&_SUN4C_PFN_MASK);
+	pte_val(pte) |= (pgprot_val(pgprot) & _SUN4C_MMU_MASK);
+	return pte;
+}
+
+void
+sun4c_pgd_set(pgd_t * pgdp, pte_t * ptep)
+{
+	pgd_val(*pgdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK);
+	pgd_val(*pgdp) |= (((((unsigned long) ptep)) >>
+			    (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK);
+}
+
+pte_t
+sun4c_pte_modify(pte_t pte, pgprot_t newprot)
+{
+	pte_val(pte) = (pte_val(pte) & _SUN4C_PAGE_CHG_MASK);
+	pte_val(pte) |= pgprot_val(newprot);
+	return pte;
+}
+
+/* to find an entry in a page-table-directory */
+pgd_t *
+sun4c_pgd_offset(struct task_struct * tsk, unsigned long address)
+{
+	return ((pgd_t *) (tsk->tss.pgd_ptr)) +
+		(address >> SUN4C_PGDIR_SHIFT);
+}
+
+/* Find an entry in the second-level page table.. */
+pmd_t *
+sun4c_pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */ 
+pte_t *
+sun4c_pte_offset(pmd_t * dir, unsigned long address)
+{
+	return (pte_t *) sun4c_pmd_page(*dir) +	((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+void
+sun4c_pte_free_kernel(pte_t *pte)
+{
+	mem_map[MAP_NR(pte)] = 1;
+	free_page((unsigned long) pte);
+}
+
+static inline void
+sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+	pmd_val(*pmdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK);
+	pmd_val(*pmdp) |= ((((unsigned long) ptep) >> (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK);
+}
+
+
+pte_t *
+sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+	pte_t *page;
+
+
+	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
+	if (sun4c_pmd_none(*pmd)) {
+		/* New scheme, use a whole page */
+		page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (sun4c_pmd_none(*pmd)) {
+			if (page) {
+				sun4c_pmd_set(pmd, page);
+				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
+				return page + address;
+			}
+			sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (sun4c_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+		sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+
+	return (pte_t *) sun4c_pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+void
+sun4c_pmd_free_kernel(pmd_t *pmd)
+{
+	return;
+}
+
+pmd_t *
+sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+void
+sun4c_pte_free(pte_t *pte)
+{
+	free_page((unsigned long) pte);
+}
+
+pte_t *
+sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	pte_t *page;
+
+	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
+	if (sun4c_pmd_none(*pmd)) {
+		page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (sun4c_pmd_none(*pmd)) {
+			if (page) {
+				sun4c_pmd_set(pmd, page);
+				return page + address;
+			}
+			sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (sun4c_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		halt();
+		return NULL;
+	}
+
+	return (pte_t *) sun4c_pmd_page(*pmd) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+void 
+sun4c_pmd_free(pmd_t * pmd)
+{
+	return;
+}
+
+pmd_t *
+sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+	return (pmd_t *) pgd;
+}
+
+/* This now works, as both our pgd's and pte's have 1024 entries. */
+void
+sun4c_pgd_free(pgd_t *pgd)
+{
+	free_page((unsigned long) pgd);
+}
+
+/* A page directory on the sun4c needs 64k, thus we request an order of
+ * four.  We must also clear it by hand, very inefficient.
+ */
+
+pgd_t *
+sun4c_pgd_alloc(void)
+{
+	return (pgd_t *) get_free_page(GFP_KERNEL);
+}
+
+void
+sun4c_invalidate(void)
+{
+	flush_vac_context();
+}
+
+void
+sun4c_switch_to_context(int context)
+{
+	__asm__ __volatile__("stba %0, [%1] %2" : :
+			     "r" (context),
+			     "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+	return;
+}
+
+int 
+sun4c_get_context(void)
+{
+	register int ctx;
+
+	__asm__ __volatile__("lduba [%1] %2, %0" :
+			     "=r" (ctx) :
+			     "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+	return ctx;
+}
+
+/* Low level IO area allocation on the Sun4c MMU.  This function is called
+ * for each page of IO area you need.  Kernel code should not call this
+ * routine directly, use sparc_alloc_io() instead.
+ */
+void
+sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+		int bus_type, int rdonly)
+{
+  unsigned long page_entry;
+
+  page_entry = ((physaddr >> PAGE_SHIFT) & _SUN4C_PFN_MASK);
+
+  if(!rdonly)
+	  page_entry |= (PTE_V | PTE_ACC | PTE_NC | PTE_IO);  /* kernel io addr */
+  else
+	  page_entry |= (PTE_V | PTE_P | PTE_NC | PTE_IO);  /* readonly io addr */
+
+  page_entry &= (~PTE_RESV);
+
+  /* Maybe have to do something with the bus_type on sun4c's? */
+
+
+  put_pte(virt_addr, page_entry);
+  return;
+}
+
+/* Paging initialization on the Sun4c. */
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long eintstack, intstack;
+
+/* This code was soooo krufty, I have to rewrite this now! XXX
+ * Ok, things are cleaning up.  I have now decided that it makes
+ * a lot of sense to put the free page pool in upper ram right
+ * after the kernel.  We map these free pages to be virtually
+ * contiguous, that way we don't get so many reserved pages
+ * during mem_init().  I think this will work out nicely.
+ */
+extern unsigned long start;
+
+static unsigned long mempool;  /* This allows us to work with elf bootloaders */
+
+unsigned long
+sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+	unsigned long addr, vaddr, kern_begin, kern_end;
+	unsigned long prom_begin, prom_end;
+	int phys_seg, i, min_prom_segmap;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	mempool = start_mem;
+
+	/* 127 on most sun4c's, 255 on SS2 and IPX. */
+	invalid_segment = (num_segmaps - 1);
+
+	memset(swapper_pg_dir, 0, PAGE_SIZE);
+	memset(pg0, 0, PAGE_SIZE);
+	/* Delete low mapping of the kernel and sanitize invalid segmap. */
+	for(vaddr=0; vaddr<(4*1024*1024); vaddr+=SUN4C_REAL_PGDIR_SIZE) 
+		put_segmap(vaddr, invalid_segment);
+	for(vaddr=0; vaddr<(256*1024); vaddr+=PAGE_SIZE) put_pte(vaddr, 0);
+
+	/* Initialize phys_seg_map[] */
+	for(i=0; i<num_segmaps; i++) phys_seg_map[i] = PSEG_AVL;
+	for(i=num_segmaps; i<PSEG_ENTRIES; i++) phys_seg_map[i] = PSEG_RSV;
+
+	kern_begin = KERNBASE;
+	kern_end = ((unsigned long) &end);
+	prom_begin = LINUX_OPPROM_BEGVM;
+	prom_end = LINUX_OPPROM_ENDVM;
+
+	/* Set up swapper_pg_dir based upon three things:
+	 * 1) Where the kernel lives (KERNBASE)
+	 * 2) Where the PROM lives (PROM_BEGVM -> PROM_ENDVM)
+	 *    This is cheese, should do it dynamically XXX
+	 * 3) Where the valid physical pages are (sp_banks[])
+	 *    This is done first.
+	 *
+	 * I'm trying to concentrate this into one big loop and localize
+	 * the logic because it is so messy to do it in seperate loop
+	 * stages.  If anyone else has better ideas, let me know.
+	 */
+
+	if(sp_banks[0].base_addr != 0)
+		panic("sun4c_paging_init: First physical address in first bank is not zero!\n");
+	/* First, linearly map all physical RAM to the equivalent virtual pages.
+	 * Then, we invalidate everything the kernel uses by either invalidating
+	 * the entire segmep (if the whole segment is used by the kernel) or
+	 * just invalidating the relevant pte's.
+	 */
+
+	for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
+		pgdp = sun4c_pgd_offset(current, vaddr);
+		pmdp = sun4c_pmd_offset(pgdp, vaddr);
+		if(sun4c_pmd_none(*pmdp)) {
+			pgd_set(pgdp, (pte_t *) mempool);
+			mempool += PAGE_SIZE;
+		}
+		ptep = sun4c_pte_offset(pmdp, vaddr);
+		*ptep = sun4c_mk_pte(vaddr, SUN4C_PAGE_KERNEL);
+	}
+
+	/* Now map the kernel, and mark the segmaps as PSEG_KERN.
+	 *
+	 * NOTE: The first address of the upper kernel mapping must be
+	 *       segment aligned.
+	 */
+	if(kern_begin & (~SUN4C_REAL_PGDIR_MASK)) {
+		panic("paging_init() Kernel not segmap aligned, halting...");
+	}
+
+	/* Mark the segmaps so that our phys_seg allocator doesn't try to
+	 * use them for TLB misses.
+	 */
+	for(addr=kern_begin; addr < kern_end; addr += SUN4C_REAL_PGDIR_SIZE) {
+		if(get_segmap(addr) == invalid_segment) {
+			panic("paging_init() AIEEE, Kernel has invalid mapping, halting...");
+		}
+		phys_seg = get_segmap(addr);
+		phys_seg_map[phys_seg] = PSEG_KERNEL;
+		/* Map this segment in every context */
+		for(i=0; i<num_contexts; i++)
+			(*romvec->pv_setctxt)(i, (char *) addr, phys_seg);
+	}
+
+	for(addr=((unsigned long) (&empty_zero_page)) + PAGE_SIZE; 
+	    addr < ((unsigned long) (&etext)); addr += PAGE_SIZE)
+		put_pte(addr, (get_pte(addr) & (~(PTE_W | PTE_NC))));
+
+	/* Finally map the prom's address space.  Any segments that
+	 * are not the invalid segment are marked as PSEG_RESV so
+	 * they are never re-allocated.  This guarentees the PROM
+	 * a sane state if we have to return execution over to it.
+	 * Our kernel static tables make it look like nothing is
+	 * mapped in these segments, if we get a page fault for
+	 * a prom address either the user is gonna die or the kernel
+	 * is doing something *really* bad.
+	 */
+	if(prom_begin & (~SUN4C_REAL_PGDIR_MASK)) {
+		panic("paging_init() Boot PROM not segmap aligned, halting...");
+		halt();
+	}
+
+	min_prom_segmap = 254;
+	for(addr=KADB_DEBUGGER_BEGVM; addr < prom_end; addr += SUN4C_REAL_PGDIR_SIZE) {
+		if(get_segmap(addr) == invalid_segment)
+			continue;
+		phys_seg = get_segmap(addr);
+		if(phys_seg < min_prom_segmap) min_prom_segmap = phys_seg;
+		phys_seg_map[phys_seg] = PSEG_RSV;
+		/* Make the prom pages unaccessible from userland.  However, we
+		 * don't touch debugger segmaps/ptes.
+		 */
+		if((addr>=LINUX_OPPROM_BEGVM) && (addr<LINUX_OPPROM_ENDVM))
+			for(vaddr=addr; vaddr < (addr+SUN4C_REAL_PGDIR_SIZE); vaddr+=PAGE_SIZE)
+				put_pte(vaddr, (get_pte(vaddr) | PTE_P));
+
+		/* Map this segment in every context */
+		for(i=0; i<num_contexts; i++)
+			(*romvec->pv_setctxt)(i, (char *) addr, phys_seg);
+	}
+
+	/* Finally, unmap kernel page zero. */
+	put_pte(0x0, 0x0);
+
+	/* Hard pin down the IO area segmaps */
+	phys_seg = (min_prom_segmap - 1);
+	for(addr = (IOBASE_VADDR + SUN4C_REAL_PGDIR_SIZE); addr < (IOBASE_VADDR + IOBASE_LEN);
+	    addr += SUN4C_REAL_PGDIR_SIZE) {
+		if(addr & (~SUN4C_REAL_PGDIR_MASK)) {
+			panic("paging_init() IO segment not aligned, halting...");
+		}
+		phys_seg_map[phys_seg] = PSEG_RSV; /* Don't touch */
+		put_segmap(addr, phys_seg--);
+	}
+	phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV;
+
+	start_mem = PAGE_ALIGN(mempool);
+	start_mem = free_area_init(start_mem, end_mem);
+	start_mem = PAGE_ALIGN(start_mem);
+
+	/* That should be it. */
+	invalidate();
+
+	return start_mem;
+}
+
+/* Test the WP bit on the sun4c. */
+unsigned long
+sun4c_test_wp(unsigned long start_mem)
+{
+	unsigned long addr, segmap;
+	unsigned long page_entry;
+
+	wp_works_ok = -1;
+	page_entry = pte_val(sun4c_mk_pte(PAGE_OFFSET, SUN4C_PAGE_READONLY));
+	put_pte((unsigned long) 0x0, page_entry);
+
+	/* Let it rip... */
+	__asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
+	put_pte((unsigned long) 0x0, 0x0);
+	if (wp_works_ok < 0)
+		wp_works_ok = 0;
+
+	/* Make all kernet static segmaps PSEG_KERNEL. */
+	for(addr=PAGE_OFFSET; addr<start_mem; addr+=SUN4C_REAL_PGDIR_SIZE)
+		phys_seg_map[get_segmap(addr)]=PSEG_KERNEL;
+
+	/* Map all the segmaps not valid on this machine as reserved. */
+	for(segmap=invalid_segment; segmap<PSEG_ENTRIES; segmap++)
+		phys_seg_map[segmap]=PSEG_RSV;
+
+	return start_mem;
+}
+
+/* Real work gets done here. */
+
+/* Load up routines and constants for sun4c mmu */
+void
+ld_mmu_sun4c(void)
+{
+	printk("Loading sun4c MMU routines\n");
+
+	/* First the constants */
+	pmd_shift = SUN4C_PMD_SHIFT;
+	pmd_size = SUN4C_PMD_SIZE;
+	pmd_mask = SUN4C_PMD_MASK;
+	pgdir_shift = SUN4C_PGDIR_SHIFT;
+	pgdir_size = SUN4C_PGDIR_SIZE;
+	pgdir_mask = SUN4C_PGDIR_MASK;
+
+	ptrs_per_pte = SUN4C_PTRS_PER_PTE;
+	ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
+	ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
+
+	page_none = SUN4C_PAGE_NONE;
+	page_shared = SUN4C_PAGE_SHARED;
+	page_copy = SUN4C_PAGE_COPY;
+	page_readonly = SUN4C_PAGE_READONLY;
+	page_kernel = SUN4C_PAGE_KERNEL;
+	page_invalid = SUN4C_PAGE_INVALID;
+	
+	/* Functions */
+	invalidate = sun4c_invalidate;
+	switch_to_context = sun4c_switch_to_context;
+	pmd_align = sun4c_pmd_align;
+	pgdir_align = sun4c_pgdir_align;
+	vmalloc_start = sun4c_vmalloc_start;
+
+	pte_page = sun4c_pte_page;
+	pmd_page = sun4c_pmd_page;
+	pgd_page = sun4c_pgd_page;
+
+	sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
+
+	pte_none = sun4c_pte_none;
+	pte_present = sun4c_pte_present;
+	pte_inuse = sun4c_pte_inuse;
+	pte_clear = sun4c_pte_clear;
+	pte_reuse = sun4c_pte_reuse;
+
+	pmd_none = sun4c_pmd_none;
+	pmd_bad = sun4c_pmd_bad;
+	pmd_present = sun4c_pmd_present;
+	pmd_inuse = sun4c_pmd_inuse;
+	pmd_clear = sun4c_pmd_clear;
+	pmd_reuse = sun4c_pmd_reuse;
+
+	pgd_none = sun4c_pgd_none;
+	pgd_bad = sun4c_pgd_bad;
+	pgd_present = sun4c_pgd_present;
+	pgd_inuse = sun4c_pgd_inuse;
+	pgd_clear = sun4c_pgd_clear;
+	pgd_reuse = sun4c_pgd_reuse;
+
+	mk_pte = sun4c_mk_pte;
+	pgd_set = sun4c_pgd_set;
+	pte_modify = sun4c_pte_modify;
+	pgd_offset = sun4c_pgd_offset;
+	pmd_offset = sun4c_pmd_offset;
+	pte_offset = sun4c_pte_offset;
+	pte_free_kernel = sun4c_pte_free_kernel;
+	pmd_free_kernel = sun4c_pmd_free_kernel;
+	pte_alloc_kernel = sun4c_pte_alloc_kernel;
+	pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
+	pte_free = sun4c_pte_free;
+	pte_alloc = sun4c_pte_alloc;
+	pmd_free = sun4c_pmd_free;
+	pmd_alloc = sun4c_pmd_alloc;
+	pgd_free = sun4c_pgd_free;
+	pgd_alloc = sun4c_pgd_alloc;
+
+	pte_read = sun4c_pte_read;
+	pte_write = sun4c_pte_write;
+	pte_exec = sun4c_pte_exec;
+	pte_dirty = sun4c_pte_dirty;
+	pte_young = sun4c_pte_young;
+	pte_cow = sun4c_pte_cow;
+	pte_wrprotect = sun4c_pte_wrprotect;
+	pte_rdprotect = sun4c_pte_rdprotect;
+	pte_exprotect = sun4c_pte_exprotect;
+	pte_mkclean = sun4c_pte_mkclean;
+	pte_mkold = sun4c_pte_mkold;
+	pte_uncow = sun4c_pte_uncow;
+	pte_mkwrite = sun4c_pte_mkwrite;
+	pte_mkread = sun4c_pte_mkread;
+	pte_mkexec = sun4c_pte_mkexec;
+	pte_mkdirty = sun4c_pte_mkdirty;
+	pte_mkyoung = sun4c_pte_mkyoung;
+	pte_mkcow = sun4c_pte_mkcow;
+
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/Makefile linux/arch/sparc/prom/Makefile
--- v1.3.3/linux/arch/sparc/prom/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/Makefile	Wed Jun  7 06:11:36 1995
@@ -0,0 +1,33 @@
+#
+# Makefile for the Sun Boot PROM interface library under
+# Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+
+OBJS  = bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
+        palloc.o ranges.o segment.o tree.o console.o printf.o
+
+all: promlib.a
+
+promlib.a: $(OBJS)
+	$(AR) rcs promlib.a $(OBJS)
+	sync
+
+dep:
+	$(CPP) -M *.c > .depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c
--- v1.3.3/linux/arch/sparc/prom/bootstr.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/bootstr.c	Wed Jun  7 11:35:01 1995
@@ -0,0 +1,40 @@
+/* bootstr.c:  Boot string/argument acquisition from the PROM.
+ *
+ * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/oplib.h>
+
+static char barg_buf[128];
+
+char *
+prom_getbootargs(void)
+{
+	int iter;
+	char *cp;
+
+	switch(prom_vers) {
+	case PROM_V0:
+		cp = barg_buf;
+		for(iter = 0; iter < 8; iter++) {
+			strcpy(cp, (*(romvec->pv_v0bootargs))->argv[iter]);
+			cp += strlen(cp); *cp++=' ';
+		}
+		*cp = 0;
+		break;
+	case PROM_V2:
+	case PROM_V3:
+		cp = barg_buf;
+		strcpy(cp, *romvec->pv_v2bootargs.bootpath);
+		cp += strlen(cp);
+		*cp++ = ' ';
+		strcpy(cp, *romvec->pv_v2bootargs.bootargs);
+		cp += strlen(cp);
+		*cp = 0;
+		break;
+	default:
+		barg_buf[0] = 0;
+		break;
+	}
+	return barg_buf;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c
--- v1.3.3/linux/arch/sparc/prom/console.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/console.c	Sat Jun 17 10:46:22 1995
@@ -0,0 +1,73 @@
+/* console.c: Routines that deal with sending and receiving IO
+ *            to/from the current console device using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Non blocking get character from console input device, returns -1
+ * if no input was taken.  This can be used for polling.
+ */
+int
+prom_nbgetchar(void)
+{
+	static char inc;
+
+	switch(prom_vers) {
+	case PROM_V0:
+		return (*(romvec->pv_nbgetchar))();
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1)
+			return inc;
+		return -1;
+		break;
+	};
+	return 0; /* Ugh, we could spin forever on unsupported proms ;( */
+}
+
+/* Non blocking put character to console device, returns -1 if
+ * unsuccessful.
+ */
+int
+prom_nbputchar(char c)
+{
+	static char outc;
+
+	switch(prom_vers) {
+	case PROM_V0:
+		return (*(romvec->pv_nbputchar))(c);
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		outc = c;
+		if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1)
+			return 0;
+		return -1;
+		break;
+	};
+	return 0; /* Ugh, we could spin forever on unsupported proms ;( */
+}
+
+/* Blocking version of get character routine above. */
+char
+prom_getchar(void)
+{
+	int character;
+	while((character = prom_nbgetchar()) == -1) ;
+	return (char) character;
+}
+
+/* Blocking version of put character routine above. */
+void
+prom_putchar(char c)
+{
+	while(prom_nbputchar(c) == -1) ;
+	return;
+}
+
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/devmap.c linux/arch/sparc/prom/devmap.c
--- v1.3.3/linux/arch/sparc/prom/devmap.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/devmap.c	Mon Jun  5 11:16:47 1995
@@ -0,0 +1,34 @@
+/* promdevmap.c:  Map device/IO areas to virtual addresses.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Just like the routines in palloc.c, these should not be used
+ * by the kernel at all.  Bootloader facility mainly.  And again,
+ * this is only available on V2 proms and above.
+ */
+
+/* Map physical device address 'paddr' in IO space 'ios' of size
+ * 'num_bytes' to a virtual address, with 'vhint' being a hint to
+ * the prom as to where you would prefer the mapping.  We return
+ * where the prom actually mapped it.
+ */
+char *
+prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes)
+{
+	if((num_bytes == 0) || (paddr == 0)) return (char *) 0x0;
+	return (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr,
+						     num_bytes);
+}
+
+/* Unmap an IO/device area that was mapped using the above routine. */
+void
+prom_unmapio(char *vaddr, unsigned int num_bytes)
+{
+	if(num_bytes == 0x0) return;
+	(*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes);
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c
--- v1.3.3/linux/arch/sparc/prom/devops.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/devops.c	Sat Jun 17 10:03:28 1995
@@ -0,0 +1,69 @@
+/* devops.c:  Device operations using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Open the device described by the string 'dstr'.  Returns the handle
+ * to that device used for subsequent operations on that device.
+ * Returns -1 on failure.
+ */
+int
+prom_devopen(char *dstr)
+{
+	int handle;
+	switch(prom_vers) {
+	case PROM_V0:
+		handle = (*(romvec->pv_v0devops.v0_devopen))(dstr);
+		if(handle == 0) return -1;
+		return handle;
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
+		return handle;
+		break;
+	};
+
+	return -1;
+}
+
+/* Close the device described by device handle 'dhandle'. */
+void
+prom_close(int dhandle)
+{
+	switch(prom_vers) {
+	case PROM_V0:
+		(*(romvec->pv_v0devops.v0_devclose))(dhandle);
+		return;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		(*(romvec->pv_v2devops.v2_dev_close))(dhandle);
+		return;
+	};
+	return;
+}
+
+/* Seek to specified location described by 'seekhi' and 'seeklo'
+ * for device 'dhandle'.
+ */
+void
+prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
+{
+	switch(prom_vers) {
+	case PROM_V0:
+		(*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo);
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		(*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
+		break;
+	};
+
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/init.c linux/arch/sparc/prom/init.c
--- v1.3.3/linux/arch/sparc/prom/init.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/init.c	Sat Jun 17 10:03:46 1995
@@ -0,0 +1,79 @@
+/* init.c:  Initialize internal variables used by the PROM
+ *          library functions.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+struct linux_romvec *romvec;
+enum prom_major_version prom_vers;
+unsigned int prom_rev, prom_prev;
+
+/* The root node of the prom device tree. */
+int prom_root_node;
+
+/* Pointer to the device tree operations structure. */
+struct linux_nodeops *prom_nodeops;
+
+/* You must call prom_init() before you attempt to use any of the
+ * routines in the prom library.  It returns 0 on success, 1 on
+ * failure.  It gets passed the pointer to the PROM vector.
+ */
+
+extern void prom_meminit(void);
+extern void prom_ranges_init(void);
+
+int
+prom_init(struct linux_romvec *rp)
+{
+	if(!rp) return 1;
+	romvec = rp;
+	if(romvec->pv_magic_cookie != LINUX_OPPROM_MAGIC)
+		return 1;
+
+	/* Ok, we seem to have a sane romvec here. */
+	switch(romvec->pv_romvers) {
+	case 0:
+		prom_vers = PROM_V0;
+		break;
+	case 2:
+		prom_vers = PROM_V2;
+		break;
+	case 3:
+		prom_vers = PROM_V3;
+		break;
+	case 4:
+		prom_vers = PROM_P1275;
+		prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
+		return 1;
+		break;
+	default:
+		prom_printf("PROMLIB: Bad PROM version %d\n",
+			    romvec->pv_romvers);
+		return 1;
+		break;
+	};
+
+	prom_rev = romvec->pv_plugin_revision;
+	prom_prev = romvec->pv_printrev;
+	prom_nodeops = romvec->pv_nodeops;
+
+	prom_root_node = prom_getsibling(0);
+	if((prom_root_node == 0) || (prom_root_node == -1))
+		return 1;
+
+	if((((unsigned long) prom_nodeops) == 0) || 
+	   (((unsigned long) prom_nodeops) == -1))
+		return 1;
+
+	prom_meminit();
+	prom_ranges_init();
+
+	prom_printf("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
+		    romvec->pv_romvers, prom_rev);
+
+	/* Initialization successful. */
+	return 0;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c
--- v1.3.3/linux/arch/sparc/prom/memory.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/memory.c	Sat Jun 17 10:45:40 1995
@@ -0,0 +1,193 @@
+/* memory.c: Prom routine for acquiring various bits of information
+ *           about RAM on the machine, both virtual and physical.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* This routine, for consistancy, returns the ram parameters in the
+ * V0 prom memory descriptor format.  I choose this format becuase I
+ * think it was the easiest to work with.  I feel the religious
+ * arguments now... ;)  Also, I return the linked lists sorted to
+ * prevent paging_init() upset stomache as I have not yet written
+ * the pepto-bismal kernel module yet.
+ */
+
+struct linux_prom_registers prom_reg_memlist[64];
+struct linux_prom_registers prom_reg_tmp[64];
+
+struct linux_mlist_v0 prom_phys_total[64];
+struct linux_mlist_v0 prom_prom_taken[64];
+struct linux_mlist_v0 prom_phys_avail[64];
+
+struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total;
+struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken;
+struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail;
+
+struct linux_mem_v0 prom_memlist;
+
+
+/* Internal Prom library routine to sort a linux_mlist_v0 memory
+ * list.  Used below in initialization.
+ */
+void
+prom_sortmemlist(struct linux_mlist_v0 *thislist)
+{
+	int swapi = 0;
+	int i, mitr, tmpsize;
+	char *tmpaddr;
+	char *lowest;
+
+	for(i=0; thislist[i].theres_more != 0; i++) {
+		lowest = thislist[i].start_adr;
+		for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)
+			if(thislist[mitr].start_adr < lowest) {
+				lowest = thislist[mitr].start_adr;
+				swapi = mitr;
+			}
+		if(lowest == thislist[i].start_adr) continue;
+		tmpaddr = thislist[swapi].start_adr;
+		tmpsize = thislist[swapi].num_bytes;
+		for(mitr = swapi; mitr > i; mitr--) {
+			thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+			thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+		}
+		thislist[i].start_adr = tmpaddr;
+		thislist[i].num_bytes = tmpsize;
+	}
+
+	return;
+}
+
+/* Initialize the memory lists based upon the prom version. */
+void
+prom_meminit(void)
+{
+	int node = 0;
+	unsigned int iter, num_regs;
+	struct linux_mlist_v0 *mptr;  /* ptr for traversal */
+
+	switch(prom_vers) {
+	case PROM_V0:
+		/* Nice, kind of easier to do in this case. */
+		/* First, the total physical descriptors. */
+		for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0;
+		    mptr; mptr=mptr->theres_more, iter++) {
+			prom_phys_total[iter].start_adr = mptr->start_adr;
+			prom_phys_total[iter].num_bytes = mptr->num_bytes;
+			prom_phys_total[iter].theres_more = &prom_phys_total[iter+1];
+		}
+		prom_phys_total[iter-1].theres_more = 0x0;
+		/* Second, the total prom taken descriptors. */
+		for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0;
+		    mptr; mptr=mptr->theres_more, iter++) {
+			prom_prom_taken[iter].start_adr = mptr->start_adr;
+			prom_prom_taken[iter].num_bytes = mptr->num_bytes;
+			prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1];
+		}
+		prom_prom_taken[iter-1].theres_more = 0x0;
+		/* Last, the available physical descriptors. */
+		for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0;
+		    mptr; mptr=mptr->theres_more, iter++) {
+			prom_phys_avail[iter].start_adr = mptr->start_adr;
+			prom_phys_avail[iter].num_bytes = mptr->num_bytes;
+			prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1];
+		}
+		prom_phys_avail[iter-1].theres_more = 0x0;
+		/* Sort all the lists. */
+		prom_sortmemlist(prom_phys_total);
+		prom_sortmemlist(prom_prom_taken);
+		prom_sortmemlist(prom_phys_avail);
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		/* Grrr, have to traverse the prom device tree ;( */
+		node = prom_getchild(prom_root_node);
+		node = prom_searchsiblings(node, "memory");
+		num_regs = prom_getproperty(node, "available",
+					    (char *) prom_reg_memlist,
+					    sizeof(prom_reg_memlist));
+		num_regs = (num_regs/sizeof(struct linux_prom_registers));
+		for(iter=0; iter<num_regs; iter++) {
+			prom_phys_avail[iter].start_adr =
+				prom_reg_memlist[iter].phys_addr;
+			prom_phys_avail[iter].num_bytes =
+				(unsigned long) prom_reg_memlist[iter].reg_size;
+			prom_phys_avail[iter].theres_more =
+				&prom_phys_avail[iter+1];
+		}
+		prom_phys_avail[iter-1].theres_more = 0x0;
+
+		num_regs = prom_getproperty(node, "reg",
+					    (char *) prom_reg_memlist,
+					    sizeof(prom_reg_memlist));
+		num_regs = (num_regs/sizeof(struct linux_prom_registers));
+		for(iter=0; iter<num_regs; iter++) {
+			prom_phys_total[iter].start_adr =
+				prom_reg_memlist[iter].phys_addr;
+			prom_phys_total[iter].num_bytes =
+				(unsigned long) prom_reg_memlist[iter].reg_size;
+			prom_phys_total[iter].theres_more =
+				&prom_phys_total[iter+1];
+		}
+		prom_phys_total[iter-1].theres_more = 0x0;
+
+		node = prom_getchild(prom_root_node);
+		node = prom_searchsiblings(node, "virtual-memory");
+		num_regs = prom_getproperty(node, "available",
+					    (char *) prom_reg_memlist,
+					    sizeof(prom_reg_memlist));
+		num_regs = (num_regs/sizeof(struct linux_prom_registers));
+
+		/* Convert available virtual areas to taken virtual
+		 * areas.  First sort, then convert.
+		 */
+		for(iter=0; iter<num_regs; iter++) {
+			prom_prom_taken[iter].start_adr =
+				prom_reg_memlist[iter].phys_addr;
+			prom_prom_taken[iter].num_bytes =
+				(unsigned long) prom_reg_memlist[iter].reg_size;
+			prom_prom_taken[iter].theres_more =
+				&prom_phys_total[iter+1];
+		}
+		prom_prom_taken[iter-1].theres_more = 0x0;
+
+		prom_sortmemlist(prom_prom_taken);
+
+		/* Finally, convert. */
+		for(iter=0; iter<num_regs; iter++) {
+			prom_prom_taken[iter].start_adr =
+				prom_prom_taken[iter].start_adr +
+					prom_prom_taken[iter].num_bytes;
+			prom_prom_taken[iter].num_bytes =
+				prom_prom_taken[iter+1].start_adr -
+					prom_prom_taken[iter].start_adr;
+		}
+		prom_prom_taken[iter-1].num_bytes =
+			0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr;
+
+		/* Sort the other two lists. */
+		prom_sortmemlist(prom_phys_total);
+		prom_sortmemlist(prom_phys_avail);
+
+	};
+
+	/* Link all the lists into the top-level descriptor. */
+	prom_memlist.v0_totphys=&prom_ptot_ptr;
+	prom_memlist.v0_prommap=&prom_ptak_ptr;
+	prom_memlist.v0_available=&prom_pavl_ptr;
+
+	return;
+}
+
+/* This returns a pointer to our libraries internal v0 format
+ * memory descriptor.
+ */
+struct linux_mem_v0 *
+prom_meminfo(void)
+{
+	return &prom_memlist;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c
--- v1.3.3/linux/arch/sparc/prom/misc.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/misc.c	Wed Jun  7 11:51:11 1995
@@ -0,0 +1,99 @@
+/* misc.c:  Miscellaneous prom functions that don't belong
+ *          anywhere else.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Reset and reboot the machine with the command 'bcommand'. */
+void
+prom_reboot(char *bcommand)
+{
+	(*(romvec->pv_reboot))(bcommand);
+	/* Never get here. */
+	return;
+}
+
+/* Forth evaluate the expression contained in 'fstring'. */
+void
+prom_feval(char *fstring)
+{
+	if(!fstring || fstring[0] == 0) return;
+	if(prom_vers == PROM_V0)
+		(*(romvec->pv_fortheval.v0_eval))(strlen(fstring), fstring);
+	else
+		(*(romvec->pv_fortheval.v2_eval))(fstring);
+	return;
+}
+
+/* Drop into the prom, with the chance to continue with the 'go'
+ * prom command.
+ */
+void
+prom_halt(void)
+{
+	(*(romvec->pv_abort))();
+	return;
+}
+
+/* Drop into the prom, but completely terminate the program.
+ * No chance of continuing.
+ */
+void
+prom_die(void)
+{
+	(*(romvec->pv_halt))();
+	/* Never get here. */
+	return;
+}
+
+typedef void (*sfunc_t)(void);
+
+/* Set prom sync handler to call function 'funcp'. */
+void
+prom_setsync(sfunc_t funcp)
+{
+	if(!funcp) return;
+	*romvec->pv_synchook = funcp;
+	return;
+}
+
+/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
+ * format type.  'num_bytes' is the number of bytes that your idbuf
+ * has space for.  Returns 0xff on error.
+ */
+unsigned char
+prom_getidp(char *idbuf, int num_bytes)
+{
+	int len;
+
+	len = prom_getproplen(prom_root_node, "idprom");
+	if((len>num_bytes) || (len==-1)) return 0xff;
+	if(!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
+		return idbuf[0];
+
+	return 0xff;
+}
+
+/* Get the major prom version number. */
+int
+prom_version(void)
+{
+	return romvec->pv_romvers;
+}
+
+/* Get the prom plugin-revision. */
+int
+prom_getrev(void)
+{
+	return prom_rev;
+}
+
+/* Get the prom firmware print revision. */
+int
+prom_getprev(void)
+{
+	return prom_prev;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c
--- v1.3.3/linux/arch/sparc/prom/mp.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/mp.c	Sat Jun 17 10:46:00 1995
@@ -0,0 +1,86 @@
+/* mp.c:  OpenBoot Prom Multiprocessor support routines.  Don't call
+ *        these on a UP or else you will halt and catch fire. ;)
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Start cpu with prom-tree node 'cpunode' using context described
+ * by 'ctable_reg' in context 'ctx' at program counter 'pc'.
+ *
+ * XXX Have to look into what the return values mean. XXX
+ */
+int
+prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, char *pc)
+{
+	switch(prom_vers) {
+	case PROM_V0:
+	case PROM_V2:
+		break;
+	case PROM_V3:
+	case PROM_P1275:
+		return (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, pc);
+		break;
+	};
+
+	return -1;
+}
+
+/* Stop CPU with device prom-tree node 'cpunode'.
+ * XXX Again, what does the return value really mean? XXX
+ */
+int
+prom_stopcpu(int cpunode)
+{
+	switch(prom_vers) {
+	case PROM_V0:
+	case PROM_V2:
+		break;
+	case PROM_V3:
+	case PROM_P1275:
+		return (*(romvec->v3_cpustop))(cpunode);
+		break;
+	};
+
+	return -1;
+}
+
+/* Make CPU with device prom-tree node 'cpunode' idle.
+ * XXX Return value, anyone? XXX
+ */
+int
+prom_idlecpu(int cpunode)
+{
+	switch(prom_vers) {
+	case PROM_V0:
+	case PROM_V2:
+		break;
+	case PROM_V3:
+	case PROM_P1275:
+		return (*(romvec->v3_cpuidle))(cpunode);
+		break;
+	};
+
+	return -1;
+}
+
+/* Resume the execution of CPU with nodeid 'cpunode'.
+ * XXX Come on, somebody has to know... XXX
+ */
+int
+prom_restartcpu(int cpunode)
+{
+	switch(prom_vers) {
+	case PROM_V0:
+	case PROM_V2:
+		break;
+	case PROM_V3:
+	case PROM_P1275:
+		return (*(romvec->v3_cpuresume))(cpunode);
+		break;
+	};
+
+	return -1;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/palloc.c linux/arch/sparc/prom/palloc.c
--- v1.3.3/linux/arch/sparc/prom/palloc.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/palloc.c	Wed Jun  7 11:55:55 1995
@@ -0,0 +1,43 @@
+/* palloc.c:  Memory allocation from the Sun PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* You should not call these routines after memory management
+ * has been initialized in the kernel, if fact you should not
+ * use these if at all possible in the kernel.  They are mainly
+ * to be used for a bootloader for temporary allocations which
+ * it will free before jumping into the kernel it has loaded.
+ *
+ * Also, these routines don't work on V0 proms, only V2 and later.
+ */
+
+/* Allocate a chunk of memory of size 'num_bytes' giving a suggestion
+ * of virtual_hint as the preferred virtual base address of this chunk.
+ * There are no guarentees that you will get the allocation, or that
+ * the prom will abide by your "hint".  So check your return value.
+ */
+char *
+prom_alloc(char *virtual_hint, unsigned int num_bytes)
+{
+	if(prom_vers == PROM_V0) return (char *) 0x0;
+	if(num_bytes == 0x0) return (char *) 0x0;
+	return (*(romvec->pv_v2devops.v2_dumb_mem_alloc))(virtual_hint, num_bytes);
+}
+
+/* Free a previously allocated chunk back to the prom at virtual address
+ * 'vaddr' of size 'num_bytes'.  NOTE: This vaddr is not the hint you
+ * used for the allocation, but the virtual address the prom actually
+ * returned to you.  They may be have been the same, they may have not,
+ * doesn't matter.
+ */
+void
+prom_free(char *vaddr, unsigned int num_bytes)
+{
+	if((prom_vers == PROM_V0) || (num_bytes == 0x0)) return;
+	(*(romvec->pv_v2devops.v2_dumb_mem_free))(vaddr, num_bytes);
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/printf.c linux/arch/sparc/prom/printf.c
--- v1.3.3/linux/arch/sparc/prom/printf.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/printf.c	Thu Jun  8 07:14:32 1995
@@ -0,0 +1,108 @@
+/* printf.c:  Internal prom library printf facility.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* This routine is internal to the prom library, no one else should know
+ * about or use it!  It's simple and smelly anyway....
+ */
+
+#include <stdarg.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+char hexstring[] = "0123456789abcdef";
+
+void
+prom_printf(char *fmt, ...)
+{
+	va_list args;
+	unsigned int ui_val;
+	int i_val, n_ctr;
+	char c_val;
+	char nstr_buf[32];
+	char *s_val;
+	
+	va_start(args, fmt);
+	while(*fmt) {
+		if(*fmt != '%') {
+			if(*fmt == '\n')
+				prom_putchar('\r');
+			prom_putchar(*fmt++);
+			continue;
+		}
+
+		fmt++;
+		if(!*fmt) break;
+		n_ctr = 0;
+		switch(*fmt) {
+		case 'c':
+			c_val = va_arg(args, char);
+			if(c_val == '\n')
+				prom_putchar('\r');
+			prom_putchar(c_val);
+			fmt++;
+			break;
+		case 's':
+			s_val = va_arg(args, char *);
+			while(*s_val != 0) {
+				prom_putchar(*s_val);
+				s_val++;
+			}
+			fmt++;
+			break;
+		case 'd':
+			/* Base 10 */
+			i_val = va_arg(args, int);
+			if(i_val==0x0)
+				prom_putchar('0');
+			else
+				while(i_val != 0x0) {
+					nstr_buf[n_ctr] = hexstring[i_val%0xa];
+					i_val = ((unsigned long)i_val) / (unsigned) 0xa;
+					n_ctr++;
+				};
+			while(--n_ctr >= 0)
+				prom_putchar(nstr_buf[n_ctr]);
+			fmt++;
+			break;
+		case 'x':
+			/* Base 16 */
+			ui_val = va_arg(args, unsigned int);
+			if(ui_val==0x0)
+				prom_putchar('0');
+			else
+				while(ui_val != 0x0) {
+					nstr_buf[n_ctr] = hexstring[ui_val%0x10];
+					ui_val = ((unsigned long) ui_val) / (unsigned) 0x10;
+					n_ctr++;
+				};
+			while(--n_ctr >= 0)
+				prom_putchar(nstr_buf[n_ctr]);
+			fmt++;
+			break;
+		case 'o':
+			/* Base 8 */
+			ui_val = va_arg(args, unsigned int);
+			if(ui_val==0x0)
+				prom_putchar('0');
+			else
+				while(ui_val != 0x0) {
+					nstr_buf[n_ctr] = hexstring[ui_val%0x8];
+					ui_val = ((unsigned long) ui_val) / (unsigned) 0x8;
+				};
+			while(--n_ctr >= 0)
+				prom_putchar(nstr_buf[n_ctr]);
+			fmt++;
+			break;
+		default:
+			/* Uh oh, something we can't handle... skip it */
+			fmt++;
+			break;
+		};
+	}
+
+	/* We are done... */
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c
--- v1.3.3/linux/arch/sparc/prom/ranges.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/ranges.c	Thu Jun  8 07:33:18 1995
@@ -0,0 +1,109 @@
+/* ranges.c: Handle ranges in newer proms for obio.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
+struct linux_prom_ranges promlib_sbus_ranges[PROMREG_MAX];
+int num_obio_ranges, num_sbus_ranges;
+
+/* Adjust register values based upon the ranges parameters. */
+void
+prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
+		 struct linux_prom_ranges *rangep, int nranges)
+{
+	int regc, rngc;
+
+	for(regc=0; regc < nregs; regc++) {
+		for(rngc=0; rngc < nranges; rngc++)
+			if(regp[regc].which_io == rangep[rngc].ot_child_space)
+				break; /* Fount it */
+		if(rngc==nranges) /* oops */
+			prom_printf("adjust_regs: Could not find range with matching bus type...\n");
+		regp[regc].which_io = rangep[rngc].ot_parent_space;
+		regp[regc].phys_addr += rangep[rngc].ot_parent_base;
+	}
+
+	return;
+}
+
+void
+prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1,
+		   struct linux_prom_ranges *ranges2, int nranges2)
+{
+	int rng1c, rng2c;
+
+	for(rng1c=0; rng1c < nranges1; rng1c++) {
+		for(rng2c=0; rng2c < nranges2; rng2c++)
+			if(ranges1[rng1c].ot_child_space ==
+			   ranges2[rng2c].ot_child_space) break;
+		if(rng2c == nranges2) /* oops */
+			prom_printf("adjust_ranges: Could not find matching bus type...\n");
+		ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space;
+		ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base;
+	}
+
+	return;
+}
+
+/* Apply probed obio ranges to registers passed, if no ranges return. */
+void
+prom_apply_obio_ranges(struct linux_prom_registers *regs, int nregs)
+{
+	if(!num_obio_ranges) return;
+	prom_adjust_regs(regs, nregs, promlib_obio_ranges, num_obio_ranges);
+	return;
+}
+
+/* Apply probed sbus ranges to registers passed, if no ranges return. */
+void
+prom_apply_sbus_ranges(struct linux_prom_registers *regs, int nregs)
+{
+	if(!num_sbus_ranges) return;
+	prom_adjust_regs(regs, nregs, promlib_sbus_ranges, num_sbus_ranges);
+	return;
+}
+
+void
+prom_ranges_init(void)
+{
+	int node, obio_node, sbus_node;
+	int success;
+
+	num_obio_ranges = 0;
+	num_sbus_ranges = 0;
+
+	/* Check for obio and sbus ranges. */
+	node = prom_getchild(prom_root_node);
+	obio_node = prom_searchsiblings(node, "obio");
+	sbus_node = prom_searchsiblings(node, "iommu");
+	if(sbus_node) {
+		sbus_node = prom_getchild(sbus_node);
+		sbus_node = prom_searchsiblings(sbus_node, "sbus");
+	}
+
+	if(obio_node) {
+		success = prom_getproperty(obio_node, "ranges",
+					   (char *) promlib_obio_ranges,
+					   sizeof(promlib_obio_ranges));
+		if(success != -1)
+			num_obio_ranges = (success/sizeof(struct linux_prom_ranges));
+	}
+
+	if(sbus_node) {
+		success = prom_getproperty(sbus_node, "ranges",
+					   (char *) promlib_sbus_ranges,
+					   sizeof(promlib_sbus_ranges));
+		if(success != -1)
+			num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
+	}
+
+	if(num_obio_ranges || num_sbus_ranges)
+		prom_printf("PROMLIB: obio_ranges %d sbus_ranges %d\n",
+			    num_obio_ranges, num_sbus_ranges);
+
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/segment.c linux/arch/sparc/prom/segment.c
--- v1.3.3/linux/arch/sparc/prom/segment.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/segment.c	Sun Jun  4 21:17:54 1995
@@ -0,0 +1,19 @@
+/* segment.c:  Prom routine to map segments in other contexts before
+ *             a standalone is completely mapped.  This is for sun4 and
+ *             sun4c architectures only.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Set physical segment 'segment' at virtual address 'vaddr' in
+ * context 'ctx'.
+ */
+void
+prom_putsegment(int ctx, unsigned long vaddr, int segment)
+{
+	(*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment);
+	return;
+}
diff -u --recursive --new-file v1.3.3/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c
--- v1.3.3/linux/arch/sparc/prom/tree.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/tree.c	Wed Jun  7 12:21:08 1995
@@ -0,0 +1,185 @@
+/* tree.c: Basic device tree traversal/scanning for the Linux
+ *         prom library.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/string.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+static char promlib_buf[128];
+
+/* Return the child of node 'node' or zero if no this node has no
+ * direct descendent.
+ */
+int
+prom_getchild(int node)
+{
+	int cnode;
+
+	if(node == -1) return 0;
+	cnode = prom_nodeops->no_child(node);
+	if((cnode == 0) || (cnode == -1)) return 0;
+	return cnode;
+}
+
+/* Return the next sibling of node 'node' or zero if no more siblings
+ * at this level of depth in the tree.
+ */
+int
+prom_getsibling(int node)
+{
+	int sibnode;
+
+	if(node == -1) return 0;
+	sibnode = prom_nodeops->no_nextnode(node);
+	if((sibnode == 0) || (sibnode == -1)) return 0;
+	return sibnode;
+}
+
+/* Return the length in bytes of property 'prop' at node 'node'.
+ * Return -1 on error.
+ */
+int
+prom_getproplen(int node, char *prop)
+{
+	if((!node) || (!prop)) return -1;
+	return prom_nodeops->no_proplen(node, prop);
+}
+
+/* Acquire a property 'prop' at node 'node' and place it in
+ * 'buffer' which has a size of 'bufsize'.  If the acquisition
+ * was successful the length will be returned, else -1 is returned.
+ */
+int
+prom_getproperty(int node, char *prop, char *buffer, int bufsize)
+{
+	int plen;
+
+	plen = prom_getproplen(node, prop);
+	if((plen > bufsize) || (plen == 0) || (plen == -1)) return -1;
+
+	/* Ok, things seem all right. */
+	return prom_nodeops->no_getprop(node, prop, buffer);
+}
+
+/* Acquire an integer property and return it's value.  Returns -1
+ * on failure.
+ */
+int
+prom_getint(int node, char *prop)
+{
+	static int intprop;
+
+	if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
+		return intprop;
+
+	return -1;
+}
+
+/* Acquire an integer property, upon error return the passed default
+ * integer.
+ */
+
+int
+prom_getintdefault(int node, char *property, int deflt)
+{
+	int retval;
+
+	retval = prom_getint(node, property);
+	if(retval == -1) return deflt;
+
+	return retval;
+}
+
+/* Acquire a boolean property, 1=TRUE 0=FALSE. */
+int
+prom_getbool(int node, char *prop)
+{
+	int retval;
+
+	retval = prom_getproplen(node, prop);
+	if(retval == -1) return 0;
+	return 1;
+}
+
+/* Acquire a property whose value is a string, returns a null
+ * string on error.  The char pointer is the user supplied string
+ * buffer.
+ */
+void
+prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+{
+	int len;
+
+	len = prom_getproperty(node, prop, user_buf, ubuf_size);
+	if(len != -1) return;
+	user_buf[0] = 0;
+	return;
+}
+
+
+/* Does the device at node 'node' have name 'name'?
+ * YES = 1   NO = 0
+ */
+int
+prom_nodematch(int node, char *name)
+{
+	static char namebuf[128];
+	prom_getproperty(node, "name", namebuf, sizeof(namebuf));
+	if(strcmp(namebuf, name) == 0) return 1;
+	return 0;
+}
+
+/* Search siblings at 'node_start' for a node with name
+ * 'nodename'.  Return node if successful, zero if not.
+ */
+int
+prom_searchsiblings(int node_start, char *nodename)
+{
+	int thisnode, error;
+
+	for(thisnode = node_start; thisnode;
+	    thisnode=prom_getsibling(thisnode)) {
+		error = prom_getproperty(thisnode, "name", promlib_buf,
+					 sizeof(promlib_buf));
+		/* Should this ever happen? */
+		if(error == -1) continue;
+		if(strcmp(nodename, promlib_buf)==0) return thisnode;
+	}
+
+	return 0;
+}
+
+/* Return the first property type for node 'node'.
+ */
+char *
+prom_firstprop(int node)
+{
+	if(node == -1) return "";
+	return prom_nodeops->no_nextprop(node, (char *) 0x0);
+}
+
+/* Return the property type string after property type 'oprop'
+ * at node 'node' .  Returns NULL string if no more
+ * property types for this node.
+ */
+char *
+prom_nextprop(int node, char *oprop)
+{
+	if(node == -1) return "";
+	return prom_nodeops->no_nextprop(node, oprop);
+}
+
+/* Set property 'pname' at node 'node' to value 'value' which has a length
+ * of 'size' bytes.  Return the number of bytes the prom accepted.
+ */
+int
+prom_setprop(int node, char *pname, char *value, int size)
+{
+	if(size == 0) return 0;
+	if((pname == 0) || (value == 0)) return 0;
+	return prom_nodeops->no_setprop(node, pname, value, size);
+}
diff -u --recursive --new-file v1.3.3/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v1.3.3/linux/drivers/block/Makefile	Mon Jun 12 19:37:21 1995
+++ linux/drivers/block/Makefile	Tue Jun 20 08:22:35 1995
@@ -28,6 +28,8 @@
 ifdef CONFIG_BLK_DEV_FD
 OBJS := $(OBJS) floppy.o
 SRCS := $(SRCS) floppy.c
+else
+BLOCK_MODULE_OBJS := $(MODULES) floppy.o
 endif
 
 ifdef CONFIG_CDU31A
diff -u --recursive --new-file v1.3.3/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.3.3/linux/drivers/block/aztcd.c	Sun Mar 26 11:56:23 1995
+++ linux/drivers/block/aztcd.c	Tue Jun 20 20:49:59 1995
@@ -134,10 +134,8 @@
 
 #define MAJOR_NR AZTECH_CDROM_MAJOR 
 
-#ifdef MODULE
-# include "/usr/src/linux/drivers/block/blk.h"
-#else
-# include "blk.h"
+#include "blk.h"
+#ifndef MODULE
 # define MOD_INC_USE_COUNT
 # define MOD_DEC_USE_COUNT
 #endif
diff -u --recursive --new-file v1.3.3/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.3.3/linux/drivers/block/blk.h	Tue Apr  4 09:06:42 1995
+++ linux/drivers/block/blk.h	Tue Jun 20 08:29:03 1995
@@ -56,13 +56,7 @@
 #endif CONFIG_SBPCD
 extern void set_device_ro(int dev,int flag);
 
-extern void floppy_init(void);
-#ifdef FD_MODULE
-static
-#else
-extern
-#endif
-int new_floppy_init(void);
+extern int floppy_init(void);
 extern void rd_load(void);
 extern long rd_init(long mem_start, int length);
 extern int ramdisk_size;
diff -u --recursive --new-file v1.3.3/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.3/linux/drivers/block/floppy.c	Mon Apr  3 11:31:31 1995
+++ linux/drivers/block/floppy.c	Mon Jun 26 11:06:50 1995
@@ -81,6 +81,12 @@
  * errors to allow safe writing by specialized programs.
  */
 
+/* 1994/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
+ * by defining bit 1 of the "stretch" parameter to mean put sectors on the
+ * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
+ * drives are "upside-down").
+ */
+
 #define CONFIG_FLOPPY_SANITY
 #undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
 
@@ -94,6 +100,24 @@
 /* do print messages for unexpected interrupts */
 static int print_unex=1;
 
+#ifdef MODULE
+#define FD_MODULE
+
+#include <linux/module.h>
+/*
+ * NB. we must include the kernel idenfication string in to install the module.
+ */
+#include <linux/version.h>
+char kernel_version[] = UTS_RELEASE;
+
+int FLOPPY_IRQ=6;
+int FLOPPY_DMA=2;
+int ALLOWED_DRIVE_MASK = 0x33;
+int FDC1 = 0x3f0;
+int FDC2 = -1;
+
+#endif
+
 #ifndef FD_MODULE
 /* the following is the mask of allowed drives. By default units 2 and
  * 3 of both floppy controllers are disabled, because switching on the
@@ -120,10 +144,12 @@
 #include <linux/fd.h>
 #include <linux/errno.h>
 #include <linux/malloc.h>
+#include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/ioport.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -134,20 +160,49 @@
 #define MAJOR_NR FLOPPY_MAJOR
 #include "blk.h"
 
+
+/* Dma Memory related stuff */
+
+/* Pure 2^n version of get_order */
+static inline int __get_order (int size)
+{
+	int order;
+
+#ifdef  _ASM_IO_H2
+	__asm__ __volatile__("bsr %1,%0"
+			     : "=r" (order)
+			     : "r" (size / PAGE_SIZE) );	
+#else
+	for (order = 0; order < NR_MEM_LISTS; ++order)
+		if (size <= (PAGE_SIZE << order))
+			return order; 
+#endif
+	return NR_MEM_LISTS;
+}
+
+static unsigned long dma_mem_alloc(int size)
+{
+	int order = __get_order(size);
+	
+	if (order >= NR_MEM_LISTS)
+		return(0);
+	return __get_dma_pages(GFP_KERNEL,order);
+}
+
+/* End dma memory related stuff */
+
 static unsigned int fake_change = 0;
 static int initialising=1;
 
-#define FLOPPY0_TYPE	((CMOS_READ(0x10) >> 4) & 15)
-#define FLOPPY1_TYPE	(CMOS_READ(0x10) & 15)
-
 /*
  * Again, the CMOS information doesn't work on the alpha..
  */
 #ifdef __alpha__
-#undef FLOPPY0_TYPE
-#undef FLOPPY1_TYPE
 #define FLOPPY0_TYPE 6
 #define FLOPPY1_TYPE 0
+#else
+#define FLOPPY0_TYPE	((CMOS_READ(0x10) >> 4) & 15)
+#define FLOPPY1_TYPE	(CMOS_READ(0x10) & 15)
 #endif
 
 #define N_FDC 2
@@ -186,6 +241,9 @@
 #define DPRINT3(x,x1,x2,x3) \
 printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
 
+#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)
+#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
+
 /* read/write */
 #define COMMAND raw_cmd.cmd[0]
 #define DR_SELECT raw_cmd.cmd[1]
@@ -213,6 +271,7 @@
 #define MAX_DISK_SIZE 2 /* 3984*/
 
 
+#define K_64	0x10000		/* 64KB */
 
 /*
  * The DMA channel used by the floppy controller cannot access data at
@@ -222,8 +281,12 @@
  * driver otherwise. It doesn't matter much for performance anyway, as most
  * floppy accesses go through the track buffer.
  */
-#define LAST_DMA_ADDR	(0x1000000)
-#define K_64 (0x10000) /* 64 k */
+#ifdef __alpha__
+# define CROSS_64KB(a,s)	(0)
+#else
+# define CROSS_64KB(a,s) \
+	((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)
+#endif
 
 /*
  * globals used by 'result()'
@@ -299,9 +362,16 @@
 /*
  * This struct defines the different floppy types.
  *
- * The 'stretch' tells if the tracks need to be doubled for some
- * types (ie 360kB diskette in 1.2MB drive etc). Others should
- * be self-explanatory.
+ * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
+ * types (e.g. 360kB diskette in 1.2MB drive, etc.).  Bit 1 of 'stretch'
+ * tells if the disk is in Commodore 1581 format, which means side 0 sectors
+ * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
+ * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
+ * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
+ * side 0 is on physical side 0 (but with the misnamed sector IDs).
+ * 'stretch' should probably be renamed to something more general, like
+ * 'options'.  Other parameters should be self-explanatory (see also
+ * setfdprm(8)).
  */
 static struct floppy_struct floppy_type[32] = {
 	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },	/*  0 no testing    */
@@ -399,8 +469,8 @@
  * corrupted/lost. Alignment of these is enforced in boot/head.S.
  * Note that you must not change the sizes below without updating head.S.
  */
-extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
-#define max_buffer_sectors MAX_BUFFER_SECTORS
+char *floppy_track_buffer=0;
+int max_buffer_sectors=0;
 
 int *errors;
 typedef void (*done_f)(int);
@@ -410,7 +480,7 @@
 void (*redo)(void); /* this is called to retry the operation */
 void (*error)(void); /* this is called to tally an error */
 done_f done; /* this is called to say if the operation has succeeded/failed */
-} *cont;
+} *cont=NULL;
 
 static void floppy_ready(void);
 static void floppy_start(void);
@@ -483,6 +553,65 @@
 #endif
 }
 
+typedef void (*timeout_fn)(unsigned long);
+static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, 
+					       (timeout_fn) floppy_shutdown };
+
+static char *timeout_message;
+
+#ifdef CONFIG_FLOPPY_SANITY
+static void is_alive(char *message)
+{
+	/* this routine checks whether the floppy driver is "alive" */
+	if (fdc_busy && command_status < 2 && !fd_timeout.prev){
+		DPRINT1("timeout handler died: %s\n",message);
+	}
+}
+#endif
+
+#ifdef CONFIG_FLOPPY_SANITY
+
+#define OLOGSIZE 20
+
+void (*lasthandler)(void) = NULL;
+int interruptjiffies=0;
+int resultjiffies=0;
+int resultsize=0;
+int lastredo=0;
+
+static struct output_log {
+	unsigned char data;
+	unsigned char status;
+	unsigned long jiffies;
+} output_log[OLOGSIZE];
+
+static int output_log_pos=0;
+#endif
+
+#define CURRENTD -1
+#define MAXTIMEOUT -2
+
+
+
+static void reschedule_timeout(int drive, char *message, int marg)
+{
+	if (drive == CURRENTD )
+		drive = current_drive;
+	del_timer(&fd_timeout);
+	if (drive < 0 || drive > N_DRIVE) {
+		fd_timeout.expires = 2000;
+		drive=0;
+	} else
+		fd_timeout.expires = UDP->timeout;
+	add_timer(&fd_timeout);
+	if (UDP->flags & FD_DEBUG){
+		DPRINT("reschedule timeout ");
+		printk(message, marg);
+		printk("\n");
+	}
+	timeout_message = message;
+}
+
 /*
  * Bottom half floppy driver.
  * ==========================
@@ -668,15 +797,13 @@
 	sti();
 	command_status = FD_COMMAND_NONE;
 	set_fdc(drive);
+	reschedule_timeout(drive, "lock fdc", 0);
 	return 0;
 }
 
 #define LOCK_FDC(drive,interruptible) \
 if(lock_fdc(drive,interruptible)) return -EINTR;
 
-typedef void (*timeout_fn)(unsigned long);
-static struct timer_list fd_timeout ={ NULL, NULL, 0, 0, 
-					       (timeout_fn) floppy_shutdown };
 
 /* unlocks the driver */
 static inline void unlock_fdc(void)
@@ -689,6 +816,7 @@
 			DEVICE_INTR);
 	command_status = FD_COMMAND_NONE;
 	del_timer(&fd_timeout);
+	cont = NULL;
 	fdc_busy = 0;
 	floppy_release_irq_and_dma();
 	wake_up(&fdc_wait);
@@ -878,15 +1006,13 @@
 		FDCS->reset=1;
 		return;
 	}
-	if ( ( (long)current_addr & ~(64*1024-1) ) !=
-	    ((long)(current_addr + raw_cmd.length-1)  & ~(64*1024-1))){
+	if (CROSS_64KB(current_addr, raw_cmd.length)) {
 		printk("DMA crossing 64-K boundary %p-%p\n",
 		       current_addr, current_addr + raw_cmd.length);
 		cont->done(0);
 		FDCS->reset=1;
 		return;
 	}
-
 #endif
 	cli();
 	disable_dma(FLOPPY_DMA);
@@ -894,7 +1020,7 @@
 	set_dma_mode(FLOPPY_DMA,
 		     (raw_cmd.flags & FD_RAW_READ)?
 		     DMA_MODE_READ : DMA_MODE_WRITE);
-	set_dma_addr(FLOPPY_DMA, (long) current_addr);
+	set_dma_addr(FLOPPY_DMA, virt_to_bus(current_addr));
 	set_dma_count(FLOPPY_DMA, raw_cmd.length);
 	enable_dma(FLOPPY_DMA);
 	sti();
@@ -906,15 +1032,24 @@
 {
 	int counter;
 	unsigned char status;
+	unsigned char rstatus;
 
 	if (FDCS->reset)
 		return -1;
 	for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
-		status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
+		rstatus = inb_p(FD_STATUS); 
+		status =  rstatus &(STATUS_READY|STATUS_DIR|STATUS_DMA);
 		if (!(status & STATUS_READY))
 			continue;
 		if (status == STATUS_READY){
 			outb_p(byte,FD_DATA);
+
+#ifdef CONFIG_FLOPPY_SANITY
+			output_log[output_log_pos].data = byte;
+			output_log[output_log_pos].status = rstatus;
+			output_log[output_log_pos].jiffies = jiffies;
+			output_log_pos = (output_log_pos + 1) % OLOGSIZE;
+#endif
 			return 0;
 		} else
 			break;
@@ -939,8 +1074,13 @@
 			(STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
 		if (!(status & STATUS_READY))
 			continue;
-		if (status == STATUS_READY)
+		if (status == STATUS_READY){
+#ifdef CONFIG_FLOPPY_SANITY
+			resultjiffies = jiffies;
+			resultsize = i;
+#endif
 			return i;
+		}
 		if (status & STATUS_DMA )
 			break;
 		if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
@@ -1112,7 +1252,7 @@
 	 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
 	 */
 	FDCS->dtr = raw_cmd.rate;
-	return(wait_for_completion(jiffies+2,
+	return(wait_for_completion(jiffies+2*HZ/100,
 				   (timeout_fn) floppy_ready));
 } /* fdc_dtr */
 
@@ -1467,6 +1607,9 @@
 {
 	void (*handler)(void) = DEVICE_INTR;
 
+	lasthandler = handler;
+	interruptjiffies = jiffies;
+
 	floppy_enable_hlt();
 	CLEAR_INTR;
 	if ( fdc >= N_FDC || FDCS->address == -1){
@@ -1474,11 +1617,13 @@
 		printk("DOR0=%x\n", fdc_state[0].dor);
 		printk("floppy interrupt on bizarre fdc %d\n",fdc);
 		printk("handler=%p\n", handler);
+		is_alive("bizarre fdc");
 		return;
 	}
 	inr = result();
 	if (!handler){
 		unexpected_floppy_interrupt();
+		is_alive("unexpected");
 		return;
 	}
 	if ( inr == 0 ){
@@ -1489,6 +1634,7 @@
 	}
 	floppy_tq.routine = (void *)(void *) handler;
 	queue_task_irq(&floppy_tq, &tq_timer);
+	is_alive("normal interrupt end");
 }
 
 static void recalibrate_floppy(void)
@@ -1545,6 +1691,27 @@
 	printk("\n");
 	printk("floppy driver state\n");
 	printk("-------------------\n");
+	printk("now=%ld last interrupt=%d last called handler=%p\n", 
+	       jiffies, interruptjiffies, lasthandler);
+
+
+#ifdef CONFIG_FLOPPY_SANITY
+	printk("timeout_message=%s\n", timeout_message);
+	printk("last output bytes:\n");
+	for(i=0; i < OLOGSIZE; i++)
+		printk("%2x %2x %ld\n",		       
+		       output_log[(i+output_log_pos) % OLOGSIZE].data,
+		       output_log[(i+output_log_pos) % OLOGSIZE].status,
+		       output_log[(i+output_log_pos) % OLOGSIZE].jiffies);
+	printk("last result at %d\n", resultjiffies);
+	printk("last redo_fd_request at %d\n", lastredo);
+	for(i=0; i<resultsize; i++){
+		printk("%2x ", reply_buffer[i]);
+	}
+	printk("\n");
+#endif
+
+#if 0
 	for(i=0; i<N_FDC; i++){
 		if(FDCS->address != -1){
 			printk("dor %d = %x\n", i, fdc_state[i].dor );
@@ -1552,6 +1719,7 @@
 			udelay(1000); /* maybe we'll catch an interrupt... */
 		}
 	}
+#endif
 	printk("status=%x\n", inb_p(FD_STATUS));
 	printk("fdc_busy=%d\n", fdc_busy);
 	if( DEVICE_INTR)
@@ -1573,6 +1741,8 @@
 
 static void floppy_shutdown(void)
 {
+	if(!initialising)
+		show_floppy();
 	CLEAR_INTR;
 	floppy_tq.routine = (void *)(void *) empty;
 	del_timer( &fd_timer);
@@ -1584,8 +1754,14 @@
 	if(!initialising)
 		DPRINT("floppy timeout\n");
 	FDCS->reset = 1;
-	cont->done(0);
-	cont->redo(); /* this will recall reset when needed */
+	if (cont){
+		cont->done(0);
+		cont->redo(); /* this will recall reset when needed */
+	} else {
+		printk("no cont in shutdown!\n");
+		process_fd_request();
+	}
+	is_alive("floppy shutdown");
 }
 /*typedef void (*timeout_fn)(unsigned long);*/
 
@@ -1646,9 +1822,7 @@
 
 static void floppy_start(void)
 {
-	del_timer(&fd_timeout);
-	fd_timeout.expires = DP->timeout;
-	add_timer(&fd_timeout);
+	reschedule_timeout(CURRENTD, "floppy start", 0);
 
 	scandrives();
 #ifdef DCL_DEBUG
@@ -1663,7 +1837,7 @@
 /*
  * ========================================================================
  * here ends the bottom half. Exported routines are:
-  * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
+ * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
  * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
  * Initialisation also uses output_byte, result, set_dor, floppy_interrupt
  * and set_dor.
@@ -1676,7 +1850,7 @@
 
 static void do_wakeup(void)
 {
-	del_timer(&fd_timeout);
+	reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
 	cont = 0;
 	command_status += 2;
 	wake_up(&command_done);
@@ -1697,7 +1871,8 @@
 	queue_task(&floppy_tq, &tq_timer);
 
 	cli();
-	while(command_status < 2 && NO_SIGNAL)
+	while(command_status < 2 && NO_SIGNAL){
+		is_alive("wait_til_done");	
 		if (current->pid)
 			interruptible_sleep_on(&command_done);
 		else {
@@ -1705,6 +1880,7 @@
 			run_task_queue(&tq_timer);
 			cli();
 		}
+	}
 	if(command_status < 2){
 		sti();
 		floppy_shutdown();
@@ -1834,7 +2010,7 @@
 	raw_cmd.rate = floppy->rate & 0x3;
 	raw_cmd.cmd_count = NR_F;
 	COMMAND = FM_MODE(floppy,FD_FORMAT);
-	DR_SELECT = UNIT(current_drive) + ( format_req.head << 2 );
+	DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,format_req.head);
 	F_SIZECODE = FD_SIZECODE(floppy);
 	F_SECT_PER_TRACK = floppy->sect << 2 >> F_SIZECODE;
 	F_GAP = floppy->fmt_gap;
@@ -1881,7 +2057,7 @@
 
 static void redo_format(void)
 {
-	raw_cmd.track = format_req.track << floppy->stretch;
+	raw_cmd.track = format_req.track << STRETCH(floppy);
 	buffer_track = -1;
 	setup_format_params();
 	floppy_start();
@@ -1933,7 +2109,7 @@
 	int block;
 
 	probing = 0;
-	del_timer(&fd_timeout);
+	reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate);
 
 	if (!CURRENT){
 		DPRINT("request list destroyed in floppy request done\n");
@@ -2222,13 +2398,15 @@
 	}
 
 	max_sector = floppy->sect * floppy->head;
+
 	TRACK = CURRENT->sector / max_sector;
 	sector_t = CURRENT->sector % max_sector;
 	if ( floppy->track && TRACK >= floppy->track )
 		return 0;
 	HEAD = sector_t / floppy->sect;
 
-	if ( TESTF( FD_NEED_TWADDLE) && sector_t < floppy->sect )
+	if (((floppy->stretch & FD_SWAPSIDES) || TESTF( FD_NEED_TWADDLE)) && 
+	    sector_t < floppy->sect )
 		max_sector = floppy->sect;
 
 	/* 2M disks have phantom sectors on the first track */
@@ -2253,8 +2431,8 @@
 		SIZECODE2 = 0xff;
 	else
 		SIZECODE2 = 0x80;
-	raw_cmd.track = TRACK << floppy->stretch;
-	DR_SELECT = UNIT(current_drive) + ( HEAD << 2 );
+	raw_cmd.track = TRACK << STRETCH(floppy);
+	DR_SELECT = UNIT(current_drive) + PH_HEAD(floppy,HEAD);
 	GAP = floppy->gap;
 	CODE2SIZE;
 	SECT_PER_TRACK = floppy->sect << 2 >> SIZECODE;
@@ -2296,18 +2474,17 @@
 		raw_cmd.flags &= ~FD_RAW_WRITE;
 		raw_cmd.flags |= FD_RAW_READ;
 		COMMAND = FM_MODE(floppy,FD_READ);
-	} else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
+	} else if ((unsigned long)CURRENT->buffer < MAX_DMA_ADDRESS ) {
 		int direct, indirect;
 
 		indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
 			sector_t;
 
 		max_size = buffer_chain_size();
-		if ( max_size > ( LAST_DMA_ADDR - ((long) CURRENT->buffer))>>9)
-			max_size=(LAST_DMA_ADDR - ((long)CURRENT->buffer))>>9;
+		if ( max_size > ( MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9)
+			max_size=(MAX_DMA_ADDRESS - ((unsigned long) CURRENT->buffer))>>9;
 		/* 64 kb boundaries */
-		if ( ((max_size << 9) + ((long) CURRENT->buffer)) / K_64 !=
-		     ((long) CURRENT->buffer ) / K_64 )
+		if (CROSS_64KB(CURRENT->buffer, max_size << 9))
 			max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
 		direct = transfer_size(ssize,max_sector,max_size) - sector_t;
 		/*
@@ -2443,11 +2620,16 @@
 	int tmp;
 	int error;
 
+
 	error = -1;
+	lastredo = jiffies;
 	if (current_drive < N_DRIVE)
 		floppy_off(current_drive);
 
-	if (CURRENT && CURRENT->dev < 0) return;
+	if (CURRENT && CURRENT->dev < 0){
+		DPRINT("current dev < 0!\n");
+		return;
+	}
 
 	while(1){
 		if (!CURRENT) {
@@ -2470,10 +2652,7 @@
 		error=-1;
 		device = CURRENT->dev;
 		set_fdc( DRIVE(device));
-
-		del_timer(&fd_timeout);
-		fd_timeout.expires = DP->timeout;
-		add_timer(&fd_timeout);
+		reschedule_timeout(CURRENTD, "redo fd request", 0);
 
 		set_floppy(device);
 		if(start_motor(redo_fd_request)) return;
@@ -2531,14 +2710,18 @@
 
 static void do_fd_request(void)
 {
-	if (fdc_busy)
+	if (fdc_busy){
 		/* fdc busy, this new request will be treated when the
 		   current one is done */
+		is_alive("do fd request, old request running");
 		return;
+	}
 	/* fdc_busy cannot be set by an interrupt or a bh */
 	floppy_grab_irq_and_dma();
 	fdc_busy=1;
+	reschedule_timeout(MAXTIMEOUT, "do fd request",0);
 	process_fd_request();
+	is_alive("do fd request");
 }
 
 static struct cont_t poll_cont={
@@ -2592,9 +2775,7 @@
 		FDCS->reset=1;
 	if ( FDCS->reset ){
 		cont = &reset_cont;
-		del_timer(&fd_timeout);
-		fd_timeout.expires = DP->timeout;
-		add_timer(&fd_timeout);
+		reschedule_timeout(CURRENTD, "user reset fdc", 0);
 		WAIT(reset_fdc);
 	}
 	process_fd_request();
@@ -2757,8 +2938,7 @@
 			return i;
 		name = drive_name(type,drive);
 		for ( cnt=0; cnt<16; cnt++){
-			put_fs_byte(name[cnt],
-				    ((char*)param)+cnt);
+			put_user(name[cnt], ((char*)param)+cnt);
 			if ( ! *name )
 				break;
 		}
@@ -2831,8 +3011,9 @@
 		if(newparams.sect <= 0 ||
 		   newparams.head <= 0 ||
 		   newparams.track <= 0 ||
-		   newparams.track >
-		   UDP->tracks>>newparams.stretch)
+		   newparams.track > UDP->tracks>> STRETCH(&newparams) ||
+		   /* check if reserved bits are set */
+		   (newparams.stretch & ~(FD_STRETCH | FD_SWAPSIDES)) != 0)
 			return -EINVAL;
 		if ( type){
 			if ( !suser() )
@@ -3022,6 +3203,8 @@
 {
 	int drive;
 	int old_dev;
+	int try;
+	char *tmp;
 
 	if (!filp) {
 		DPRINT("Weird, open called with filp=0\n");
@@ -3029,6 +3212,7 @@
 	}
 
 	drive = DRIVE(inode->i_rdev);
+
 	if (drive >= N_DRIVE || 
 	    !( ALLOWED_DRIVE_MASK & ( 1 << drive)) ||
 	    fdc_state[FDC(drive)].version == FDC_NONE)
@@ -3057,6 +3241,33 @@
 	else
 		UDRS->fd_ref++;
 
+	if (!floppy_track_buffer){
+		/* if opening an ED drive, reserve a big buffer,
+		 * else reserve a small one */
+		if ((UDP->cmos == 6) || (UDP->cmos == 5))
+			try = 64; /* Only 48 actually useful */
+		else
+			try = 32; /* Only 24 actually useful */
+
+		tmp=(char *)dma_mem_alloc(1024 * try);
+		if (!tmp) {
+			try >>= 1; /* buffer only one side */
+			if (try < 16)
+				try=16;
+			tmp= (char *)dma_mem_alloc(1024*try);
+		}
+		if (!tmp) {
+			DPRINT("Unable to allocate DMA memory\n");
+			RETERR(ENXIO);
+		}
+		if (floppy_track_buffer){
+			free_pages((unsigned long)tmp,__get_order(try*1024));
+		}else {
+			floppy_track_buffer = tmp;
+			max_buffer_sectors = try;
+		}
+	}
+
 	UDRS->fd_device = inode->i_rdev;
 
 	if (old_dev && old_dev != inode->i_rdev) {
@@ -3353,10 +3564,7 @@
 	DPRINT("Read linux/drivers/block/README.fd\n");
 }
 
-#ifdef FD_MODULE
-static
-#endif
-int new_floppy_init(void)
+int floppy_init(void)
 {
 	int i,drive;
 	int have_no_fdc=0;
@@ -3377,7 +3585,7 @@
 	blk_size[MAJOR_NR] = floppy_sizes;
 	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-	del_timer(&fd_timeout);
+	reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
 	config_types();
 
 	fdc_state[0].address = FDC1;
@@ -3407,6 +3615,8 @@
 		UDRS->keep_data = 0;
 		UDRS->fd_ref = 0;
 		UDRS->fd_device = 0;
+		floppy_track_buffer = NULL;
+		max_buffer_sectors = 0;
 		UDRWE->write_errors = 0;
 		UDRWE->first_error_sector = 0;
 		UDRWE->first_error_generation = 0;
@@ -3430,6 +3640,11 @@
 			FDCS->address = -1;
 			continue;
 		}
+		
+		request_region(FDCS->address, 6, "floppy");
+		request_region(FDCS->address+7, 1, "floppy DIR");
+		/* address + 6 is reserved, and may be taken by IDE.
+		 * Unfortunately, Adaptec doesn't know this :-(, */
 
 		have_no_fdc = 0;
 		/* Not all FDCs seem to be able to handle the version command
@@ -3440,6 +3655,7 @@
 		user_reset_fdc(-1,FD_RESET_ALWAYS,0);
 	}
 	fdc=0;
+	del_timer(&fd_timeout);
 	current_drive = 0;
 	floppy_release_irq_and_dma();
 	initialising=0;
@@ -3448,12 +3664,6 @@
 	return have_no_fdc;
 }
 
-/* stupid compatibility hack... */
-void floppy_init(void)
-{
-	new_floppy_init();
-}
-
 static int floppy_grab_irq_and_dma(void)
 {
 	int i;
@@ -3499,6 +3709,9 @@
 #ifdef CONFIG_FLOPPY_SANITY
 	int drive;
 #endif
+	long tmpsize;
+	void *tmpaddr;
+
 	cli();
 	if (--usage_count){
 		sti();
@@ -3518,13 +3731,22 @@
 	set_dor(1, ~8, 0);
 #endif
 	floppy_enable_hlt();
+
+	if (floppy_track_buffer && max_buffer_sectors) {
+		tmpsize = max_buffer_sectors*1024;
+		tmpaddr = (void *)floppy_track_buffer;
+		floppy_track_buffer = 0;
+		max_buffer_sectors = 0;
+		free_pages((unsigned long)tmpaddr, __get_order(tmpsize));
+	}
+
 #ifdef CONFIG_FLOPPY_SANITY
 	for(drive=0; drive < N_FDC * 4; drive++)
 		if( motor_off_timer[drive].next )
 			printk("motor off timer %d still active\n", drive);
 	
 	if(fd_timeout.next)
-		printk("floppy timer still active\n");
+		printk("floppy timer still active:%s\n", timeout_message);
 	if (fd_timer.next)
 		printk("auxiliary floppy timer still active\n");
 	if(floppy_tq.sync)
@@ -3532,3 +3754,82 @@
 #endif
 }
 
+
+#ifdef MODULE
+
+extern char *get_options(char *str, int *ints);
+
+#if 0
+/* assuming that insmod is compiled as a.out binary using a shared
+   C library ... */
+int ENVIRON = 0x60090b34;
+
+static void
+mod_setup(char *name,
+	  void (*setup)(char *, int *)) {
+	char **environ,*env,*ptr,c,i;
+	char line[100];
+	int ints[11];
+
+	environ = (char **) get_fs_long( ENVIRON );
+	
+	while((env = (char *)get_fs_long(environ))){
+		for(i=0; i<strlen(name); i++)
+			if ( (char) get_fs_byte(env++) != name[i] )
+				break;
+		if(i == strlen(name)){
+			ptr=line;
+			while(ptr < line+99){
+			        c = (char)get_fs_byte(env++);
+				if ( c== ' ' || !c ){
+					*ptr='\0';
+					if(ptr!=line)
+						setup(get_options(line,ints),
+						      ints);
+					ptr=line;
+					if (!c)
+						break;
+				} else
+					*ptr++ = c;
+			}
+		}
+		environ++;
+	}
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int init_module(void)
+{
+	int ret;
+	printk("inserting floppy driver for %s\n", kernel_version);
+
+	/*mod_setup("floppy=", floppy_setup);*/
+	/* Can't do that any more, insmod is now ELF */
+
+	ret = floppy_init();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	int fdc;
+
+	for(fdc=0; fdc<2; fdc++)
+		if (FDCS->address != -1){
+			release_region(FDCS->address, 6);
+			release_region(FDCS->address+7, 1);
+		      }
+
+	unregister_blkdev(MAJOR_NR, "fd");
+
+	blk_dev[MAJOR_NR].request_fn = 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff -u --recursive --new-file v1.3.3/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.3.3/linux/drivers/block/hd.c	Wed Apr  5 12:47:54 1995
+++ linux/drivers/block/hd.c	Mon Jun 26 11:32:57 1995
@@ -375,9 +375,9 @@
 	int	i;
 
 	outb_p(4,HD_CMD);
-	for(i = 0; i < 1000; i++) nop();
+	for(i = 0; i < 1000; i++) barrier();
 	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
-	for(i = 0; i < 1000; i++) nop();
+	for(i = 0; i < 1000; i++) barrier();
 	if (drive_busy())
 		printk("hd: controller still busy\n");
 	else if ((hd_error = inb(HD_ERROR)) != 1)
@@ -794,13 +794,13 @@
 			err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
 			if (err)
 				return err;
-			put_fs_byte(bios_info[dev].head,
+			put_user(bios_info[dev].head,
 				(char *) &loc->heads);
-			put_fs_byte(bios_info[dev].sect,
+			put_user(bios_info[dev].sect,
 				(char *) &loc->sectors);
-			put_fs_word(bios_info[dev].cyl,
+			put_user(bios_info[dev].cyl,
 				(short *) &loc->cylinders);
-			put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
+			put_user(hd[MINOR(inode->i_rdev)].start_sect,
 				(long *) &loc->start);
 			return 0;
 		case BLKRASET:
@@ -813,14 +813,14 @@
 			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 			if (err)
 				return err;
-			put_fs_long(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
+			put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
 			return 0;
          	case BLKGETSIZE:   /* Return device size */
 			if (!arg)  return -EINVAL;
 			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 			if (err)
 				return err;
-			put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
+			put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
 			return 0;
 		case BLKFLSBUF:
 			if(!suser())  return -EACCES;
@@ -843,7 +843,7 @@
 			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 			if (err)
 				return err;
-			put_fs_long(unmask_intr[dev], (long *) arg);
+			put_user(unmask_intr[dev], (long *) arg);
 			return 0;
 
                 case HDIO_GET_MULTCOUNT:
@@ -851,7 +851,7 @@
 			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 			if (err)
 				return err;
-			put_fs_long(mult_count[dev], (long *) arg);
+			put_user(mult_count[dev], (long *) arg);
 			return 0;
 
 		case HDIO_SET_MULTCOUNT:
@@ -954,12 +954,14 @@
  */
 static void hd_geninit(void)
 {
-	int drive, i;
-	extern struct drive_info drive_info;
-	unsigned char *BIOS = (unsigned char *) &drive_info;
-	int cmos_disks;
+	int i;
+
+#ifdef __i386__
+	if (!NR_HD) {
+		extern struct drive_info drive_info;
+		unsigned char *BIOS = (unsigned char *) &drive_info;
+		int cmos_disks, drive;
 
-	if (!NR_HD) {	   
 		for (drive=0 ; drive<2 ; drive++) {
 			bios_info[drive].cyl   = hd_info[drive].cyl = *(unsigned short *) BIOS;
 			bios_info[drive].head  = hd_info[drive].head = *(2+BIOS);
@@ -1002,6 +1004,7 @@
 			else
 				NR_HD = 1;
 	}
+#endif /* __i386__ */
 	i = NR_HD;
 	while (i-- > 0) {
 		/*
diff -u --recursive --new-file v1.3.3/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.3/linux/drivers/block/ide.c	Thu Jun  1 11:23:04 1995
+++ linux/drivers/block/ide.c	Mon Jun 26 11:32:57 1995
@@ -155,6 +155,12 @@
 #define REALLY_SLOW_IO			/* most systems can safely undef this */
 #include <asm/io.h>
 
+#ifdef __alpha__
+# ifndef SUPPORT_VLB_SYNC
+#  define SUPPORT_VLB_SYNC	0
+# endif
+#endif
+
 #undef	REALLY_FAST_IO			/* define if ide ports are perfect */
 #define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
 #ifndef SUPPORT_VLB_32BIT		/* 1 to support 32bit I/O on VLB */
@@ -286,11 +292,11 @@
 /*
  * Timeouts for various operations:
  */
-#define WAIT_DRQ	5	/* 50msec - spec allows up to 20ms */
-#define WAIT_READY	3	/* 30msec - should be instantaneous */
-#define WAIT_PIDENTIFY	100	/* 1sec   - should be less than 3ms (?) */
-#define WAIT_WORSTCASE	3000	/* 30sec  - worst case when spinning up */
-#define WAIT_CMD	1000	/* 10sec  - maximum wait for an IRQ to happen */
+#define WAIT_DRQ	(5*HZ/100)	/* 50msec - spec allows up to 20ms */
+#define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
+#define WAIT_PIDENTIFY	(1*HZ)	/* 1sec   - should be less than 3ms (?) */
+#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
+#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 
 /*
  * Now for the data we need to maintain per-device:  ide_dev_t
@@ -409,7 +415,7 @@
 #include "blk.h"
 
 /*
- * For really screwy hardware (hey, at least it *can* be used with Linux!
+ * For really screwy hardware (hey, at least it *can* be used with Linux!)
  */
 #if (DISK_RECOVERY_TIME > 0)
 static unsigned long	ide_lastreq[] = {0,0}; /* completion time of last I/O */
@@ -1505,7 +1511,7 @@
 		return -EINVAL;
 	if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
 		return err;
-	put_fs_long((unsigned)value, (long *) useraddr);
+	put_user((unsigned)value, (long *) useraddr);
 	return 0;
 }
 
@@ -1526,13 +1532,13 @@
 			if (!loc || dev->type != disk) return -EINVAL;
 			err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
 			if (err) return err;
-			put_fs_byte(dev->bios_head,
+			put_user(dev->bios_head,
 				(char *) &loc->heads);
-			put_fs_byte(dev->bios_sect,
+			put_user(dev->bios_sect,
 				(char *) &loc->sectors);
-			put_fs_word(dev->bios_cyl,
+			put_user(dev->bios_cyl,
 				(short *) &loc->cylinders);
-			put_fs_long((unsigned)ide_hd[DEV_HWIF][MINOR(inode->i_rdev)].start_sect,
+			put_user((unsigned)ide_hd[DEV_HWIF][MINOR(inode->i_rdev)].start_sect,
 				(long *) &loc->start);
 			return 0;
 
@@ -1636,9 +1642,9 @@
 			else {
 				if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long))))
 				{
-					args = get_fs_long((long *)arg);
+					args = get_user((long *)arg);
 					err = do_drive_cmd(inode->i_rdev,(char *)&args);
-					put_fs_long(args,(long *)arg);
+					put_user(args,(long *)arg);
 				}
 			}
 			return err;
@@ -1808,8 +1814,11 @@
 
 		/* check for word-swapped "capacity" field in id information */
 		check = (id->cur_capacity0 << 16) | id->cur_capacity1;
-		if (check == capacity)		/* was it swapped? */
-			*((int *)&id->cur_capacity0) = capacity; /* fix it */
+		if (check == capacity) {	/* was it swapped? */
+			/* yes, bring it into little-endian order: */
+			id->cur_capacity0 = (capacity >>  0) & 0xffff;
+			id->cur_capacity1 = (capacity >> 16) & 0xffff;
+		}
 	}
 	/* Use physical geometry if what we have still makes no sense */
 	if ((!dev->head || dev->head > 16) && id->heads && id->heads <= 16) {
@@ -1848,9 +1857,13 @@
 	printk("\n");
 }
 
+/*
+ * Delay for *at least* 10ms.  As we don't know how much time is left
+ * until the next tick occurs, we wait an extra tick to be safe.
+ */
 static void delay_10ms (void)
 {
-	unsigned long timer = jiffies + 2;
+	unsigned long timer = jiffies + (HZ + 99)/100 + 1;
 	while (timer > jiffies);
 }
 
@@ -1872,6 +1885,7 @@
 	OUT_BYTE(dev->ctl|2,HD_CMD);		/* disable device irq */
 #if PROBE_FOR_IRQS
 	if (!irq_probed[DEV_HWIF]) {		/* already probed for IRQ? */
+		probe_irq_off(probe_irq_on());	/* clear dangling irqs */
 		irqs = probe_irq_on();		/* start monitoring irqs */
 		OUT_BYTE(dev->ctl,HD_CMD);	/* enable device irq */
 	}
@@ -2167,9 +2181,10 @@
  * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value 
  * means we have an AT controller hard disk for that drive.
  */
-extern struct drive_info_struct drive_info;
 static void probe_cmos_for_drives (void)
 {
+#ifdef __i386__
+	extern struct drive_info_struct drive_info;
 	byte drive, cmos_disks, *BIOS = (byte *) &drive_info;
 
 	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
@@ -2190,6 +2205,7 @@
 		}
 		BIOS += 16;
 	}
+#endif
 }
 #endif	/* CONFIG_BLK_DEV_HD */
 
@@ -2378,7 +2394,7 @@
 				continue;
 #else
 				probe_cmos_for_drives ();
-#endif /* CONFIG_BLJ_DEV_HD */
+#endif /* CONFIG_BLK_DEV_HD */
 			probe_mem_start = (mem_start + 3uL) & ~3uL;
 			probe_for_drives (hwif);
 			mem_start = probe_mem_start;
diff -u --recursive --new-file v1.3.3/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.3/linux/drivers/block/ll_rw_blk.c	Fri Jun  2 15:24:46 1995
+++ linux/drivers/block/ll_rw_blk.c	Tue Jun 20 11:24:22 1995
@@ -520,9 +520,9 @@
 
 void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
 {
-	int i;
+	int i, j;
 	int buffersize;
-	struct request * req;
+	struct request * req[8];
 	unsigned int major = MAJOR(dev);
 	struct semaphore sem = MUTEX_LOCKED;
 
@@ -542,20 +542,34 @@
 	
 	buffersize = PAGE_SIZE / nb;
 
-	for (i=0; i<nb; i++, buf += buffersize)
+	for (j=0, i=0; i<nb;)
 	{
-		req = get_request_wait(NR_REQUEST, dev);
-		req->cmd = rw;
-		req->errors = 0;
-		req->sector = (b[i] * buffersize) >> 9;
-		req->nr_sectors = buffersize >> 9;
-		req->current_nr_sectors = buffersize >> 9;
-		req->buffer = buf;
-		req->sem = &sem;
-		req->bh = NULL;
-		req->next = NULL;
-		add_request(major+blk_dev,req);
-		down(&sem);
+		for (; j < 8 && i < nb; j++, i++, buf += buffersize)
+		{
+			if (j == 0) {
+				req[j] = get_request_wait(NR_REQUEST, dev);
+			} else {
+				cli();
+				req[j] = get_request(NR_REQUEST, dev);
+				sti();
+				if (req[j] == NULL)
+					break;
+			}
+			req[j]->cmd = rw;
+			req[j]->errors = 0;
+			req[j]->sector = (b[i] * buffersize) >> 9;
+			req[j]->nr_sectors = buffersize >> 9;
+			req[j]->current_nr_sectors = buffersize >> 9;
+			req[j]->buffer = buf;
+			req[j]->sem = &sem;
+			req[j]->bh = NULL;
+			req[j]->next = NULL;
+			add_request(major+blk_dev,req[j]);
+		}
+		while (j > 0) {
+			j--;
+			down(&sem);
+		}
 	}
 }
 
diff -u --recursive --new-file v1.3.3/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v1.3.3/linux/drivers/block/xd.c	Mon Jan 23 23:04:09 1995
+++ linux/drivers/block/xd.c	Mon Jun 26 11:06:50 1995
@@ -246,10 +246,10 @@
 				if (arg) {
 					if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
 						return (err);
-					put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
-					put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
-					put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
-					put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
+					put_user(xd_info[dev].heads, &geometry->heads);
+					put_user(xd_info[dev].sectors, &geometry->sectors);
+					put_user(xd_info[dev].cylinders, &geometry->cylinders);
+					put_user(xd[MINOR(inode->i_rdev)].start_sect,&geometry->start);
 
 					return (0);
 				}
@@ -264,7 +264,7 @@
 				if (arg) {
 					if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
 						return (err);
-					put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+					put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
 
 					return (0);
 				}
@@ -398,7 +398,7 @@
 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
 {
 	if (buffer < ((u_char *) 0x1000000 - count)) {		/* transfer to address < 16M? */
-		if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
+		if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) {
 #ifdef DEBUG_OTHER
 			printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 #endif /* DEBUG_OTHER */
diff -u --recursive --new-file v1.3.3/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v1.3.3/linux/drivers/char/atixlmouse.c	Mon Jan 16 07:17:35 1995
+++ linux/drivers/char/atixlmouse.c	Mon Jun 26 11:06:50 1995
@@ -128,19 +128,19 @@
 		return -EAGAIN;
 	ATIXL_MSE_DISABLE_UPDATE();
 	/* Allowed interrupts to occur during data gathering - shouldn't hurt */
-	put_fs_byte((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
+	put_user((char)(~mouse.latch_buttons&7) | 0x80 , buffer);
 	if (mouse.dx < -127)
 		mouse.dx = -127;
 	if (mouse.dx > 127)
 		mouse.dx =  127;
-	put_fs_byte((char)mouse.dx, buffer + 1);
+	put_user((char)mouse.dx, buffer + 1);
 	if (mouse.dy < -127)
 		mouse.dy = -127;
 	if (mouse.dy > 127)
 		mouse.dy =  127;
-	put_fs_byte((char)-mouse.dy, buffer + 2);
+	put_user((char)-mouse.dy, buffer + 2);
 	for(i = 3; i < count; i++)
-		put_fs_byte(0x00, buffer + i);
+		put_user(0x00, buffer + i);
 	mouse.dx = 0;
 	mouse.dy = 0;
 	mouse.latch_buttons = mouse.buttons;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v1.3.3/linux/drivers/char/busmouse.c	Mon Jan 23 23:04:09 1995
+++ linux/drivers/char/busmouse.c	Mon Jun 26 11:06:50 1995
@@ -151,7 +151,7 @@
 	 * Obtain the current mouse parameters and limit as appropriate for
 	 * the return data format.  Interrupts are only disabled while 
 	 * obtaining the parameters, NOT during the puts_fs_byte() calls,
-	 * so paging in put_fs_byte() does not effect mouse tracking.
+	 * so paging in put_user() does not effect mouse tracking.
 	 */
 
 	MSE_INT_OFF();
@@ -171,11 +171,11 @@
 	mouse.ready = 0;
 	MSE_INT_ON();
 
-	put_fs_byte(buttons | 0x80, buffer);
-	put_fs_byte((char)dx, buffer + 1);
-	put_fs_byte((char)dy, buffer + 2);
+	put_user(buttons | 0x80, buffer);
+	put_user((char)dx, buffer + 1);
+	put_user((char)dy, buffer + 2);
 	for (r = 3; r < count; r++)
-	    put_fs_byte(0x00, buffer + r);
+	    put_user(0x00, buffer + r);
 	return r;
 }
 
diff -u --recursive --new-file v1.3.3/linux/drivers/char/console.c linux/drivers/char/console.c
--- v1.3.3/linux/drivers/char/console.c	Tue Jun 20 09:10:32 1995
+++ linux/drivers/char/console.c	Mon Jun 26 11:06:50 1995
@@ -2441,10 +2441,10 @@
 	    arg += cmapsz;
 	    if (set)
 	      for (i=0; i<cmapsz ; i++)
-		*(charmap+i) = get_fs_byte(arg+i);
+		*(charmap+i) = get_user(arg+i);
 	    else
 	      for (i=0; i<cmapsz ; i++)
-		put_fs_byte(*(charmap+i), arg+i);
+		put_user(*(charmap+i), arg+i);
 	  };
 
 	cli();
diff -u --recursive --new-file v1.3.3/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- v1.3.3/linux/drivers/char/consolemap.c	Tue Jun 13 15:40:16 1995
+++ linux/drivers/char/consolemap.c	Mon Jun 26 11:06:50 1995
@@ -221,7 +221,7 @@
 		return i;
 
 	for (i=0; i<E_TABSZ ; i++)
-		p[i] = UNI_DIRECT_BASE | get_fs_byte(arg+i);
+		p[i] = UNI_DIRECT_BASE | get_user(arg+i);
 
 	set_inverse_transl(USER_MAP);
 	return 0;
@@ -239,7 +239,7 @@
 	for (i=0; i<E_TABSZ ; i++)
 	  {
 	    ch = conv_uni_to_pc(p[i]);
-	    put_fs_byte((ch & ~0xff) ? 0 : ch, arg+i);
+	    put_user((ch & ~0xff) ? 0 : ch, arg+i);
 	  }
 	return 0;
 }
@@ -254,7 +254,7 @@
 		return i;
 
 	for (i=0; i<E_TABSZ ; i++)
-	  p[i] = get_fs_word(arg+i);
+	  p[i] = get_user(arg+i);
 
 	set_inverse_transl(USER_MAP);
 	return 0;
@@ -271,7 +271,7 @@
 		return i;
 
 	for (i=0; i<E_TABSZ ; i++)
-	  put_fs_word(p[i], arg+i);
+	  put_user(p[i], arg+i);
 	
 	return 0;
 }
@@ -331,7 +331,7 @@
 	if (!hashtable_contents_valid)
 	  con_clear_unimap(&hashdefaults);
 	while(ct) {
-	    u = get_fs_word(&list->unicode);
+	    u = get_user(&list->unicode);
 	    i = u % hashsize;
 	    lct = 1;
 	    while ((hu = hashtable[i].unicode) != 0xffff && hu != u) {
@@ -344,7 +344,7 @@
 	    if (lct > hashlevel)
 	      hashlevel = lct;
 	    hashtable[i].unicode = u;
-	    hashtable[i].fontpos = get_fs_word(&list->fontpos);
+	    hashtable[i].fontpos = get_user(&list->fontpos);
 	    list++;
 	    ct--;
 	}
@@ -364,12 +364,12 @@
 	  for (i = 0; i<hashsize; i++)
 	    if (hashtable[i].unicode != 0xffff) {
 		if (ect++ < ct) {
-		    put_fs_word(hashtable[i].unicode, &list->unicode);
-		    put_fs_word(hashtable[i].fontpos, &list->fontpos);
+		    put_user(hashtable[i].unicode, &list->unicode);
+		    put_user(hashtable[i].fontpos, &list->fontpos);
 		    list++;
 		}
 	    }
-	put_fs_word(ect, uct);
+	put_user(ect, uct);
 	return ((ect <= ct) ? 0 : -ENOMEM);
 }
 
diff -u --recursive --new-file v1.3.3/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v1.3.3/linux/drivers/char/cyclades.c	Fri Jun  2 13:46:26 1995
+++ linux/drivers/char/cyclades.c	Mon Jun 26 11:06:51 1995
@@ -1851,7 +1851,7 @@
             | ((status  & CyRI) ? TIOCM_RNG : 0)
             | ((status  & CyDSR) ? TIOCM_DSR : 0)
             | ((status  & CyCTS) ? TIOCM_CTS : 0);
-    put_fs_long(result,(unsigned long *) value);
+    put_user(result,value);
     return 0;
 } /* get_modem_info */
 
@@ -1862,7 +1862,7 @@
   int card,chip,channel;
   unsigned char *base_addr;
   unsigned long flags;
-  unsigned int arg = get_fs_long((unsigned long *) value);
+  unsigned int arg = get_user(value);
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
@@ -2175,8 +2175,8 @@
                 ret_val = error;
                 break;
             }
-            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
-                        (unsigned long *) arg);
+            put_user(C_CLOCAL(tty) ? 1 : 0,
+                        (unsigned int *) arg);
             break;
         case TIOCSSOFTCAR:
             arg = get_fs_long((unsigned long *) arg);
diff -u --recursive --new-file v1.3.3/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v1.3.3/linux/drivers/char/lp.c	Mon Jan 23 10:38:29 1995
+++ linux/drivers/char/lp.c	Mon Jun 26 11:06:51 1995
@@ -248,7 +248,7 @@
 
 	temp = buf;
 	while (count > 0) {
-		c = get_fs_byte(temp);
+		c = get_user(temp);
 		retval = lp_char_polled(c, minor);
 		/* only update counting vars if character was printed */
 		if (retval) { count--; temp++;
@@ -527,17 +527,25 @@
 	lp_release
 };
 
-#ifndef MODULE
+#ifdef MODULE
+char kernel_version[]=UTS_RELEASE;
 
+int init_module(void)
+#else
 long lp_init(long kmem_start)
+#endif
 {
 	int offset = 0;
 	unsigned int testvalue = 0;
 	int count = 0;
 
 	if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
-		printk("unable to get major %d for line printer\n", LP_MAJOR);
+		printk("lp: unable to get major %d\n", LP_MAJOR);
+#ifdef MODULE
+		return -EIO;
+#else		
 		return kmem_start;
+#endif
 	}
 	/* take on all known port values */
 	for (offset = 0; offset < LP_NO; offset++) {
@@ -554,65 +562,35 @@
 			printk("lp%d at 0x%04x, ", offset,LP_B(offset));
 			request_region(LP_B(offset), 3, "lp");
 			if (LP_IRQ(offset))
-				printk("using IRQ%d\n", LP_IRQ(offset));
+				printk("(irq = %d)\n", LP_IRQ(offset));
 			else
-				printk("using polling driver\n");
+				printk("(polling)\n");
 			count++;
 		}
 	}
 	if (count == 0)
-		printk("lp_init: no lp devices found\n");
-	return kmem_start;
-}
+		printk("lp: Driver configured but no interfaces found.\n");
 
-#else
 
-char kernel_version[]= UTS_RELEASE;
-
-int init_module(void)
-{
-	int offset = 0;
-	unsigned int testvalue = 0;
-	int count = 0;
-
-	if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
-		printk("unable to get major %d for line printer\n", LP_MAJOR);
-		return -EIO;
-	}
-	/* take on all known port values */
-	for (offset = 0; offset < LP_NO; offset++) {
-		/* write to port & read back to check */
-		outb_p( LP_DUMMY, LP_B(offset));
-		for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
-			;
-		testvalue = inb_p(LP_B(offset));
-		if (testvalue == LP_DUMMY) {
-			LP_F(offset) |= LP_EXIST;
-			lp_reset(offset);
-			printk("lp%d at 0x%04x, ", offset,LP_B(offset));
-			request_region(LP_B(offset),3,"lp");
-			if (LP_IRQ(offset))
-				printk("using IRQ%d\n", LP_IRQ(offset));
-			else
-				printk("using polling driver\n");
-			count++;
-		}
-	}
-	if (count == 0)
-		printk("lp_init: no lp devices found\n");
+#ifdef MODULE
 	return 0;
+#else	
+	return kmem_start;
+#endif
 }
 
+#ifdef MODULE
 void cleanup_module(void)
 {
         int offset;
 	if(MOD_IN_USE)
                printk("lp: busy - remove delayed\n");
-        else
+        else {
                unregister_chrdev(LP_MAJOR,"lp");
 	       for (offset = 0; offset < LP_NO; offset++) 
 			if(LP_F(offset) && LP_EXIST) 
 		 		release_region(LP_B(offset),3);
+	}
 }
 
 #endif
diff -u --recursive --new-file v1.3.3/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v1.3.3/linux/drivers/char/mem.c	Tue Mar  7 14:59:28 1995
+++ linux/drivers/char/mem.c	Mon Jun 26 11:06:51 1995
@@ -48,7 +48,7 @@
 		count = high_memory - p;
 	read = 0;
 	while (p < PAGE_SIZE && count > 0) {
-		put_fs_byte(0,buf);
+		put_user(0,buf);
 		buf++;
 		p++;
 		count--;
@@ -126,7 +126,7 @@
 	char * tmp = buf;
 
 	while (count-- > 0 && i < 65536) {
-		put_fs_byte(inb(i),tmp);
+		put_user(inb(i),tmp);
 		i++;
 		tmp++;
 	}
@@ -140,7 +140,7 @@
 	char * tmp = buf;
 
 	while (count-- > 0 && i < 65536) {
-		outb(get_fs_byte(tmp),i);
+		outb(get_user(tmp),i);
 		i++;
 		tmp++;
 	}
@@ -163,7 +163,7 @@
 	int left;
 
 	for (left = count; left > 0; left--) {
-		put_fs_byte(0,buf);
+		put_user(0,buf);
 		buf++;
 	}
 	return count;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v1.3.3/linux/drivers/char/msbusmouse.c	Mon Jan 16 07:17:35 1995
+++ linux/drivers/char/msbusmouse.c	Mon Jun 26 11:06:51 1995
@@ -109,13 +109,13 @@
 		return -EINVAL;
 	if (!mouse.ready)
 		return -EAGAIN;
-	put_fs_byte(mouse.buttons | 0x80, buffer);
+	put_user(mouse.buttons | 0x80, buffer);
 	dx = mouse.dx < -127 ? -127 : mouse.dx > 127 ?  127 :  mouse.dx;
 	dy = mouse.dy < -127 ?  127 : mouse.dy > 127 ? -127 : -mouse.dy;
-	put_fs_byte((char)dx, buffer + 1);
-	put_fs_byte((char)dy, buffer + 2);
+	put_user((char)dx, buffer + 1);
+	put_user((char)dy, buffer + 2);
 	for (i = 3; i < count; i++)
-		put_fs_byte(0x00, buffer + i);
+		put_user(0x00, buffer + i);
 	mouse.dx -= dx;
 	mouse.dy += dy;
 	mouse.ready = 0;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.3.3/linux/drivers/char/n_tty.c	Sat Jun 10 19:13:12 1995
+++ linux/drivers/char/n_tty.c	Mon Jun 26 11:06:51 1995
@@ -803,7 +803,7 @@
 		if (tty->packet && tty->link->ctrl_status) {
 			if (b != buf)
 				break;
-			put_fs_byte(tty->link->ctrl_status, b++);
+			put_user(tty->link->ctrl_status, b++);
 			tty->link->ctrl_status = 0;
 			break;
 		}
@@ -840,7 +840,7 @@
 
 		/* Deal with packet mode. */
 		if (tty->packet && b == buf) {
-			put_fs_byte(TIOCPKT_DATA, b++);
+			put_user(TIOCPKT_DATA, b++);
 			nr--;
 		}
 
@@ -861,7 +861,7 @@
 				tty->read_cnt--;
 				enable_bh(TQUEUE_BH);
 				if (!eol) {
-					put_fs_byte(c, b++);
+					put_user(c, b++);
 					if (--nr)
 						continue;
 					break;
@@ -870,7 +870,7 @@
 					tty->canon_data = 0;
 				}
 				if (c != __DISABLED_CHAR) {
-					put_fs_byte(c, b++);
+					put_user(c, b++);
 					nr--;
 				}
 				break;
@@ -939,7 +939,7 @@
 		}
 		if (O_OPOST(tty)) {
 			while (nr > 0) {
-				c = get_fs_byte(b);
+				c = get_user(b);
 				if (opost(c, tty) < 0)
 					break;
 				b++; nr--;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v1.3.3/linux/drivers/char/psaux.c	Mon Jan 16 07:17:35 1995
+++ linux/drivers/char/psaux.c	Mon Jun 26 11:06:51 1995
@@ -140,7 +140,7 @@
 	while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL
 	            && retries < MAX_RETRIES) {          /* wait for ack */
        		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 5;
+		current->timeout = jiffies + (5*HZ + 99) / 100;
 		schedule();
 		retries++;
         }
@@ -232,7 +232,9 @@
 
 static void release_aux(struct inode * inode, struct file * file)
 {
+#ifndef __alpha__
 	aux_write_dev(AUX_DISABLE_DEV);		/* disable aux device */
+#endif
 	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */
 	poll_aux_status();
 	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
@@ -342,7 +344,7 @@
 		outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
 		if (!poll_aux_status())
 			return -EIO;
-		outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
+		outb_p(get_user(buffer++),AUX_OUTPUT_PORT);
 	}
 	inode->i_mtime = CURRENT_TIME;
 	return count;
@@ -361,7 +363,7 @@
 	while (i--) {
 		if (!poll_qp_status())
 			return -EIO;
-		outb_p(get_fs_byte(buffer++), qp_data);
+		outb_p(get_user(buffer++), qp_data);
 	}
 	inode->i_mtime = CURRENT_TIME;
 	return count;
@@ -394,7 +396,7 @@
 	}		
 	while (i > 0 && !queue_empty()) {
 		c = get_from_queue();
-		put_fs_byte(c, buffer++);
+		put_user(c, buffer++);
 		i--;
 	}
 	aux_ready = !queue_empty();
@@ -489,7 +491,7 @@
  		if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)
 			inb_p(AUX_INPUT_PORT);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 5;
+		current->timeout = jiffies + (5*HZ + 99) / 100;
 		schedule();
 		retries++;
 	}
@@ -512,7 +514,7 @@
 	        if (inb_p(qp_status)&(QP_RX_FULL))
 		        inb_p(qp_data);
 		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + 5;
+		current->timeout = jiffies + (5*HZ + 99) / 100;
 		schedule();
 		retries++;
 	}
diff -u --recursive --new-file v1.3.3/linux/drivers/char/scc.c linux/drivers/char/scc.c
--- v1.3.3/linux/drivers/char/scc.c	Tue Jun  6 11:22:06 1995
+++ linux/drivers/char/scc.c	Mon Jun 26 11:06:51 1995
@@ -1018,7 +1018,7 @@
 		if (scc2 == scc || !(scc2->tty && grp2)) 
 			return 0;
 		
-		if (grp1 & 0x3f == grp2 & 0x3f)
+		if ((grp1 & 0x3f) == (grp2 & 0x3f))
 		{
 			if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
 				return 1;
@@ -1821,7 +1821,7 @@
 		
 		restore_flags(flags);
 			
-		put_fs_long(result,(unsigned long *) arg);
+		put_user(result,(unsigned int *) arg);
 		return 0;
 	case TIOCMBIS:
 	case TIOCMBIC:
@@ -1836,7 +1836,7 @@
 			scc->wreg[R5] &= ~RTS;
 			break;
 		case TIOCMSET:
-			value = get_fs_long((unsigned long *) arg);
+			value = get_user((unsigned int *) arg);
 			
 			if(value & TIOCM_DTR)
 				scc->wreg[R5] |= DTR;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v1.3.3/linux/drivers/char/selection.c	Wed Feb 22 12:27:52 1995
+++ linux/drivers/char/selection.c	Mon Jun 26 11:06:51 1995
@@ -121,11 +121,11 @@
 	{ unsigned short *args, xs, ys, xe, ye;
 
 	  args = (unsigned short *)(arg + 1);
-	  xs = get_fs_word(args++) - 1;
-	  ys = get_fs_word(args++) - 1;
-	  xe = get_fs_word(args++) - 1;
-	  ye = get_fs_word(args++) - 1;
-	  sel_mode = get_fs_word(args);
+	  xs = get_user(args++) - 1;
+	  ys = get_user(args++) - 1;
+	  xe = get_user(args++) - 1;
+	  ye = get_user(args++) - 1;
+	  sel_mode = get_user(args);
 
 	  xs = limit(xs, video_num_columns - 1);
 	  ys = limit(ys, video_num_lines - 1);
diff -u --recursive --new-file v1.3.3/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.3.3/linux/drivers/char/serial.c	Sat Jun 10 19:13:12 1995
+++ linux/drivers/char/serial.c	Mon Jun 26 11:06:51 1995
@@ -1571,7 +1571,7 @@
 	status = serial_in(info, UART_LSR);
 	sti();
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	put_fs_long(result,(unsigned long *) value);
+	put_user(result,value);
 	return 0;
 }
 
@@ -1591,7 +1591,7 @@
 		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
 		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
 		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	put_fs_long(result,(unsigned long *) value);
+	put_user(result,value);
 	return 0;
 }
 
@@ -1604,7 +1604,7 @@
 	error = verify_area(VERIFY_READ, value, sizeof(int));
 	if (error)
 		return error;
-	arg = get_fs_long((unsigned long *) value);
+	arg = get_user(value);
 	switch (cmd) {
 	case TIOCMBIS: 
 		if (arg & TIOCM_RTS) {
diff -u --recursive --new-file v1.3.3/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.3/linux/drivers/char/tty_io.c	Tue Jun 20 09:10:32 1995
+++ linux/drivers/char/tty_io.c	Mon Jun 26 11:06:51 1995
@@ -1289,11 +1289,11 @@
 			c = (char *)(*p);
 			d = (char *)(ts->tasks+n);
 			for (i=0 ; i<sizeof(struct task_struct) ; i++)
-				put_fs_byte(*c++, d++);
-			put_fs_long(1, (unsigned long *)(ts->present+n));
+				put_user(*c++, d++);
+			put_user(1, ts->present+n);
 		}
 		else	
-			put_fs_long(0, (unsigned long *)(ts->present+n));
+			put_user(0, ts->present+n);
 	return(0);			
 }
 #endif
@@ -1326,7 +1326,7 @@
 			retval = verify_area(VERIFY_READ, (void *) arg, 1);
 			if (retval)
 				return retval;
-			ch = get_fs_byte((char *) arg);
+			ch = get_user((char *) arg);
 			tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
 			return 0;
 		case TIOCGWINSZ:
@@ -1367,10 +1367,10 @@
 			redirect = real_tty;
 			return 0;
 		case FIONBIO:
-			retval = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
+			retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int));
 			if (retval)
 				return retval;
-			arg = get_fs_long((unsigned long *) arg);
+			arg = get_user((unsigned int *) arg);
 			if (arg)
 				file->f_flags |= O_NONBLOCK;
 			else
@@ -1432,7 +1432,7 @@
 					     sizeof (pid_t));
 			if (retval)
 				return retval;
-			put_fs_long(real_tty->pgrp, (pid_t *) arg);
+			put_user(real_tty->pgrp, (pid_t *) arg);
 			return 0;
 		case TIOCSPGRP:
 			retval = tty_check_change(real_tty);
@@ -1442,7 +1442,7 @@
 			    (current->tty != real_tty) ||
 			    (real_tty->session != current->session))
 				return -ENOTTY;
-			pgrp = get_fs_long((pid_t *) arg);
+			pgrp = get_user((pid_t *) arg);
 			if (pgrp < 0)
 				return -EINVAL;
 			if (session_of_pgrp(pgrp) != current->session)
@@ -1451,16 +1451,16 @@
 			return 0;
 		case TIOCGETD:
 			retval = verify_area(VERIFY_WRITE, (void *) arg,
-					     sizeof (unsigned long));
+					     sizeof (int));
 			if (retval)
 				return retval;
-			put_fs_long(tty->ldisc.num, (unsigned long *) arg);
+			put_user(tty->ldisc.num, (int *) arg);
 			return 0;
 		case TIOCSETD:
 			retval = tty_check_change(tty);
 			if (retval)
 				return retval;
-			arg = get_fs_long((unsigned long *) arg);
+			arg = get_user((int *) arg);
 			return tty_set_ldisc(tty, arg);
 		case TIOCLINUX:
 			if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
@@ -1470,7 +1470,7 @@
 			retval = verify_area(VERIFY_READ, (void *) arg, 1);
 			if (retval)
 				return retval;
-			switch (retval = get_fs_byte((char *)arg))
+			switch (retval = get_user((char *)arg))
 			{
 				case 0:
 				case 8:
@@ -1498,10 +1498,10 @@
 			 * kernel-internal variable; programs not closely
 			 * related to the kernel should not use this.
 			 */
-					put_fs_byte(shift_state,arg);
+					put_user(shift_state,(char *) arg);
 					return 0;
 				case 7:
-					put_fs_byte(mouse_reporting(),arg);
+					put_user(mouse_reporting(),(char *) arg);
 					return 0;
 				case 10:
 					set_vesa_blanking(arg);
diff -u --recursive --new-file v1.3.3/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- v1.3.3/linux/drivers/char/tty_ioctl.c	Wed Feb  8 12:25:17 1995
+++ linux/drivers/char/tty_ioctl.c	Mon Jun 26 11:06:51 1995
@@ -300,14 +300,14 @@
 			return 0;
 		case TIOCOUTQ:
 			retval = verify_area(VERIFY_WRITE, (void *) arg,
-					     sizeof (unsigned long));
+					     sizeof (int));
 			if (retval)
 				return retval;
 			if (tty->driver.chars_in_buffer)
-				put_fs_long(tty->driver.chars_in_buffer(tty),
-					    (unsigned long *) arg);
+				put_user(tty->driver.chars_in_buffer(tty),
+					 (int *) arg);
 			else
-				put_fs_long(0, (unsigned long *) arg);
+				put_user(0, (int *) arg);
 			return 0;
 		case TIOCINQ:
 			retval = verify_area(VERIFY_WRITE, (void *) arg,
@@ -346,10 +346,10 @@
 			    tty->driver.subtype != PTY_TYPE_MASTER)
 				return -ENOTTY;
 			retval = verify_area(VERIFY_READ, (void *) arg,
-					     sizeof (unsigned long));
+					     sizeof (int));
 			if (retval)
 				return retval;
-			if (get_fs_long(arg)) {
+			if (get_user((int*)arg)) {
 				if (!tty->packet) {
 					tty->packet = 1;
 					tty->link->ctrl_status = 0;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v1.3.3/linux/drivers/char/vc_screen.c	Sun Apr  2 10:21:20 1995
+++ linux/drivers/char/vc_screen.c	Mon Jun 26 11:06:51 1995
@@ -90,7 +90,7 @@
 	if (!attr) {
 		org = screen_pos(cons, p, viewed);
 		while (count-- > 0)
-			put_fs_byte(scr_readw(org++) & 0xff, buf++);
+			put_user(scr_readw(org++) & 0xff, buf++);
 	} else {
 		if (p < HEADER_SIZE) {
 			char header[HEADER_SIZE];
@@ -98,19 +98,19 @@
 			header[1] = (char) video_num_columns;
 			getconsxy(cons, header+2);
 			while (p < HEADER_SIZE && count-- > 0)
-			    put_fs_byte(header[p++], buf++);
+			    put_user(header[p++], buf++);
 		}
 		p -= HEADER_SIZE;
 		org = screen_pos(cons, p/2, viewed);
 		if ((p & 1) && count-- > 0)
-			put_fs_byte(scr_readw(org++) >> 8, buf++);
+			put_user(scr_readw(org++) >> 8, buf++);
 		while (count > 1) {
-			put_fs_word(scr_readw(org++), buf);
+			put_user(scr_readw(org++), (unsigned short *) buf);
 			buf += 2;
 			count -= 2;
 		}
 		if (count > 0)
-			put_fs_byte(scr_readw(org) & 0xff, buf++);
+			put_user(scr_readw(org) & 0xff, buf++);
 	}
 	read = buf - buf0;
 	file->f_pos += read;
@@ -149,7 +149,7 @@
 		org = screen_pos(cons, p, viewed);
 		while (count-- > 0) {
 			scr_writew((scr_readw(org) & 0xff00) |
-				get_fs_byte(buf++), org);
+				   get_user(buf++), org);
 			org++;
 		}
 	} else {
@@ -157,25 +157,25 @@
 			char header[HEADER_SIZE];
 			getconsxy(cons, header+2);
 			while (p < HEADER_SIZE && count-- > 0)
-				header[p++] = get_fs_byte(buf++);
+				header[p++] = get_user(buf++);
 			if (!viewed)
 				putconsxy(cons, header+2);
 		}
 		p -= HEADER_SIZE;
 		org = screen_pos(cons, p/2, viewed);
 		if ((p & 1) && count-- > 0) {
-			scr_writew((get_fs_byte(buf++) << 8) |
+			scr_writew((get_user(buf++) << 8) |
 				   (scr_readw(org) & 0xff), org);
 			org++;
 		}
 		while (count > 1) {
-			scr_writew(get_fs_word(buf), org++);
+			scr_writew(get_user((unsigned short *) buf), org++);
 			buf += 2;
 			count -= 2;
 		}
 		if (count > 0)
 			scr_writew((scr_readw(org) & 0xff00) |
-				   get_fs_byte(buf++), org);
+				   get_user(buf++), org);
 	}
 	written = buf - buf0;
 	file->f_pos += written;
diff -u --recursive --new-file v1.3.3/linux/drivers/char/vesa_blank.c linux/drivers/char/vesa_blank.c
--- v1.3.3/linux/drivers/char/vesa_blank.c	Mon Jan  9 08:17:07 1995
+++ linux/drivers/char/vesa_blank.c	Mon Jun 26 11:20:04 1995
@@ -240,7 +240,7 @@
 
 void set_vesa_blanking(const unsigned long arg)
 {
-	char *argp = (char *)(arg + 1);
-	unsigned int mode = get_fs_byte(argp);
+	unsigned char *argp = (unsigned char *)(arg + 1);
+	unsigned int mode = get_user(argp);
 	vesa_blanking_mode = ((mode < 3) ? mode : 0);
 }
diff -u --recursive --new-file v1.3.3/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v1.3.3/linux/drivers/char/vt.c	Tue Jun 20 09:10:32 1995
+++ linux/drivers/char/vt.c	Mon Jun 26 11:06:51 1995
@@ -234,7 +234,7 @@
 		 */
 		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
 		if (!i)
-			put_fs_byte(KB_101, (char *) arg);
+			put_user(KB_101, (char *) arg);
 		return i;
 
 	case KDADDIO:
@@ -286,9 +286,9 @@
 		return 0;
 
 	case KDGETMODE:
-		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
 		if (!i)
-			put_fs_long(vt_cons[console]->vc_mode, (unsigned long *) arg);
+			put_user(vt_cons[console]->vc_mode, (int *) arg);
 		return i;
 
 	case KDMAPDISP:
@@ -325,13 +325,13 @@
 		return 0;
 
 	case KDGKBMODE:
-		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
 		if (!i) {
 			ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
 				 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
 				 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
 				 K_XLATE);
-			put_fs_long(ucval, (unsigned long *) arg);
+			put_user(ucval, (int *) arg);
 		}
 		return i;
 
@@ -351,11 +351,11 @@
 		return 0;
 
 	case KDGKBMETA:
-		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
 		if (!i) {
 			ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX :
 				 K_METABIT);
-			put_fs_long(ucval, (unsigned long *) arg);
+			put_user(ucval, (int *) arg);
 		}
 		return i;
 
@@ -368,11 +368,11 @@
 		i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbkeycode));
 		if (i)
 			return i;
-		sc = get_fs_long((int *) &a->scancode);
+		sc = get_user(&a->scancode);
 		kc = getkeycode(sc);
 		if (kc < 0)
 			return kc;
-		put_fs_long(kc, (int *) &a->keycode);
+		put_user(kc, &a->keycode);
 		return 0;
 	}
 
@@ -386,8 +386,8 @@
 		i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbkeycode));
 		if (i)
 			return i;
-		sc = get_fs_long((int *) &a->scancode);
-		kc = get_fs_long((int *) &a->keycode);
+		sc = get_user(&a->scancode);
+		kc = get_user(&a->keycode);
 		return setkeycode(sc, kc);
 	}
 
@@ -400,9 +400,9 @@
 		i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
 		if (i)
 			return i;
-		if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
+		if ((i = get_user(&a->kb_index)) >= NR_KEYS)
 			return -EINVAL;
-		if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
+		if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
 			return -EINVAL;
 		key_map = key_maps[s];
 		if (key_map) {
@@ -411,7 +411,7 @@
 			val = K_HOLE;
 		} else
 		    val = (i ? K_HOLE : K_NOSUCHMAP);
-		put_fs_word(val, (short *) &a->kb_value);
+		put_user(val, &a->kb_value);
 		return 0;
 	}
 
@@ -427,11 +427,11 @@
 		i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
 		if (i)
 			return i;
-		if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
+		if ((i = get_user(&a->kb_index)) >= NR_KEYS)
 			return -EINVAL;
-		if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
+		if ((s = get_user(&a->kb_table)) >= MAX_NR_KEYMAPS)
 			return -EINVAL;
-		v = get_fs_word(&a->kb_value);
+		v = get_user(&a->kb_value);
 		if (!i && v == K_NOSUCHMAP) {
 			/* disallocate map */
 			key_map = key_maps[s];
@@ -497,7 +497,7 @@
 		i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
 		if (i)
 			return i;
-		if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
+		if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
 			return -EINVAL;
 		sz = sizeof(a->kb_string) - 1; /* sz should have been
 						  a struct member */
@@ -505,8 +505,8 @@
 		p = func_table[i];
 		if(p)
 			for ( ; *p && sz; p++, sz--)
-				put_fs_byte(*p, q++);
-		put_fs_byte(0, q);
+				put_user(*p, q++);
+		put_user('\0', q);
 		return ((p && *p) ? -EOVERFLOW : 0);
 	}
 
@@ -524,7 +524,7 @@
 		i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
 		if (i)
 			return i;
-		if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC)
+		if ((i = get_user(&a->kb_func)) >= MAX_NR_FUNC)
 			return -EINVAL;
 		q = func_table[i];
 
@@ -538,7 +538,7 @@
 		delta = (q ? -strlen(q) : 1);
 		sz = sizeof(a->kb_string); 	/* sz should have been
 						   a struct member */
-		for (p = a->kb_string; get_fs_byte(p) && sz; p++,sz--)
+		for (p = a->kb_string; get_user(p) && sz; p++,sz--)
 			delta++;
 		if (!sz)
 			return -EOVERFLOW;
@@ -581,7 +581,7 @@
 		    funcbufsize = sz;
 		}
 		for (p = a->kb_string, q = func_table[i]; ; p++, q++)
-			if (!(*q = get_fs_byte(p)))
+			if (!(*q = get_user(p)))
 				break;
 		return 0;
 	}
@@ -593,7 +593,7 @@
 		i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
 		if (i)
 			return i;
-		put_fs_long(accent_table_size, &a->kb_cnt);
+		put_user(accent_table_size, &a->kb_cnt);
 		memcpy_tofs(a->kbdiacr, accent_table,
 			    accent_table_size*sizeof(struct kbdiacr));
 		return 0;
@@ -609,7 +609,7 @@
 		i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
 		if (i)
 			return i;
-		ct = get_fs_long(&a->kb_cnt);
+		ct = get_user(&a->kb_cnt);
 		if (ct >= MAX_DIACR)
 			return -EINVAL;
 		accent_table_size = ct;
@@ -623,8 +623,8 @@
 		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
 		if (i)
 			return i;
-		put_fs_byte(kbd->ledflagstate |
-			    (kbd->default_ledflagstate << 4), (char *) arg);
+		put_user(kbd->ledflagstate |
+			 (kbd->default_ledflagstate << 4), (char *) arg);
 		return 0;
 
 	case KDSKBLED:
@@ -643,7 +643,7 @@
 		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
 		if (i)
 			return i;
-		put_fs_byte(getledstate(), (char *) arg);
+		put_user(getledstate(), (char *) arg);
 		return 0;
 
 	case KDSETLED:
@@ -684,13 +684,13 @@
 		i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
 		if (i)
 			return i;
-		mode = get_fs_byte(&vtmode->mode);
+		mode = get_user(&vtmode->mode);
 		if (mode != VT_AUTO && mode != VT_PROCESS)
 			return -EINVAL;
 		vt_cons[console]->vt_mode.mode = mode;
-		vt_cons[console]->vt_mode.waitv = get_fs_byte(&vtmode->waitv);
-		vt_cons[console]->vt_mode.relsig = get_fs_word(&vtmode->relsig);
-		vt_cons[console]->vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
+		vt_cons[console]->vt_mode.waitv = get_user(&vtmode->waitv);
+		vt_cons[console]->vt_mode.relsig = get_user(&vtmode->relsig);
+		vt_cons[console]->vt_mode.acqsig = get_user(&vtmode->acqsig);
 		/* the frsig is ignored, so we set it to 0 */
 		vt_cons[console]->vt_mode.frsig = 0;
 		vt_cons[console]->vt_pid = current->pid;
@@ -705,11 +705,11 @@
 		i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode));
 		if (i)
 			return i;
-		put_fs_byte(vt_cons[console]->vt_mode.mode, &vtmode->mode);
-		put_fs_byte(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
-		put_fs_word(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
-		put_fs_word(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
-		put_fs_word(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
+		put_user(vt_cons[console]->vt_mode.mode, &vtmode->mode);
+		put_user(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
+		put_user(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
+		put_user(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
+		put_user(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
 		return 0;
 	}
 
@@ -726,12 +726,12 @@
 		i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
 		if (i)
 			return i;
-		put_fs_word(fg_console + 1, &vtstat->v_active);
+		put_user(fg_console + 1, &vtstat->v_active);
 		state = 1;	/* /dev/tty0 is always open */
 		for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
 			if (VT_IS_IN_USE(i))
 				state |= mask;
-		put_fs_word(state, &vtstat->v_state);
+		put_user(state, &vtstat->v_state);
 		return 0;
 	}
 
@@ -739,14 +739,13 @@
 	 * Returns the first available (non-opened) console.
 	 */
 	case VT_OPENQRY:
-		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
 		if (i)
 			return i;
 		for (i = 0; i < MAX_NR_CONSOLES; ++i)
 			if (! VT_IS_IN_USE(i))
 				break;
-		put_fs_long(i < MAX_NR_CONSOLES ? (i+1) : -1,
-			    (unsigned long *)arg);
+		put_user(i < MAX_NR_CONSOLES ? (i+1) : -1, (int *) arg);
 		return 0;
 
 	/*
@@ -869,8 +868,8 @@
 		i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
 		if (i)
 			return i;
-		ll = get_fs_word(&vtsizes->v_rows);
-		cc = get_fs_word(&vtsizes->v_cols);
+		ll = get_user(&vtsizes->v_rows);
+		cc = get_user(&vtsizes->v_cols);
 		i = vc_resize(ll, cc);
 		return i ? i : 	kd_size_changed(ll, cc);
 	}
@@ -884,12 +883,12 @@
 		i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
 		if (i)
 			return i;
-		ll = get_fs_word(&vtconsize->v_rows);
-		cc = get_fs_word(&vtconsize->v_cols);
-		vlin = get_fs_word(&vtconsize->v_vlin);
-		clin = get_fs_word(&vtconsize->v_clin);
-		vcol = get_fs_word(&vtconsize->v_vcol);
-		ccol = get_fs_word(&vtconsize->v_ccol);
+		ll = get_user(&vtconsize->v_rows);
+		cc = get_user(&vtconsize->v_cols);
+		vlin = get_user(&vtconsize->v_vlin);
+		clin = get_user(&vtconsize->v_clin);
+		vcol = get_user(&vtconsize->v_vcol);
+		ccol = get_user(&vtconsize->v_ccol);
 		vlin = vlin ? vlin : video_scan_lines;
 		if ( clin )
 		  {
@@ -926,7 +925,7 @@
 
 		kd_size_changed(ll, cc);
 		return 0;
-	}
+  	}
 
 	case PIO_FONT:
 		if (!perm)
@@ -1043,8 +1042,8 @@
 		i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
 		if (i == 0) {
 		    ud = (struct unimapdesc *) arg;
-		    ct = get_fs_word(&ud->entry_ct);
-		    list = (struct unipair *) get_fs_long(&ud->entries);
+		    ct = get_user(&ud->entry_ct);
+		    list = get_user(&ud->entries);
 		    i = verify_area(VERIFY_READ, (void *) list,
 				    ct*sizeof(struct unipair));
 		}
@@ -1061,8 +1060,8 @@
 		i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
 		if (i == 0) {
 		    ud = (struct unimapdesc *) arg;
-		    ct = get_fs_word(&ud->entry_ct);
-		    list = (struct unipair *) get_fs_long(&ud->entries);
+		    ct = get_user(&ud->entry_ct);
+		    list = get_user(&ud->entries);
 		    if (ct)
 		      i = verify_area(VERIFY_WRITE, (void *) list,
 				      ct*sizeof(struct unipair));
diff -u --recursive --new-file v1.3.3/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.3/linux/drivers/net/Makefile	Wed Jun  7 11:39:06 1995
+++ linux/drivers/net/Makefile	Mon Jun 26 10:15:25 1995
@@ -170,6 +170,12 @@
 MODULES := $(MODULES) eexpress.o
 endif
 
+ifdef CONFIG_EEXPRESS_PRO
+NETDRV_OBJS := $(NETDRV_OBJS) eepro.o
+else
+MODULES := $(MODULES) eepro.o
+endif
+
 ifdef CONFIG_WAVELAN
 NETDRV_OBJS := $(NETDRV_OBJS) wavelan.o
 else
diff -u --recursive --new-file v1.3.3/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.3.3/linux/drivers/net/Space.c	Tue Jun  6 11:22:07 1995
+++ linux/drivers/net/Space.c	Mon Jun 26 10:15:25 1995
@@ -46,6 +46,7 @@
 extern int hp_plus_probe(struct device *dev);
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
+extern int eepro_probe(struct device *);
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
@@ -111,6 +112,9 @@
 #endif
 #ifdef CONFIG_EEXPRESS		/* Intel EtherExpress */
 	&& express_probe(dev)
+#endif
+#ifdef CONFIG_EEXPRESS_PRO	/* Intel EtherExpress Pro/10 */
+	&& eepro_probe(dev)
 #endif
 #ifdef CONFIG_DEPCA		/* DEC DEPCA */
 	&& depca_probe(dev)
diff -u --recursive --new-file v1.3.3/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.3.3/linux/drivers/net/arcnet.c	Tue Jun  6 12:23:16 1995
+++ linux/drivers/net/arcnet.c	Mon Jun 26 10:27:16 1995
@@ -2,7 +2,7 @@
 	Written 1994-95 by Avery Pennarun, derived from skeleton.c by
         Donald Becker.
 
-	Contact Avery at: apenwarr@tourism.807-city.on.ca or
+	Contact Avery at: apenwarr@foxnet.net or
 	RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
 	
 	**********************
@@ -15,6 +15,13 @@
          
 	**********************
 
+	v1.02 (95/06/21)
+	  - A fix to make "exception" packets sent from Linux receivable
+	    on other systems.  (The protocol_id byte was sometimes being set
+	    incorrectly, and Linux wasn't checking it on receive so it
+	    didn't show up)
+	  - Updated my email address.  Please use apenwarr@foxnet.net
+	    from now on.
 	v1.01 (95/03/24)
 	  - Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski
             <motyl@tichy.ch.uj.edu.pl> for the patches to make arcnet work
@@ -79,7 +86,7 @@
  * 8 times every second.
  *
  * This should no longer be necessary.  if you experience "stuck" ARCnet
- * drivers, please email apenwarr@tourism.807-city.on.ca or I will remove
+ * drivers, please email apenwarr@foxnet.net or I will remove
  * this feature in a future release.
  */
 #undef USE_TIMER_HANDLER
@@ -87,7 +94,7 @@
 /**************************************************************************/
  
 static char *version =
- "arcnet.c:v1.01 95/03/24 Avery Pennarun <apenwarr@tourism.807-city.on.ca>\n";
+ "arcnet.c:v1.02 95/06/21 Avery Pennarun <apenwarr@foxnet.net>\n";
 
 /*
   Sources:
@@ -1249,7 +1256,7 @@
 		 * make the packet long enough to fit in a 512-byte
 		 * frame.
 		 */
-		arcpacket->raw[offset+0]=arcsoft->protocol_id;
+		arcpacket->raw[offset+0]=hdr->protocol_id;
 		arcpacket->raw[offset+1]=0xFF; /* FF flag */
 			arcpacket->raw[offset+2]=0xFF; /* FF padding */
 			arcpacket->raw[offset+3]=0xFF; /* FF padding */
diff -u --recursive --new-file v1.3.3/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v1.3.3/linux/drivers/net/eepro.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/eepro.c	Mon Jun 26 10:14:20 1995
@@ -0,0 +1,1160 @@
+/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
+/*
+	Written 1994, 1995 by Bao C. Ha.
+
+	Copyright (C) 1994, 1995 by Bao C. Ha.
+
+	This software may be used and distributed
+	according to the terms of the GNU Public License,
+	incorporated herein by reference.
+
+	The author may be reached at bao@saigon.async.com 
+	or 418 Hastings Place, Martinez, GA 30907.
+
+	Things remaining to do:
+	Better record keeping of errors.
+	Eliminate transmit interrupt to reduce overhead.
+	Implement "concurrent processing". I won't be doing it!
+	Allow changes to the partition of the transmit and receive
+	buffers, currently the ratio is 3:1 of receive to transmit
+	buffer ratio.  
+
+	Bugs:
+
+	If you have a problem of not detecting the 82595 during a
+	reboot (warm reset), disable the FLASH memory should fix it.
+	This is a compatibility hardware problem.
+	
+	Versions:
+
+	0.07a	Fix a stat report which counts every packet as a
+		heart-beat failure. (BCH, 6/3/95)
+
+	0.07	Modified to support all other 82595-based lan cards.  
+		The IRQ vector of the EtherExpress Pro will be set
+		according to the value saved in the EEPROM.  For other
+		cards, I will do autoirq_request() to grab the next
+		available interrupt vector. (BCH, 3/17/95)
+
+	0.06a,b	Interim released.  Minor changes in the comments and
+		print out format. (BCH, 3/9/95 and 3/14/95)
+
+	0.06	First stable release that I am comfortable with. (BCH,
+		3/2/95)	
+
+	0.05	Complete testing of multicast. (BCH, 2/23/95)	
+
+	0.04	Adding multicast support. (BCH, 2/14/95)	
+
+	0.03	First widely alpha release for public testing. 
+		(BCH, 2/14/95)	
+
+*/
+
+static char *version =
+	"eepro.c: v0.07a 6/5/95 Bao C. Ha (bao@saigon.async.com)\n";
+
+/* Always include 'config.h' first in case the user wants to turn on
+   or override something. */
+#include <linux/config.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+/*
+  Sources:
+
+	This driver wouldn't have been written without the availability 
+	of the Crynwr's Lan595 driver source code.  It helps me to 
+	familiarize with the 82595 chipset while waiting for the Intel 
+	documentation.  I also learned how to detect the 82595 using 
+	the packet driver's technique.
+
+	This driver is written by cutting and pasting the skeleton.c driver
+	provided by Donald Becker.  I also borrowed the EEPROM routine from
+	Donald Becker's 82586 driver.
+
+	Datasheet for the Intel 82595. It provides just enough info that 
+	the casual reader might think that it documents the i82595.
+
+	The User Manual for the 82595.  It provides a lot of the missing
+	information.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+extern struct device *init_etherdev(struct device *dev, int sizeof_private,
+						unsigned long *mem_startp);
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int eepro_portlist[] =
+   { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0x360, 0};
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define EEPRO_IO_EXTENT	16
+
+/* Information that need to be kept for each board. */
+struct eepro_local {
+	struct enet_statistics stats;
+	unsigned rx_start;
+	unsigned tx_start; /* start of the transmit chain */
+	int tx_last;  /* pointer to last packet in the transmit chain */
+	unsigned tx_end;   /* end of the transmit chain (plus 1) */
+	int eepro;	/* a flag, TRUE=1 for the EtherExpress Pro/10,
+			   FALSE = 0 for other 82595-based lan cards. */
+};
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00
+#define SA_ADDR1 0xaa
+#define SA_ADDR2 0x00
+
+/* Index to functions, as function prototypes. */
+
+extern int eepro_probe(struct device *dev);	
+
+static int	eepro_probe1(struct device *dev, short ioaddr);
+static int	eepro_open(struct device *dev);
+static int	eepro_send_packet(struct sk_buff *skb, struct device *dev);
+static void	eepro_interrupt(int irq, struct pt_regs *regs);
+static void 	eepro_rx(struct device *dev);
+static void 	eepro_transmit_interrupt(struct device *dev);
+static int	eepro_close(struct device *dev);
+static struct enet_statistics *eepro_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+
+static int read_eeprom(int ioaddr, int location);
+static void hardware_send_packet(struct device *dev, void *buf, short length);
+static int	eepro_grab_irq(struct device *dev);
+
+/*
+  			Details of the i82595.
+
+You will need either the datasheet or the user manual to understand what
+is going on here.  The 82595 is very different from the 82586, 82593.
+
+The receive algorithm in eepro_rx() is just an implementation of the
+RCV ring structure that the Intel 82595 imposes at the hardware level.
+The receive buffer is set at 24K, and the transmit buffer is 8K.  I
+am assuming that the total buffer memory is 32K, which is true for the
+Intel EtherExpress Pro/10.  If it is less than that on a generic card,
+the driver will be broken.
+
+The transmit algorithm in the hardware_send_packet() is similar to the
+one in the eepro_rx().  The transmit buffer is a ring linked list.
+I just queue the next available packet to the end of the list.  In my
+system, the 82595 is so fast that the list seems to always contain a
+single packet.  In other systems with faster computers and more congested
+network traffics, the ring linked list should improve performance by
+allowing up to 8K worth of packets to be queued.
+
+*/
+#define	RAM_SIZE	0x8000
+#define	RCV_HEADER	8
+#define	RCV_RAM		0x6000	/* 24KB for RCV buffer */
+#define	RCV_LOWER_LIMIT	0x00	/* 0x0000 */
+#define	RCV_UPPER_LIMIT	((RCV_RAM - 2) >> 8)	/* 0x5ffe */
+#define	XMT_RAM		(RAM_SIZE - RCV_RAM)	/* 8KB for XMT buffer */
+#define	XMT_LOWER_LIMIT	(RCV_RAM >> 8)	/* 0x6000 */
+#define	XMT_UPPER_LIMIT	((RAM_SIZE - 2) >> 8)	/* 0x7ffe */
+#define	XMT_HEADER	8
+
+#define	RCV_DONE	0x0008
+#define	RX_OK		0x2000
+#define	RX_ERROR	0x0d81
+
+#define	TX_DONE_BIT	0x0080
+#define	CHAIN_BIT	0x8000
+#define	XMT_STATUS	0x02
+#define	XMT_CHAIN	0x04
+#define	XMT_COUNT	0x06
+
+#define	BANK0_SELECT	0x00		
+#define	BANK1_SELECT	0x40		
+#define	BANK2_SELECT	0x80		
+
+/* Bank 0 registers */
+#define	COMMAND_REG	0x00	/* Register 0 */
+#define	MC_SETUP	0x03
+#define	XMT_CMD		0x04
+#define	DIAGNOSE_CMD	0x07
+#define	RCV_ENABLE_CMD	0x08
+#define	RCV_DISABLE_CMD	0x0a
+#define	STOP_RCV_CMD	0x0b
+#define	RESET_CMD	0x0e
+#define	POWER_DOWN_CMD	0x18
+#define	RESUME_XMT_CMD	0x1c
+#define	SEL_RESET_CMD	0x1e
+#define	STATUS_REG	0x01	/* Register 1 */
+#define	RX_INT		0x02
+#define	TX_INT		0x04
+#define	EXEC_STATUS	0x30
+#define	ID_REG		0x02	/* Register 2	*/
+#define	R_ROBIN_BITS	0xc0	/* round robin counter */
+#define	ID_REG_MASK	0x2c
+#define	ID_REG_SIG	0x24
+#define	AUTO_ENABLE	0x10
+#define	INT_MASK_REG	0x03	/* Register 3	*/
+#define	RX_STOP_MASK	0x01
+#define	RX_MASK		0x02
+#define	TX_MASK		0x04
+#define	EXEC_MASK	0x08
+#define	ALL_MASK	0x0f
+#define	RCV_BAR		0x04	/* The following are word (16-bit) registers */
+#define	RCV_STOP	0x06
+#define	XMT_BAR		0x0a
+#define	HOST_ADDRESS_REG	0x0c
+#define	IO_PORT		0x0e
+
+/* Bank 1 registers */
+#define	REG1	0x01
+#define	WORD_WIDTH	0x02
+#define	INT_ENABLE	0x80
+#define INT_NO_REG	0x02
+#define	RCV_LOWER_LIMIT_REG	0x08
+#define	RCV_UPPER_LIMIT_REG	0x09
+#define	XMT_LOWER_LIMIT_REG	0x0a
+#define	XMT_UPPER_LIMIT_REG	0x0b
+
+/* Bank 2 registers */
+#define	XMT_Chain_Int	0x20	/* Interrupt at the end of the transmit chain */
+#define	XMT_Chain_ErrStop	0x40 /* Interrupt at the end of the chain even if there are errors */
+#define	RCV_Discard_BadFrame	0x80 /* Throw bad frames away, and continue to receive others */
+#define	REG2		0x02
+#define	PRMSC_Mode	0x01
+#define	Multi_IA	0x20
+#define	REG3		0x03
+#define	TPE_BIT		0x04
+#define	BNC_BIT		0x20
+	
+#define	I_ADD_REG0	0x04
+#define	I_ADD_REG1	0x05
+#define	I_ADD_REG2	0x06
+#define	I_ADD_REG3	0x07
+#define	I_ADD_REG4	0x08
+#define	I_ADD_REG5	0x09
+
+#define EEPROM_REG 0x0a
+#define EESK 0x01
+#define EECS 0x02
+#define EEDI 0x04
+#define EEDO 0x08
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, allocate space for the device and return success
+   (detachable devices only).
+   */
+#ifdef HAVE_DEVLIST
+/* Support for a alternate probe manager, which will eliminate the
+   boilerplate below. */
+struct netdev_entry netcard_drv =
+{"eepro", eepro_probe1, EEPRO_IO_EXTENT, eepro_portlist};
+#else
+int
+eepro_probe(struct device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	if (base_addr > 0x1ff)		/* Check a single specified location. */
+		return eepro_probe1(dev, base_addr);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return ENXIO;
+
+	for (i = 0; eepro_portlist[i]; i++) {
+		int ioaddr = eepro_portlist[i];
+		if (check_region(ioaddr, EEPRO_IO_EXTENT))
+			continue;
+		if (eepro_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+
+	return ENODEV;
+}
+#endif
+
+/* This is the real probe routine.  Linux has a history of friendly device
+   probes on the ISA bus.  A good device probes avoids doing writes, and
+   verifies that the correct device exists and functions.  */
+
+int eepro_probe1(struct device *dev, short ioaddr)
+{
+	unsigned short station_addr[6], id, counter;
+	int i;
+	int eepro;	/* a flag, TRUE=1 for the EtherExpress Pro/10,
+			   FALSE = 0 for other 82595-based lan cards. */
+	char *ifmap[] = {"AUI", "10Base2", "10BaseT"};
+	enum iftype { AUI=0, BNC=1, TPE=2 };
+
+	/* Now, we are going to check for the signature of the
+	   ID_REG (register 2 of bank 0) */
+
+	if (((id=inb(ioaddr + ID_REG)) & ID_REG_MASK) == ID_REG_SIG) {
+
+		/* We seem to have the 82595 signature, let's
+		   play with its counter (last 2 bits of
+		   register 2 of bank 0) to be sure. */
+	
+		counter = (id & R_ROBIN_BITS);	
+		if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == 
+			(counter + 0x40)) {
+
+			/* Yes, the 82595 has been found */
+
+			/* Now, get the ethernet hardware address from
+			   the EEPROM */
+
+			station_addr[0] = read_eeprom(ioaddr, 2);
+			station_addr[1] = read_eeprom(ioaddr, 3);
+			station_addr[2] = read_eeprom(ioaddr, 4);
+
+			/* Check the station address for the manufacturer's code */
+
+			if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
+				eepro = 0;
+				printk("%s: Intel 82595-based lan card at %#x,", 
+					dev->name, ioaddr);
+			}
+			else {
+				eepro = 1;
+				printk("%s: Intel EtherExpress Pro/10 at %#x,", 
+					dev->name, ioaddr);
+			}
+
+   			/* Fill in the 'dev' fields. */
+			dev->base_addr = ioaddr;
+			
+			for (i=0; i < 6; i++) {
+				dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
+				printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+			}
+				
+			outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+			id = inb(ioaddr + REG3);
+			if (id & TPE_BIT)
+				dev->if_port = TPE;
+			else dev->if_port = BNC;
+
+			if (dev->irq < 2 && eepro) {
+				i = read_eeprom(ioaddr, 1);
+				switch (i & 0x07) {
+					case 0:	dev->irq = 9; break;
+					case 1:	dev->irq = 3; break;
+					case 2:	dev->irq = 5; break;
+					case 3:	dev->irq = 10; break;
+					case 4:	dev->irq = 11; break;
+					default: /* should never get here !!!!! */
+						printk(" illegal interrupt vector stored in EEPROM.\n");
+						return ENODEV;
+					}
+				}
+			else if (dev->irq == 2)
+				dev->irq = 9;
+
+			if (dev->irq > 2) {
+				printk(", IRQ %d, %s.\n", dev->irq,
+						ifmap[dev->if_port]);
+				if (request_irq(dev->irq, &eepro_interrupt, 0, "eepro")) {
+					printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+					return -EAGAIN;
+				}
+			}
+			else printk(", %s.\n", ifmap[dev->if_port]);
+			
+			if ((dev->mem_start & 0xf) > 0)
+				net_debug = dev->mem_start & 7;
+
+			if (net_debug > 3) {
+				i = read_eeprom(ioaddr, 5);
+				if (i & 0x2000) /* bit 13 of EEPROM word 5 */
+					printk("%s: Concurrent Processing is enabled but not used!\n",
+						dev->name);
+			}
+
+			if (net_debug) 
+				printk(version);
+
+			/* Grab the region so we can find another board if autoIRQ fails. */
+			request_region(ioaddr, EEPRO_IO_EXTENT,"eepro");
+
+			/* Initialize the device structure */
+			if (dev->priv == NULL)
+				dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
+			memset(dev->priv, 0, sizeof(struct eepro_local));
+
+			dev->open = eepro_open;
+			dev->stop = eepro_close;
+			dev->hard_start_xmit = eepro_send_packet;
+			dev->get_stats = eepro_get_stats;
+			dev->set_multicast_list = &set_multicast_list;
+
+			/* Fill in the fields of the device structure with
+			   ethernet generic values */
+
+			ether_setup(dev);
+
+			outb(RESET_CMD, ioaddr); /* RESET the 82595 */
+
+			return 0;
+			}
+		else return ENODEV;
+		}
+	else if (net_debug > 3)
+		printk ("EtherExpress Pro probed failed!\n");
+	return ENODEV;
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+   */
+
+static char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
+static int	eepro_grab_irq(struct device *dev)
+{
+	int irqlist[] = { 5, 9, 10, 11, 4, 3, 0};	
+	int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
+
+	outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */
+
+	/* Enable the interrupt line. */
+	temp_reg = inb(ioaddr + REG1);
+	outb(temp_reg | INT_ENABLE, ioaddr + REG1); 
+	
+	outb(BANK0_SELECT, ioaddr); /* be CAREFULL, BANK 0 now */
+
+	/* clear all interrupts */
+	outb(ALL_MASK, ioaddr + STATUS_REG); 
+	/* Let EXEC event to interrupt */
+	outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG); 
+
+	do {
+		outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */
+
+		temp_reg = inb(ioaddr + INT_NO_REG);
+		outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG); 
+
+		outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+		if (request_irq (*irqp, NULL, 0, "bogus") != EBUSY) {
+			/* Twinkle the interrupt, and check if it's seen */
+			autoirq_setup(0);
+
+			outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */
+				
+			if (*irqp == autoirq_report(2) &&  /* It's a good IRQ line */
+				(request_irq(dev->irq = *irqp, &eepro_interrupt, 0, "eepro") == 0)) 
+					break;
+
+			/* clear all interrupts */
+			outb(ALL_MASK, ioaddr + STATUS_REG); 
+		}
+	} while (*++irqp);
+
+	outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+
+	/* Disable the physical interrupt line. */
+	temp_reg = inb(ioaddr + REG1);
+	outb(temp_reg & 0x7f, ioaddr + REG1); 
+
+	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+	/* Mask all the interrupts. */
+	outb(ALL_MASK, ioaddr + INT_MASK_REG); 
+
+	/* clear all interrupts */
+	outb(ALL_MASK, ioaddr + STATUS_REG); 
+
+	return dev->irq;
+}
+
+static int
+eepro_open(struct device *dev)
+{
+	unsigned short temp_reg;
+	int i, ioaddr = dev->base_addr;
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+
+	if (net_debug > 3)
+		printk("eepro: entering eepro_open routine.\n");
+
+	if (dev->dev_addr[0] == SA_ADDR0 &&
+			dev->dev_addr[1] == SA_ADDR1 &&
+			dev->dev_addr[2] == SA_ADDR2)
+		lp->eepro = 1; /* Yes, an Intel EtherExpress Pro/10 */
+	else lp->eepro = 0; /* No, it is a generic 82585 lan card */
+
+	/* Get the interrupt vector for the 82595 */	
+	if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
+		printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+				
+	if (irq2dev_map[dev->irq] != 0
+		|| (irq2dev_map[dev->irq] = dev) == 0)
+		return -EAGAIN;
+
+	/* Initialize the 82595. */
+
+	outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+	temp_reg = inb(ioaddr + EEPROM_REG);
+	if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
+		outb(temp_reg & 0xef, ioaddr + EEPROM_REG);
+	for (i=0; i < 6; i++) 
+		outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); 
+			
+	temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
+	outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
+		| RCV_Discard_BadFrame, ioaddr + REG1);  
+
+	temp_reg = inb(ioaddr + REG2); /* Match broadcast */
+	outb(temp_reg | 0x14, ioaddr + REG2);
+
+	temp_reg = inb(ioaddr + REG3);
+	outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
+
+	/* Set the receiving mode */
+	outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */
+	
+	temp_reg = inb(ioaddr + INT_NO_REG);
+	outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); 
+
+	/* Initialize the RCV and XMT upper and lower limits */
+	outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); 
+	outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); 
+	outb(XMT_LOWER_LIMIT, ioaddr + XMT_LOWER_LIMIT_REG); 
+	outb(XMT_UPPER_LIMIT, ioaddr + XMT_UPPER_LIMIT_REG); 
+
+	/* Enable the interrupt line. */
+	temp_reg = inb(ioaddr + REG1);
+	outb(temp_reg | INT_ENABLE, ioaddr + REG1); 
+
+	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+	/* Let RX and TX events to interrupt */
+	outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+	/* clear all interrupts */
+	outb(ALL_MASK, ioaddr + STATUS_REG); 
+
+	/* Initialize RCV */
+	outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); 
+	lp->rx_start = (RCV_LOWER_LIMIT << 8) ;
+	outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); 
+
+	/* Initialize XMT */
+	outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR); 
+	
+	outb(SEL_RESET_CMD, ioaddr);
+	/* We are supposed to wait for 2 us after a SEL_RESET */
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;	
+
+	lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */
+	lp->tx_last = 0;  
+	
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	if (net_debug > 3)
+		printk("eepro: exiting eepro_open routine.\n");
+
+	outb(RCV_ENABLE_CMD, ioaddr);
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+static int
+eepro_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (net_debug > 5)
+		printk("eepro: entering eepro_send_packet routine.\n");
+	
+	if (dev->tbusy) {
+		/* If we get here, some higher level has decided we are broken.
+		   There should really be a "kick me" function call instead. */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5)
+			return 1;
+		if (net_debug > 1)
+			printk("%s: transmit timed out, %s?\n", dev->name,
+				   "network cable problem");
+		lp->stats.tx_errors++;
+		/* Try to restart the adaptor. */
+		outb(SEL_RESET_CMD, ioaddr); 
+		/* We are supposed to wait for 2 us after a SEL_RESET */
+		SLOW_DOWN_IO;
+		SLOW_DOWN_IO;
+
+		/* Do I also need to flush the transmit buffers here? YES? */
+		lp->tx_start = lp->tx_end = RCV_RAM; 
+		lp->tx_last = 0;
+	
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+
+		outb(RCV_ENABLE_CMD, ioaddr);
+
+	}
+
+	/* If some higher layer thinks we've missed an tx-done interrupt
+	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+	   itself. */
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 0;
+	}
+
+	/* Block a timer-based transmit from overlapping. */
+	if (set_bit(0, (void*)&dev->tbusy) != 0)
+		printk("%s: Transmitter access conflict.\n", dev->name);
+	else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = skb->data;
+
+		hardware_send_packet(dev, buf, length);
+		dev->trans_start = jiffies;
+	}
+
+	dev_kfree_skb (skb, FREE_WRITE);
+
+	/* You might need to clean up and record Tx statistics here. */
+	/* lp->stats.tx_aborted_errors++; */
+
+	if (net_debug > 5)
+		printk("eepro: exiting eepro_send_packet routine.\n");
+	
+	return 0;
+}
+
+
+/*	The typical workload of the driver:
+	Handle the network interface interrupts. */
+static void
+eepro_interrupt(int irq, struct pt_regs * regs)
+{
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	int ioaddr, status, boguscount = 0;
+
+	if (net_debug > 5)
+		printk("eepro: entering eepro_interrupt routine.\n");
+	
+	if (dev == NULL) {
+		printk ("eepro_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	dev->interrupt = 1;
+	
+	ioaddr = dev->base_addr;
+
+	do { 
+		status = inb(ioaddr + STATUS_REG);
+
+		if (status & RX_INT) {
+			if (net_debug > 4)
+				printk("eepro: packet received interrupt.\n");
+
+			/* Acknowledge the RX_INT */
+			outb(RX_INT, ioaddr + STATUS_REG); 
+
+			/* Get the received packets */
+			eepro_rx(dev);
+		}
+		else if (status & TX_INT) {
+			if (net_debug > 4)
+				printk("eepro: packet transmit interrupt.\n");
+
+			/* Acknowledge the TX_INT */
+			outb(TX_INT, ioaddr + STATUS_REG); 
+
+			/* Process the status of transmitted packets */
+			eepro_transmit_interrupt(dev);
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}		
+	} while ((++boguscount < 10) && (status & 0x06));
+
+	dev->interrupt = 0;
+	if (net_debug > 5)
+		printk("eepro: exiting eepro_interrupt routine.\n");
+	
+	return;
+}
+
+static int
+eepro_close(struct device *dev)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	short temp_reg;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+
+	/* Disable the physical interrupt line. */
+	temp_reg = inb(ioaddr + REG1);
+	outb(temp_reg & 0x7f, ioaddr + REG1); 
+
+	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+
+	/* Flush the Tx and disable Rx. */
+	outb(STOP_RCV_CMD, ioaddr); 
+	lp->tx_start = lp->tx_end = RCV_RAM ;
+	lp->tx_last = 0;  
+
+	/* Mask all the interrupts. */
+	outb(ALL_MASK, ioaddr + INT_MASK_REG); 
+
+	/* clear all interrupts */
+	outb(ALL_MASK, ioaddr + STATUS_REG); 
+
+	/* Reset the 82595 */
+	outb(RESET_CMD, ioaddr); 
+
+	/* release the interrupt */
+	free_irq(dev->irq);
+
+	irq2dev_map[dev->irq] = 0;
+
+	/* release the ioport-region */
+	release_region(ioaddr, 16);
+
+	/* Update the statistics here. What statistics? */
+
+	/* We are supposed to wait for 200 us after a RESET */
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO; /* May not be enough? */
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+eepro_get_stats(struct device *dev)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+
+	return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1	Promiscuous mode, receive all packets
+   num_addrs == 0	Normal mode, clear multicast list
+   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	short ioaddr = dev->base_addr;
+	unsigned short mode;
+
+	if (num_addrs < -1 || num_addrs > 63) {
+		outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+		mode = inb(ioaddr + REG2);
+		outb(mode | PRMSC_Mode, ioaddr + REG2);	
+		mode = inb(ioaddr + REG3);
+		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+		printk("%s: promiscuous mode enabled.\n", dev->name);
+	} 
+	else if (num_addrs == 0) {
+		outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+		mode = inb(ioaddr + REG2);
+		outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
+		mode = inb(ioaddr + REG3);
+		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+	}
+	else {
+		unsigned short status, *eaddrs = addrs;
+		int i, boguscount = 0;
+		
+		/* Disable RX and TX interrupts.  Neccessary to avoid
+		   corruption of the HOST_ADDRESS_REG by interrupt
+		   service routines. */
+		outb(ALL_MASK, ioaddr + INT_MASK_REG);
+
+		outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
+		mode = inb(ioaddr + REG2);
+		outb(mode | Multi_IA, ioaddr + REG2);	
+		mode = inb(ioaddr + REG3);
+		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
+		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+		outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
+		outw(MC_SETUP, ioaddr + IO_PORT);
+		outw(0, ioaddr + IO_PORT);
+		outw(0, ioaddr + IO_PORT);
+		outw(6*(num_addrs + 1), ioaddr + IO_PORT);
+		for (i = 0; i < num_addrs; i++) {
+			outw(*eaddrs++, ioaddr + IO_PORT);
+			outw(*eaddrs++, ioaddr + IO_PORT);
+			outw(*eaddrs++, ioaddr + IO_PORT);
+		}
+		eaddrs = (unsigned short *) dev->dev_addr;
+		outw(eaddrs[0], ioaddr + IO_PORT);
+		outw(eaddrs[1], ioaddr + IO_PORT);
+		outw(eaddrs[2], ioaddr + IO_PORT);
+		outw(lp->tx_end, ioaddr + XMT_BAR);
+		outb(MC_SETUP, ioaddr);
+
+		/* Update the transmit queue */
+		i = lp->tx_end + XMT_HEADER + 6*(num_addrs + 1);
+		if (lp->tx_start != lp->tx_end) { 
+			/* update the next address and the chain bit in the 
+			   last packet */
+			outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+			outw(i, ioaddr + IO_PORT);
+			outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+			status = inw(ioaddr + IO_PORT);
+			outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+			lp->tx_end = i ;
+		} else lp->tx_start = lp->tx_end = i ;
+
+		/* Acknowledge that the MC setup is done */
+		do { /* We should be doing this in the eepro_interrupt()! */
+			SLOW_DOWN_IO;
+			SLOW_DOWN_IO;
+			if (inb(ioaddr + STATUS_REG) & 0x08) {
+				i = inb(ioaddr);
+				outb(0x08, ioaddr + STATUS_REG);
+				if (i & 0x20) { /* command ABORTed */
+					printk("%s: multicast setup failed.\n", 
+						dev->name);
+					break;
+				} else if ((i & 0x0f) == 0x03)	{ /* MC-Done */
+					printk("%s: set Rx mode to %d addresses.\n", 
+						dev->name, num_addrs);
+					break;
+				}
+			}
+		} while (++boguscount < 100);
+
+		/* Re-enable RX and TX interrupts */
+		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+	
+	}
+	outb(RCV_ENABLE_CMD, ioaddr);
+}
+
+/* The horrible routine to read a word from the serial EEPROM. */
+/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
+
+/* The delay between EEPROM clock transitions. */
+#define eeprom_delay()	{ int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}
+#define EE_READ_CMD (6 << 6)
+
+int
+read_eeprom(int ioaddr, int location)
+{
+	int i;
+	unsigned short retval = 0;
+	short ee_addr = ioaddr + EEPROM_REG;
+	int read_cmd = location | EE_READ_CMD;
+	short ctrl_val = EECS ;
+	
+	outb(BANK2_SELECT, ioaddr);
+	outb(ctrl_val, ee_addr);
+	
+	/* Shift the read command bits out. */
+	for (i = 8; i >= 0; i--) {
+		short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
+			: ctrl_val;
+		outb(outval, ee_addr);
+		outb(outval | EESK, ee_addr);	/* EEPROM clock tick. */
+		eeprom_delay();
+		outb(outval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay();
+	}
+	outb(ctrl_val, ee_addr);
+	
+	for (i = 16; i > 0; i--) {
+		outb(ctrl_val | EESK, ee_addr);	 eeprom_delay();
+		retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
+		outb(ctrl_val, ee_addr);  eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	ctrl_val &= ~EECS;
+	outb(ctrl_val | EESK, ee_addr);
+	eeprom_delay();
+	outb(ctrl_val, ee_addr);
+	eeprom_delay();
+	outb(BANK0_SELECT, ioaddr);
+	return retval;
+}
+
+static void
+hardware_send_packet(struct device *dev, void *buf, short length)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	short ioaddr = dev->base_addr;
+	unsigned status, tx_available, last, end, boguscount = 10;
+
+	if (net_debug > 5)
+		printk("eepro: entering hardware_send_packet routine.\n");
+
+	while (boguscount-- > 0) {
+
+		/* determine how much of the transmit buffer space is available */
+		if (lp->tx_end > lp->tx_start)
+			tx_available = XMT_RAM - (lp->tx_end - lp->tx_start);
+		else if (lp->tx_end < lp->tx_start)
+			tx_available = lp->tx_start - lp->tx_end;
+		else tx_available = XMT_RAM;
+
+		/* Disable RX and TX interrupts.  Neccessary to avoid
+		   corruption of the HOST_ADDRESS_REG by interrupt
+		   service routines. */
+		outb(ALL_MASK, ioaddr + INT_MASK_REG);
+
+		if (((((length + 1) >> 1) << 1) + 2*XMT_HEADER) 
+			>= tx_available)   /* No space available ??? */
+			continue;
+
+		last = lp->tx_end;
+		end = last + (((length + 1) >> 1) << 1) + XMT_HEADER;
+
+		if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */
+			if ((RAM_SIZE - last) <= XMT_HEADER) {	
+			/* Arrrr!!!, must keep the xmt header together,
+			  several days were lost to chase this one down. */
+				last = RCV_RAM;
+				end = last + (((length + 1) >> 1) << 1) + XMT_HEADER;
+			}	
+			else end = RCV_RAM + (end - RAM_SIZE);
+		}
+
+		outw(last, ioaddr + HOST_ADDRESS_REG);
+		outw(XMT_CMD, ioaddr + IO_PORT);
+		outw(0, ioaddr + IO_PORT);
+		outw(end, ioaddr + IO_PORT);
+		outw(length, ioaddr + IO_PORT);
+		outsw(ioaddr + IO_PORT, buf, (length + 1) >> 1);
+
+		if (lp->tx_start != lp->tx_end) { 
+			/* update the next address and the chain bit in the 
+			   last packet */
+			if (lp->tx_end != last) {
+				outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+				outw(last, ioaddr + IO_PORT);
+			}
+			outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+			status = inw(ioaddr + IO_PORT);
+			outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+		}
+
+		/* A dummy read to flush the DRAM write pipeline */
+		status = inw(ioaddr + IO_PORT); 
+
+		/* Enable RX and TX interrupts */
+		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+	
+		if (lp->tx_start == lp->tx_end) {
+			outw(last, ioaddr + XMT_BAR);
+			outb(XMT_CMD, ioaddr);
+			lp->tx_start = last;   /* I don't like to change tx_start here */
+		}
+		else	outb(RESUME_XMT_CMD, ioaddr);
+
+		lp->tx_last = last;
+		lp->tx_end = end;
+
+		if (dev->tbusy) {
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+
+		if (net_debug > 5)
+			printk("eepro: exiting hardware_send_packet routine.\n");
+		return;
+	}
+	dev->tbusy = 1;
+	if (net_debug > 5)
+		printk("eepro: exiting hardware_send_packet routine.\n");
+}
+
+static void
+eepro_rx(struct device *dev)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	short ioaddr = dev->base_addr;
+	short boguscount = 20;
+	short rcv_car = lp->rx_start;
+	unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
+
+	if (net_debug > 5)
+		printk("eepro: entering eepro_rx routine.\n");
+	
+	/* Set the read pointer to the start of the RCV */
+	outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
+	rcv_event = inw(ioaddr + IO_PORT);
+
+	while (rcv_event == RCV_DONE) {
+		rcv_status = inw(ioaddr + IO_PORT);
+		rcv_next_frame = inw(ioaddr + IO_PORT);
+		rcv_size = inw(ioaddr + IO_PORT);
+
+		if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
+			/* Malloc up new buffer. */
+			struct sk_buff *skb;
+
+			rcv_size &= 0x3fff;
+			skb = alloc_skb(rcv_size, GFP_ATOMIC);
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->len = rcv_size;
+			skb->dev = dev;
+
+			insw(ioaddr+IO_PORT, skb->data, (rcv_size + 1) >> 1);
+	
+			skb->protocol = eth_type_trans(skb,dev);	
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+		else { /* Not sure will ever reach here, 
+			  I set the 595 to discard bad received frames */
+			lp->stats.rx_errors++;
+			if (rcv_status & 0x0100)
+				lp->stats.rx_over_errors++;
+			else if (rcv_status & 0x0400)
+				lp->stats.rx_frame_errors++;
+			else if (rcv_status & 0x0800)
+				lp->stats.rx_crc_errors++;
+			printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", 
+				dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
+		}
+		if (rcv_status & 0x1000)
+			lp->stats.rx_length_errors++;
+		if (--boguscount == 0)
+			break;
+
+		rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+		lp->rx_start = rcv_next_frame;
+		outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+		rcv_event = inw(ioaddr + IO_PORT);
+
+	} 
+	if (rcv_car == 0)
+		rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff;
+	outw(rcv_car - 1, ioaddr + RCV_STOP);
+
+	if (net_debug > 5)
+		printk("eepro: exiting eepro_rx routine.\n");
+}
+
+static void
+eepro_transmit_interrupt(struct device *dev)
+{
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
+	short ioaddr = dev->base_addr;
+	short boguscount = 10; 
+	short xmt_status;
+
+	while (lp->tx_start != lp->tx_end) { 
+
+		outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
+		xmt_status = inw(ioaddr+IO_PORT);
+		if ((xmt_status & TX_DONE_BIT) == 0) break;
+		xmt_status = inw(ioaddr+IO_PORT);
+		lp->tx_start = inw(ioaddr+IO_PORT);
+	
+		if (dev->tbusy) {
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+
+		if (xmt_status & 0x2000)
+			lp->stats.tx_packets++;
+		else {
+			lp->stats.tx_errors++;
+			if (xmt_status & 0x0400)
+				lp->stats.tx_carrier_errors++;
+			printk("%s: XMT status = %#x\n",
+				dev->name, xmt_status);
+		}
+		if (xmt_status & 0x000f)
+			lp->stats.collisions += (xmt_status & 0x000f);
+		if ((xmt_status & 0x0040) == 0x0)
+			lp->stats.tx_heartbeat_errors++;
+
+		if (--boguscount == 0)
+			break;  
+	}
+}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_eepro = {
+	"        " /*"eepro"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, eepro_probe };
+
+int
+init_module(void)
+{
+	if (register_netdev(&dev_eepro) != 0)
+		return -EIO;
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("eepro: device busy, remove delayed\n");
+	else
+	{
+		unregister_netdev(&dev_eepro);
+		kfree_s(dev_eepro.priv,sizeof(struct eepro_local));
+		dev_eepro.priv=NULL;
+	}
+}
+#endif /* MODULE */
diff -u --recursive --new-file v1.3.3/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v1.3.3/linux/drivers/net/eql.c	Fri Jun 16 22:02:55 1995
+++ linux/drivers/net/eql.c	Thu Jun 22 10:29:49 1995
@@ -958,7 +958,7 @@
 
 	      if ( slave->dev != 0)
 		{
-		  if ( slave->dev->flags & IFF_UP == IFF_UP )
+		  if ((slave->dev->flags & IFF_UP) == IFF_UP )
 		    {
 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 
 			(priority_Bps) + bytes_queued * 8;
@@ -1105,7 +1105,7 @@
 	{
 	  if (slave != 0)
 	    {
-	      if ( slave->dev->flags & IFF_UP == IFF_UP )
+	      if ((slave->dev->flags & IFF_UP) == IFF_UP )
 		{
 		  slave->bytes_queued -= slave->priority_Bps;
 	      
diff -u --recursive --new-file v1.3.3/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v1.3.3/linux/drivers/net/ne.c	Tue Jun 20 09:10:32 1995
+++ linux/drivers/net/ne.c	Mon Jun 19 15:22:39 1995
@@ -342,7 +342,7 @@
 	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
 	    break;
 	}
-    outb_p(ENISR_RESET, NE_BASE + NE_RESET);	/* Ack intr. */
+    outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
 }
 
 /* Block input and output, similar to the Crynwr packet driver.  If you
diff -u --recursive --new-file v1.3.3/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.3.3/linux/drivers/net/ppp.c	Tue Jun 20 09:10:32 1995
+++ linux/drivers/net/ppp.c	Mon Jun 26 11:06:52 1995
@@ -1292,12 +1292,12 @@
 	return -EOVERFLOW;		/* ZZZ; HACK! */
       } else {
 	/* have the space: copy the packet, faking the first two bytes */
-	put_fs_byte (PPP_ADDRESS, buf++);
-	put_fs_byte (PPP_CONTROL, buf++);
+	put_user (PPP_ADDRESS, buf++);
+	put_user (PPP_CONTROL, buf++);
 	i = len;
 	while (i-- > 0) {
 	  GETC (c);
-	  put_fs_byte (c, buf++);
+	  put_user (c, buf++);
 	}
       }
 
@@ -1392,7 +1392,7 @@
   ppp->fcs = PPP_FCS_INIT;
   i = nr;
   while (i-- > 0)
-    ppp_stuff_char(ppp,get_fs_byte(buf++));
+    ppp_stuff_char(ppp,get_user(buf++));
 
   ppp_add_fcs(ppp);		/* concatenate FCS at end */
 
@@ -1438,7 +1438,7 @@
   case PPPIOCSMRU:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      temp_i = (int) get_fs_long (l);
+      temp_i = get_user ((int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %d\n", temp_i));
       if (ppp->mru != temp_i)
 	ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
@@ -1452,7 +1452,7 @@
 #ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
       temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
-      put_fs_long ((long) temp_i, l);
+      put_user (temp_i, (int *) l);
       PRINTKN (3,(KERN_DEBUG "ppp_ioctl: get flags: addr %lx flags %x\n",
 		  l,
 		  temp_i));
@@ -1462,7 +1462,7 @@
   case PPPIOCSFLAGS:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      temp_i      = (int) get_fs_long (l);
+      temp_i      = get_user ((int *) l);
       ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i));
     }
@@ -1471,7 +1471,7 @@
   case PPPIOCGASYNCMAP:
     error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      put_fs_long (ppp->xmit_async_map[0], l);
+      put_user (ppp->xmit_async_map[0], (int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
 		  l, ppp->xmit_async_map[0]));
     }
@@ -1480,7 +1480,7 @@
   case PPPIOCSASYNCMAP:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp->xmit_async_map[0] = get_fs_long (l);
+      ppp->xmit_async_map[0] = get_user ((int *) l);
       bset (ppp->xmit_async_map, PPP_FLAG);
       bset (ppp->xmit_async_map, PPP_ESC);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n",
@@ -1491,7 +1491,7 @@
   case PPPIOCRASYNCMAP:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp->recv_async_map = get_fs_long (l);
+      ppp->recv_async_map = get_user ((int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n",
 		  ppp->recv_async_map));
     }
@@ -1500,7 +1500,7 @@
   case PPPIOCGUNIT:
     error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      put_fs_long (ppp->dev->base_addr, l);
+      put_user (ppp->dev->base_addr, (int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr));
     }
     break;
@@ -1508,7 +1508,7 @@
   case PPPIOCSINPSIG:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp->inp_sig     = (int) get_fs_long (l);
+      ppp->inp_sig     = get_user ((int *) l);
       ppp->inp_sig_pid = current->pid;
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set input signal %d\n", ppp->inp_sig));
     }
@@ -1517,7 +1517,7 @@
   case PPPIOCSDEBUG:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      ppp_debug = (int) get_fs_long (l);
+      ppp_debug = get_int ((int *) l);
       ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
       ppp_debug &= 0xff;
       PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n", 
@@ -1528,7 +1528,7 @@
   case PPPIOCGDEBUG:
     error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      put_fs_long ((long) (ppp_debug | (ppp_debug_netpackets << 8)), l);
+      put_user ((long) (ppp_debug | (ppp_debug_netpackets << 8)), (int *) l);
       PRINTKN (3,(KERN_INFO "ppp_ioctl: get debug level %d\n", 
 		  ppp_debug | (ppp_debug_netpackets << 8)));
     }
@@ -1596,7 +1596,7 @@
   case PPPIOCSMAXCID:
     error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
     if (error == 0) {
-      temp_i = (int) get_fs_long (l) + 1;
+      temp_i = get_user ((int *) l) + 1;
       PRINTKN (3,(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i));
       if (ppp->slcomp != NULL)
 	slhc_free (ppp->slcomp);
@@ -2007,7 +2007,7 @@
   register unsigned char next_ch;
 
   while (count-- > 0) {
-    next_ch = (unsigned char) get_fs_byte (in);
+    next_ch = (unsigned char) get_user (in);
 
     *out++  = hex[(next_ch >> 4) & 0x0F];
     *out++  = hex[next_ch        & 0x0F];
@@ -2021,7 +2021,7 @@
   register unsigned char next_ch;
 
   while (count-- > 0) {
-    next_ch = (unsigned char) get_fs_byte (in);
+    next_ch = (unsigned char) get_user (in);
 
     if (next_ch < 0x20 || next_ch > 0x7e)
       *out++ = '.';
diff -u --recursive --new-file v1.3.3/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v1.3.3/linux/drivers/net/sk_g16.c	Tue Jun  6 11:22:10 1995
+++ linux/drivers/net/sk_g16.c	Thu Jun 22 10:29:03 1995
@@ -1529,7 +1529,7 @@
 	 * not to be concerned (see Data sheet)
 	 */
 
-	if (rmdstat & (RX_STP | RX_ENP) != (RX_STP | RX_ENP))
+	if ((rmdstat & (RX_STP | RX_ENP)) != (RX_STP | RX_ENP))
 	{
 	    /* Start of a frame > 1518 Bytes ? */
 
diff -u --recursive --new-file v1.3.3/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.3.3/linux/drivers/net/slip.c	Tue Jun  6 12:23:16 1995
+++ linux/drivers/net/slip.c	Mon Jun 26 11:06:52 1995
@@ -996,19 +996,19 @@
 		return 0;
 
 	case SIOCGIFENCAP:
-		err = verify_area(VERIFY_WRITE, arg, sizeof(long));
+		err = verify_area(VERIFY_WRITE, arg, sizeof(int));
 		if (err)  {
 			return -err;
 		}
-		put_fs_long(sl->mode, (long *)arg);
+		put_user(sl->mode, (int *)arg);
 		return 0;
 
 	case SIOCSIFENCAP:
-		err = verify_area(VERIFY_READ, arg, sizeof(long));
+		err = verify_area(VERIFY_READ, arg, sizeof(int));
 		if (err)  {
 			return -err;
 		}
-		tmp = get_fs_long((long *)arg);
+		tmp = get_user((int *)arg);
 #ifndef SL_INCLUDE_CSLIP
 		if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))  {
 			return -EINVAL;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v1.3.3/linux/drivers/scsi/53c7,8xx.c	Wed Jun  7 11:48:09 1995
+++ linux/drivers/scsi/53c7,8xx.c	Mon Jun 26 11:32:57 1995
@@ -7,6 +7,7 @@
 
 
 #define PERM_OPTIONS (OPTION_IO_MAPPED|OPTION_DEBUG_TEST1)
+
 /*
  * Define SCSI_MALLOC to use scsi_malloc instead of kmalloc.  Other than
  * preventing deadlock, I'm not sure why we'd want to do this.
@@ -181,12 +182,12 @@
 static int NCR53c8xx_script_len;
 static int NCR53c8xx_dsa_len;
 static void NCR53c7x0_intr(int irq, struct pt_regs * regs);
-static int halt (struct Scsi_Host *host);
+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, unsigned long *dsa);
-static int print_insn (struct Scsi_Host *host, unsigned long *insn,
+static void print_dsa (struct Scsi_Host *host, u32 *dsa);
+static int print_insn (struct Scsi_Host *host, u32 *insn,
     char *prefix, int kernel);
 
 static void NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
@@ -271,8 +272,8 @@
 struct pci_chip {
     unsigned short pci_device_id;
     int chip;
-    int max_revision;
     int min_revision;
+    int max_revision;
 };
 
 static struct pci_chip pci_chip_ids[] = { 
@@ -351,7 +352,7 @@
 	} else {
 	    overrides[commandline_current].data.pci.bus = ints[1];
 	    overrides[commandline_current].data.pci.device = ints[2];
-	    overrides[commandline_current].data.pci.device = ints[3];
+	    overrides[commandline_current].data.pci.function = ints[3];
     	    overrides[commandline_current].options = (ints[0] >= 4) ?
     	    	ints[4] : 0;
 	}
@@ -463,7 +464,7 @@
 
 /* Only the ISTAT register is readable when the NCR is running, so make 
    sure it's halted. */
-    halt(host);
+    ncr_halt(host);
 
 /* 
  * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
@@ -533,7 +534,7 @@
 	    case DMODE_BL_4: i = 4; break;
 	    case DMODE_BL_8: i = 8; break;
 	    case DMODE_BL_16: i = 16; break;
-            default: i = 0;
+	     default: i = 0;
 	    }
 	    printk ("scsi%d : burst length %d\n", host->host_no, i);
 	}
@@ -608,7 +609,7 @@
 
     hostdata->issue_queue = hostdata->running_list = 
     	hostdata->finished_queue = NULL;
-    hostdata->issue_dsa_head = NULL;
+    hostdata->issue_dsa_head = 0;
     hostdata->issue_dsa_tail = NULL;
 
     if (hostdata->init_save_regs)
@@ -671,7 +672,7 @@
  */
 
 static int normal_init (Scsi_Host_Template *tpnt, int board, int chip, 
-    int base, int io_port, int irq, int dma, int pci_valid, 
+    u32 base, int io_port, int irq, int dma, int pci_valid, 
     unsigned char pci_bus, unsigned char pci_device_fn, int options) {
     struct Scsi_Host *instance;
     struct NCR53c7x0_hostdata *hostdata;
@@ -708,7 +709,7 @@
 	printk ("scsi-ncr53c7,8xx : for better reliability and performance, please use the\n" 
 		"        PCI override instead.\n"
 		"	 Syntax : ncr53c8{10,15,20,25}=pci,<bus>,<device>,<function>\n"
-		"	          <bus> and <device> are usually 0.\n");
+		"                 <bus> and <device> are usually 0.\n");
 
     if (options & OPTION_DEBUG_PROBE_ONLY) {
     	printk ("scsi-ncr53c7,8xx : probe only enabled, aborting initialization\n");
@@ -762,7 +763,7 @@
     hostdata = (struct NCR53c7x0_hostdata *) 
     	instance->hostdata;
     hostdata->size = size;
-    hostdata->script_count = script_len / sizeof(long);
+    hostdata->script_count = script_len / sizeof(u32);
     hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
     hostdata->board = board;
     hostdata->chip = chip;
@@ -786,7 +787,7 @@
      */
 
     if (base) {
-	instance->base = (unsigned char *) base;
+	instance->base = (unsigned char*) (unsigned long) base;
 	/* Check for forced I/O mapping */
     	if (!(options & OPTION_IO_MAPPED)) {
 	    options |= OPTION_MEMORY_MAPPED;
@@ -831,7 +832,7 @@
 
 
 /* 
- * Function : static int ncr_init(Scsi_Host_Template *tpnt, int board, 
+ * Function : static int pci_init(Scsi_Host_Template *tpnt, int board, 
  *	int chip, int bus, int device_fn, int options)
  *
  * Purpose : initializes a NCR53c800 family based on the PCI
@@ -851,10 +852,11 @@
  *
  */
 
-static int ncr_init (Scsi_Host_Template *tpnt, int board, int chip, 
+static int ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip, 
     unsigned char bus, unsigned char device_fn, int options) {
     unsigned short vendor_id, device_id, command;
-    unsigned long base, io_port; 
+    u32 base;
+    int io_port; 
     unsigned char irq, revision;
     int error, expected_chip;
     int expected_id = -1, max_revision = -1, min_revision = -1;
@@ -885,8 +887,8 @@
 	(error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE,
 	    &irq))) {
 	printk ("scsi-ncr53c7,8xx : error %s not initializing due to error reading configuration space\n"
-		"	 perhaps you specified an incorrect PCI bus, device, or function.\n"
-		, pcibios_strerror(error));
+		"        perhaps you specified an incorrect PCI bus, device, or function.\n"
+		, pci_strbioserr(error));
 	return -1;
     }
 
@@ -907,13 +909,13 @@
 
     if (command & PCI_COMMAND_IO) { 
 	if ((io_port & 3) != 1) {
-	    printk ("scsi-ncr53c7,8xx : disabling I/O mapping since base address 0 (0x%lx)\n"
+	    printk ("scsi-ncr53c7,8xx : disabling I/O mapping since base address 0 (0x%x)\n"
     	    	    "        bits 0..1 indicate a non-IO mapping\n", io_port);
 	    io_port = 0;
 	} else
 	    io_port &= PCI_BASE_ADDRESS_IO_MASK;
     } else {
-    	io_port = 0;
+	    io_port = 0;
     }
 
     if (command & PCI_COMMAND_MEMORY) {
@@ -924,7 +926,7 @@
 	} else 
 	    base &= PCI_BASE_ADDRESS_MEM_MASK;
     } else {
-    	base = 0;
+	    base = 0;
     }
 	
     if (!io_port && !base) {
@@ -959,7 +961,7 @@
 	printk ("scsi-ncr53c7,8xx : warning : revision of %d is less than %d.\n",
 	    (int) revision, min_revision);
 
-    return normal_init (tpnt, board, chip, (int) base, (int) io_port, 
+    return normal_init (tpnt, board, chip, (int) base, io_port, 
 	(int) irq, DMA_NONE, 1, bus, device_fn, options);
 }
 
@@ -988,7 +990,7 @@
     for (current_override = count = 0; current_override < OVERRIDE_LIMIT; 
 	 ++current_override) {
 	 if (overrides[current_override].pci ? 
-	    !ncr_init (tpnt, overrides[current_override].board,
+	    !ncr_pci_init (tpnt, overrides[current_override].board,
 		overrides[current_override].chip,
 		(unsigned char) overrides[current_override].data.pci.bus,
 		(((overrides[current_override].data.pci.device
@@ -1013,7 +1015,7 @@
 		!pcibios_find_device (PCI_VENDOR_ID_NCR, 
 		    pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, 
 		    &pci_device_fn) && 
-	        !ncr_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, 
+	        !ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip, 
 		    pci_bus, pci_device_fn, /* no options */ 0); 
 		++count, ++pci_index);
     }
@@ -1042,7 +1044,7 @@
 	host->hostdata;
     unsigned char tmp;
     int i, ncr_to_memory, memory_to_ncr, ncr_to_ncr;
-    unsigned long base;
+    u32 base;
     NCR53c7x0_local_setup(host);
 
 
@@ -1053,18 +1055,23 @@
 	sizeof(SCRIPT));
     /* Fixup labels */
     for (i = 0; i < PATCHES; ++i) 
-	hostdata->script[LABELPATCHES[i]] += 
-    	    (unsigned long) hostdata->script;
+	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, 
-    	(long) &(hostdata->NCR53c7xx_msg_abort));
+    	virt_to_bus(&hostdata->NCR53c7xx_msg_abort));
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject, 
-    	(long) &(hostdata->NCR53c7xx_msg_reject));
+    	virt_to_bus(&hostdata->NCR53c7xx_msg_reject));
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero, 
-    	(long) &(hostdata->NCR53c7xx_zero));
+    	virt_to_bus(&hostdata->NCR53c7xx_zero));
     patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink, 
-    	(long) &(hostdata->NCR53c7xx_sink));
+    	virt_to_bus(&hostdata->NCR53c7xx_sink));
+
+    /* 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.
@@ -1085,12 +1092,12 @@
     tmp &= (DMODE_800_ERL | DMODE_BL_MASK);
 
     if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
-    	base = (long) host->io_port;
+    	base = (u32) host->io_port;
     	memory_to_ncr = tmp|DMODE_800_DIOM;
     	ncr_to_memory = tmp|DMODE_800_SIOM;
     	ncr_to_ncr = tmp|DMODE_800_DIOM|DMODE_800_SIOM;
     } else {
-    	base = (long) host->base;
+    	base = virt_to_phys(host->base);
     	ncr_to_ncr = memory_to_ncr = ncr_to_memory = tmp;
     }
 
@@ -1112,18 +1119,20 @@
     patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
     patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_ncr, ncr_to_ncr);
 
-    patch_abs_32 (hostdata->script, 0, issue_dsa_head, 
-    	(long) &(hostdata->issue_dsa_head));
-    patch_abs_32 (hostdata->script, 0, msg_buf, (long) &(hostdata->msg_buf));
-    patch_abs_32 (hostdata->script, 0, reconnect_dsa_head, 
-    	(long) &(hostdata->reconnect_dsa_head));
-    patch_abs_32 (hostdata->script, 0, reselected_identify, 
-    	(long) &(hostdata->reselected_identify));
-    patch_abs_32 (hostdata->script, 0, reselected_tag, 
-    	(long) &(hostdata->reselected_tag));
-
-    patch_abs_32 (hostdata->script, 0, test_dest, (long) &(hostdata->test_dest));
-    patch_abs_32 (hostdata->script, 0, test_src, (long) &(hostdata->test_source));
+    patch_abs_32 (hostdata->script, 0, issue_dsa_head,
+		  virt_to_bus((void*)&hostdata->issue_dsa_head));
+    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, reselected_identify,
+		  virt_to_bus((void*)&hostdata->reselected_identify));
+    patch_abs_32 (hostdata->script, 0, reselected_tag,
+		  virt_to_bus((void*)&hostdata->reselected_tag));
+
+    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));
 
 
     /*
@@ -1132,7 +1141,7 @@
      */
 
 /* 
- * XXX - for cleanness, E_* fields should be type unsigned long *
+ * XXX - for cleanness, E_* fields should be type u32 *
  * and should reflect the _relocated_ addresses.  Change this.
  */
     hostdata->E_accept_message = Ent_accept_message;
@@ -1178,8 +1187,8 @@
     	    host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - 
     	    Ent_dsa_zero);
 
-    printk("scsi%d : NCR code relocated to 0x%lx\n", host->host_no,
-	(unsigned long) hostdata->script);
+    printk("scsi%d : NCR code relocated to 0x%p\n", host->host_no,
+	hostdata->script);
 }
 
 /*
@@ -1201,10 +1210,10 @@
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
-    unsigned long timeout, start;
+    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 */
@@ -1225,7 +1234,7 @@
     if (hostdata->issue_dsa_head) {
 	printk ("scsi%d : hostdata->issue_dsa_head corrupt before test 1\n",
 	    host->host_no);
-	hostdata->issue_dsa_head = NULL;
+	hostdata->issue_dsa_head = 0;
     }
 	
     if (hostdata->options & OPTION_DEBUG_TEST1) {
@@ -1234,14 +1243,15 @@
 	hostdata->test_completed = -1;
 	hostdata->test_dest = 0;
 	hostdata->test_source = 0xdeadbeef;
-	start = ((unsigned long) hostdata->script) + hostdata->E_test_1;
+	start = virt_to_bus(hostdata->script) + hostdata->E_test_1;
     	hostdata->state = STATE_RUNNING;
 	printk ("scsi%d : test 1", host->host_no);
 	NCR53c7x0_write32 (DSP_REG, start);
+	mb();
 	printk (" started\n");
 	sti();
 
-	timeout = jiffies + 50;	/* arbitrary */
+	timeout = jiffies + 5 * HZ / 10;	/* arbitrary */
 	while ((hostdata->test_completed == -1) && jiffies < timeout)
 		barrier();
 
@@ -1251,31 +1261,31 @@
 		(hostdata->test_dest == 0xdeadbeef) ? 
 		    " due to lost interrupt.\n"
 		    "         Please verify that the correct IRQ is being used for your board,\n"
-		    "	      and that the motherboard IRQ jumpering matches the PCI setup on\n"
+		    "         and that the motherboard IRQ jumpering matches the PCI setup on\n"
 		    "         PCI systems.\n"
 		    "         If you are using a NCR53c810 board in a PCI system, you should\n" 
 		    "         also verify that the board is jumpered to use PCI INTA, since\n"
 		    "         most PCI motherboards lack support for INTB, INTC, and INTD.\n"
 		    : "");
 	else if (hostdata->test_completed != 1) 
-	    printk ("scsi%d : test 1 bad interrupt value (%ld)\n", host->host_no,
+	    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",
+                    "        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%lx (script at 0x%lx, start at 0x%lx)\n",
-		host->host_no, (unsigned long) NCR53c7x0_read32(DSP_REG),
-		(unsigned long) hostdata->script, start);
-	    printk ("scsi%d : DSPS = 0x%lx\n", host->host_no,
-		(unsigned long) NCR53c7x0_read32(DSPS_REG));
+	    printk ("scsi%d : DSP = 0x%x (script at 0x%p, start at 0x%x)\n",
+		host->host_no, 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;
 	}
@@ -1285,11 +1295,11 @@
     if (hostdata->issue_dsa_head) {
 	printk ("scsi%d : hostdata->issue_dsa_head corrupt after test 1\n",
 	    host->host_no);
-	hostdata->issue_dsa_head = NULL;
+	hostdata->issue_dsa_head = 0;
     }
 
     if (hostdata->options & OPTION_DEBUG_TEST2) {
-	unsigned long dsa[48];
+	u32 dsa[48];
     	unsigned char identify = IDENTIFY(0, 0);
 	unsigned char cmd[6];
 	unsigned char data[36];
@@ -1301,18 +1311,18 @@
     	cmd[4] = sizeof(data); 
 
     	dsa[2] = 1;
-    	dsa[3] = (unsigned long) &identify;
+    	dsa[3] = virt_to_bus(&identify);
     	dsa[4] = 6;
-    	dsa[5] = (unsigned long) &cmd;
+    	dsa[5] = virt_to_bus(&cmd);
     	dsa[6] = sizeof(data);
-    	dsa[7] = (unsigned long) &data;
+    	dsa[7] = virt_to_bus(&data);
     	dsa[8] = 1;
-    	dsa[9] = (unsigned long) &status;
+    	dsa[9] = virt_to_bus(&status);
     	dsa[10] = 1;
-    	dsa[11] = (unsigned long) &msg;
+    	dsa[11] = virt_to_bus(&msg);
 
 	for (i = 0; i < 3; ++i) {
-    	    cli();
+	    cli();
 	    if (!hostdata->idle) {
 		printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
 		restore_flags(flags);
@@ -1324,16 +1334,18 @@
 	    hostdata->idle = 0;
 	    hostdata->test_running = 2;
 	    hostdata->test_completed = -1;
-	    start = ((unsigned long) hostdata->script) + hostdata->E_test_2;
+	    start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
 	    hostdata->state = STATE_RUNNING;
-	    NCR53c7x0_write32 (DSA_REG, (unsigned long) dsa);
+	    NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
 	    NCR53c7x0_write32 (DSP_REG, start);
+	    mb();
 	    sti();
 
-	    timeout = jiffies + 500;	/* arbitrary */
+	    timeout = jiffies + 5 * HZ;	/* arbitrary */
 	    while ((hostdata->test_completed == -1) && jiffies < timeout)
 	    	barrier();
 	    NCR53c7x0_write32 (DSA_REG, 0);
+	    mb();
 
 	    if (hostdata->test_completed == 2) {
 		data[35] = 0;
@@ -1361,7 +1373,7 @@
 	    if (hostdata->issue_dsa_head) {
 		printk ("scsi%d : hostdata->issue_dsa_head corrupt after test 2 id %d\n",
 		    host->host_no, i);
-		hostdata->issue_dsa_head = NULL;
+		hostdata->issue_dsa_head = 0;
 	}
 	}
     }
@@ -1390,16 +1402,16 @@
     memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
     	hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
 
-    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(long), 
-    	dsa_temp_jump_resume, ((unsigned long) cmd->dsa) + 
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_jump_resume, virt_to_bus(cmd->dsa) + 
     	Ent_dsa_jump_resume - Ent_dsa_zero);
-    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(long),
+    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
     	dsa_temp_lun, c->lun);
-    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(long),
-    	dsa_temp_dsa_next, ((unsigned long) cmd->dsa) + A_dsa_next);
-    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(long), 
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_dsa_next, virt_to_bus(cmd->dsa) + A_dsa_next);
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
     	dsa_temp_sync, hostdata->sync[c->target].select_indirect);
-    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(long),
+    patch_abs_rwri_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
     	dsa_temp_target, c->target);
 }
 
@@ -1424,21 +1436,21 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
     	host->hostdata;
     unsigned long flags;
-    char **prev, *search;
+    volatile u32 *prev, search;
     int i;
 
     save_flags(flags);
     cli();
     for (i = 0; i < 2; ++i) {
-    	for (search = (char *) (i ? hostdata->issue_dsa_head : 
-    	    	hostdata->reconnect_dsa_head), prev = (char **) (i ? 
-    	    	&(hostdata->issue_dsa_head) : &(hostdata->reconnect_dsa_head));
-    	     search && (search + hostdata->dsa_start) != (char *) cmd->dsa;
-    	     prev = (char **) (search + hostdata->dsa_next), 
+    	for (search = (i ? hostdata->issue_dsa_head :
+    	    	hostdata->reconnect_dsa_head), prev = (i ? 
+    	    	&hostdata->issue_dsa_head : &hostdata->reconnect_dsa_head);
+    	     search && ((char*)bus_to_virt(search) + hostdata->dsa_start) != (char *) cmd->dsa;
+    	     prev = (u32*) ((char*)bus_to_virt(search) + hostdata->dsa_next),
     	    	search = *prev);
 
     	if (search)
-    	    *prev = *(char **) (search + hostdata->dsa_next);
+    	    *prev = *(u32*) ((char*)bus_to_virt(search) + hostdata->dsa_next);
     }
 
     if (cmd->prev)
@@ -1479,7 +1491,7 @@
 #if 0
     Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
 #endif
-    unsigned long *dsp;
+    u32 *dsp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;		
     unsigned long flags;
@@ -1490,9 +1502,10 @@
      * dump the appropriate debugging information to standard 
      * output.  
      */
+
     save_flags(flags);
     cli();
-    dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
     for (bp = hostdata->breakpoints; bp && bp->address != dsp; 
     	bp = bp->next);
     if (!bp) 
@@ -1507,13 +1520,14 @@
 
     NCR53c7x0_write8 (hostdata->dmode, 
 	NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
+    mb();
 
     /*
      * And update the DSP register, using the size of the old 
      * instruction in bytes.
      */
 
-    restore_flags(flags);
+     restore_flags(flags);
 }
 
 /*
@@ -1552,6 +1566,7 @@
 	}
     /* Offset = 0, transfer period = divide SCLK by 4 */
 	NCR53c7x0_write8 (SXFER_REG, 0);
+	mb();
     }
     return 0;
 }
@@ -1599,7 +1614,7 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     int desire, divisor, i, limit;
-    unsigned long *script;
+    u32 *script;
     unsigned char scntl3, sxfer;
    
 /* Scale divisor by 10 to accommodate fractions */ 
@@ -1628,7 +1643,7 @@
 	hostdata->sync[target].select_indirect = (scntl3 << 24) | (target << 16) | 
 		(sxfer << 8);
 
-	script = (long *) hostdata->sync[target].script;
+	script = (u32*) hostdata->sync[target].script;
 
 	/* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
 	if ((hostdata->chip / 100) == 8) {
@@ -1670,13 +1685,13 @@
     Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;		
-    unsigned long dsps,*dsp;	/* Argument of the INT instruction */
+    u32 dsps,*dsp;	/* Argument of the INT instruction */
     NCR53c7x0_local_setup(host);
     dsps = NCR53c7x0_read32(DSPS_REG);
-    dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
 
     if (hostdata->options & OPTION_DEBUG_INTR) 
-	printk ("scsi%d : DSPS = 0x%lx\n", host->host_no, dsps);
+	printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
 
     switch (dsps) {
     case A_int_msg_1:
@@ -1692,14 +1707,14 @@
 	 */
 	case MESSAGE_REJECT:
 	    hostdata->dsp = hostdata->script + hostdata->E_accept_message /
-		sizeof(long);
+		sizeof(u32);
 	    hostdata->dsp_changed = 1;
 	    break;
 	case INITIATE_RECOVERY:
 	    printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
 		host->host_no);
 	    hostdata->dsp = hostdata->script + hostdata->E_reject_message /
-		sizeof(long);
+		sizeof(u32);
 	    hostdata->dsp_changed = 1;
 	}
 	return SPECIFIC_INT_NOTHING;
@@ -1718,26 +1733,26 @@
    	 */
 	    if (cmd->flags & CMD_FLAG_SDTR) {
 		cmd->flags &= ~CMD_FLAG_SDTR; 
-		synchronous (host, c->target, (unsigned char *) 
+		synchronous (host, c->target, (unsigned char *)
 		    hostdata->msg_buf);
 		hostdata->dsp = hostdata->script + hostdata->E_accept_message /
-		    sizeof(long);
+		    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);
+			hostdata->msg_buf);
 		} else {
 		    hostdata->msg_buf[4] = 0;		/* 0 offset = async */
 		}
 
 		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
 		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, 
-		    hostdata->msg_buf);
+		    virt_to_bus((void*)hostdata->msg_buf));
 		hostdata->dsp = hostdata->script + 
-		hostdata->E_respond_message / sizeof(long);
+		hostdata->E_respond_message / sizeof(u32);
 		hostdata->dsp_changed = 1;
 	    }
 
@@ -1760,7 +1775,7 @@
 	/* Fall through to abort */
     case A_int_msg_wdtr:
 	hostdata->dsp = hostdata->script + hostdata->E_reject_message /
-	    sizeof(long);
+	    sizeof(u32);
 	hostdata->dsp_changed = 1;
 	return SPECIFIC_INT_NOTHING;
     case A_int_err_unexpected_phase:
@@ -1771,14 +1786,14 @@
 	printk ("scsi%d : selected by target %d\n", host->host_no,
 	    (int) NCR53c7x0_read8(SSID_REG_800) &7);
 	hostdata->dsp = hostdata->script + hostdata->E_target_abort / 
-    	    sizeof(long);
+    	    sizeof(u32);
 	hostdata->dsp_changed = 1;
 	return SPECIFIC_INT_NOTHING;
     case A_int_err_unexpected_reselect:
 	printk ("scsi%d : unexpected reselect by target %d\n", host->host_no,
 	    (int) NCR53c7x0_read8(SSID_REG_800));
 	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-    	    sizeof(long);
+    	    sizeof(u32);
 	hostdata->dsp_changed = 1;
 	return SPECIFIC_INT_NOTHING;
 /*
@@ -1841,10 +1856,10 @@
 	 */
 
     	patch_dsa_32 (cmd->dsa, dsa_dataout, 0, hostdata->E_other_transfer);
-    	patch_dsa_32 (cmd->dsa, dsa_datain, 0, cmd->data_transfer_start);
+    	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] = (unsigned long) c->sense_buffer;
+    	cmd->data_transfer_start[1] = virt_to_bus(c->sense_buffer);
 
 	cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
     	    << 24) | DBC_TCI_TRUE;
@@ -1863,14 +1878,14 @@
 	 * Restart command as a REQUEST SENSE.
 	 */
 	hostdata->dsp = hostdata->script + hostdata->E_select /
-	    sizeof(long);
+	    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 = hostdata->script + hostdata->E_schedule / 
-		sizeof(long);
+		sizeof(u32);
 	hostdata->dsp_changed = 1;
 	if (cmd)
 	    abnormal_finished (cmd, DID_ERROR << 16);
@@ -1880,13 +1895,13 @@
 	hostdata->idle = 1;
 	hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
 	if (hostdata->options & OPTION_DEBUG_INTR)
-	    printk("scsi%d : test%ld complete\n", host->host_no,
+	    printk("scsi%d : test %d complete\n", host->host_no,
 		hostdata->test_completed);
 	return SPECIFIC_INT_NOTHING;
 #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%lx scheduled\n", host->host_no,
+	    printk("scsi%d : new I/O 0x%x scheduled\n", host->host_no,
 	    	NCR53c7x0_read32(DSA_REG));
 	}
 	return SPECIFIC_INT_RESTART;
@@ -1908,7 +1923,7 @@
 #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%lx\n", host->host_no,
+	    printk("scsi%d : DSA loaded with 0x%x\n", host->host_no,
 		NCR53c7x0_read32(DSA_REG));
 	}
 	return SPECIFIC_INT_RESTART; 
@@ -1925,14 +1940,14 @@
 #ifdef A_int_debug_head
     case A_int_debug_head:
 	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
-	    printk("scsi%d : issue_dsa_head now 0x%lx\n",
-		host->host_no, (unsigned long) hostdata->issue_dsa_head);
+	    printk("scsi%d : issue_dsa_head now 0x%x\n",
+		host->host_no, hostdata->issue_dsa_head);
 	}
     return SPECIFIC_INT_RESTART;
 #endif
     default:
 	if ((dsps & 0xff000000) == 0x03000000) {
-	     printk ("scsi%d : misc debug interrupt 0x%lx\n",
+	     printk ("scsi%d : misc debug interrupt 0x%x\n",
 		host->host_no, dsps);
 	    return SPECIFIC_INT_RESTART;
 	}
@@ -1989,7 +2004,7 @@
 "ms <addr> <size> <value>	- store memory\n"
 "rp <num> <size>		- print register\n"
 "rs <num> <size> <value> 	- store register\n"
-"s				- single step\n"	
+"s				- single step\n"
 "tb				- begin trace \n"
 "te				- end trace\n";
 
@@ -1999,7 +2014,7 @@
  */
 
 static int debugger_fn_bc (struct Scsi_Host *host, struct debugger_token *token,
-    unsigned long args[]) {
+    u32 args[]) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	instance->hostdata;
     struct NCR53c7x0_break *bp, **prev;
@@ -2031,7 +2046,7 @@
 
 
 static int debugger_fn_bl (struct Scsi_Host *host, struct debugger_token *token,
-    unsigned long args[]) {
+    u32 args[]) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     struct NCR53c7x0_break *bp;
@@ -2057,7 +2072,7 @@
 	    len = strlen(buf);
 	    if ((bp->old[0] & (DCMD_TYPE_MASK << 24)) ==
 		(DCMD_TYPE_MMI << 24)) {
-		sprintf(buf + len, "%08x\n", * (long *) bp->addr);
+		sprintf(buf + len, "%08x\n", * (u32 *) bp->addr);
 	    } else {
 		sprintf(buf + len, "\n");
 	    }
@@ -2069,13 +2084,14 @@
 }
 
 static int debugger_fn_bs (struct Scsi_Host *host, struct debugger_token *token,
-    unsigned long args[]) {
+    u32 args[]) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     struct NCR53c7x0_break *bp;
     char buf[80];
     size_t len;
     unsigned long flags;
+
     save_flags(flags);
     cli();
 
@@ -2093,10 +2109,10 @@
 	return -1;
     }
 
-    bp->address = (unsigned long *) args[0];
+    bp->address = (u32 *) args[0];
     memcpy ((void *) bp->old_instruction, (void *) bp->address, 8);
     bp->old_size = (((bp->old_instruction[0] >> 24) & DCMD_TYPE_MASK) ==
-	DCMD_TYPE_MMI ? 3 : 2;
+	DCMD_TYPE_MMI ? 3 : 2);
     bp->next = hostdata->breakpoints;
     hostdata->breakpoints = bp->next;
     memcpy ((void *) bp->address, (void *) hostdata->E_debug_break, 8);
@@ -2109,7 +2125,7 @@
 static const struct debugger_token {
     char *name;
     int numargs;
-    int (*fn)(struct debugger_token *token, unsigned long args[]);
+    int (*fn)(struct debugger_token *token, u32 args[]);
 } debugger_tokens[] = {
     TOKEN(bc,1), TOKEN(bl,0), TOKEN(bs,1), TOKEN(g,0), TOKEN(halt,0),
     {DT_help, "?", 0} , TOKEN(h,0), TOKEN(i,0), TOKEN(mp,2), 
@@ -2134,7 +2150,7 @@
     struct NCR53c7x0_hostadata *hostdata;	
     char input_buf[80], 			/* Kernel space copy of buf */
 	*ptr;					/* Pointer to argument list */
-    unsigned long args[3];			/* Arguments */
+    u32 args[3];				/* Arguments */
     int i, j, error, len;
 
     if (!(host = inode_to_host(inode)))
@@ -2192,6 +2208,7 @@
 	host->hostdata;
     int copy, left;
     unsigned long flags;
+    
     save_flags(flags);
     cli();
     while (buflen) {
@@ -2242,7 +2259,9 @@
      */
 
     NCR53c7x0_write8(ISTAT_REG_800, ISTAT_10_SRST);
+    mb();
     NCR53c7x0_write8(ISTAT_REG_800, 0);
+    mb();
     NCR53c7x0_write8(hostdata->dmode, hostdata->saved_dmode & ~DMODE_MAN);
 
 
@@ -2300,7 +2319,7 @@
     /* Enable active negation */
     NCR53c7x0_write8(STEST3_REG_800, STEST3_800_TE);
 
-    
+    mb();
 }
 
 /*
@@ -2331,12 +2350,12 @@
 	dataout;
     int data_transfer_instructions, /* Count of dynamic instructions */
     	i;			/* Counter */
-    unsigned long *cmd_datain,	/* Address of datain/dataout code */
+    u32 *cmd_datain,		/* Address of datain/dataout code */
 	*cmd_dataout;		/* Incremented as we assemble */
 #ifdef notyet
     void *real;			/* Real address */
     int size;			/* Size of *tmp */
-    int	alignment;		/* Alignment adjustment (0 - 4) */
+    int alignment;		/* Alignment adjustment (0 - sizeof(long)-1) */
 #endif
     unsigned long flags;
     NCR53c7x0_local_setup(cmd->host);
@@ -2367,9 +2386,9 @@
 #else
     /* kmalloc() can allocate any size, but historically has returned 
        unaligned addresses, so we need to allow for alignment */
-	    size = hostdata->max_cmd_size + 4;
+	    size = hostdata->max_cmd_size + sizeof(void*);
 	    real = kmalloc (size, GFP_ATOMIC);
-	    alignment = 4 - (((unsigned) real) & 3);
+	    alignment = sizeof(void*) - (((unsigned) real) & (sizeof(void*)-1));
 	    tmp = (struct NCR53c7x0_cmd *) (((char *) real) + alignment);
 	    if (!tmp)
 		break;
@@ -2397,7 +2416,6 @@
     	}
     }
 
-
     /*
      * Decide whether we need to generate commands for DATA IN,
      * DATA OUT, neither, or both based on the SCSI command 
@@ -2465,7 +2483,6 @@
     if (data_transfer_instructions < 2)
     	data_transfer_instructions = 2;
 
-
     /*
      * Initialize Linux specific fields.
      */
@@ -2479,7 +2496,7 @@
      */
 
     tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end - 
-    	hostdata->dsa_start) / sizeof(long);
+    	hostdata->dsa_start) / sizeof(u32);
     tmp->data_transfer_end = tmp->data_transfer_start + 
     	2 * data_transfer_instructions;
 
@@ -2498,8 +2515,8 @@
     if (hostdata->dsa_fixup)
     	hostdata->dsa_fixup(tmp);
 
-    patch_dsa_32(tmp->dsa, dsa_next, 0, NULL);
-    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, cmd);
+    patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
     patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
     	select_indirect);
     /*
@@ -2512,26 +2529,24 @@
 #else
     tmp->select[0] = IDENTIFY (0, cmd->lun);
 #endif
-    patch_dsa_32(tmp->dsa, dsa_msgout, 1, tmp->select);
+    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, cmd->cmnd);
-    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
-    	cmd_dataout : hostdata->script + hostdata->E_other_transfer / 
-    	    sizeof (long));
-    patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ? 
-    	cmd_datain : hostdata->script + hostdata->E_other_transfer / 
-    	    sizeof (long));
+    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);
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, (((unsigned long) &cmd->result) + 1));
+    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, &cmd->result);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
-    	&(hostdata->NCR53c7xx_msg_nop));
+    	virt_to_bus(&hostdata->NCR53c7xx_msg_nop));
 
     
     /*
@@ -2571,12 +2586,12 @@
 
     for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, 
 	cmd_dataout += 4, ++i) {
-	unsigned long buf = (unsigned long) (cmd->use_sg ? 
-	    ((struct scatterlist *)cmd->buffer)[i].address :
-	    cmd->request_buffer);
-	unsigned long count = (unsigned long) (cmd->use_sg ?
+	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);
+	    cmd->request_bufflen;
 
 	if (datain) {
 	    cmd_datain[0] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
@@ -2585,8 +2600,8 @@
 	    cmd_datain[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
 		DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) | 
 		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
-	    cmd_datain[3] = (unsigned long) hostdata->script + 
-    	    	hostdata->E_msg_in;
+	    cmd_datain[3] = virt_to_bus(hostdata->script) +
+	        hostdata->E_msg_in;
 #if 0
 	    print_insn (host, cmd_datain, "dynamic ", 1);
 	    print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -2599,8 +2614,8 @@
 	    cmd_dataout[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
 		DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) | 
 		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
-	    cmd_dataout[3] = (unsigned long) hostdata->script + 
-    	    	hostdata->E_msg_in;
+	    cmd_dataout[3] = virt_to_bus(hostdata->script) +
+	        hostdata->E_msg_in;
 #if 0
 	    print_insn (host, cmd_dataout, "dynamic ", 1);
 	    print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -2617,8 +2632,8 @@
     if (datain) {
 	cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
     	    DBC_TCI_TRUE;
-	cmd_datain[1] = (unsigned long) hostdata->script + 
-    	    hostdata->E_other_transfer;
+	cmd_datain[1] = virt_to_bus(hostdata->script) +
+	    hostdata->E_other_transfer;
 #if 0
 	print_insn (host, cmd_datain, "dynamic jump ", 1);
 #endif
@@ -2636,8 +2651,8 @@
     if (dataout) {
 	cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
     	    DBC_TCI_TRUE;
-	cmd_dataout[1] = (unsigned long) hostdata->script + 
-    	    hostdata->E_other_transfer;
+	cmd_dataout[1] = virt_to_bus(hostdata->script) +
+	    hostdata->E_other_transfer;
 #if 0
 	print_insn (host, cmd_dataout, "dynamic jump ", 1);
 #endif
@@ -2762,23 +2777,24 @@
 		- hostdata->dsa_start;	
     	    	/* dsa start is negative, so subtraction is used */
 #if 0	
-	printk("scsi%d : new dsa is 0x%x\n", host->host_no, (unsigned) dsa);
+	printk("scsi%d : new dsa is 0x%p\n", host->host_no, dsa);
 #endif
 
     	if (hostdata->running_list)
     	    hostdata->running_list->prev = tmp;
 
-    	tmp->next = hostdata->running_list;
+    	tmp->next = (struct NCR53c7x0_cmd*) hostdata->running_list;
 
 	if (!hostdata->running_list)
-	    hostdata->running_list = tmp;
+	    hostdata->running_list = (struct NCR53c7x0_cmd*) tmp;
     	
 
 	if (hostdata->idle) {
 	    hostdata->idle = 0;
     	    hostdata->state = STATE_RUNNING;
-	    NCR53c7x0_write32 (DSP_REG,  ((unsigned long) hostdata->script) +
+	    NCR53c7x0_write32 (DSP_REG,  virt_to_bus(hostdata->script) +
 		hostdata->E_schedule);
+	    mb();
 	}
 
 /* XXX - make function */
@@ -2793,9 +2809,11 @@
 #if 0
 		printk ("scsi%d : no issue queue\n", host->host_no);
 #endif
-    	    	hostdata->issue_dsa_tail = hostdata->issue_dsa_head = dsa;
+    	    	hostdata->issue_dsa_tail = (u32 *) dsa;
+		hostdata->issue_dsa_head = virt_to_bus(dsa);
     	    	NCR53c7x0_write8(hostdata->istat, 
     	    	    NCR53c7x0_read8(hostdata->istat) | ISTAT_10_SIGP);
+		mb();
 		break;
 	    /*
 	     * Otherwise, we blindly perform an atomic write 
@@ -2806,9 +2824,9 @@
  	     */
  	    } else {
 		printk ("scsi%d : existing issue queue\n", host->host_no);
-	    /* XXX - Replace with XCHG or equivalent */
-    	    	hostdata->issue_dsa_tail = *((unsigned char **) 
-    	    	    (hostdata->issue_dsa_tail + hostdata->dsa_next)) = dsa;
+		hostdata->issue_dsa_tail[hostdata->dsa_next/sizeof(u32)]
+		  = virt_to_bus(dsa);
+		hostdata->issue_dsa_tail = (u32 *) dsa;
 	    /*
 	     * After which, one of two things will happen : 
 	     * The NCR will have scheduled a command, either this
@@ -2839,7 +2857,7 @@
 }
 
 
-int fix_pointers (unsigned long dsa) {
+int fix_pointers (u32 dsa) {
     return 0;
 }
 
@@ -2861,11 +2879,13 @@
     unsigned char sstat0_sist0, sist1, 		/* Registers */
 	    fatal; 				/* Did a fatal interrupt 
 						   occur ? */
+    int is_8xx_chip;
     NCR53c7x0_local_setup(host);
 
     fatal = 0;
   
-    if ((hostdata->chip / 100) == 8) {
+    is_8xx_chip = ((unsigned) (hostdata->chip - 800)) < 100;
+    if (is_8xx_chip) {
     	sstat0_sist0 = NCR53c7x0_read8(SIST0_REG_800);
 	udelay(1);
     	sist1 = NCR53c7x0_read8(SIST1_REG_800);
@@ -2878,9 +2898,9 @@
 	printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
 	    sstat0_sist0, sist1);
 
-    /* 250ms selection timeout */
-    if ((((hostdata->chip / 100) == 8) && (sist1 & SIST1_800_STO)) || 
-        (((hostdata->chip / 100) != 8) && (sstat0_sist0 & SSTAT0_700_STO))) {
+    /* selection timeout */
+    if ((is_8xx_chip && (sist1 & SIST1_800_STO)) ||
+        (!is_8xx_chip && (sstat0_sist0 & SSTAT0_700_STO))) {
 	fatal = 1;
 	if (hostdata->options & OPTION_DEBUG_INTR) {
 	    printk ("scsi%d : Selection Timeout\n", host->host_no);
@@ -2924,7 +2944,7 @@
 	    abnormal_finished(cmd, DID_ERROR << 16);
 	}
 	hostdata->dsp = hostdata->script + hostdata->E_schedule / 
-	    sizeof(long);
+	    sizeof(u32);
 	hostdata->dsp_changed = 1;
     /* SCSI PARITY error */
     } 
@@ -2941,7 +2961,7 @@
 
 	/* XXX - Reduce synchronous transfer rate! */
 	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-    	    sizeof(long);
+    	    sizeof(u32);
 	hostdata->dsp_changed = 1; 
     /* SCSI GROSS error */
     } 
@@ -2951,7 +2971,7 @@
 	printk("scsi%d : gross error\n", host->host_no);
 	/* XXX Reduce synchronous transfer rate! */
 	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-    	    sizeof(long);
+    	    sizeof(u32);
 	hostdata->dsp_changed = 1;
     /* Phase mismatch */
     } 
@@ -2981,17 +3001,20 @@
 #if 0
     	    if (NCR53c7x0_read8 (CTEST2_REG_800) & CTEST2_800_DDIR) {
     	    	NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_FLF);
+		mb();
     	    	while (!((hostdata->dstat = NCR53c7x0_read8(DSTAT_REG)) &
     	    	    DSTAT_DFE));
     	    } else 
 #endif
 	    {
     	    	NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_CLF);
+		mb();
     	    	while (NCR53c7x0_read8 (CTEST3_REG_800) & CTEST3_800_CLF);
     	    }
     	}
 
 	NCR53c7x0_write8 (STEST3_REG_800, STEST3_800_CSF);
+	mb();
 	while (NCR53c7x0_read8 (STEST3_REG_800) & STEST3_800_CSF);
     }
 #endif
@@ -3015,12 +3038,12 @@
     struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata */
     struct NCR53c7x0_cmd *cmd,			/* command which halted */
 	**cmd_prev_ptr;
-    unsigned long *dsa;				/* DSA */
+    u32 *dsa;					/* DSA */
     int done = 1;				/* Indicates when handler 
 						   should terminate */
     int interrupted = 0;			/* This HA generated 
 						   an interrupt */
-    unsigned long flags;				
+    unsigned long flags;
 
 #ifdef NCR_DEBUG
     char buf[80];				/* Debugging sprintf buffer */
@@ -3033,8 +3056,7 @@
 
     do {
 	done = 1;
-	for (host = first_host; host; host = hostdata->next ?
-	     hostdata->next : NULL) {
+	for (host = first_host; host; host = hostdata->next) {
     	    NCR53c7x0_local_setup(host);
 
 	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
@@ -3043,6 +3065,8 @@
 
 
 	    do {
+		int is_8xx_chip;
+
 		hostdata->dstat_valid = 0;
 		interrupted = 0;
 		/*
@@ -3058,8 +3082,9 @@
 		 * at the contents of the DSA register and continue running.
 		 */
 /* XXX - this is getting big, and should move to intr_intfly() */
+		is_8xx_chip = ((unsigned) (hostdata->chip - 800)) < 100;
 		if ((hostdata->options & OPTION_INTFLY) && 
-		    ((hostdata->chip / 100) == 8 && (istat & ISTAT_800_INTF))) {
+		    (is_8xx_chip && (istat & ISTAT_800_INTF))) {
 		    char search_found = 0;	/* Got at least one ? */
 		    done = 0;
 		    interrupted = 1;
@@ -3069,6 +3094,7 @@
 		     * is self-clearing.
 		     */
 		    NCR53c7x0_write8(hostdata->istat, istat|ISTAT_800_INTF);
+		    mb();
 
 		    if (hostdata->options & OPTION_DEBUG_INTR)
 			printk ("scsi%d : INTFLY\n", host->host_no); 
@@ -3170,10 +3196,10 @@
 		    if (hostdata->options & OPTION_700) {
 			cmd = (struct NCR53c7x0_cmd *) hostdata->current;
 		    } else {
-			dsa = (unsigned long *) NCR53c7x0_read32(DSA_REG);
+			dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
 			for (cmd = (struct NCR53c7x0_cmd *) 
 			    hostdata->running_list; cmd &&
-    	    	    	    (dsa + (hostdata->dsa_start / sizeof(long))) != 
+    	    	    	    (dsa + (hostdata->dsa_start / sizeof(u32))) != 
     	    	    	    	cmd->dsa;
 			    cmd = (struct NCR53c7x0_cmd *)(cmd->next));
 		    }
@@ -3212,12 +3238,14 @@
 	    #if 0
 			if (NCR53c7x0_read8 (CTEST2_REG_800) & CTEST2_800_DDIR) {
 			    NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_FLF);
+			    mb();
 			    while (!((hostdata->dstat = NCR53c7x0_read8(DSTAT_REG)) &
 				DSTAT_DFE));
 			} else 
 	    #endif
 			{
 			    NCR53c7x0_write8 (CTEST3_REG_800, CTEST3_800_CLF);
+			    mb();
 			    while (NCR53c7x0_read8 (CTEST3_REG_800) & CTEST3_800_CLF);
 			}
 		    }
@@ -3240,16 +3268,17 @@
 
 	    if (!hostdata->idle && hostdata->state == STATE_HALTED) {
 		if (!hostdata->dsp_changed) {
-		    hostdata->dsp = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+		    hostdata->dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
 		}
 			
 #if 0
-		printk("scsi%d : new dsp is 0x%lx\n", host->host_no, 
-		    (long) hostdata->dsp);
+		printk("scsi%d : new dsp is 0x%p\n", host->host_no, 
+		    hostdata->dsp);
 #endif
 		
 		hostdata->state = STATE_RUNNING;
-		NCR53c7x0_write32 (DSP_REG, (unsigned long) hostdata->dsp);
+		NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
+		mb();
 	    }
 	}
     } while (!done);
@@ -3274,7 +3303,7 @@
 	host->hostdata;
 
     hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
-	sizeof(long);
+	sizeof(u32);
     hostdata->dsp_changed = 1;
     printk ("scsi%d : DANGER : abort_connected() called \n",
 	host->host_no);
@@ -3304,7 +3333,7 @@
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
     *cmd) {
     NCR53c7x0_local_declare();
-    unsigned long dbc_dcmd, *dsp, *dsp_next;
+    u32 dbc_dcmd, *dsp, *dsp_next;
     unsigned char dcmd, sbcl;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
     	host->hostdata;
@@ -3323,12 +3352,12 @@
      * occurred, as well as which SCSI phase we are currently in.
      */
 
-    dsp_next = (unsigned long *) NCR53c7x0_read32(DSP_REG);
+    dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
 
     /*
      * Like other processors, the NCR adjusts the DSP pointer before
      * instruction decode.  Set the DSP address back to what it should
-     * be for this instruction based on its size (2 or 3 longs).
+     * be for this instruction based on its size (2 or 3 words).
      */
 
     dbc_dcmd = NCR53c7x0_read32(DBC_REG);
@@ -3372,7 +3401,7 @@
      * mismatches should only occur in the data transfer routines, or
      * when a command is being aborted.  
      */
-    if (dsp >= cmd->data_transfer_start & dsp < cmd->data_transfer_end) {
+    if (dsp >= cmd->data_transfer_start && dsp < cmd->data_transfer_end) {
 
 	/*
 	 * There are three instructions used in our data transfer routines with
@@ -3391,7 +3420,7 @@
 	    if (hostdata->options & OPTION_DEBUG_INTR) 
 		printk ("scsi%d : new phase = STATIN\n", host->host_no);
 	    hostdata->dsp = hostdata->script + hostdata->E_command_complete /
-    	    	sizeof(long);
+    	    	sizeof(u32);
 	    hostdata->dsp_changed = 1;
 	    return;
 	/*
@@ -3409,9 +3438,10 @@
 		    DCMD_BMI_OP_MOVE_I)) {
 		dsp[0] = dbc_dcmd;
 		dsp[1] = NCR53c7x0_read32(DNAD_REG);
-		NCR53c7x0_write32(TEMP_REG, (unsigned long) dsp);
+		NCR53c7x0_write32(TEMP_REG, virt_to_bus(dsp));
+		mb();
 		hostdata->dsp = hostdata->script + hostdata->E_msg_in /
-    	    	    sizeof(long);
+    	    	    sizeof(u32);
 		hostdata->dsp_changed = 1;
 	    } else {
 		printk("scsi%d : unexpected MSGIN in dynamic NCR code, dcmd=0x%x.\n",
@@ -3440,8 +3470,8 @@
      * Any other phase mismatches abort the currently executing command.
      */
     } else {
-	printk ("scsi%d : unexpected phase %s at dsp = 0x%x\n",
-	    host->host_no, phase, (unsigned) dsp);
+	printk ("scsi%d : unexpected phase %s at dsp = 0x%p\n",
+	    host->host_no, phase, dsp);
 	print_insn (host, dsp, "", 1);
 	print_insn (host, dsp_next, "", 1);
 	abort_connected(host);
@@ -3464,7 +3494,7 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     unsigned char dstat;	/* DSTAT */	
-    unsigned long *dsp,
+    u32 *dsp,
 	*next_dsp,		/* Current dsp */
     	*dsa,
 	dbc_dcmd;		/* DCMD (high eight bits) + DBC */
@@ -3483,10 +3513,10 @@
 	printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
 
     dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
-    next_dsp = (unsigned long *) NCR53c7x0_read32(DSP_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 = (unsigned long *) NCR53c7x0_read32(DSA_REG);
+    dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
 
     /*
      * DSTAT_ABRT is the aborted interrupt.  This is set whenever the 
@@ -3529,6 +3559,7 @@
 
 	    NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) & 
     	    	~DCNTL_SSM) | DCNTL_STD);
+	    mb();
 	    restore_flags(flags);
 	} else {
 	    printk("scsi%d : unexpected single step interrupt at\n"
@@ -3561,9 +3592,9 @@
      * can ignore it.
      */
 
-	if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(long))) &&
+	if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
 	    (dsp <= (hostdata->script + hostdata->E_select_msgout / 
-    	    sizeof(long) + 8))) || (hostdata->test_running == 2)) {
+    	    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);
@@ -3581,12 +3612,12 @@
 	} else {
 	    printk("scsi%d : illegal instruction ", host->host_no);
 	    print_insn (host, dsp, "", 1);
-	    printk("scsi%d : DSP=0x%lx, DCMD|DBC=0x%lx, DSA=0x%lx\n"
-	       "         DSPS=0x%lx, TEMP=0x%lx, DMODE=0x%x,\n" 
-	       "	 DNAD=0x%lx\n",
-	     host->host_no, (unsigned long) dsp, dbc_dcmd,
-	     (unsigned long) dsa, NCR53c7x0_read32(DSPS_REG),
-	     NCR53c7x0_read32(TEMP_REG), (int) NCR53c7x0_read8(hostdata->dmode),
+	    printk("scsi%d : DSP=0x%p, DCMD|DBC=0x%x, DSA=0x%p\n"
+	       "         DSPS=0x%x, TEMP=0x%x, DMODE=0x%x,\n" 
+	       "         DNAD=0x%x\n",
+	     host->host_no, dsp, dbc_dcmd,
+	     dsa, NCR53c7x0_read32(DSPS_REG),
+	     NCR53c7x0_read32(TEMP_REG), NCR53c7x0_read8(hostdata->dmode),
 	     NCR53c7x0_read32(DNAD_REG));
 	    panic("         mail drew@Colorado.EDU\n");
 	}
@@ -3598,11 +3629,11 @@
      */
     
     if (dstat & DSTAT_800_BF) {
-	printk("scsi%d : BUS FAULT, DSP=0x%lx, DCMD|DBC=0x%lx, DSA=0x%lx\n"
-	       "         DSPS=0x%lx, TEMP=0x%lx, DMODE=0x%x\n", 
-	     host->host_no, (unsigned long) dsp, NCR53c7x0_read32(DBC_REG),
-	     (unsigned long) dsa, NCR53c7x0_read32(DSPS_REG),
-	     NCR53c7x0_read32(TEMP_REG), (int) NCR53c7x0_read8(hostdata->dmode));
+	printk("scsi%d : BUS FAULT, DSP=0x%p, DCMD|DBC=0x%x, DSA=0x%p\n"
+	       "         DSPS=0x%x, TEMP=0x%x, DMODE=0x%x\n", 
+	     host->host_no, dsp, NCR53c7x0_read32(DBC_REG),
+	     dsa, NCR53c7x0_read32(DSPS_REG),
+	     NCR53c7x0_read32(TEMP_REG), NCR53c7x0_read8(hostdata->dmode));
 	print_dsa (host, dsa);
 	printk("scsi%d : DSP->\n", host->host_no);
 	print_insn(host, dsp, "", 1);
@@ -3652,12 +3683,13 @@
 
 /* All DMA interrupts are fatal.  Flush SCSI queue */
     NCR53c7x0_write8 (STEST3_REG_800, STEST3_800_CSF);
+    mb();
     while (NCR53c7x0_read8 (STEST3_REG_800) & STEST3_800_CSF);
 }
 
 /*
  * Function : static int print_insn (struct Scsi_Host *host, 
- * 	unsigned long *insn, int kernel)
+ * 	u32 *insn, int kernel)
  *
  * Purpose : print numeric representation of the instruction pointed
  * 	to by insn to the debugging or kernel message buffer
@@ -3669,10 +3701,10 @@
  * Inputs : host, insn - host, pointer to instruction, prefix - 
  *	string to prepend, kernel - use printk instead of debugging buffer.
  *
- * Returns : size, in longs, of instruction printed.
+ * Returns : size, in ints, of instruction printed.
  */
 
-static int print_insn (struct Scsi_Host *host, unsigned long *insn,
+static int print_insn (struct Scsi_Host *host, u32 *insn,
     char *prefix, int kernel) {
     char buf[80], 		/* Temporary buffer and pointer */
 	*tmp;			
@@ -3680,11 +3712,11 @@
     int size;
 
     dcmd = (insn[0] >> 24) & 0xff;
-    sprintf(buf, "%s%08lx : 0x%08lx 0x%08lx", (prefix ? prefix : ""), 
-	(unsigned long) insn, insn[0], insn[1]);
+    sprintf(buf, "%s%p : 0x%08x 0x%08x", (prefix ? prefix : ""), 
+	insn, insn[0], insn[1]);
     tmp = buf + strlen(buf);
     if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
-	sprintf (tmp, " 0x%08lx\n", insn[2]);
+	sprintf (tmp, " 0x%08x\n", insn[2]);
 	size = 3;
     } else {
 	sprintf (tmp, "\n");
@@ -3719,7 +3751,7 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) 
 	host->hostdata;
     unsigned long flags;
-    struct NCR53c7x0_cmd *curr, **prev;
+    volatile struct NCR53c7x0_cmd *curr, **prev;
     save_flags(flags);
     cli();
 
@@ -3733,10 +3765,10 @@
  * pull the command out of the old queue, and call it aborted.
  */
 
-    for (curr = (struct NCR53c7x0_cmd *) hostdata->issue_queue, 
-         prev = (struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
-	 curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
-         &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+    for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->issue_queue, 
+         prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
+	 curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **)
+         &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
 	*prev = (struct NCR53c7x0_cmd *) curr->next;
@@ -3758,10 +3790,10 @@
  * 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);
+    for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->running_list, 
+    	 prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->running_list);
+	 curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **) 
+         &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
 	restore_flags(flags);
@@ -3802,8 +3834,8 @@
  *
  * Returns : 0 on success.
  */
- 
-int 
+
+int
 NCR53c7xx_reset (Scsi_Cmnd *cmd) {
     NCR53c7x0_local_declare();
     unsigned long flags;
@@ -3814,8 +3846,9 @@
     struct NCR53c7x0_hostdata *hostdata = host ? 
     (struct NCR53c7x0_hostdata *) host->hostdata : NULL;
     NCR53c7x0_local_setup(host);
+
     save_flags(flags);
-    halt (host);
+    ncr_halt (host);
     NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
     udelay(25);	/* Minimum amount of time to assert RST */
     NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
@@ -3840,9 +3873,6 @@
     	cmd->scsi_done(cmd);
     }
     restore_flags(flags);
-
-    printk ("scsi%d : DANGER : NCR53c7xx_reset is NOP\n",
-	cmd->host->host_no);
     return SCSI_RESET_SUCCESS;
 }
 
@@ -3851,20 +3881,20 @@
  * therefore shares the scsicam_bios_param function.
  */
 
-static void print_dsa (struct Scsi_Host *host, unsigned long *dsa) {
+static void print_dsa (struct Scsi_Host *host, u32 *dsa) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
 	host->hostdata;
     int i, len;
     char *ptr;
 
-    printk("scsi%d : dsa at 0x%x\n"
-	    "        + %ld : dsa_msgout length = %lu, data = 0x%lx\n" ,
-    	    host->host_no, (unsigned) dsa, hostdata->dsa_msgout,
-    	    dsa[hostdata->dsa_msgout / sizeof(long)],
-	    dsa[hostdata->dsa_msgout / sizeof(long) + 1]);
+    printk("scsi%d : dsa at 0x%p\n"
+	    "        + %d : dsa_msgout length = %d, data = 0x%x\n" ,
+    	    host->host_no, dsa, hostdata->dsa_msgout,
+    	    dsa[hostdata->dsa_msgout / sizeof(u32)],
+	    dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
 
-    for (i = dsa[hostdata->dsa_msgout / sizeof(long)],
-	ptr = (char *) dsa[hostdata->dsa_msgout / sizeof(long) + 1]; i > 0;
+    for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
+	ptr = bus_to_virt(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]); i > 0;
 	ptr += len, i -= len) {
 	printk("               ");
 	len = print_msg (ptr);
@@ -3891,7 +3921,7 @@
     NCR53c7x0_local_setup(host);
     save_flags (flags);
     cli();
-    halt (host);
+    ncr_halt (host);
     hostdata->soft_reset(host);
 /* 
  * For now, we take the simplest solution : reset the SCSI bus. Eventually,
@@ -3910,7 +3940,7 @@
 
 
 /*
- * Function : static int halt (struct Scsi_Host *host)
+ * Function : static int ncr_halt (struct Scsi_Host *host)
  * 
  * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
  *
@@ -3920,7 +3950,7 @@
  */
 
 static int 
-halt (struct Scsi_Host *host) {
+ncr_halt (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     unsigned long flags;
     unsigned char istat, tmp;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h
--- v1.3.3/linux/drivers/scsi/53c7,8xx.h	Fri Apr 28 11:17:57 1995
+++ linux/drivers/scsi/53c7,8xx.h	Mon Jun 26 11:32:57 1995
@@ -39,6 +39,26 @@
 #ifndef NCR53c7x0_H
 #define NCR53c7x0_H
 
+#ifdef __alpha__
+
+# define ncr_readb(a)		((unsigned int)readb((unsigned long)(a)))
+# define ncr_readw(a)		((unsigned int)readw((unsigned long)(a)))
+# define ncr_readl(a)		((unsigned int)readl((unsigned long)(a)))
+# define ncr_writeb(v,a)	(writeb((v), (unsigned long)(a)))
+# define ncr_writew(v,a)	(writew((v), (unsigned long)(a)))
+# define ncr_writel(v,a)	(writel((v), (unsigned long)(a)))
+
+#else
+
+# define ncr_readb(a)		(*(unsigned char*)(a))
+# define ncr_readw(a)		(*(unsigned short*)(a))
+# define ncr_readl(a)		(*(unsigned int*)(a))
+# define ncr_writeb(v,a)	(*(unsigned char*)(a) = (v))
+# define ncr_writew(v,a)	(*(unsigned short*)(a) = (v))
+# define ncr_writel(v,a)	(*(unsigned int*)(a) = (v))
+
+#endif
+
 
 /* 
  * Prevent name space pollution in hosts.c, and only provide the 
@@ -713,7 +733,7 @@
 #define DCMD_RWRI_OP_ADDC	0x07
 
 #define DCMD_TYPE_MMI		0xc0	/* Indicates a Memory Move instruction 
-					   (three longs) */
+					   (three words) */
 
 
 #define DNAD_REG		0x28	/* through 0x2b DMA next address for 
@@ -919,8 +939,8 @@
 #endif
 				
 struct NCR53c7x0_synchronous {
-    unsigned long select_indirect;	/* Value used for indirect selection */
-    unsigned long script[6];		/* Size ?? Script used when target is 
+    u32 select_indirect;		/* Value used for indirect selection */
+    u32 script[6];			/* Size ?? Script used when target is 
 						reselected */
     unsigned renegotiate:1;		/* Force renegotiation on next   
 					   select */
@@ -933,7 +953,7 @@
 #define CMD_FLAG_DID_SDTR	4	/* did SDTR */
 
 struct NCR53c7x0_table_indirect {
-    unsigned long count;
+    u32 count;
     void *address;
 };
 
@@ -966,11 +986,11 @@
     					 
 
 
-    unsigned long *data_transfer_start;	/* Start of data transfer routines */
-    unsigned long *data_transfer_end;	/* Address after end of data transfer o
+    u32 *data_transfer_start;		/* Start of data transfer routines */
+    u32 *data_transfer_end;		/* Address after end of data transfer o
     	    	    	    	    	   routines */
 
-    unsigned long residual[8];		/* Residual data transfer
+    u32 residual[8];			/* Residual data transfer
 					   shadow of data_transfer code.
 
 					   Has instruction with modified
@@ -978,13 +998,13 @@
 					   CALL routine following command.
 					 */
 	     
-    unsigned long dsa[0];		/* Variable length (depending
+    u32 dsa[0];				/* Variable length (depending
 					   on host type, number of scatter /
 					   gather buffers, etc).  */
 };
 
 struct NCR53c7x0_break {
-    unsigned long *address, old_instruction[2];
+    u32 *address, old_instruction[2];
     struct NCR53c7x0_break *next;
     unsigned char old_size;		/* Size of old instruction */
 };
@@ -1050,7 +1070,7 @@
     unsigned char pci_bus, pci_device_fn;
     unsigned pci_valid:1;
 
-    unsigned long *dsp;			/* dsp to restart with after
+    u32 *dsp;				/* dsp to restart with after
 					   all stacked interrupts are
 					   handled. */
 
@@ -1095,52 +1115,52 @@
      * chip.  
      */
 
-    long dsa_start;			
-    long dsa_end;			
-    long dsa_next;
-    long dsa_prev;
-    long dsa_cmnd;
-    long dsa_select;
-    long dsa_msgout;
-    long dsa_cmdout;
-    long dsa_dataout;
-    long dsa_datain;
-    long dsa_msgin;
-    long dsa_msgout_other;
-    long dsa_write_sync;
-    long dsa_write_resume;
-    long dsa_jump_resume;
-    long dsa_check_reselect;
-    long dsa_status;
+    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_jump_resume;
+    s32 dsa_check_reselect;
+    s32 dsa_status;
 
     /* 
      * Important entry points that generic fixup code needs
      * to know about, fixed up.
      */
 
-    long E_accept_message;
-    long E_dsa_code_template;
-    long E_dsa_code_template_end;
-    long E_command_complete;		
-    long E_msg_in;
-    long E_initiator_abort;
-    long E_other_transfer;
-    long E_target_abort;
-    long E_schedule;			
-    long E_debug_break;	
-    long E_reject_message;
-    long E_respond_message;
-    long E_select;
-    long E_select_msgout;
-    long E_test_0;
-    long E_test_1;
-    long E_test_2;
-    long E_test_3;
-    long E_dsa_zero;
-    long E_dsa_jump_resume;
+    s32 E_accept_message;
+    s32 E_dsa_code_template;
+    s32 E_dsa_code_template_end;
+    s32 E_command_complete;		
+    s32 E_msg_in;
+    s32 E_initiator_abort;
+    s32 E_other_transfer;
+    s32 E_target_abort;
+    s32 E_schedule;			
+    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_dsa_jump_resume;
 
     int options;			/* Bitfielded set of options enabled */
-    long test_completed;		/* Test completed */
+    volatile u32 test_completed;	/* Test completed */
     int test_running;			/* Test currently running */
     int test_source;
     volatile int test_dest;
@@ -1250,17 +1270,18 @@
 						
 
     /* Shared variables between SCRIPT and host driver */
-    volatile unsigned char *issue_dsa_head;	
+    volatile u32 issue_dsa_head;
 						/* commands waiting to be 
 						   issued, insertions are 
 						   done by Linux driver,
 						   deletions are done by
 						   NCR */
-    volatile unsigned char *issue_dsa_tail;
+    u32 *issue_dsa_tail;			/* issue queue tail pointer;
+						   used by Linux driver only */
     volatile unsigned char msg_buf[16];		/* buffer for messages
 						   other than the command
 						   complete message */
-    volatile unsigned char *reconnect_dsa_head;	
+    volatile u32 reconnect_dsa_head;
 						/* disconnected commands,
 						   maintained by NCR */
     /* Data identifying nexus we are trying to match during reselection */
@@ -1269,14 +1290,14 @@
 						   message or 0 */
     /* These were static variables before we moved them */
 
-    long NCR53c7xx_zero;
-    long NCR53c7xx_sink;
+    s32 NCR53c7xx_zero;
+    s32 NCR53c7xx_sink;
     char NCR53c7xx_msg_reject;
     char NCR53c7xx_msg_abort;
     char NCR53c7xx_msg_nop;
 
-    int script_count;				/* Size of script in longs */
-    unsigned long script[0];			/* Relocated SCSI script */
+    int script_count;				/* Size of script in words */
+    u32 script[0];				/* Relocated SCSI script */
 
 };
 
@@ -1293,62 +1314,59 @@
 
 #define NCR53c7x0_local_declare()					\
     volatile unsigned char *NCR53c7x0_address_memory;			\
-    unsigned short NCR53c7x0_address_io;				\
+    unsigned int NCR53c7x0_address_io;					\
     int NCR53c7x0_memory_mapped
 
 #define NCR53c7x0_local_setup(host)					\
     NCR53c7x0_address_memory = (void *) (host)->base;			\
-    NCR53c7x0_address_io = (unsigned short) (host)->io_port;		\
+    NCR53c7x0_address_io = (unsigned int) (host)->io_port;		\
     NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) 		\
 	host->hostdata)-> options & OPTION_MEMORY_MAPPED 
 
 #define NCR53c7x0_read8(address) 					\
     (NCR53c7x0_memory_mapped ? 						\
-	*( (NCR53c7x0_address_memory) + (address))  : 			\
+	ncr_readb(NCR53c7x0_address_memory + (address))  :		\
 	inb(NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_read16(address) 					\
     (NCR53c7x0_memory_mapped ? 						\
-	*((unsigned short *) (NCR53c7x0_address_memory) + (address))  :	\
+	ncr_readw(NCR53c7x0_address_memory + (address))  :		\
 	inw(NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_read32(address) 					\
     (NCR53c7x0_memory_mapped ? 						\
-	*((unsigned long *) (NCR53c7x0_address_memory) + (address))  : 	\
+	ncr_readl(NCR53c7x0_address_memory + (address))  :		\
 	inl(NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_write8(address,value) 				\
     (NCR53c7x0_memory_mapped ? 						\
-	*((unsigned char *) (NCR53c7x0_address_memory) + (address)) =	\
-	  (value) :							\
+	ncr_writeb((value), NCR53c7x0_address_memory + (address)) :	\
 	outb((value), NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_write16(address,value) 				\
     (NCR53c7x0_memory_mapped ? 						\
-	*((unsigned short *) (NCR53c7x0_address_memory) + (address)) =	\
-	  (value) : 							\
+	ncr_writew((value), NCR53c7x0_address_memory + (address)) :	\
 	outw((value), NCR53c7x0_address_io + (address)))
 
 #define NCR53c7x0_write32(address,value) 				\
     (NCR53c7x0_memory_mapped ? 						\
-	*((unsigned long *) (NCR53c7x0_address_memory) + (address)) =  	\
-	  (value) : 							\
+	ncr_writel((value), NCR53c7x0_address_memory + (address)) :	\
 	outl((value), NCR53c7x0_address_io + (address)))
 
 #define patch_abs_32(script, offset, symbol, value)			\
     	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
-    	    (unsigned long)); ++i) {					\
+    	    (u32)); ++i) {						\
 	    (script)[A_##symbol##_used[i] - (offset)] += (value);	\
 	    if (hostdata->options & OPTION_DEBUG_FIXUP) 		\
-	      printk("scsi%d : %s reference %d at 0x%lx in %s is now 0x%lx\n",\
+	      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] - 	\
-		(offset), #script, (script)[A_##symbol##_used[i] - 	\
+		(int)(offset), #script, (script)[A_##symbol##_used[i] -	\
 		(offset)]);						\
     	}
 
 #define patch_abs_rwri_data(script, offset, symbol, value)	        \
     	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
-    	    (unsigned long)); ++i)					\
+    	    (u32)); ++i)						\
     	    (script)[A_##symbol##_used[i] - (offset)] =			\
 	    	((script)[A_##symbol##_used[i] - (offset)] & 		\
 	    	~DBC_RWRI_IMMEDIATE_MASK) | 				\
@@ -1357,12 +1375,12 @@
 
 #define patch_dsa_32(dsa, symbol, word, value)				\
 	{								\
-	(dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(long)	\
-		+ (word)] = (unsigned long) (value);			\
+	(dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32)	\
+		+ (word)] = (value);					\
 	if (hostdata->options & OPTION_DEBUG_DSA)			\
-	    printk("scsi : dsa %s symbol %s(%ld) word %d now 0x%lx\n",	\
-		#dsa, #symbol, (long) hostdata->##symbol, 		\
-		(int) (word), (long) (value));					\
+	    printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",	\
+		#dsa, #symbol, hostdata->##symbol,	 		\
+		(word), (u32)(value));				\
 	}
     
 
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/53c7,8xx.scr linux/drivers/scsi/53c7,8xx.scr
--- v1.3.3/linux/drivers/scsi/53c7,8xx.scr	Mon Apr 17 13:52:38 1995
+++ linux/drivers/scsi/53c7,8xx.scr	Mon Jun 26 11:32:57 1995
@@ -115,7 +115,7 @@
 	JUMP reselected_check_next
 
 ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines weather or not the current target and
+; 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:
@@ -402,7 +402,7 @@
 issue_remove:
 ;	The actual UPDATE of the issue_dsa_head variable is 
 ; 	atomic, with all of the setup code being irrelevant to
-;	weather the updated value being the old or new contents of 
+;	whether the updated value being the old or new contents of 
 ;	dsa_next field.
 ;
 ; 	To insure synchronization, the host system merely needs to 
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/53c8xx_d.h linux/drivers/scsi/53c8xx_d.h
--- v1.3.3/linux/drivers/scsi/53c8xx_d.h	Mon Apr 17 13:52:55 1995
+++ linux/drivers/scsi/53c8xx_d.h	Mon Jun 26 11:32:58 1995
@@ -1,4 +1,4 @@
-unsigned long SCRIPT[] = {
+u32 SCRIPT[] = {
 /*
 ; NCR 53c810 driver, main script
 ; Sponsored by 
@@ -135,7 +135,7 @@
 /*
 
 ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines weather or not the current target and
+; 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:
@@ -578,7 +578,7 @@
 issue_remove:
 ;	The actual UPDATE of the issue_dsa_head variable is 
 ; 	atomic, with all of the setup code being irrelevant to
-;	weather the updated value being the old or new contents of 
+;	whether the updated value being the old or new contents of 
 ;	dsa_next field.
 ;
 ; 	To insure synchronization, the host system merely needs to 
@@ -1816,31 +1816,31 @@
 };
 
 #define A_NCR53c7xx_msg_abort	0x00000000
-unsigned long A_NCR53c7xx_msg_abort_used[] = {
+u32 A_NCR53c7xx_msg_abort_used[] = {
 	0x000001f5,
 };
 
 #define A_NCR53c7xx_msg_reject	0x00000000
-unsigned long A_NCR53c7xx_msg_reject_used[] = {
+u32 A_NCR53c7xx_msg_reject_used[] = {
 	0x00000133,
 };
 
 #define A_NCR53c7xx_sink	0x00000000
-unsigned long A_NCR53c7xx_sink_used[] = {
+u32 A_NCR53c7xx_sink_used[] = {
 	0x000001e5,
 	0x000001e9,
 	0x000001ed,
 };
 
 #define A_NCR53c7xx_zero	0x00000000
-unsigned long A_NCR53c7xx_zero_used[] = {
+u32 A_NCR53c7xx_zero_used[] = {
 	0x0000015d,
 	0x000001e1,
 	0x000001f1,
 };
 
 #define A_addr_scratch	0x00000000
-unsigned long A_addr_scratch_used[] = {
+u32 A_addr_scratch_used[] = {
 	0x00000007,
 	0x0000003a,
 	0x00000046,
@@ -1854,17 +1854,17 @@
 };
 
 #define A_addr_sfbr	0x00000000
-unsigned long A_addr_sfbr_used[] = {
+u32 A_addr_sfbr_used[] = {
 	0x00000016,
 };
 
 #define A_addr_temp	0x00000000
-unsigned long A_addr_temp_used[] = {
+u32 A_addr_temp_used[] = {
 	0x00000027,
 };
 
 #define A_dmode_memory_to_memory	0x00000000
-unsigned long A_dmode_memory_to_memory_used[] = {
+u32 A_dmode_memory_to_memory_used[] = {
 	0x00000008,
 	0x00000019,
 	0x00000029,
@@ -1880,7 +1880,7 @@
 };
 
 #define A_dmode_memory_to_ncr	0x00000000
-unsigned long A_dmode_memory_to_ncr_used[] = {
+u32 A_dmode_memory_to_ncr_used[] = {
 	0x00000003,
 	0x00000012,
 	0x0000004c,
@@ -1888,7 +1888,7 @@
 };
 
 #define A_dmode_ncr_to_memory	0x00000000
-unsigned long A_dmode_ncr_to_memory_used[] = {
+u32 A_dmode_ncr_to_memory_used[] = {
 	0x00000024,
 	0x00000037,
 	0x00000043,
@@ -1900,140 +1900,140 @@
 };
 
 #define A_dmode_ncr_to_ncr	0x00000000
-unsigned long A_dmode_ncr_to_ncr_used[] = {
+u32 A_dmode_ncr_to_ncr_used[] = {
 };
 
 #define A_dsa_check_reselect	0x00000000
-unsigned long A_dsa_check_reselect_used[] = {
+u32 A_dsa_check_reselect_used[] = {
 	0x0000017f,
 };
 
 #define A_dsa_cmdout	0x00000048
-unsigned long A_dsa_cmdout_used[] = {
+u32 A_dsa_cmdout_used[] = {
 	0x0000008c,
 };
 
 #define A_dsa_cmnd	0x00000038
-unsigned long A_dsa_cmnd_used[] = {
+u32 A_dsa_cmnd_used[] = {
 };
 
 #define A_dsa_datain	0x00000054
-unsigned long A_dsa_datain_used[] = {
+u32 A_dsa_datain_used[] = {
 	0x000000b3,
 };
 
 #define A_dsa_dataout	0x00000050
-unsigned long A_dsa_dataout_used[] = {
+u32 A_dsa_dataout_used[] = {
 	0x0000009d,
 };
 
 #define A_dsa_end	0x00000070
-unsigned long A_dsa_end_used[] = {
+u32 A_dsa_end_used[] = {
 };
 
 #define A_dsa_fields_start	0x00000024
-unsigned long A_dsa_fields_start_used[] = {
+u32 A_dsa_fields_start_used[] = {
 };
 
 #define A_dsa_msgin	0x00000058
-unsigned long A_dsa_msgin_used[] = {
+u32 A_dsa_msgin_used[] = {
 	0x00000147,
 };
 
 #define A_dsa_msgout	0x00000040
-unsigned long A_dsa_msgout_used[] = {
+u32 A_dsa_msgout_used[] = {
 	0x0000006c,
 };
 
 #define A_dsa_msgout_other	0x00000068
-unsigned long A_dsa_msgout_other_used[] = {
+u32 A_dsa_msgout_other_used[] = {
 	0x0000013f,
 };
 
 #define A_dsa_next	0x00000030
-unsigned long A_dsa_next_used[] = {
+u32 A_dsa_next_used[] = {
 	0x0000002f,
 	0x0000006f,
 };
 
 #define A_dsa_select	0x0000003c
-unsigned long A_dsa_select_used[] = {
+u32 A_dsa_select_used[] = {
 	0x00000067,
 };
 
 #define A_dsa_status	0x00000060
-unsigned long A_dsa_status_used[] = {
+u32 A_dsa_status_used[] = {
 	0x00000143,
 };
 
 #define A_dsa_temp_dsa_next	0x00000000
-unsigned long A_dsa_temp_dsa_next_used[] = {
+u32 A_dsa_temp_dsa_next_used[] = {
 	0x00000001,
 	0x00000006,
 	0x0000001c,
 };
 
 #define A_dsa_temp_jump_resume	0x00000000
-unsigned long A_dsa_temp_jump_resume_used[] = {
+u32 A_dsa_temp_jump_resume_used[] = {
 	0x00000028,
 };
 
 #define A_dsa_temp_lun	0x00000000
-unsigned long A_dsa_temp_lun_used[] = {
+u32 A_dsa_temp_lun_used[] = {
 	0x00000017,
 };
 
 #define A_dsa_temp_sync	0x00000000
-unsigned long A_dsa_temp_sync_used[] = {
+u32 A_dsa_temp_sync_used[] = {
 	0x00000021,
 };
 
 #define A_dsa_temp_target	0x00000000
-unsigned long A_dsa_temp_target_used[] = {
+u32 A_dsa_temp_target_used[] = {
 	0x00000010,
 };
 
 #define A_int_debug_break	0x03000000
-unsigned long A_int_debug_break_used[] = {
+u32 A_int_debug_break_used[] = {
 	0x000001d3,
 };
 
 #define A_int_debug_dsa_loaded	0x03030000
-unsigned long A_int_debug_dsa_loaded_used[] = {
+u32 A_int_debug_dsa_loaded_used[] = {
 };
 
 #define A_int_debug_head	0x03050000
-unsigned long A_int_debug_head_used[] = {
+u32 A_int_debug_head_used[] = {
 };
 
 #define A_int_debug_idle	0x03020000
-unsigned long A_int_debug_idle_used[] = {
+u32 A_int_debug_idle_used[] = {
 };
 
 #define A_int_debug_reselected	0x03040000
-unsigned long A_int_debug_reselected_used[] = {
+u32 A_int_debug_reselected_used[] = {
 };
 
 #define A_int_debug_scheduled	0x03010000
-unsigned long A_int_debug_scheduled_used[] = {
+u32 A_int_debug_scheduled_used[] = {
 };
 
 #define A_int_err_check_condition	0x00030000
-unsigned long A_int_err_check_condition_used[] = {
+u32 A_int_err_check_condition_used[] = {
 	0x00000157,
 };
 
 #define A_int_err_no_phase	0x00040000
-unsigned long A_int_err_no_phase_used[] = {
+u32 A_int_err_no_phase_used[] = {
 };
 
 #define A_int_err_selected	0x00010000
-unsigned long A_int_err_selected_used[] = {
+u32 A_int_err_selected_used[] = {
 	0x0000019e,
 };
 
 #define A_int_err_unexpected_phase	0x00000000
-unsigned long A_int_err_unexpected_phase_used[] = {
+u32 A_int_err_unexpected_phase_used[] = {
 	0x00000084,
 	0x0000008a,
 	0x0000008e,
@@ -2046,73 +2046,73 @@
 };
 
 #define A_int_err_unexpected_reselect	0x00020000
-unsigned long A_int_err_unexpected_reselect_used[] = {
+u32 A_int_err_unexpected_reselect_used[] = {
 	0x0000017c,
 };
 
 #define A_int_msg_1	0x01020000
-unsigned long A_int_msg_1_used[] = {
+u32 A_int_msg_1_used[] = {
 	0x000000e2,
 	0x000000e4,
 };
 
 #define A_int_msg_sdtr	0x01010000
-unsigned long A_int_msg_sdtr_used[] = {
+u32 A_int_msg_sdtr_used[] = {
 	0x0000012d,
 };
 
 #define A_int_msg_wdtr	0x01000000
-unsigned long A_int_msg_wdtr_used[] = {
+u32 A_int_msg_wdtr_used[] = {
 	0x00000121,
 };
 
 #define A_int_norm_aborted	0x02040000
-unsigned long A_int_norm_aborted_used[] = {
+u32 A_int_norm_aborted_used[] = {
 	0x000001f9,
 };
 
 #define A_int_norm_command_complete	0x02020000
-unsigned long A_int_norm_command_complete_used[] = {
+u32 A_int_norm_command_complete_used[] = {
 };
 
 #define A_int_norm_disconnected	0x02030000
-unsigned long A_int_norm_disconnected_used[] = {
+u32 A_int_norm_disconnected_used[] = {
 };
 
 #define A_int_norm_reselect_complete	0x02010000
-unsigned long A_int_norm_reselect_complete_used[] = {
+u32 A_int_norm_reselect_complete_used[] = {
 };
 
 #define A_int_norm_reset	0x02050000
-unsigned long A_int_norm_reset_used[] = {
+u32 A_int_norm_reset_used[] = {
 };
 
 #define A_int_norm_select_complete	0x02000000
-unsigned long A_int_norm_select_complete_used[] = {
+u32 A_int_norm_select_complete_used[] = {
 };
 
 #define A_int_test_1	0x04000000
-unsigned long A_int_test_1_used[] = {
+u32 A_int_test_1_used[] = {
 	0x000001b9,
 };
 
 #define A_int_test_2	0x04010000
-unsigned long A_int_test_2_used[] = {
+u32 A_int_test_2_used[] = {
 	0x000001d1,
 };
 
 #define A_int_test_3	0x04020000
-unsigned long A_int_test_3_used[] = {
+u32 A_int_test_3_used[] = {
 };
 
 #define A_issue_dsa_head	0x00000000
-unsigned long A_issue_dsa_head_used[] = {
+u32 A_issue_dsa_head_used[] = {
 	0x0000004f,
 	0x00000080,
 };
 
 #define A_msg_buf	0x00000000
-unsigned long A_msg_buf_used[] = {
+u32 A_msg_buf_used[] = {
 	0x000000d6,
 	0x0000010f,
 	0x00000119,
@@ -2122,7 +2122,7 @@
 };
 
 #define A_reconnect_dsa_head	0x00000000
-unsigned long A_reconnect_dsa_head_used[] = {
+u32 A_reconnect_dsa_head_used[] = {
 	0x0000003f,
 	0x00000047,
 	0x00000162,
@@ -2130,23 +2130,23 @@
 };
 
 #define A_reselected_identify	0x00000000
-unsigned long A_reselected_identify_used[] = {
+u32 A_reselected_identify_used[] = {
 	0x00000015,
 	0x0000015b,
 };
 
 #define A_reselected_tag	0x00000000
-unsigned long A_reselected_tag_used[] = {
+u32 A_reselected_tag_used[] = {
 	0x0000015e,
 };
 
 #define A_test_dest	0x00000000
-unsigned long A_test_dest_used[] = {
+u32 A_test_dest_used[] = {
 	0x000001b7,
 };
 
 #define A_test_src	0x00000000
-unsigned long A_test_src_used[] = {
+u32 A_test_src_used[] = {
 	0x000001b6,
 };
 
@@ -2174,7 +2174,7 @@
 #define Ent_test_1	0x000006d4
 #define Ent_test_2	0x000006e8
 #define Ent_test_2_msgout	0x00000700
-unsigned long LABELPATCHES[] = {
+u32 LABELPATCHES[] = {
 	0x00000002,
 	0x0000000b,
 	0x0000000d,
@@ -2249,5 +2249,12 @@
 	0x000001ef,
 };
 
-unsigned long INSTRUCTIONS	= 0x00000104;
-unsigned long PATCHES	= 0x00000048;
+struct {
+	u32	offset;
+	void		*address;
+} EXTERNAL_PATCHES[] = {
+};
+
+u32 INSTRUCTIONS	= 260;
+u32 PATCHES	= 72;
+u32 EXTERNAL_PATCHES_LEN	= 0;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.3/linux/drivers/scsi/Makefile	Fri Jun  9 11:30:29 1995
+++ linux/drivers/scsi/Makefile	Mon Jun 26 12:42:51 1995
@@ -76,9 +76,9 @@
 SCSI_SRCS := $(SCSI_SRCS) aha1740.c
 endif
 
-ifdef CONFIG_SCSI_AHA274X
-SCSI_OBJS := $(SCSI_OBJS) aha274x.o
-SCSI_SRCS := $(SCSI_SRCS) aha274x.c
+ifdef CONFIG_SCSI_AIC7XXX
+SCSI_OBJS := $(SCSI_OBJS) aic7xxx.o
+SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
 endif
 
 ifdef CONFIG_SCSI_BUSLOGIC
@@ -180,8 +180,8 @@
 aic7770:	aic7770.c
 		$(CC) $(CFLAGS) -o $@ aic7770.c
 
-aha274x_seq.h:	aic7770 aha274x.seq
-		./aic7770 -o $@ aha274x.seq
+aic7xxx_seq.h:	aic7770 aic7xxx.seq
+		./aic7770 -o $@ aic7xxx.seq
 
 seagate.o: seagate.c
 	$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c 
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/README-FIRST.aic7xxx linux/drivers/scsi/README-FIRST.aic7xxx
--- v1.3.3/linux/drivers/scsi/README-FIRST.aic7xxx	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README-FIRST.aic7xxx	Mon Jun 26 12:42:51 1995
@@ -0,0 +1,17 @@
+The 274x/284x support is basically the same as in the kernel, with
+some minor structural changes.  The 294x support is preliminary, with
+a few things still hardwired (like the SCSI ID and FIFO threshold).
+You have been warned.
+
+To function properly, you must use this with a kernel version 1.1.68
+or above - these have the SCSI changes in the kernel which support
+varying numbers of outstanding SCSI commands per driver instance (they
+also contain the Adaptec PCI definitions).
+
+You can find instructions in the SCSI-HOWTO on how to install SCSI
+drivers into the kernel.  In a nutshell, find all the aha274x stuff
+and change it to aic7xxx.
+
+Please direct all problems to the AIC7770 mailing list - see the README
+for details.
+:ja
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/README.aha274x linux/drivers/scsi/README.aha274x
--- v1.3.3/linux/drivers/scsi/README.aha274x	Sun Nov 20 21:50:47 1994
+++ linux/drivers/scsi/README.aha274x	Thu Jan  1 02:00:00 1970
@@ -1,94 +0,0 @@
-@(#)README 1.15 94/10/29 jda
-
-AHA274x/284x DRIVER
-
-***  THIS SHOULD BE CONSIDERED BETA SOFTWARE  ***
-
-BACKGROUND & LIMITATIONS
-
-For various reasons, we ended up with one of these cards under the
-impression that support was soon forthcoming.  In mid-May, I asked
-Scott Ferris (the official person who's supposed to be writing this
-driver) what documentation he used, _finally_ got it from Adaptec,
-and started writing this driver.  It is now at what I would consider
-a stable state - it runs our news server and is battered by SCSI
-requests 24 hours a day without dying.  There are a few devices it
-reportedly doesn't like working with - those are being sorted out.  Due
-to some unexpected equipment loans, I am able to support this at least
-for the time being.
-
-YOU MUST HAVE THE BIOS ENABLED OR THIS WILL NOT WORK.  The BIOS extracts
-some configuration information that I cannot get to portably yet, as
-well as provides some self-tests which this driver does not attempt to
-duplicate.
-
-Scott's driver development is stalled for now, and after discussions
-with him, this is now officially out of "pre-alpha" status and into
-beta until the remaining device problems can be resolved.  The latest
-patches can be obtained via anonymous ftp from ftp.cpsc.ucalgary.ca in
-/pub/systems/linux/aha274x.
-
-It supports both EISA 274x and VL-bus 284x, either single or twin-bus cards
-(but not the second SCSI bus of twin cards - see aha274x.c), and supports
-disconnection, synchronous SCSI, and scatter-gather.  Unlike previous
-versions, abort() and reset() are now implemented, and both hosts.c and
-aha274x.c should give a clean compile.  Code is now present to detect parity
-errors, but has not been tested.
-
-I wrote this using a 1.0.9 kernel.  Unfortunately, I'm getting tired of
-#ifdef'ing everything to handle two or three different evolutionary steps
-in the SCSI kernel code, so I've upgraded my system to 1.1.49, and will
-only leave in code to support versions from about 1.1.45 onward.
-
-Thanks to patches supplied by Mark Olson <molson@tricord.com>, this driver
-will now work with the 284x series (the VL-bus version of this card).  The
-294x (PCI-bus) is being worked on, and initial support for it will be ready
-soon.
-
-Under protest, this driver is subject to the GPL - see the file
-COPYING for details.
-
-Thanks to the following people for bug fixes/code improvements (also
-thanks to the people who have sent me feedback):
-
-	"David F. Carlson" <dave@ee.rochester.edu>
-	Jimen Ching <jiching@wiliki.eng.hawaii.edu>
-	mday@artisoft.com (Matt Day)
-	"Dean W. Gehnert" <deang@ims.com>
-	Darcy Grant <darcy@cpsc.ucalgary.ca>
-	Alan Hourihane <alanh@fairlite.demon.co.uk>
-	isely@fncrd8.fnal.gov (Mike Isely)
-	Mike Jerger <jerger@ux1.cso.uiuc.edu>
-	tm@netcom.com (Toshiyasu Morita)
-	neal@interact.org (Neal Norwitz)
-	Mark Olson <molson@tricord.com>
-	map@europa.ecn.uoknor.edu (Michael A. Parker)
-	Thomas Scheunemann <thomas@dagobert.uni-duisburg.de>
-
-Special thanks to Drew Eckhardt <drew@kinglear.cs.Colorado.EDU> for
-fielding my questions about synchronous negotiation.  Steffen Moeller
-<smoe0024@rz.uni-hildesheim.de> sent me installation instructions which
-were previously included in this README.
-
-David Pirie <pirie@cpsc.ucalgary.ca> was nice enough to loan me his
-2842 card for a week so I could track down one bug, as well as his
-CD-ROM drive later, and also thanks to Doug Fortune at Riley's Data Share
-in Calgary, who arranged a long-term loan of a 2842 board for further work.
-
-Many thanks to the fearless prerelease testers!  Dean Gehnert has been
-building Slackware boot disks for the driver, which are available from
-ftp.cpsc.ucalgary.ca in /pub/systems/linux/aha274x/slackware_boot.
-
-Carl Riches <cgr@poplar1.cfr.washington.edu> has set up a mailing list
-for aic7xxx driver development.  To subscribe, send a message to
-aic7770-list@poplar1.cfr.washington.edu with a message body of:
-
-    subscribe AIC7770-LIST <your name here, without the angle brackets>
-
-Please direct questions and discussions to that list instead of me.  When
-sending bug reports, please include a description of your hardware, the
-release numbers displayed by the driver at boot time, and as accurate a
-facsimile of any error message you're mailing about.
-
-John Aycock
-aycock@cpsc.ucalgary.ca
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v1.3.3/linux/drivers/scsi/README.aic7xxx	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.aic7xxx	Mon Jun 26 12:42:51 1995
@@ -0,0 +1,95 @@
+@(#)README 1.19 94/11/30 jda
+
+AHA274x/284x/294x DRIVER
+
+***  THIS SHOULD BE CONSIDERED BETA SOFTWARE  ***
+
+BACKGROUND & LIMITATIONS
+
+For various reasons, we ended up with one of these cards under the
+impression that support was soon forthcoming.  In mid-May, I asked
+Scott Ferris (the official person who's supposed to be writing this
+driver) what documentation he used, _finally_ got it from Adaptec,
+and started writing this driver.  It is now at what I would consider
+a stable state - it runs our news server and is battered by SCSI
+requests 24 hours a day without dying.  There are a few devices it
+reportedly doesn't like working with - those are being sorted out.  Due
+to some unexpected equipment loans, I am able to support this at least
+for the time being.
+
+YOU MUST HAVE THE BIOS ENABLED OR THIS WILL NOT WORK.  The BIOS extracts
+some configuration information that I cannot get to portably yet, as
+well as provides some self-tests which this driver does not attempt to
+duplicate.
+
+Scott's driver development is stalled for now, and after discussions
+with him, this is now officially out of "pre-alpha" status and into
+beta until the remaining device problems can be resolved.  The latest
+patches can be obtained via anonymous ftp from ftp.cpsc.ucalgary.ca in
+/pub/systems/linux/aha274x.
+
+It supports EISA 274x, VL-bus 284x, and PCI 294x, either single or twin-bus
+cards (but not the second SCSI bus of twin cards - see aha274x.c), and supports
+disconnection, synchronous SCSI, and scatter-gather.  Unlike previous
+versions, abort() and reset() are now implemented, and both hosts.c and
+aha274x.c should give a clean compile.  Code is now present to detect parity
+errors, but has not been tested.  Wide cards are not yet supported.
+
+I wrote this using a 1.0.9 kernel.  Unfortunately, I'm getting tired of
+#ifdef'ing everything to handle two or three different evolutionary steps
+in the SCSI kernel code, so I've upgraded my system to 1.1.49, and will
+only leave in code to support versions from about 1.1.45 onward.
+
+Thanks to patches supplied by Mark Olson <molson@tricord.com>, this driver
+will now work with the 284x series (the VL-bus version of this card).  The
+294x (PCI-bus) support is based on patches sent to me by Mark Olson and
+Alan Hourihane <alanh@fairlite.demon.co.uk>.
+
+Under protest, this driver is subject to the GPL - see the file
+COPYING for details.
+
+Thanks to the following people for bug fixes/code improvements (also
+thanks to the people who have sent me feedback):
+
+	"David F. Carlson" <dave@ee.rochester.edu>
+	Jimen Ching <jiching@wiliki.eng.hawaii.edu>
+	mday@artisoft.com (Matt Day)
+	"Dean W. Gehnert" <deang@ims.com>
+	Darcy Grant <darcy@cpsc.ucalgary.ca>
+	Alan Hourihane <alanh@fairlite.demon.co.uk>
+	isely@fncrd8.fnal.gov (Mike Isely)
+	Mike Jerger <jerger@ux1.cso.uiuc.edu>
+	tm@netcom.com (Toshiyasu Morita)
+	neal@interact.org (Neal Norwitz)
+	Mark Olson <molson@tricord.com>
+	map@europa.ecn.uoknor.edu (Michael A. Parker)
+	Thomas Scheunemann <thomas@dagobert.uni-duisburg.de>
+	Eric Youngdale <eric@aib.com>
+
+Special thanks to Drew Eckhardt <drew@kinglear.cs.Colorado.EDU> for
+fielding my questions about synchronous negotiation.  Steffen Moeller
+<smoe0024@rz.uni-hildesheim.de> sent me installation instructions which
+were previously included in this README.
+
+David Pirie <pirie@cpsc.ucalgary.ca> was nice enough to loan me his
+2842 card for a week so I could track down one bug, as well as his
+CD-ROM drive later, and also thanks to Doug Fortune at Riley's Data Share
+in Calgary, who arranged a long-term loan of a 2842 board for further work.
+
+Many thanks to the fearless prerelease testers!  Dean Gehnert has been
+building Slackware boot disks for the driver, which are available from
+ftp.cpsc.ucalgary.ca in /pub/systems/linux/aha274x/slackware_boot.
+
+Carl Riches <cgr@poplar1.cfr.washington.edu> has set up a mailing list
+for aic7xxx driver development.  To subscribe, send a message to
+aic7770-list-request@poplar1.cfr.washington.edu with a message body of:
+
+    subscribe AIC7770-LIST <your name here, without the angle brackets>
+
+Please direct questions and discussions to that list instead of me.  When
+sending bug reports, please include a description of your hardware, the
+release numbers displayed by the driver at boot time, and as accurate a
+facsimile of any error message you're mailing about.
+
+John Aycock
+aycock@cpsc.ucalgary.ca
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aha274x.c linux/drivers/scsi/aha274x.c
--- v1.3.3/linux/drivers/scsi/aha274x.c	Mon Jan 16 07:17:37 1995
+++ linux/drivers/scsi/aha274x.c	Thu Jan  1 02:00:00 1970
@@ -1,1490 +0,0 @@
-/*
- *  @(#)aha274x.c 1.29 94/10/29 jda
- *
- *  Adaptec 274x device driver for Linux.
- *  Copyright (c) 1994 The University of Calgary Department of Computer Science.
- *  
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *  Sources include the Adaptec 1740 driver (aha1740.c), the
- *  Ultrastor 24F driver (ultrastor.c), various Linux kernel
- *  source, the Adaptec EISA config file (!adp7771.cfg), the
- *  Adaptec AHA-2740A Series User's Guide, the Linux Kernel
- *  Hacker's Guide, Writing a SCSI Device Driver for Linux,
- *  the Adaptec 1542 driver (aha1542.c), the Adaptec EISA
- *  overlay file (adp7770.ovl), the Adaptec AHA-2740 Series
- *  Technical Reference Manual, the Adaptec AIC-7770 Data
- *  Book, the ANSI SCSI specification, the ANSI SCSI-2
- *  specification (draft 10c), ...
- *
- *  On a twin-bus adapter card, channel B is ignored.  Rationale:
- *  it would greatly complicate the sequencer and host driver code,
- *  and both busses are multiplexed on to the EISA bus anyway.  So
- *  I don't really see any technical advantage to supporting both.
- *
- *  As well, multiple adapter card using the same IRQ level are
- *  not supported.  It doesn't make sense to configure the cards
- *  this way from a performance standpoint.  Not to mention that
- *  the kernel would have to support two devices per registered IRQ.
- */
-
-#include <stdarg.h>
-#include <asm/io.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-
-#include "../block/blk.h"
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "aha274x.h"
-
-/*
- *  There should be a specific return value for this in scsi.h, but
- *  it seems that most drivers ignore it.
- */
-#define DID_UNDERFLOW	DID_ERROR
-
-/* EISA stuff */
-
-#define MINEISA		1
-#define MAXEISA		15
-#define SLOTBASE(x)	((x) << 12)
-
-#define MAXIRQ		15
-
-/* AIC-7770 offset definitions */
-
-#define O_MINREG(x)	((x) + 0xc00)		/* i/o range to reserve */
-#define O_MAXREG(x)	((x) + 0xcbf)
-
-#define O_SCSISEQ(x)	((x) + 0xc00)		/* scsi sequence control */
-#define O_SCSISIGI(x)	((x) + 0xc03)		/* scsi control signal read */
-#define O_SCSISIGO(x)	((x) + 0xc03)		/* scsi control signal write */
-#define O_SCSIID(x)	((x) + 0xc05)		/* scsi id */
-#define O_SSTAT0(x)	((x) + 0xc0b)		/* scsi status register 0 */
-#define O_CLRSINT1(x)	((x) + 0xc0c)		/* clear scsi interrupt 1 */
-#define O_SSTAT1(x)	((x) + 0xc0c)		/* scsi status register 1 */
-#define O_SELID(x)	((x) + 0xc19)		/* [re]selection id */
-#define O_SBLKCTL(x)	((x) + 0xc1f)		/* scsi block control */
-#define O_SEQCTL(x)	((x) + 0xc60)		/* sequencer control */
-#define O_SEQRAM(x)	((x) + 0xc61)		/* sequencer ram data */
-#define O_SEQADDR(x)	((x) + 0xc62)		/* sequencer address (W) */
-#define O_BIDx(x)	((x) + 0xc80)		/* board id */
-#define O_BCTL(x)	((x) + 0xc84)		/* board control */
-#define O_HCNTRL(x)	((x) + 0xc87)		/* host control */
-#define O_SCBPTR(x)	((x) + 0xc90)		/* scb pointer */
-#define O_INTSTAT(x)	((x) + 0xc91)		/* interrupt status */
-#define O_ERROR(x)	((x) + 0xc92)		/* hard error */
-#define O_CLRINT(x)	((x) + 0xc92)		/* clear interrupt status */
-#define O_SCBCNT(x)	((x) + 0xc9a)		/* scb auto increment */
-#define O_QINFIFO(x)	((x) + 0xc9b)		/* queue in fifo */
-#define O_QINCNT(x)	((x) + 0xc9c)		/* queue in count */
-#define O_QOUTFIFO(x)	((x) + 0xc9d)		/* queue out fifo */
-#define O_QOUTCNT(x)	((x) + 0xc9e)		/* queue out count */
-#define O_SCBARRAY(x)	((x) + 0xca0)		/* scb array start */
-
-/* host adapter offset definitions */
-
-#define HA_REJBYTE(x)	((x) + 0xc31)		/* 1st message in byte */
-#define HA_MSG_FLAGS(x)	((x) + 0xc35)		/* outgoing message flag */
-#define HA_MSG_LEN(x)	((x) + 0xc36)		/* outgoing message length */
-#define HA_MSG_START(x)	((x) + 0xc37)		/* outgoing message body */
-#define HA_ARG_1(x)	((x) + 0xc4c)		/* sdtr <-> rate parameters */
-#define HA_ARG_2(x)	((x) + 0xc4d)
-#define HA_RETURN_1(x)	((x) + 0xc4c)
-#define HA_RETURN_2(x)	((x) + 0xc4d)
-#define HA_SIGSTATE(x)	((x) + 0xc4e)		/* value in SCSISIGO */
-#define HA_NEEDSDTR(x)	((x) + 0xc4f)		/* synchronous negotiation? */
-
-#define HA_SCSICONF(x)	((x) + 0xc5a)		/* SCSI config register */
-#define HA_INTDEF(x)	((x) + 0xc5c)		/* interrupt def'n register */
-#define HA_HOSTCONF(x)	((x) + 0xc5d)		/* host config def'n register */
-
-/* debugging code */
-
-#define AHA274X_DEBUG
-
-/*
- *  If a parity error occurs during a data transfer phase, run the
- *  command to completion - it's easier that way - making a note
- *  of the error condition in this location.  This then will modify
- *  a DID_OK status into a DID_PARITY one for the higher-level SCSI
- *  code.
- */
-#define aha274x_parity(cmd)	((cmd)->SCp.Status)
-
-/*
- *  Since the sequencer code DMAs the scatter-gather structures
- *  directly from memory, we use this macro to assert that the
- *  kernel structure hasn't changed.
- */
-#define SG_STRUCT_CHECK(sg) \
-	((char *)&(sg).address - (char *)&(sg) != 0 ||	\
-	 (char *)&(sg).length  - (char *)&(sg) != 8 ||	\
-	 sizeof((sg).address) != 4 ||			\
-	 sizeof((sg).length)  != 4 ||			\
-	 sizeof(sg)	      != 12)
-
-/*
- *  "Static" structures.  Note that these are NOT initialized
- *  to zero inside the kernel - we have to initialize them all
- *  explicitly.
- *
- *  We support a maximum of one adapter card per IRQ level (see the
- *  rationale for this above).  On an interrupt, use the IRQ as an
- *  index into aha274x_boards[] to locate the card information.
- */
-static struct Scsi_Host *aha274x_boards[MAXIRQ + 1];
-
-struct aha274x_host {
-	int base;					/* card base address */
-	int startup;					/* intr type check */
-	volatile int unpause;				/* value for HCNTRL */
-	volatile Scsi_Cmnd *SCB_array[AHA274X_MAXSCB];	/* active commands */
-};
-
-struct aha274x_scb {
-	unsigned char control;
-	unsigned char target_channel_lun;		/* 4/1/3 bits */
-	unsigned char SG_segment_count;
-	unsigned char SG_list_pointer[4];
-	unsigned char SCSI_cmd_pointer[4];
-	unsigned char SCSI_cmd_length;
-	unsigned char RESERVED[2];			/* must be zero */
-	unsigned char target_status;
-	unsigned char residual_data_count[3];
-	unsigned char residual_SG_segment_count;
-	unsigned char data_pointer[4];
-	unsigned char data_count[3];
-#if 0
-	/*
-	 *  No real point in transferring this to the
-	 *  SCB registers.
-	 */
-	unsigned char RESERVED[6];
-#endif
-};
-
-/*
- *  NB.  This table MUST be ordered shortest period first.
- */
-static struct {
-	short period;
-	short rate;
-	char *english;
-} aha274x_synctab[] = {
-	{100,	0,	"10.0"},
-	{125,	1,	"8.0"},
-	{150,	2,	"6.67"},
-	{175,	3,	"5.7"},
-	{200,	4,	"5.0"},
-	{225,	5,	"4.4"},
-	{250,	6,	"4.0"},
-	{275,	7,	"3.6"}
-};
-
-static int aha274x_synctab_max =
-	sizeof(aha274x_synctab) / sizeof(aha274x_synctab[0]);
-
-enum aha_type {
-	T_NONE,
-	T_274X,
-	T_284X,
-	T_MAX
-};
-
-#ifdef AHA274X_DEBUG
-
-	extern int vsprintf(char *, const char *, va_list);
-
-	static
-	void debug(const char *fmt, ...)
-	{
-		va_list ap;
-		char buf[256];
-
-		va_start(ap, fmt);
-		  vsprintf(buf, fmt, ap);
-		  printk(buf);
-		va_end(ap);
-	}
-
-	static
-	void debug_config(enum aha_type type, int base)
-	{
-		int ioport2, ioport3, ioport4;
-
-		static char *BRT[T_MAX][16] = {
-			{ },					/* T_NONE */
-			{
-				"2",   "???", "???", "12",	/* T_274X */
-				"???", "???", "???", "28",
-				"???", "???", "???", "44",
-				"???", "???", "???", "60"
-			},
-			{
-				"2",  "4",  "8",  "12",		/* T_284X */
-				"16", "20", "24", "28",
-				"32", "36", "40", "44",
-				"48", "52", "56", "60"
-			}
-		};
-		static int DFT[4] = {
-			0, 50, 75, 100
-		};
-		static int SST[4] = {
-			256, 128, 64, 32
-		};
-
-		ioport2 = inb(HA_HOSTCONF(base));
-		ioport3 = inb(HA_SCSICONF(base));
-		ioport4 = inb(HA_INTDEF(base));
-
-		if (type == T_284X)
-			printk("AHA284X AT SLOT %d:\n", base >> 12);
-		else
-			printk("AHA274X AT EISA SLOT %d:\n", base >> 12);
-
-		printk("    irq %d\n"
-		       "    bus release time %s bclks\n"
-		       "    data fifo threshold %d%%\n",
-		       ioport4 & 0xf,
-		       BRT[type][(ioport2 >> 2) & 0xf],
-		       DFT[(ioport2 >> 6) & 0x3]);
-
-		printk("    SCSI CHANNEL A:\n"
-		       "        scsi id %d\n"
-		       "        scsi bus parity check %sabled\n"
-		       "        scsi selection timeout %d ms\n"
-		       "        scsi bus reset at power-on %sabled\n",
-		       ioport3 & 0x7,
-		       (ioport3 & 0x20) ? "en" : "dis",
-		       SST[(ioport3 >> 3) & 0x3],
-		       (ioport3 & 0x40) ? "en" : "dis");
-
-		if (type == T_274X) {
-			printk("        scsi bus termination %sabled\n",
-			       (ioport3 & 0x80) ? "en" : "dis");
-		}
-	}
-
-	static
-	void debug_rate(int base, int rate)
-	{
-		int target = inb(O_SCSIID(base)) >> 4;
-
-		if (rate) {
-			printk("aha274x: target %d now synchronous at %sMb/s\n",
-			       target,
-			       aha274x_synctab[(rate >> 4) & 0x7].english);
-		} else {
-			printk("aha274x: target %d using asynchronous mode\n",
-			       target);
-		}
-	}
-
-#else
-
-#	define debug(fmt, args...)
-#	define debug_config(x)
-#	define debug_rate(x,y)
-
-#endif AHA274X_DEBUG
-
-/*
- *  XXX - these options apply unilaterally to _all_ 274x/284x
- *	  cards in the system.  This should be fixed, but then,
- *	  does anyone really have more than one in a machine?
- */
-static int aha274x_extended = 0;		/* extended translation on? */
-
-void aha274x_setup(char *s, int *dummy)
-{
-	int i;
-	char *p;
-
-	static struct {
-		char *name;
-		int *flag;
-	} options[] = {
-		{"extended",	&aha274x_extended},
-		{NULL, NULL }
-	};
-
-	for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
-		for (i = 0; options[i].name; i++)
-			if (!strcmp(options[i].name, p))
-				*(options[i].flag) = !0;
-	}
-}
-
-static
-void aha274x_getscb(int base, struct aha274x_scb *scb)
-{
-	/*
-	 *  This is almost identical to aha274x_putscb().
-	 */
-	outb(0x80, O_SCBCNT(base));	/* SCBAUTO */
-
-	asm volatile("cld\n\t"
-		     "rep\n\t"
-		     "insb"
-		     : /* no output */
-		     :"D" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
-		     :"di", "cx", "dx");
-
-	outb(0, O_SCBCNT(base));
-}
-
-/*
- *  How much data should be transferred for this SCSI command?  Stop
- *  at segment sg_last if it's a scatter-gather command so we can
- *  compute underflow easily.
- */
-static
-unsigned aha274x_length(Scsi_Cmnd *cmd, int sg_last)
-{
-	int i, segments;
-	unsigned length;
-	struct scatterlist *sg;
-
-	segments = cmd->use_sg - sg_last;
-	sg = (struct scatterlist *)cmd->buffer;
-
-	if (cmd->use_sg) {
-		for (i = length = 0;
-		     i < cmd->use_sg && i < segments;
-		     i++)
-		{
-			length += sg[i].length;
-		}
-	} else
-		length = cmd->request_bufflen;
-
-	return(length);
-}
-
-static
-void aha274x_sg_check(Scsi_Cmnd *cmd)
-{
-	int i;
-	struct scatterlist *sg = (struct scatterlist *)cmd->buffer;
-
-	if (cmd->use_sg) {
-		for (i = 0; i < cmd->use_sg; i++)
-			if ((unsigned)sg[i].length > 0xffff)
-				panic("aha274x_sg_check: s/g segment > 64k\n");
-	}
-}
-
-static
-void aha274x_to_scsirate(unsigned char *rate,
-			 unsigned char transfer,
-			 unsigned char offset)
-{
-	int i;
-
-	transfer *= 4;
-
-	for (i = 0; i < aha274x_synctab_max-1; i++) {
-
-		if (transfer == aha274x_synctab[i].period) {
-			*rate = (aha274x_synctab[i].rate << 4) | (offset & 0xf);
-			return;
-		}
-
-		if (transfer > aha274x_synctab[i].period &&
-		    transfer < aha274x_synctab[i+1].period)
-		{
-			*rate = (aha274x_synctab[i+1].rate << 4) |
-				(offset & 0xf);
-			return;
-		}
-	}
-	*rate = 0;
-}
-
-/*
- *  Pause the sequencer and wait for it to actually stop - this
- *  is important since the sequencer can disable pausing for critical
- *  sections.
- */
-#define PAUSE_SEQUENCER(p)	\
-	do {								\
-		outb(0xe, O_HCNTRL(p->base));	/* IRQMS|PAUSE|INTEN */	\
-									\
-		while ((inb(O_HCNTRL(p->base)) & 0x4) == 0)		\
-			;						\
-	} while (0)
-
-/*
- *  Unpause the sequencer.  Unremarkable, yet done often enough to
- *  warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p)	\
-	outb(p->unpause, O_HCNTRL(p->base))	/* IRQMS|INTEN */
-
-/*
- *  See comments in aha274x_loadram() wrt this.
- */
-#define RESTART_SEQUENCER(p)	\
-	do {						\
-		do {					\
-			outb(0x2, O_SEQCTL(p->base));	\
-		} while (inw(O_SEQADDR(p->base)) != 0);	\
-							\
-		UNPAUSE_SEQUENCER(p);			\
-	} while (0)
-
-/*
- *  Since we declared this using SA_INTERRUPT, interrupts should
- *  be disabled all through this function unless we say otherwise.
- */
-static
-void aha274x_isr(int irq, struct pt_regs * regs)
-{
-	int base, intstat;
-	struct aha274x_host *p;
-	
-	p = (struct aha274x_host *)aha274x_boards[irq]->hostdata;
-	base = p->base;
-
-	/*
-	 *  Check the startup flag - if no commands have been queued,
-	 *  we probably have the interrupt type set wrong.  Reverse
-	 *  the stored value and the active one in the host control
-	 *  register.
-	 */
-	if (p->startup) {
-		p->unpause ^= 0x8;
-		outb(inb(O_HCNTRL(p->base)) ^ 0x8, O_HCNTRL(p->base));
-		return;
-	}
-
-	/*
-	 *  Handle all the interrupt sources - especially for SCSI
-	 *  interrupts, we won't get a second chance at them.
-	 */
-	intstat = inb(O_INTSTAT(base));
-
-	if (intstat & 0x8) {				/* BRKADRINT */
-
-		panic("aha274x_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
-		      inb(O_ERROR(base)), inw(O_SEQADDR(base)));
-	}
-
-	if (intstat & 0x4) {				/* SCSIINT */
-
-		int scbptr = inb(O_SCBPTR(base));
-		int status = inb(O_SSTAT1(base));
-		Scsi_Cmnd *cmd;
-
-		cmd = (Scsi_Cmnd *)p->SCB_array[scbptr];
-		if (!cmd) {
-			printk("aha274x_isr: no command for scb (scsiint)\n");
-			/*
-			 *  Turn off the interrupt and set status
-			 *  to zero, so that it falls through the
-			 *  reset of the SCSIINT code.
-			 */
-			outb(status, O_CLRSINT1(base));
-			UNPAUSE_SEQUENCER(p);
-			outb(0x4, O_CLRINT(base));	/* undocumented */
-			status = 0;
-		}
-		p->SCB_array[scbptr] = NULL;
-
-		/*
-		 *  Only the SCSI Status 1 register has information
-		 *  about exceptional conditions that we'd have a
-		 *  SCSIINT about; anything in SSTAT0 will be handled
-		 *  by the sequencer.  Note that there can be multiple
-		 *  bits set.
-		 */
-		if (status & 0x80) {			/* SELTO */
-			/*
-			 *  Hardware selection timer has expired.  Turn
-			 *  off SCSI selection sequence.
-			 */
-			outb(0, O_SCSISEQ(base));
-			cmd->result = DID_TIME_OUT << 16;
-
-			/*
-			 *  If there's an active message, it belongs to the
-			 *  command that is getting punted - remove it.
-			 */
-			outb(0, HA_MSG_FLAGS(base));
-
-			/*
-			 *  Shut off the offending interrupt sources, reset
-			 *  the sequencer address to zero and unpause it,
-			 *  then call the high-level SCSI completion routine.
-			 *
-			 *  WARNING!  This is a magic sequence!  After many
-			 *  hours of guesswork, turning off the SCSI interrupts
-			 *  in CLRSINT? does NOT clear the SCSIINT bit in
-			 *  INTSTAT.  By writing to the (undocumented, unused
-			 *  according to the AIC-7770 manual) third bit of
-			 *  CLRINT, you can clear INTSTAT.  But, if you do it
-			 *  while the sequencer is paused, you get a BRKADRINT
-			 *  with an Illegal Host Address status, so the
-			 *  sequencer has to be restarted first.
-			 */
-			outb(0x80, O_CLRSINT1(base));	/* CLRSELTIMO */
-			RESTART_SEQUENCER(p);
-
-			outb(0x4, O_CLRINT(base));	/* undocumented */
-			cmd->scsi_done(cmd);
-		}
-
-		if (status & 0x4) {			/* SCSIPERR */
-			/*
-			 *  A parity error has occurred during a data
-			 *  transfer phase.  Flag it and continue.
-			 */
-			printk("aha274x: parity error on target %d, lun %d\n",
-			       cmd->target,
-			       cmd->lun);
-			aha274x_parity(cmd) = DID_PARITY;
-
-			/*
-			 *  Clear interrupt and resume as above.
-			 */
-			outb(0x4, O_CLRSINT1(base));	/* CLRSCSIPERR */
-			UNPAUSE_SEQUENCER(p);
-
-			outb(0x4, O_CLRINT(base));	/* undocumented */
-		}
-
-		if ((status & (0x8|0x4)) == 0 && status) {
-			/*
-			 *  We don't know what's going on.  Turn off the
-			 *  interrupt source and try to continue.
-			 */
-			printk("aha274x_isr: sstat1 = 0x%x\n", status);
-			outb(status, O_CLRSINT1(base));
-			UNPAUSE_SEQUENCER(p);
-			outb(0x4, O_CLRINT(base));	/* undocumented */
-		}
-	}
-
-	if (intstat & 0x2) {				/* CMDCMPLT */
-
-		int complete, old_scbptr;
-		struct aha274x_scb scb;
-		unsigned actual;
-		Scsi_Cmnd *cmd;
-
-		/*
-		 *  The sequencer will continue running when it
-		 *  issues this interrupt.  There may be >1 commands
-		 *  finished, so loop until we've processed them all.
-		 */
-		do {
-			complete = inb(O_QOUTFIFO(base));
-
-			cmd = (Scsi_Cmnd *)p->SCB_array[complete];
-			if (!cmd) {
-				printk("aha274x warning: "
-				       "no command for scb (cmdcmplt)\n");
-				continue;
-			}
-			p->SCB_array[complete] = NULL;
-			
-			PAUSE_SEQUENCER(p);
-
-			/*
-			 *  After pausing the sequencer (and waiting
-			 *  for it to stop), save its SCB pointer, then
-			 *  write in our completed one and read the SCB
-			 *  registers.  Afterwards, restore the saved
-			 *  pointer, unpause the sequencer and call the
-			 *  higher-level completion function - unpause
-			 *  first since we have no idea how long done()
-			 *  will take.
-			 */
-			old_scbptr = inb(O_SCBPTR(base));
-			outb(complete, O_SCBPTR(base));
-
-			aha274x_getscb(base, &scb);
-			outb(old_scbptr, O_SCBPTR(base));
-
-			UNPAUSE_SEQUENCER(p);
-
-			cmd->result = scb.target_status |
-				     (aha274x_parity(cmd) << 16);
-
-			/*
-			 *  Did we underflow?  At this time, there's only
-			 *  one other driver that bothers to check for this,
-			 *  and cmd->underflow seems to be set rather half-
-			 *  heartedly in the higher-level SCSI code.
-			 */
-			actual = aha274x_length(cmd,
-						scb.residual_SG_segment_count);
-
-			actual -= ((scb.residual_data_count[2] << 16) |
-				   (scb.residual_data_count[1] <<  8) |
-				   (scb.residual_data_count[0]));
-
-			if (actual < cmd->underflow) {
-				printk("aha274x: target %d underflow - "
-				       "wanted (at least) %u, got %u\n",
-				       cmd->target, cmd->underflow, actual);
-
-				cmd->result = scb.target_status |
-					     (DID_UNDERFLOW << 16);
-			}
-
-			cmd->scsi_done(cmd);
-
-			/*
-			 *  Clear interrupt status before checking
-			 *  the output queue again.  This eliminates
-			 *  a race condition whereby a command could
-			 *  complete between the queue poll and the
-			 *  interrupt clearing, so notification of the
-			 *  command being complete never made it back
-			 *  up to the kernel.
-			 */
-			outb(0x2, O_CLRINT(base));	/* CLRCMDINT */
-
-		} while (inb(O_QOUTCNT(base)));
-	}
-
-	if (intstat & 0x1) {				/* SEQINT */
-
-		unsigned char transfer, offset, rate;
-
-		/*
-		 *  Although the sequencer is paused immediately on
-		 *  a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
-		 *  condition will have unpaused the sequencer before
-		 *  this point.
-		 */
-		PAUSE_SEQUENCER(p);
-
-		switch (intstat & 0xf0) {
-		    case 0x00:
-			panic("aha274x_isr: unknown scsi bus phase\n");
-		    case 0x10:
-			debug("aha274x_isr warning: "
-			      "issuing message reject, 1st byte 0x%x\n",
-			      inb(HA_REJBYTE(base)));
-			break;
-		    case 0x20:
-			panic("aha274x_isr: reconnecting target %d "
-			      "didn't issue IDENTIFY message\n",
-			      (inb(O_SELID(base)) >> 4) & 0xf);
-		    case 0x30:
-			debug("aha274x_isr: sequencer couldn't find match "
-			      "for reconnecting target %d - issuing ABORT\n",
-			      (inb(O_SELID(base)) >> 4) & 0xf);
-			break;
-		    case 0x40:
-			transfer = inb(HA_ARG_1(base));
-			offset = inb(HA_ARG_2(base));
-			aha274x_to_scsirate(&rate, transfer, offset);
-			outb(rate, HA_RETURN_1(base));
-			debug_rate(base, rate);
-			break;
-		    default:
-			debug("aha274x_isr: seqint, "
-			      "intstat = 0x%x, scsisigi = 0x%x\n",
-			      intstat, inb(O_SCSISIGI(base)));
-			break;
-		}
-
-		outb(0x1, O_CLRINT(base));		/* CLRSEQINT */
-		UNPAUSE_SEQUENCER(p);
-	}
-}
-
-/*
- *  Probing for EISA boards: it looks like the first two bytes
- *  are a manufacturer code - three characters, five bits each:
- *
- *		 BYTE 0   BYTE 1   BYTE 2   BYTE 3
- *		?1111122 22233333 PPPPPPPP RRRRRRRR
- *
- *  The characters are baselined off ASCII '@', so add that value
- *  to each to get the real ASCII code for it.  The next two bytes
- *  appear to be a product and revision number, probably vendor-
- *  specific.  This is what is being searched for at each port,
- *  and what should probably correspond to the ID= field in the
- *  ECU's .cfg file for the card - if your card is not detected,
- *  make sure your signature is listed in the array.
- *
- *  The fourth byte's lowest bit seems to be an enabled/disabled
- *  flag (rest of the bits are reserved?).
- */
-
-static
-enum aha_type aha274x_probe(int slot, int s_base)
-{
-	int i;
-	unsigned char buf[4];
-
-	static struct {
-		int n;
-		unsigned char signature[sizeof(buf)];
-		enum aha_type type;
-	} S[] = {
-		{4, { 0x04, 0x90, 0x77, 0x71 }, T_274X},	/* host adapter 274x */
-		{4, { 0x04, 0x90, 0x77, 0x70 }, T_274X},	/* motherboard 274x  */
-		{4, { 0x04, 0x90, 0x77, 0x56 }, T_284X},	/* 284x, BIOS enabled */
-	};
-
-	for (i = 0; i < sizeof(buf); i++) {
-		/*
-		 *  The VL-bus cards need to be primed by
-		 *  writing before a signature check.
-		 */
-		outb(0x80 + i, s_base);
-		buf[i] = inb(s_base + i);
-	}
-
-	for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
-		if (!memcmp(buf, S[i].signature, S[i].n)) {
-			/*
-			 *  Signature match on enabled card?
-			 */
-			if (inb(s_base + 4) & 1)
-				return(S[i].type);
-			printk("aha274x disabled at slot %d, ignored\n", slot);
-		}
-	}
-	return(T_NONE);
-}
-
-/*
- *  Return ' ' for plain 274x, 'T' for twin-channel, 'W' for
- *  wide channel, '?' for anything else.
- */
-
-static
-char aha274x_type(int base)
-{
-	/*
-	 *  The AIC-7770 can be wired so that, on chip reset,
-	 *  the SCSI Block Control register indicates how many
-	 *  busses the chip is configured for.
-	 */
-	switch (inb(O_SBLKCTL(base))) {
-	    case 0:
-		return(' ');
-	    case 2:
-		return('W');
-	    case 8:
-		return('T');
-	    default:
-		printk("aha274x has unknown bus configuration\n");
-		return('?');
-	}
-}
-
-static
-void aha274x_loadram(int base)
-{
-	static unsigned char seqprog[] = {
-		/*
-		 *  Each sequencer instruction is 29 bits
-		 *  long (fill in the excess with zeroes)
-		 *  and has to be loaded from least -> most
-		 *  significant byte, so this table has the
-		 *  byte ordering reversed.
-		 */
-#		include "aha274x_seq.h"
-	};
-
-	/*
-	 *  When the AIC-7770 is paused (as on chip reset), the
-	 *  sequencer address can be altered and a sequencer
-	 *  program can be loaded by writing it, byte by byte, to
-	 *  the sequencer RAM port - the Adaptec documentation
-	 *  recommends using REP OUTSB to do this, hence the inline
-	 *  assembly.  Since the address autoincrements as we load
-	 *  the program, reset it back to zero afterward.  Disable
-	 *  sequencer RAM parity error detection while loading, and
-	 *  make sure the LOADRAM bit is enabled for loading.
-	 */
-	outb(0x83, O_SEQCTL(base));	/* PERRORDIS|SEQRESET|LOADRAM */
-
-	asm volatile("cld\n\t"
-		     "rep\n\t"
-		     "outsb"
-		     : /* no output */
-		     :"S" (seqprog), "c" (sizeof(seqprog)), "d" (O_SEQRAM(base))
-		     :"si", "cx", "dx");
-
-	/*
-	 *  WARNING!  This is a magic sequence!  After extensive
-	 *  experimentation, it seems that you MUST turn off the
-	 *  LOADRAM bit before you play with SEQADDR again, else
-	 *  you will end up with parity errors being flagged on
-	 *  your sequencer program.  (You would also think that
-	 *  turning off LOADRAM and setting SEQRESET to reset the
-	 *  address to zero would work, but you need to do it twice
-	 *  for it to take effect on the address.  Timing problem?)
-	 */
-	outb(0, O_SEQCTL(base));
-	do {
-		/*
-		 *  Actually, reset it until
-		 *  the address shows up as
-		 *  zero just to be safe..
-		 */
-		outb(0x2, O_SEQCTL(base));	/* SEQRESET */
-
-	} while (inw(O_SEQADDR(base)) != 0);
-}
-
-static
-int aha274x_register(Scsi_Host_Template *template,
-		     enum aha_type type,
-		     int base)
-{
-	int i, irq, scsi_id;
-	struct Scsi_Host *host;
-	struct aha274x_host *p;
-
-	/*
-	 *  Give the AIC-7770 a reset - reading the 274x's registers
-	 *  returns zeroes unless you do.  This forces a pause of the
-	 *  Sequencer.
-	 */
-	outb(1, O_HCNTRL(base));	/* CHIPRST */
-
-	/*
-	 *  The IRQ level in i/o port 4 maps directly onto the real
-	 *  IRQ number.  If it's ok, register it with the kernel.
-	 *
-	 *  NB. the Adaptec documentation says the IRQ number is only
-	 *	in the lower four bits; the ECU information shows the
-	 *	high bit being used as well.  Which is correct?
-	 */
-	irq = inb(HA_INTDEF(base)) & 0xf;
-	if (irq < 9 || irq > 15) {
-		printk("aha274x uses unsupported IRQ level, ignoring\n");
-		return(0);
-	}
-	
-	/*
-	 *  Lock out other contenders for our i/o space.
-	 */
-	request_region(O_MINREG(base), O_MAXREG(base)-O_MINREG(base), "aha27x");
-
-	/*
-	 *  Any card-type-specific adjustments before we register
-	 *  the scsi host(s).
-	 */
-
-	scsi_id = inb(HA_SCSICONF(base)) & 0x7;
-
-	switch (aha274x_type(base)) {
-	    case 'T':
-		printk("aha274x warning: ignoring channel B of 274x-twin\n");
-		break;
-	    case ' ':
-		break;
-	    default:
-		printk("aha274x is an unsupported type, ignoring\n");
-		return(0);
-	}
-
-	/*
-	 *  Before registry, make sure that the offsets of the
-	 *  struct scatterlist are what the sequencer will expect,
-	 *  otherwise disable scatter-gather altogether until someone
-	 *  can fix it.  This is important since the sequencer will
-	 *  DMA elements of the SG array in while executing commands.
-	 */
-	if (template->sg_tablesize != SG_NONE) {
-		struct scatterlist sg;
-
-		if (SG_STRUCT_CHECK(sg)) {
-			printk("aha274x warning: kernel scatter-gather "
-			       "structures changed, disabling it\n");
-			template->sg_tablesize = SG_NONE;
-		}
-	}
-	
-	/*
-	 *  Register each "host" and fill in the returned Scsi_Host
-	 *  structure as best we can.  Some of the parameters aren't
-	 *  really relevant for EISA, and none of the high-level SCSI
-	 *  code looks at it anyway.. why are the fields there?  Also
-	 *  save the pointer so that we can find the information when
-	 *  an IRQ is triggered.
-	 */
-	host = scsi_register(template, sizeof(struct aha274x_host));
-	host->this_id = scsi_id;
-	host->irq = irq;
-
-	aha274x_boards[irq] = host;
-	
-	p = (struct aha274x_host *)host->hostdata;
-	for (i = 0; i < AHA274X_MAXSCB; i++)
-		p->SCB_array[i] = NULL;
-	p->base = base;
-
-	/*
-	 *  The interrupt trigger is different depending
-	 *  on whether the card is EISA or VL-bus - sometimes.
-	 *  The startup variable will be cleared once the first
-	 *  command is queued, and is checked in the isr to
-	 *  try and detect when the interrupt type is set
-	 *  incorrectly, triggering an interrupt immediately.
-	 */
-	p->unpause = (type != T_274X ? 0x2 : 0xa);
-	p->startup = !0;
-
-	/*
-	 *  Register IRQ with the kernel _after_ the host information
-	 *  is set up, in case we take an interrupt right away, due to
-	 *  the interrupt type being set wrong.
-	 */
-	if (request_irq(irq, aha274x_isr, SA_INTERRUPT, "AHA274x/284x")) {
-		printk("aha274x couldn't register irq %d, ignoring\n", irq);
-		return(0);
-	}
-
-	/*
-	 *  A reminder until this can be detected automatically.
-	 */
-	printk("aha274x: extended translation %sabled\n",
-	       aha274x_extended ? "en" : "dis");
-
-	/*
-	 *  Print out debugging information before re-enabling
-	 *  the card - a lot of registers on it can't be read
-	 *  when the sequencer is active.
-	 */
-	debug_config(type, base);
-
-	/*
-	 *  Load the sequencer program, then re-enable the board -
-	 *  resetting the AIC-7770 disables it, leaving the lights
-	 *  on with nobody home.
-	 */
-	aha274x_loadram(base);
-	outb(1, O_BCTL(base));		/* ENABLE */
-
-	/*
-	 *  Set the host adapter registers to indicate that synchronous
-	 *  negotiation should be attempted the first time the targets
-	 *  are communicated with.  Also initialize the active message
-	 *  flag to indicate that there is no message.
-	 */
-	outb(0xff, HA_NEEDSDTR(base));
-	outb(0, HA_MSG_FLAGS(base));
-
-	/*
-	 *  Unpause the sequencer before returning and enable
-	 *  interrupts - we shouldn't get any until the first
-	 *  command is sent to us by the high-level SCSI code.
-	 */
-	UNPAUSE_SEQUENCER(p);
-	return(1);
-}
-
-int aha274x_detect(Scsi_Host_Template *template)
-{
-	enum aha_type type;
-	int found = 0, slot, base;
-
-	for (slot = MINEISA; slot <= MAXEISA; slot++) {
-
-		base = SLOTBASE(slot);
-		
-		if (check_region(O_MINREG(base),
-				 O_MAXREG(base)-O_MINREG(base)))
-		{
-			/*
-			 *  Some other driver has staked a
-			 *  claim to this i/o region already.
-			 */
-			continue;
-		}
-
-		type = aha274x_probe(slot, O_BIDx(base));
-
-		if (type != T_NONE) {
-			/*
-			 *  We "find" a 274x if we locate the card
-			 *  signature and we can set it up and register
-			 *  it with the kernel without incident.
-			 */
-			found += aha274x_register(template, type, base);
-		}
-	}
-	template->name = (char *)aha274x_info(NULL);
-	return(found);
-}
-
-const char *aha274x_info(struct Scsi_Host * shost)
-{
-	return("Adaptec AHA274x/284x (EISA/VL-bus -> Fast SCSI) "
-	       AHA274X_SEQ_VERSION "/"
-	       AHA274X_H_VERSION "/"
-	       "1.29");
-}
-
-int aha274x_command(Scsi_Cmnd *cmd)
-{
-	/*
-	 *  This is a relic of non-interrupt-driven SCSI
-	 *  drivers.  With the can_queue variable set, this
-	 *  should never be called.
-	 */
-	panic("aha274x_command was called\n");
-}
-
-static
-void aha274x_buildscb(struct aha274x_host *p,
-		      Scsi_Cmnd *cmd,
-		      struct aha274x_scb *scb)
-{
-	void *addr;
-	unsigned length;
-
-	memset(scb, 0, sizeof(*scb));
-
-	/*
-	 *  NB. channel selection (bit 3) is always zero.
-	 */
-	scb->target_channel_lun = ((cmd->target << 4) & 0xf0) |
-				   (cmd->lun & 0x7);
-
-	/*
-	 *  The interpretation of request_buffer and request_bufflen
-	 *  changes depending on whether or not use_sg is zero; a
-	 *  non-zero use_sg indicates the number of elements in the
-	 *  scatter-gather array.
-	 *
-	 *  The AIC-7770 can't support transfers of any sort larger
-	 *  than 2^24 (three-byte count) without backflips.  For what
-	 *  the kernel is doing, this shouldn't occur.  I hope.
-	 */
-	length = aha274x_length(cmd, 0);
-
-	/*
-	 *  The sequencer code cannot yet handle scatter-gather segments
-	 *  larger than 64k (two-byte length).  The 1.1.x kernels, however,
-	 *  have a four-byte length field in the struct scatterlist, so
-	 *  make sure we don't exceed 64k on these kernels for now.
-	 */
-	aha274x_sg_check(cmd);
-
-	if (length > 0xffffff) {
-		panic("aha274x_buildscb: can't transfer > 2^24 - 1 bytes\n");
-	}
-
-	/*
-	 *  XXX - this relies on the host data being stored in a
-	 *	  little-endian format.
-	 */
-	addr = cmd->cmnd;
-	scb->SCSI_cmd_length = cmd->cmd_len;
-	memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
-
-	if (cmd->use_sg) {
-#if 0
-		debug("aha274x_buildscb: SG used, %d segments, length %u\n",
-		      cmd->use_sg,
-		      length);
-#endif
-		scb->SG_segment_count = cmd->use_sg;
-		memcpy(scb->SG_list_pointer,
-		       &cmd->request_buffer,
-		       sizeof(scb->SG_list_pointer));
-	} else {
-		scb->SG_segment_count = 0;
-		memcpy(scb->data_pointer,
-		       &cmd->request_buffer,
-		       sizeof(scb->data_pointer));
-		memcpy(scb->data_count,
-		       &cmd->request_bufflen,
-		       sizeof(scb->data_count));
-	}
-}
-
-static
-void aha274x_putscb(int base, struct aha274x_scb *scb)
-{
-	/*
-	 *  By turning on the SCB auto increment, any reference
-	 *  to the SCB I/O space postincrements the SCB address
-	 *  we're looking at.  So turn this on and dump the relevant
-	 *  portion of the SCB to the card.
-	 */
-	outb(0x80, O_SCBCNT(base));	/* SCBAUTO */
-
-	asm volatile("cld\n\t"
-		     "rep\n\t"
-		     "outsb"
-		     : /* no output */
-		     :"S" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
-		     :"si", "cx", "dx");
-
-	outb(0, O_SCBCNT(base));
-}
-
-int aha274x_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
-{
-	long flags;
-	int empty, old_scbptr;
-	struct aha274x_host *p;
-	struct aha274x_scb scb;
-
-#if 0
-	debug("aha274x_queue: cmd 0x%x (size %u), target %d, lun %d\n",
-	      cmd->cmnd[0],
-	      cmd->cmd_len,
-	      cmd->target,
-	      cmd->lun);
-#endif
-
-	p = (struct aha274x_host *)cmd->host->hostdata;
-
-	/*
-	 *  Construct the SCB beforehand, so the sequencer is
-	 *  paused a minimal amount of time.
-	 */
-	aha274x_buildscb(p, cmd, &scb);
-
-	/*
-	 *  Clear the startup flag - we can now legitimately
-	 *  expect interrupts.
-	 */
-	p->startup = 0;
-
-	/*
-	 *  This is a critical section, since we don't want the
-	 *  interrupt routine mucking with the host data or the
-	 *  card.  Since the kernel documentation is vague on
-	 *  whether or not we are in a cli/sti pair already, save
-	 *  the flags to be on the safe side.
-	 */
-	save_flags(flags);
-	cli();
-
-	/*
-	 *  Find a free slot in the SCB array to load this command
-	 *  into.  Since can_queue is set to AHA274X_MAXSCB, we
-	 *  should always find one.
-	 */
-	for (empty = 0; empty < AHA274X_MAXSCB; empty++)
-		if (!p->SCB_array[empty])
-			break;
-	if (empty == AHA274X_MAXSCB)
-		panic("aha274x_queue: couldn't find a free scb\n");
-
-	/*
-	 *  Pause the sequencer so we can play with its registers -
-	 *  wait for it to acknowledge the pause.
-	 *
-	 *  XXX - should the interrupts be left on while doing this?
-	 */
-	PAUSE_SEQUENCER(p);
-
-	/*
-	 *  Save the SCB pointer and put our own pointer in - this
-	 *  selects one of the four banks of SCB registers.  Load
-	 *  the SCB, then write its pointer into the queue in FIFO
-	 *  and restore the saved SCB pointer.
-	 */
-	old_scbptr = inb(O_SCBPTR(p->base));
-	outb(empty, O_SCBPTR(p->base));
-	
-	aha274x_putscb(p->base, &scb);
-
-	outb(empty, O_QINFIFO(p->base));
-	outb(old_scbptr, O_SCBPTR(p->base));
-
-	/*
-	 *  Make sure the Scsi_Cmnd pointer is saved, the struct it
-	 *  points to is set up properly, and the parity error flag
-	 *  is reset, then unpause the sequencer and watch the fun
-	 *  begin.
-	 */
-	cmd->scsi_done = fn;
-	p->SCB_array[empty] = cmd;
-	aha274x_parity(cmd) = DID_OK;
-
-	UNPAUSE_SEQUENCER(p);
-
-	restore_flags(flags);
-	return(0);
-}
-
-/* return values from aha274x_kill */
-
-enum k_state {
-	k_ok,				/* scb found and message sent */
-	k_busy,				/* message already present */
-	k_absent,			/* couldn't locate scb */
-	k_disconnect,			/* scb found, but disconnected */
-};
-
-/*
- *  This must be called with interrupts disabled - it's going to
- *  be messing around with the host data, and an interrupt being
- *  fielded in the middle could get ugly.
- *
- *  Since so much of the abort and reset code is shared, this
- *  function performs more magic than it really should.  If the
- *  command completes ok, then it will call scsi_done with the
- *  result code passed in.  The unpause parameter controls whether
- *  or not the sequencer gets unpaused - the reset function, for
- *  instance, may want to do something more aggressive.
- *
- *  Note that the command is checked for in our SCB_array first
- *  before the sequencer is paused, so if k_absent is returned,
- *  then the sequencer is NOT paused.
- */
-
-static
-enum k_state aha274x_kill(Scsi_Cmnd *cmd, unsigned char message,
-			  unsigned int result, int unpause)
-{
-	struct aha274x_host *p;
-	int i, scb, found, queued;
-	unsigned char scbsave[AHA274X_MAXSCB];
-
-	p = (struct aha274x_host *)cmd->host->hostdata;
-
-	/*
-	 *  If we can't find the command, assume it just completed
-	 *  and shrug it away.
-	 */
-	for (scb = 0; scb < AHA274X_MAXSCB; scb++)
-		if (p->SCB_array[scb] == cmd)
-			break;
-
-	if (scb == AHA274X_MAXSCB)
-		return(k_absent);
-
-	PAUSE_SEQUENCER(p);
-
-	/*
-	 *  This is the best case, really.  Check to see if the
-	 *  command is still in the sequencer's input queue.  If
-	 *  so, simply remove it.  Reload the queue afterward.
-	 */
-	queued = inb(O_QINCNT(p->base));
-	
-	for (i = found = 0; i < queued; i++) {
-		scbsave[i] = inb(O_QINFIFO(p->base));
-
-		if (scbsave[i] == scb) {
-			found = 1;
-			i -= 1;
-		}
-	}
-
-	queued -= found;
-	for (i = 0; i < queued; i++)
-		outb(scbsave[i], O_QINFIFO(p->base));
-
-	if (found)
-		goto complete;
-
-	/*
-	 *  Check the current SCB bank.  If it's not the one belonging
-	 *  to the command we want to kill, assume that the command
-	 *  is disconnected.  It's rather a pain to force a reconnect
-	 *  and send a message to the target, so we abdicate responsibility
-	 *  in this case.
-	 */
-	if (inb(O_SCBPTR(p->base)) != scb) {
-		if (unpause)
-			UNPAUSE_SEQUENCER(p);
-		return(k_disconnect);
-	}
-
-	/*
-	 *  Presumably at this point our target command is active.  Check
-	 *  to see if there's a message already in effect.  If not, place
-	 *  our message in and assert ATN so the target goes into MESSAGE
-	 *  OUT phase.
-	 */
-	if (inb(HA_MSG_FLAGS(p->base)) & 0x80) {
-		if (unpause)
-			UNPAUSE_SEQUENCER(p);
-		return(k_busy);
-	}
-
-	outb(0x80, HA_MSG_FLAGS(p->base));		/* active message */
-	outb(1, HA_MSG_LEN(p->base));			/* length = 1 */
-	outb(message, HA_MSG_START(p->base));		/* message body */
-
-	/*
-	 *  Assert ATN.  Use the value of SCSISIGO saved by the
-	 *  sequencer code so we don't alter its contents radically
-	 *  in the middle of something critical.
-	 */
-	outb(inb(HA_SIGSTATE(p->base)) | 0x10, O_SCSISIGO(p->base));
-
-	/*
-	 *  The command has been killed.  Do the bookkeeping, unpause
-	 *  the sequencer, and notify the higher-level SCSI code.
-	 */
-complete:
-	p->SCB_array[scb] = NULL;
-	if (unpause)
-		UNPAUSE_SEQUENCER(p);
-
-	cmd->result = result << 16;
-	cmd->scsi_done(cmd);
-	return(k_ok);
-}
-
-int aha274x_abort(Scsi_Cmnd *cmd)
-{
-	int rv;
-	long flags;
-
-	save_flags(flags);
-	cli();
-
-	switch (aha274x_kill(cmd, ABORT, DID_ABORT, !0)) {
-	    case k_ok:		rv = SCSI_ABORT_SUCCESS;	break;
-	    case k_busy:	rv = SCSI_ABORT_BUSY;		break;
-	    case k_absent:	rv = SCSI_ABORT_NOT_RUNNING;	break;
-	    case k_disconnect:	rv = SCSI_ABORT_SNOOZE;		break;
-	    default:
-		panic("aha274x_do_abort: internal error\n");
-	}
-
-	restore_flags(flags);
-	return(rv);
-}
-
-/*
- *  Resetting the bus always succeeds - is has to, otherwise the
- *  kernel will panic!  Try a surgical technique - sending a BUS
- *  DEVICE RESET message - on the offending target before pulling
- *  the SCSI bus reset line.
- */
-
-int aha274x_reset(Scsi_Cmnd *cmd)
-{
-	int i;
-	long flags;
-	Scsi_Cmnd *reset;
-	struct aha274x_host *p;
-
-	p = (struct aha274x_host *)cmd->host->hostdata;
-	save_flags(flags);
-	cli();
-
-	switch (aha274x_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0)) {
-
-	    case k_ok:
-		/*
-		 *  The RESET message was sent to the target
-		 *  with no problems.  Flag that target as
-		 *  needing a SDTR negotiation on the next
-		 *  connection and restart the sequencer.
-		 */
-		outb((1 << cmd->target), HA_NEEDSDTR(p->base));
-		UNPAUSE_SEQUENCER(p);
-		break;
-
-	    case k_absent:
-		/*
-		 *  The sequencer will not be paused if aha274x_kill()
-		 *  couldn't find the command.
-		 */
-		PAUSE_SEQUENCER(p);
-		/* falls through */
-
-	    case k_busy:
-	    case k_disconnect:
-		/*
-		 *  Do a hard reset of the SCSI bus.  According to the
-		 *  SCSI-2 draft specification, reset has to be asserted
-		 *  for at least 25us.  I'm invoking the kernel delay
-		 *  function for 30us since I'm not totally trusting of
-		 *  the busy loop timing.
-		 *
-		 *  XXX - I'm not convinced this works.  I tried resetting
-		 *	  the bus before, trying to get the devices on the
-		 *	  bus to revert to asynchronous transfer, and it
-		 *	  never seemed to work.
-		 */
-		debug("aha274x: attempting to reset scsi bus and card\n");
-
-		outb(1, O_SCSISEQ(p->base));		/* SCSIRSTO */
-		udelay(30);
-		outb(0, O_SCSISEQ(p->base));		/* !SCSIRSTO */
-
-		outb(0xff, HA_NEEDSDTR(p->base));
-		UNPAUSE_SEQUENCER(p);
-
-		/*
-		 *  Locate the command and return a "reset" status
-		 *  for it.  This is not completely correct and will
-		 *  probably return to haunt me later.
-		 */
-		for (i = 0; i < AHA274X_MAXSCB; i++) {
-			if (cmd == p->SCB_array[i]) {
-				reset = (Scsi_Cmnd *)p->SCB_array[i];
-				p->SCB_array[i] = NULL;
-				reset->result = DID_RESET << 16;
-				reset->scsi_done(reset);
-				break;
-			}
-		}
-		break;
-
-	    default:
-		panic("aha274x_reset: internal error\n");
-	}
-
-	restore_flags(flags);
-	return(SCSI_RESET_SUCCESS);
-}
-
-int aha274x_biosparam(Disk *disk, int devno, int geom[])
-{
-	int heads, sectors, cylinders;
-
-	/*
-	 *  XXX - if I could portably find the card's configuration
-	 *	  information, then this could be autodetected instead
-	 *	  of left to a boot-time switch.
-	 */
-	heads = 64;
-	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
-
-	if (aha274x_extended && cylinders > 1024) {
-		heads = 255;
-		sectors = 63;
-		cylinders = disk->capacity / (255 * 63);
-	}
-
-	geom[0] = heads;
-	geom[1] = sectors;
-	geom[2] = cylinders;
-
-	return(0);
-}
-
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aha274x.h linux/drivers/scsi/aha274x.h
--- v1.3.3/linux/drivers/scsi/aha274x.h	Tue Nov 29 10:07:14 1994
+++ linux/drivers/scsi/aha274x.h	Thu Jan  1 02:00:00 1970
@@ -1,63 +0,0 @@
-/* @(#)aha274x.h 1.11 94/09/06 jda */
-
-/*
- * Adaptec 274x device driver for Linux.
- * Copyright (c) 1994 The University of Calgary Department of Computer Science.
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef aha274x_h
-#define aha274x_h
-
-#define	AHA274X_MAXSCB		4
-#define AHA274X_H_VERSION	"1.11"
-
-/*
- *  Scsi_Host_Template (see hosts.h) for 274x - some fields
- *  to do with card config are filled in after the card is
- *  detected.
- */
-#define AHA274X	{						\
-	NULL,							\
-	NULL,							\
-	NULL,							\
-	aha274x_detect,						\
-	NULL,							\
-	aha274x_info,						\
-	aha274x_command,					\
-	aha274x_queue,						\
-	aha274x_abort,						\
-	aha274x_reset,						\
-	NULL,							\
-	aha274x_biosparam,					\
-	AHA274X_MAXSCB,		/* max simultaneous cmds      */\
-	-1,			/* scsi id of host adapter    */\
-	SG_ALL,			/* max scatter-gather cmds    */\
-	1,			/* cmds per lun (linked cmds) */\
-	0,			/* number of 274x's present   */\
-	0,			/* no memory DMA restrictions */\
-	DISABLE_CLUSTERING					\
-}
-
-extern int aha274x_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-extern int aha274x_biosparam(Disk *, int, int[]);
-extern int aha274x_detect(Scsi_Host_Template *);
-extern int aha274x_command(Scsi_Cmnd *);
-extern int aha274x_abort(Scsi_Cmnd *);
-extern int aha274x_reset(Scsi_Cmnd *);
-extern const char *aha274x_info(struct Scsi_Host *);
-
-#endif
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aha274x.seq linux/drivers/scsi/aha274x.seq
--- v1.3.3/linux/drivers/scsi/aha274x.seq	Sun Nov 20 21:50:47 1994
+++ linux/drivers/scsi/aha274x.seq	Thu Jan  1 02:00:00 1970
@@ -1,1021 +0,0 @@
-# @(#)aha274x.seq 1.28 94/10/04 jda
-#
-# Adaptec 274x device driver for Linux.
-# Copyright (c) 1994 The University of Calgary Department of Computer Science.
-# 
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-# 
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-VERSION AHA274X_SEQ_VERSION 1.28
-
-MAXSCB		= 4
-
-SCSISEQ		= 0x00
-SXFRCTL0	= 0x01
-SXFRCTL1	= 0x02
-SCSISIGI	= 0x03
-SCSISIGO	= 0x03
-SCSIRATE	= 0x04
-SCSIID		= 0x05
-SCSIDATL	= 0x06
-STCNT		= 0x08
-STCNT+0		= 0x08
-STCNT+1		= 0x09
-STCNT+2		= 0x0a
-SSTAT0		= 0x0b
-CLRSINT1	= 0x0c
-SSTAT1		= 0x0c
-SIMODE1		= 0x11
-SCSIBUSL	= 0x12
-SHADDR		= 0x14
-SELID		= 0x19
-SBLKCTL		= 0x1f
-SEQCTL		= 0x60
-A		= 0x64				# == ACCUM
-SINDEX		= 0x65
-DINDEX		= 0x66
-ALLZEROS	= 0x6a
-NONE		= 0x6a
-SINDIR		= 0x6c
-DINDIR		= 0x6d
-FUNCTION1	= 0x6e
-HADDR		= 0x88
-HCNT		= 0x8c
-HCNT+0		= 0x8c
-HCNT+1		= 0x8d
-HCNT+2		= 0x8e
-SCBPTR		= 0x90
-INTSTAT		= 0x91
-DFCNTRL		= 0x93
-DFSTATUS	= 0x94
-DFDAT		= 0x99
-QINFIFO		= 0x9b
-QINCNT		= 0x9c
-QOUTFIFO	= 0x9d
-
-SCSICONF	= 0x5a
-
-#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
-#  zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
-#  to indicate whether or not to reload scatter-gather parameters after
-#  a disconnect.
-#
-SCBARRAY+0	= 0xa0
-SCBARRAY+1	= 0xa1
-SCBARRAY+2	= 0xa2
-SCBARRAY+3	= 0xa3
-SCBARRAY+7	= 0xa7
-SCBARRAY+11	= 0xab
-SCBARRAY+14	= 0xae
-SCBARRAY+15	= 0xaf
-SCBARRAY+16	= 0xb0
-SCBARRAY+17	= 0xb1
-SCBARRAY+18	= 0xb2
-SCBARRAY+19	= 0xb3
-SCBARRAY+20	= 0xb4
-SCBARRAY+21	= 0xb5
-SCBARRAY+22	= 0xb6
-SCBARRAY+23	= 0xb7
-SCBARRAY+24	= 0xb8
-SCBARRAY+25	= 0xb9
-
-SIGNAL_0	= 0x01				# unknown scsi bus phase
-SIGNAL_1	= 0x11				# message reject
-SIGNAL_2	= 0x21				# no IDENTIFY after reconnect
-SIGNAL_3	= 0x31				# no cmd match for reconnect
-SIGNAL_4	= 0x41				# SDTR -> SCSIRATE conversion
-
-#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
-#  device information, 32-33 and 5a-5f as well.  Since we don't support
-#  wide or twin-bus SCSI, 28-2f can be reclaimed.  As it turns out, the
-#  BIOS trashes 20-27 anyway, writing the synchronous negotiation results
-#  on top of the BIOS values, so we re-use those for our per-target
-#  scratchspace (actually a value that can be copied directly into
-#  SCSIRATE).  This implies, since we can't get the BIOS config values,
-#  that all targets will be negotiated with for synchronous transfer.
-#  NEEDSDTR has one bit per target indicating if an SDTR message is
-#  needed for that device - this will be set initially, as well as
-#  after a bus reset condition.
-#
-#  The high bit of DROPATN is set if ATN should be dropped before the ACK
-#  when outb is called.  REJBYTE contains the first byte of a MESSAGE IN
-#  message, so the driver can report an intelligible error if a message is
-#  rejected.
-#
-#  RESELECT's high bit is true if we are currently handling a reselect;
-#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
-#  from the reselecting target.  If we haven't had IDENTIFY, then we have
-#  no idea what the lun is, and we can't select the right SCB register
-#  bank, so force a kernel panic if the target attempts a data in/out or
-#  command phase instead of corrupting something.
-#
-#  Note that SG_NEXT occupies four bytes.
-#
-SYNCNEG		= 0x20
-DISC_DSB_A	= 0x32
-
-DROPATN		= 0x30
-REJBYTE		= 0x31
-RESELECT	= 0x34
-
-MSG_FLAGS	= 0x35
-MSG_LEN		= 0x36
-MSG_START+0	= 0x37
-MSG_START+1	= 0x38
-MSG_START+2	= 0x39
-MSG_START+3	= 0x3a
-MSG_START+4	= 0x3b
-MSG_START+5	= 0x3c
--MSG_START+0	= 0xc9				# 2's complement of MSG_START+0
-
-ARG_1		= 0x4c				# sdtr conversion args & return
-ARG_2		= 0x4d
-RETURN_1	= 0x4c
-
-SIGSTATE	= 0x4e				# value written to SCSISIGO
-NEEDSDTR	= 0x4f				# send SDTR message, 1 bit/trgt
-
-SG_SIZEOF	= 12				# sizeof(struct scatterlist)
-SG_NOLOAD	= 0x50				# load SG pointer/length?
-SG_COUNT	= 0x51				# working value of SG count
-SG_NEXT		= 0x52				# working value of SG pointer
-SG_NEXT+0	= 0x52
-SG_NEXT+1	= 0x53
-SG_NEXT+2	= 0x54
-SG_NEXT+3	= 0x55
-
-#  Poll QINCNT for work - the lower three bits contain
-#  the number of entries in the Queue In FIFO.
-#
-start:
-	test	SCSISIGI,0x4	jnz reselect	# BSYI
-	test	QINCNT,0x7	jz start
-
-#  We have at least one queued SCB now.  Set the SCB pointer
-#  from the FIFO so we see the right bank of SCB registers,
-#  then set SCSI options and set the initiator and target
-#  SCSI IDs.
-#
-	mov	SCBPTR,QINFIFO
-	mov	SCBARRAY+1	call initialize
-	clr	SG_NOLOAD
-	clr	RESELECT
-
-#  As soon as we get a successful selection, the target should go
-#  into the message out phase since we have ATN asserted.  Prepare
-#  the message to send, locking out the device driver.  If the device
-#  driver hasn't beaten us with an ABORT or RESET message, then tack
-#  on a SDTR negotiation if required.
-#
-#  Messages are stored in scratch RAM starting with a flag byte (high bit
-#  set means active message), one length byte, and then the message itself.
-#
-	mov	SCBARRAY+1	call disconnect	# disconnect ok?
-
-	and	SINDEX,0x7,SCBARRAY+1		# lun
-	or	SINDEX,A			# return value from disconnect
-	or	SINDEX,0x80	call mk_mesg	# IDENTIFY message
-
-	mov	A,SINDEX
-	cmp	MSG_START+0,A	jne !message	# did driver beat us?
-	mvi	MSG_START+1	call mk_sdtr	# build SDTR message if needed
-
-!message:
-
-#  Enable selection phase as an initiator, and do automatic ATN
-#  after the selection.
-#
-	mvi	SCSISEQ,0x48			# ENSELO|ENAUTOATNO
-
-#  Wait for successful arbitration.  The AIC-7770 documentation says
-#  that SELINGO indicates successful arbitration, and that it should
-#  be used to look for SELDO.  However, if the sequencer is paused at
-#  just the right time - a parallel fsck(8) on two drives did it for
-#  me - then SELINGO can flip back to false before we've seen it.  This
-#  makes the sequencer sit in the arbitration loop forever.  This is
-#  Not Good.
-#
-#  Therefore, I've added a check in the arbitration loop for SELDO
-#  too.  This could arguably be made a critical section by disabling
-#  pauses, but I don't want to make a potentially infinite loop a CS.
-#  I suppose you could fold it into the select loop, too, but since
-#  I've been hunting this bug for four days it's kinda like a trophy.
-#
-arbitrate:
-	test	SSTAT0,0x40	jnz *select	# SELDO
-	test	SSTAT0,0x10	jz arbitrate	# SELINGO
-
-#  Wait for a successful selection.  If the hardware selection
-#  timer goes off, then the driver gets the interrupt, so we don't
-#  need to worry about it.
-#
-select:
-	test	SSTAT0,0x40	jz select	# SELDO
-	jmp	*select
-
-#  Reselection is being initiated by a target - we've seen the BSY
-#  line driven active, and we didn't do it!  Enable the reselection
-#  hardware, and wait for it to finish.  Make a note that we've been
-#  reselected, but haven't seen an IDENTIFY message from the target
-#  yet.
-#
-reselect:
-	mvi	SCSISEQ,0x10			# ENRSELI
-
-reselect1:
-	test	SSTAT0,0x20	jz reselect1	# SELDI
-	mov	SELID		call initialize
-
-	mvi	RESELECT,0x80			# reselected, no IDENTIFY
-
-#  After the [re]selection, make sure that the [re]selection enable
-#  bit is off.  This chip is flaky enough without extra things
-#  turned on.  Also clear the BUSFREE bit in SSTAT1 since we'll be
-#  using it shortly.
-#
-*select:
-	clr	SCSISEQ
-	mvi	CLRSINT1,0x8			# CLRBUSFREE
-
-#  Main loop for information transfer phases.  If BSY is false, then
-#  we have a bus free condition, expected or not.  Otherwise, wait
-#  for the target to assert REQ before checking MSG, C/D and I/O
-#  for the bus phase.
-#
-#  We can't simply look at the values of SCSISIGI here (if we want
-#  to do synchronous data transfer), because the target won't assert
-#  REQ if it's already sent us some data that we haven't acknowledged
-#  yet.
-#
-ITloop:
-	test	SSTAT1,0x8	jnz p_busfree	# BUSFREE
-	test	SSTAT1,0x1	jz ITloop	# REQINIT
-
-	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
-
-	cmp	ALLZEROS,A	je p_dataout
-	cmp	A,0x40		je p_datain
-	cmp	A,0x80		je p_command
-	cmp	A,0xc0		je p_status
-	cmp	A,0xa0		je p_mesgout
-	cmp	A,0xe0		je p_mesgin
-
-	mvi	INTSTAT,SIGNAL_0		# unknown - signal driver
-
-p_dataout:
-	mvi	0		call scsisig	# !CDO|!IOO|!MSGO
-	call	assert
-	call	sg_load
-
-	mvi	A,3
-	mvi	DINDEX,HCNT
-	mvi	SCBARRAY+23	call bcopy
-
-	mvi	A,3
-	mvi	DINDEX,STCNT
-	mvi	SCBARRAY+23	call bcopy
-
-	mvi	A,4
-	mvi	DINDEX,HADDR
-	mvi	SCBARRAY+19	call bcopy
-
-	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
-						#   DIRECTION|FIFORESET
-
-#  After a DMA finishes, save the final transfer pointer and count
-#  back into the SCB, in case a device disconnects in the middle of
-#  a transfer.  Use SHADDR and STCNT instead of HADDR and HCNT, since
-#  it's a reflection of how many bytes were transferred on the SCSI
-#  (as opposed to the host) bus.
-#
-	mvi	A,3
-	mvi	DINDEX,SCBARRAY+23
-	mvi	STCNT		call bcopy
-
-	mvi	A,4
-	mvi	DINDEX,SCBARRAY+19
-	mvi	SHADDR		call bcopy
-
-	call	sg_advance
-	mov	SCBARRAY+18,SG_COUNT		# residual S/G count
-
-	jmp	ITloop
-
-p_datain:
-	mvi	0x40		call scsisig	# !CDO|IOO|!MSGO
-	call	assert
-	call	sg_load
-
-	mvi	A,3
-	mvi	DINDEX,HCNT
-	mvi	SCBARRAY+23	call bcopy
-
-	mvi	A,3
-	mvi	DINDEX,STCNT
-	mvi	SCBARRAY+23	call bcopy
-
-	mvi	A,4
-	mvi	DINDEX,HADDR
-	mvi	SCBARRAY+19	call bcopy
-
-	mvi	0x39		call dma	# SCSIEN|SDMAEN|HDMAEN|
-						#   !DIRECTION|FIFORESET
-	mvi	A,3
-	mvi	DINDEX,SCBARRAY+23
-	mvi	STCNT		call bcopy
-
-	mvi	A,4
-	mvi	DINDEX,SCBARRAY+19
-	mvi	SHADDR		call bcopy
-
-	call	sg_advance
-	mov	SCBARRAY+18,SG_COUNT		# residual S/G count
-
-	jmp	ITloop
-
-#  Command phase.  Set up the DMA registers and let 'er rip - the
-#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
-#  so we can copy those three bytes directly into HCNT.
-#
-p_command:
-	mvi	0x80		call scsisig	# CDO|!IOO|!MSGO
-	call	assert
-
-	mvi	A,3
-	mvi	DINDEX,HCNT
-	mvi	SCBARRAY+11	call bcopy
-
-	mvi	A,3
-	mvi	DINDEX,STCNT
-	mvi	SCBARRAY+11	call bcopy
-
-	mvi	A,4
-	mvi	DINDEX,HADDR
-	mvi	SCBARRAY+7	call bcopy
-
-	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
-						#   DIRECTION|FIFORESET
-	jmp	ITloop
-
-#  Status phase.  Wait for the data byte to appear, then read it
-#  and store it into the SCB.
-#
-p_status:
-	mvi	0xc0		call scsisig	# CDO|IOO|!MSGO
-
-	mvi	SCBARRAY+14	call inb
-	jmp	ITloop
-
-#  Message out phase.  If there is no active message, but the target
-#  took us into this phase anyway, build a no-op message and send it.
-#
-p_mesgout:
-	mvi	0xa0		call scsisig	# CDO|!IOO|MSGO
-	mvi	0x8		call mk_mesg	# build NOP message
-
-#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
-#  SXFRCTL0 (SPIOEN) is already on.
-#
-	mvi	SINDEX,MSG_START+0
-	mov	DINDEX,MSG_LEN
-	clr	A
-
-#  When target asks for a byte, drop ATN if it's the last one in
-#  the message.  Otherwise, keep going until the message is exhausted.
-#  (We can't use outb for this since it wants the input in SINDEX.)
-#
-#  Keep an eye out for a phase change, in case the target issues
-#  a MESSAGE REJECT.
-#
-p_mesgout2:
-	test	SSTAT0,0x2	jz p_mesgout2	# SPIORDY
-	test	SSTAT1,0x10	jnz p_mesgout6	# PHASEMIS
-
-	cmp	DINDEX,1	jne p_mesgout3	# last byte?
-	mvi	CLRSINT1,0x40			# CLRATNO - drop ATN
-
-#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
-#  send ACKs in automatic PIO or DMA mode unless you make sure that the
-#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
-#  behaviour is completely undocumented and caused me several days of
-#  grief.
-#
-#  After plugging in different drives to test with and using a longer
-#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
-#  especially when transferring >1 byte.  It seems to be much more stable
-#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
-#  polled for transfer completion - for both output _and_ input.  The
-#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
-#  is accessed (like the documentation says it does), and that on a longer
-#  cable run, the sequencer code was fast enough to loop back and see
-#  an SPIORDY that hadn't dropped yet.
-#
-p_mesgout3:
-	call	one_stcnt
-	mov	SCSIDATL,SINDIR
-
-p_mesgout4:
-	test	SSTAT0,0x4	jz p_mesgout4	# SDONE
-	dec	DINDEX
-	inc	A
-	cmp	MSG_LEN,A	jne p_mesgout2
-
-#  If the next bus phase after ATN drops is a message out, it means
-#  that the target is requesting that the last message(s) be resent.
-#
-p_mesgout5:
-	test	SSTAT1,0x8	jnz p_mesgout6	# BUSFREE
-	test	SSTAT1,0x1	jz p_mesgout5	# REQINIT
-
-	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
-	cmp	A,0xa0		jne p_mesgout6
-	mvi	0x10		call scsisig	# ATNO - re-assert ATN
-
-	jmp	ITloop
-
-p_mesgout6:
-	mvi	CLRSINT1,0x40			# CLRATNO - in case of PHASEMIS
-	clr	MSG_FLAGS			# no active msg
-	jmp	ITloop
-
-#  Message in phase.  Bytes are read using Automatic PIO mode, but not
-#  using inb.  This alleviates a race condition, namely that if ATN had
-#  to be asserted under Automatic PIO mode, it had to beat the SCSI
-#  circuitry sending an ACK to the target.  This showed up under heavy
-#  loads and really confused things, since ABORT commands wouldn't be
-#  seen by the drive after an IDENTIFY message in until it had changed
-#  to a data I/O phase.
-#
-p_mesgin:
-	mvi	0xe0		call scsisig	# CDO|IOO|MSGO
-	mvi	A		call inb_first	# read the 1st message byte
-	mvi	REJBYTE,A			# save it for the driver
-
-	cmp	ALLZEROS,A	jne p_mesgin1
-
-#  We got a "command complete" message, so put the SCB pointer
-#  into the Queue Out, and trigger a completion interrupt.
-#
-	mov	QOUTFIFO,SCBPTR
-	mvi	INTSTAT,0x2			# CMDCMPLT
-	jmp	p_mesgin_done
-
-#  Is it an extended message?  We only support the synchronous data
-#  transfer request message, which will probably be in response to
-#  an SDTR message out from us.  If it's not an SDTR, reject it -
-#  apparently this can be done after any message in byte, according
-#  to the SCSI-2 spec.
-#
-#  XXX - we should really reject this if we didn't initiate the SDTR
-#	 negotiation; this may cause problems with unusual devices.
-#
-p_mesgin1:
-	cmp	A,1		jne p_mesgin2	# extended message code?
-	
-	mvi	A		call inb_next
-	cmp	A,3		jne p_mesginN	# extended mesg length = 3
-	mvi	A		call inb_next
-	cmp	A,1		jne p_mesginN	# SDTR code
-
-	mvi	ARG_1		call inb_next	# xfer period
-	mvi	ARG_2		call inb_next	# REQ/ACK offset
-	mvi	INTSTAT,SIGNAL_4		# call driver to convert
-
-	call	ndx_sdtr			# index sync config for target
-	mov	DINDEX,SINDEX
-	mov	DINDIR,RETURN_1			# save returned value
-
-	not	A				# turn off "need sdtr" flag
-	and	NEEDSDTR,A
-
-#  Even though the SCSI-2 specification says that a device responding
-#  to our SDTR message should honor our parameters for transmitting
-#  to us, it doesn't seem to work too well in real life.  In particular,
-#  a lot of CD-ROM and tape units don't function: try using the SDTR
-#  parameters the device sent us for both transmitting and receiving.
-#
-	mov	SCSIRATE,RETURN_1
-	jmp	p_mesgin_done
-
-#  Is it a disconnect message?  Set a flag in the SCB to remind us
-#  and await the bus going free.
-#
-p_mesgin2:
-	cmp	A,4		jne p_mesgin3	# disconnect code?
-
-	or	SCBARRAY+0,0x4			# set "disconnected" bit
-	jmp	p_mesgin_done
-
-#  Save data pointers message?  Copy working values into the SCB,
-#  usually in preparation for a disconnect.
-#
-p_mesgin3:
-	cmp	A,2		jne p_mesgin4	# save data pointers code?
-
-	call	sg_ram2scb
-	jmp	p_mesgin_done
-
-#  Restore pointers message?  Data pointers are recopied from the
-#  SCB anyway at the start of any DMA operation, so the only thing
-#  to copy is the scatter-gather values.
-#
-p_mesgin4:
-	cmp	A,3		jne p_mesgin5	# restore pointers code?
-
-	call	sg_scb2ram
-	jmp	p_mesgin_done
-
-#  Identify message?  For a reconnecting target, this tells us the lun
-#  that the reconnection is for - find the correct SCB and switch to it,
-#  clearing the "disconnected" bit so we don't "find" it by accident later.
-#
-p_mesgin5:
-	test	A,0x80		jz p_mesgin6	# identify message?
-
-	test	A,0x78		jnz p_mesginN	# !DiscPriv|!LUNTAR|!Reserved
-
-	mov	A		call findSCB	# switch to correct SCB
-
-#  If a active message is present after calling findSCB, then either it
-#  or the driver is trying to abort the command.  Either way, something
-#  untoward has happened and we should just leave it alone.
-#
-	test	MSG_FLAGS,0x80	jnz p_mesgin_done
-
-	xor	SCBARRAY+0,0x4			# clear disconnect bit in SCB
-	mvi	RESELECT,0xc0			# make note of IDENTIFY
-
-	call	sg_scb2ram			# implied restore pointers
-						#   required on reselect
-	jmp	p_mesgin_done
-
-#  Message reject?  If we have an outstanding SDTR negotiation, assume
-#  that it's a response from the target selecting asynchronous transfer,
-#  otherwise just ignore it since we have no clue what it pertains to.
-#
-#  XXX - I don't have a device that responds this way.  Does this code
-#	 actually work?
-#
-p_mesgin6:
-	cmp	A,7		jne p_mesgin7	# message reject code?
-
-	and	FUNCTION1,0x70,SCSIID		# outstanding SDTR message?
-	mov	A,FUNCTION1
-	test	NEEDSDTR,A	jz p_mesgin_done  # no - ignore rejection
-
-	call	ndx_sdtr			# note use of asynch xfer
-	mov	DINDEX,SINDEX
-	clr	DINDIR
-
-	not	A				# turn off "active sdtr" flag
-	and	NEEDSDTR,A
-
-	clr	SCSIRATE			# select asynch xfer
-	jmp	p_mesgin_done
-
-#  [ ADD MORE MESSAGE HANDLING HERE ]
-#
-p_mesgin7:
-
-#  We have no idea what this message in is, and there's no way
-#  to pass it up to the kernel, so we issue a message reject and
-#  hope for the best.  Since we're now using manual PIO mode to
-#  read in the message, there should no longer be a race condition
-#  present when we assert ATN.  In any case, rejection should be a
-#  rare occurrence - signal the driver when it happens.
-#
-p_mesginN:
-	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
-	call	scsisig
-	mvi	INTSTAT,SIGNAL_1		# let driver know
-
-	mvi	0x7		call mk_mesg	# MESSAGE REJECT message
-
-p_mesgin_done:
-	call	inb_last			# ack & turn auto PIO back on
-	jmp	ITloop
-
-#  Bus free phase.  It might be useful to interrupt the device
-#  driver if we aren't expecting this.  For now, make sure that
-#  ATN isn't being asserted and look for a new command.
-#
-p_busfree:
-	mvi	CLRSINT1,0x40			# CLRATNO
-	clr	SIGSTATE
-	jmp	start
-
-#  Bcopy: number of bytes to transfer should be in A, DINDEX should
-#  contain the destination address, and SINDEX should contain the
-#  source address.  All input parameters are trashed on return.
-#
-bcopy:
-	mov	DINDIR,SINDIR
-	dec	A
-	cmp	ALLZEROS,A	jne bcopy
-	ret
-
-#  Locking the driver out, build a one-byte message passed in SINDEX
-#  if there is no active message already.  SINDEX is returned intact.
-#
-mk_mesg:
-	mvi	SEQCTL,0x40			# PAUSEDIS
-	test	MSG_FLAGS,0x80	jnz mk_mesg1	# active message?
-
-	mvi	MSG_FLAGS,0x80			# if not, there is now
-	mvi	MSG_LEN,1			# length = 1
-	mov	MSG_START+0,SINDEX		# 1-byte message
-
-mk_mesg1:
-	clr	SEQCTL				# !PAUSEDIS
-	ret
-
-#  Input byte in Automatic PIO mode.  The address to store the byte
-#  in should be in SINDEX.  DINDEX will be used by this routine.
-#
-inb:
-	test	SSTAT0,0x2	jz inb		# SPIORDY
-	mov	DINDEX,SINDEX
-	call	one_stcnt			# xfer one byte
-	mov	DINDIR,SCSIDATL
-inb1:
-	test	SSTAT0,0x4	jz inb1		# SDONE - wait to "finish"
-	ret
-
-#  Carefully read data in Automatic PIO mode.  I first tried this using
-#  Manual PIO mode, but it gave me continual underrun errors, probably
-#  indicating that I did something wrong, but I feel more secure leaving
-#  Automatic PIO on all the time.
-#
-#  According to Adaptec's documentation, an ACK is not sent on input from
-#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
-#  latched (the usual way), then read the data byte directly off the bus
-#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
-#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
-#  spec guarantees that the target will hold the data byte on the bus until
-#  we send our ACK.
-#
-#  The assumption here is that these are called in a particular sequence,
-#  and that REQ is already set when inb_first is called.  inb_{first,next}
-#  use the same calling convention as inb.
-#
-inb_first:
-	mov	DINDEX,SINDEX
-	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
-
-inb_next:
-	mov	DINDEX,SINDEX			# save SINDEX
-
-	call	one_stcnt			# xfer one byte
-	mov	NONE,SCSIDATL			# dummy read from latch to ACK
-inb_next1:
-	test	SSTAT0,0x4	jz inb_next1	# SDONE
-inb_next2:
-	test	SSTAT0,0x2	jz inb_next2	# SPIORDY - wait for next byte
-	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
-
-inb_last:
-	call	one_stcnt			# ACK with dummy read
-	mov	NONE,SCSIDATL
-inb_last1:
-	test	SSTAT0,0x4	jz inb_last1	# wait for completion
-	ret
-
-#  Output byte in Automatic PIO mode.  The byte to output should be
-#  in SINDEX.  If DROPATN's high bit is set, then ATN will be dropped
-#  before the byte is output.
-#
-outb:
-	test	SSTAT0,0x2	jz outb		# SPIORDY
-	call	one_stcnt			# xfer one byte
-
-	test	DROPATN,0x80	jz outb1
-	mvi	CLRSINT1,0x40			# CLRATNO
-	clr	DROPATN
-outb1:
-	mov	SCSIDATL,SINDEX
-outb2:
-	test	SSTAT0,0x4	jz outb2	# SDONE
-	ret
-
-#  Write the value "1" into the STCNT registers, for Automatic PIO
-#  transfers.
-#
-one_stcnt:
-	clr	STCNT+2
-	clr	STCNT+1
-	mvi	STCNT+0,1	ret
-
-#  DMA data transfer.  HADDR and HCNT must be loaded first, and
-#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
-#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
-#  during initialization.
-#
-dma:
-	mov	DFCNTRL,SINDEX
-dma1:
-dma2:
-	test	SSTAT0,0x1	jnz dma3	# DMADONE
-	test	SSTAT1,0x10	jz dma1		# PHASEMIS, ie. underrun
-
-#  We will be "done" DMAing when the transfer count goes to zero, or
-#  the target changes the phase (in light of this, it makes sense that
-#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
-#  doing a SCSI->Host transfer, flush the data FIFO.
-#
-dma3:
-	test	SINDEX,0x4	jnz dma5	# DIRECTION
-	and	SINDEX,0xfe			# mask out FIFORESET
-	or	DFCNTRL,0x2,SINDEX		# FIFOFLUSH
-dma4:
-	test	DFCNTRL,0x2	jnz dma4	# FIFOFLUSHACK
-
-#  Now shut the DMA enables off, and copy STCNT (ie. the underrun
-#  amount, if any) to the SCB registers; SG_COUNT will get copied to
-#  the SCB's residual S/G count field after sg_advance is called.  Make
-#  sure that the DMA enables are actually off first lest we get an ILLSADDR.
-#
-dma5:
-	clr	DFCNTRL				# disable DMA
-dma6:
-	test	DFCNTRL,0x38	jnz dma6	# SCSIENACK|SDMAENACK|HDMAENACK
-
-	mvi	A,3
-	mvi	DINDEX,SCBARRAY+15
-	mvi	STCNT		call bcopy
-
-	ret
-
-#  Common SCSI initialization for selection and reselection.  Expects
-#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
-#  contents are stomped on return.
-#
-initialize:
-	clr	SBLKCTL				# channel A, !wide
-	and	SCSIID,0xf0,SINDEX		# target ID
-	and	A,0x7,SCSICONF			# SCSI_ID_A[210]
-	or	SCSIID,A
-
-#  Esundry initialization.
-#
-	clr	DROPATN
-	clr	SIGSTATE
-
-#  Turn on Automatic PIO mode now, before we expect to see an REQ
-#  from the target.  It shouldn't hurt anything to leave it on.  Set
-#  CLRCHN here before the target has entered a data transfer mode -
-#  with synchronous SCSI, if you do it later, you blow away some
-#  data in the SCSI FIFO that the target has already sent to you.
-#
-	mvi	SXFRCTL0,0xa			# SPIOEN|CLRCHN
-
-#  Set SCSI bus parity checking and the selection timeout value,
-#  and enable the hardware selection timer.  Set the SELTO interrupt
-#  to signal the driver.
-#
-	and	A,0x38,SCSICONF			# PARITY_ENB_A|SEL_TIM_A[10]
-	or	SXFRCTL1,0x4,A			# ENSTIMER
-	mvi	SIMODE1,0x84			# ENSELTIMO|ENSCSIPERR
-	
-#  Initialize scatter-gather pointers by setting up the working copy
-#  in scratch RAM.
-#
-	call	sg_scb2ram
-
-#  Initialize SCSIRATE with the appropriate value for this target.
-#
-	call	ndx_sdtr
-	mov	SCSIRATE,SINDIR
-	ret
-
-#  Assert that if we've been reselected, then we've seen an IDENTIFY
-#  message.
-#
-assert:
-	test	RESELECT,0x80	jz assert1	# reselected?
-	test	RESELECT,0x40	jnz assert1	# seen IDENTIFY?
-
-	mvi	INTSTAT,SIGNAL_2		# no - cause a kernel panic
-
-assert1:
-	ret
-
-#  Find out if disconnection is ok from the information the BIOS has left
-#  us.  The target ID should be in the upper four bits of SINDEX; A will
-#  contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
-#  on exit.
-#
-#  This is the only place the target ID is limited to three bits, so we
-#  can use the FUNCTION1 register.
-#
-disconnect:
-	and	FUNCTION1,0x70,SINDEX		# strip off extra just in case
-	mov	A,FUNCTION1
-	test	DISC_DSB_A,A	jz disconnect1	# bit nonzero if DISabled
-
-	clr	A		ret
-disconnect1:
-	mvi	A,0x40		ret
-
-#  Locate the SCB matching the target ID in SELID and the lun in the lower
-#  three bits of SINDEX, and switch the SCB to it.  Have the kernel print
-#  a warning message if it can't be found - this seems to happen occasionally
-#  under high loads.  Also, if not found, generate an ABORT message to the
-#  target.
-#
-findSCB:
-	and	A,0x7,SINDEX			# lun in lower three bits
-	or	A,A,SELID			# can I do this?
-	and	A,0xf7				# only channel A implemented
-
-	clr	SINDEX
-
-findSCB1:
-	mov	SCBPTR,SINDEX			# switch to new SCB
-	cmp	SCBARRAY+1,A	jne findSCB2	# target ID/channel/lun match?
-	test	SCBARRAY+0,0x4	jz findSCB2	# should be disconnected
-
-	ret
-
-findSCB2:
-	inc	SINDEX
-	cmp	SINDEX,MAXSCB	jne findSCB1
-
-	mvi	INTSTAT,SIGNAL_3		# not found - signal kernel
-	mvi	0x6		call mk_mesg	# ABORT message
-
-	or	SINDEX,0x10,SIGSTATE		# assert ATNO
-	call	scsisig
-	ret
-
-#  Make a working copy of the scatter-gather parameters in the SCB.
-#
-sg_scb2ram:
-	mov	SG_COUNT,SCBARRAY+2
-
-	mvi	A,4
-	mvi	DINDEX,SG_NEXT
-	mvi	SCBARRAY+3	call bcopy
-
-	mvi	SG_NOLOAD,0x80
-	test	SCBARRAY+0,0x10	jnz sg_scb2ram1	# don't reload s/g?
-	clr	SG_NOLOAD
-
-sg_scb2ram1:
-	ret
-
-#  Copying RAM values back to SCB, for Save Data Pointers message.
-#
-sg_ram2scb:
-	mov	SCBARRAY+2,SG_COUNT
-
-	mvi	A,4
-	mvi	DINDEX,SCBARRAY+3
-	mvi	SG_NEXT		call bcopy
-
-	and	SCBARRAY+0,0xef,SCBARRAY+0
-	test	SG_NOLOAD,0x80	jz sg_ram2scb1	# reload s/g?
-	or	SCBARRAY+0,0x10
-
-sg_ram2scb1:
-	ret
-
-#  Load a struct scatter if needed and set up the data address and
-#  length.  If the working value of the SG count is nonzero, then
-#  we need to load a new set of values.
-#
-#  This, like the above DMA, assumes a little-endian host data storage.
-#
-sg_load:
-	test	SG_COUNT,0xff	jz sg_load3	# SG being used?
-	test	SG_NOLOAD,0x80	jnz sg_load3	# don't reload s/g?
-
-	clr	HCNT+2
-	clr	HCNT+1
-	mvi	HCNT+0,SG_SIZEOF
-
-	mvi	A,4
-	mvi	DINDEX,HADDR
-	mvi	SG_NEXT		call bcopy
-
-	mvi	DFCNTRL,0xd			# HDMAEN|DIRECTION|FIFORESET
-
-#  Wait for DMA from host memory to data FIFO to complete, then disable
-#  DMA and wait for it to acknowledge that it's off.
-#
-sg_load1:
-	test	DFSTATUS,0x8	jz sg_load1	# HDONE
-
-	clr	DFCNTRL				# disable DMA
-sg_load2:
-	test	DFCNTRL,0x8	jnz sg_load2	# HDMAENACK
-
-#  Copy data from FIFO into SCB data pointer and data count.  This assumes
-#  that the struct scatterlist has this structure (this and sizeof(struct
-#  scatterlist) == 12 are asserted in aha274x.c):
-#
-#	struct scatterlist {
-#		char *address;		/* four bytes, little-endian order */
-#		...			/* four bytes, ignored */
-#		unsigned short length;	/* two bytes, little-endian order */
-#	}
-#
-	mov	SCBARRAY+19,DFDAT		# new data address
-	mov	SCBARRAY+20,DFDAT
-	mov	SCBARRAY+21,DFDAT
-	mov	SCBARRAY+22,DFDAT
-
-	mov	NONE,DFDAT			# throw away four bytes
-	mov	NONE,DFDAT
-	mov	NONE,DFDAT
-	mov	NONE,DFDAT
-
-	mov	SCBARRAY+23,DFDAT
-	mov	SCBARRAY+24,DFDAT
-	clr	SCBARRAY+25
-
-sg_load3:
-	ret
-
-#  Advance the scatter-gather pointers only IF NEEDED.  If SG is enabled,
-#  and the SCSI transfer count is zero (note that this should be called
-#  right after a DMA finishes), then move the working copies of the SG
-#  pointer/length along.  If the SCSI transfer count is not zero, then
-#  presumably the target is disconnecting - do not reload the SG values
-#  next time.
-#
-sg_advance:
-	test	SG_COUNT,0xff	jz sg_advance2	# s/g enabled?
-
-	test	STCNT+0,0xff	jnz sg_advance1	# SCSI transfer count nonzero?
-	test	STCNT+1,0xff	jnz sg_advance1
-	test	STCNT+2,0xff	jnz sg_advance1
-
-	clr	SG_NOLOAD			# reload s/g next time
-	dec	SG_COUNT			# one less segment to go
-
-	clr	A				# add sizeof(struct scatter)
-	add	SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
-	adc	SG_NEXT+1,A,SG_NEXT+1
-	adc	SG_NEXT+2,A,SG_NEXT+2
-	adc	SG_NEXT+3,A,SG_NEXT+3
-
-	ret
-
-sg_advance1:
-	mvi	SG_NOLOAD,0x80			# don't reload s/g next time
-sg_advance2:
-	ret
-
-#  Add the array base SYNCNEG to the target offset (the target address
-#  is in SCSIID), and return the result in SINDEX.  The accumulator
-#  contains the 3->8 decoding of the target ID on return.
-#
-ndx_sdtr:
-	shr	A,SCSIID,4
-	and	A,0x7
-	add	SINDEX,SYNCNEG,A
-
-	and	FUNCTION1,0x70,SCSIID		# 3-bit target address decode
-	mov	A,FUNCTION1	ret
-
-#  If we need to negotiate transfer parameters, build the SDTR message
-#  starting at the address passed in SINDEX.  DINDEX is modified on return.
-#
-mk_sdtr:
-	mov	DINDEX,SINDEX			# save SINDEX
-
-	call	ndx_sdtr
-	test	NEEDSDTR,A	jnz mk_sdtr1	# do we need negotiation?
-	ret
-
-mk_sdtr1:
-	mvi	DINDIR,1			# extended message
-	mvi	DINDIR,3			# extended message length = 3
-	mvi	DINDIR,1			# SDTR code
-	mvi	DINDIR,25			# REQ/ACK transfer period
-	mvi	DINDIR,15			# REQ/ACK offset
-
-	add	MSG_LEN,-MSG_START+0,DINDEX	# update message length
-	ret
-
-#  Set SCSI bus control signal state.  This also saves the last-written
-#  value into a location where the higher-level driver can read it - if
-#  it has to send an ABORT or RESET message, then it needs to know this
-#  so it can assert ATN without upsetting SCSISIGO.  The new value is
-#  expected in SINDEX.  Change the actual state last to avoid contention
-#  from the driver.
-#
-scsisig:
-	mov	SIGSTATE,SINDEX
-	mov	SCSISIGO,SINDEX	ret
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aha274x_seq.h linux/drivers/scsi/aha274x_seq.h
--- v1.3.3/linux/drivers/scsi/aha274x_seq.h	Tue Mar  7 16:02:02 1995
+++ linux/drivers/scsi/aha274x_seq.h	Thu Jan  1 02:00:00 1970
@@ -1,341 +0,0 @@
-#define AHA274X_SEQ_VERSION "1.28"
-	0x04, 0x03, 0x12, 0x1a,
-	0x07, 0x9c, 0x00, 0x1e,
-	0xff, 0x9b, 0x90, 0x02,
-	0x00, 0xa1, 0xe6, 0x16,
-	0xff, 0x6a, 0x50, 0x02,
-	0xff, 0x6a, 0x34, 0x02,
-	0x00, 0xa1, 0xf8, 0x16,
-	0x07, 0xa1, 0x65, 0x02,
-	0x00, 0x65, 0x65, 0x00,
-	0x80, 0x65, 0xb5, 0x16,
-	0xff, 0x65, 0x64, 0x02,
-	0x00, 0x37, 0x0d, 0x18,
-	0x38, 0x6a, 0x47, 0x17,
-	0x48, 0x6a, 0x00, 0x00,
-	0x40, 0x0b, 0x16, 0x1a,
-	0x10, 0x0b, 0x0e, 0x1e,
-	0x40, 0x0b, 0x10, 0x1e,
-	0x00, 0x65, 0x16, 0x10,
-	0x10, 0x6a, 0x00, 0x00,
-	0x20, 0x0b, 0x13, 0x1e,
-	0x00, 0x19, 0xe6, 0x16,
-	0x80, 0x6a, 0x34, 0x00,
-	0xff, 0x6a, 0x00, 0x02,
-	0x08, 0x6a, 0x0c, 0x00,
-	0x08, 0x0c, 0xae, 0x1a,
-	0x01, 0x0c, 0x18, 0x1e,
-	0xe0, 0x03, 0x64, 0x02,
-	0x00, 0x6a, 0x22, 0x1c,
-	0x40, 0x64, 0x38, 0x1c,
-	0x80, 0x64, 0x4e, 0x1c,
-	0xc0, 0x64, 0x5b, 0x1c,
-	0xa0, 0x64, 0x5e, 0x1c,
-	0xe0, 0x64, 0x76, 0x1c,
-	0x01, 0x6a, 0x91, 0x00,
-	0x00, 0x6a, 0x52, 0x17,
-	0x00, 0x65, 0xf4, 0x16,
-	0x00, 0x65, 0x1c, 0x17,
-	0x03, 0x6a, 0x64, 0x00,
-	0x8c, 0x6a, 0x66, 0x00,
-	0xb7, 0x6a, 0xb1, 0x16,
-	0x03, 0x6a, 0x64, 0x00,
-	0x08, 0x6a, 0x66, 0x00,
-	0xb7, 0x6a, 0xb1, 0x16,
-	0x04, 0x6a, 0x64, 0x00,
-	0x88, 0x6a, 0x66, 0x00,
-	0xb3, 0x6a, 0xb1, 0x16,
-	0x3d, 0x6a, 0xd9, 0x16,
-	0x03, 0x6a, 0x64, 0x00,
-	0xb7, 0x6a, 0x66, 0x00,
-	0x08, 0x6a, 0xb1, 0x16,
-	0x04, 0x6a, 0x64, 0x00,
-	0xb3, 0x6a, 0x66, 0x00,
-	0x14, 0x6a, 0xb1, 0x16,
-	0x00, 0x65, 0x34, 0x17,
-	0xff, 0x51, 0xb2, 0x02,
-	0x00, 0x65, 0x18, 0x10,
-	0x40, 0x6a, 0x52, 0x17,
-	0x00, 0x65, 0xf4, 0x16,
-	0x00, 0x65, 0x1c, 0x17,
-	0x03, 0x6a, 0x64, 0x00,
-	0x8c, 0x6a, 0x66, 0x00,
-	0xb7, 0x6a, 0xb1, 0x16,
-	0x03, 0x6a, 0x64, 0x00,
-	0x08, 0x6a, 0x66, 0x00,
-	0xb7, 0x6a, 0xb1, 0x16,
-	0x04, 0x6a, 0x64, 0x00,
-	0x88, 0x6a, 0x66, 0x00,
-	0xb3, 0x6a, 0xb1, 0x16,
-	0x39, 0x6a, 0xd9, 0x16,
-	0x03, 0x6a, 0x64, 0x00,
-	0xb7, 0x6a, 0x66, 0x00,
-	0x08, 0x6a, 0xb1, 0x16,
-	0x04, 0x6a, 0x64, 0x00,
-	0xb3, 0x6a, 0x66, 0x00,
-	0x14, 0x6a, 0xb1, 0x16,
-	0x00, 0x65, 0x34, 0x17,
-	0xff, 0x51, 0xb2, 0x02,
-	0x00, 0x65, 0x18, 0x10,
-	0x80, 0x6a, 0x52, 0x17,
-	0x00, 0x65, 0xf4, 0x16,
-	0x03, 0x6a, 0x64, 0x00,
-	0x8c, 0x6a, 0x66, 0x00,
-	0xab, 0x6a, 0xb1, 0x16,
-	0x03, 0x6a, 0x64, 0x00,
-	0x08, 0x6a, 0x66, 0x00,
-	0xab, 0x6a, 0xb1, 0x16,
-	0x04, 0x6a, 0x64, 0x00,
-	0x88, 0x6a, 0x66, 0x00,
-	0xa7, 0x6a, 0xb1, 0x16,
-	0x3d, 0x6a, 0xd9, 0x16,
-	0x00, 0x65, 0x18, 0x10,
-	0xc0, 0x6a, 0x52, 0x17,
-	0xae, 0x6a, 0xbc, 0x16,
-	0x00, 0x65, 0x18, 0x10,
-	0xa0, 0x6a, 0x52, 0x17,
-	0x08, 0x6a, 0xb5, 0x16,
-	0x37, 0x6a, 0x65, 0x00,
-	0xff, 0x36, 0x66, 0x02,
-	0xff, 0x6a, 0x64, 0x02,
-	0x02, 0x0b, 0x63, 0x1e,
-	0x10, 0x0c, 0x73, 0x1a,
-	0x01, 0x66, 0x67, 0x18,
-	0x40, 0x6a, 0x0c, 0x00,
-	0x00, 0x65, 0xd6, 0x16,
-	0xff, 0x6c, 0x06, 0x02,
-	0x04, 0x0b, 0x69, 0x1e,
-	0xff, 0x66, 0x66, 0x06,
-	0x01, 0x64, 0x64, 0x06,
-	0x00, 0x36, 0x63, 0x18,
-	0x08, 0x0c, 0x73, 0x1a,
-	0x01, 0x0c, 0x6d, 0x1e,
-	0xe0, 0x03, 0x64, 0x02,
-	0xa0, 0x64, 0x73, 0x18,
-	0x10, 0x6a, 0x52, 0x17,
-	0x00, 0x65, 0x18, 0x10,
-	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x6a, 0x35, 0x02,
-	0x00, 0x65, 0x18, 0x10,
-	0xe0, 0x6a, 0x52, 0x17,
-	0x64, 0x6a, 0xc2, 0x16,
-	0x00, 0x6a, 0x31, 0x00,
-	0x00, 0x6a, 0x7d, 0x18,
-	0xff, 0x90, 0x9d, 0x02,
-	0x02, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0xac, 0x10,
-	0x01, 0x64, 0x8c, 0x18,
-	0x64, 0x6a, 0xc4, 0x16,
-	0x03, 0x64, 0xa8, 0x18,
-	0x64, 0x6a, 0xc4, 0x16,
-	0x01, 0x64, 0xa8, 0x18,
-	0x4c, 0x6a, 0xc4, 0x16,
-	0x4d, 0x6a, 0xc4, 0x16,
-	0x41, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x42, 0x17,
-	0xff, 0x65, 0x66, 0x02,
-	0xff, 0x4c, 0x6d, 0x02,
-	0xff, 0x64, 0x64, 0x04,
-	0x00, 0x4f, 0x4f, 0x02,
-	0xff, 0x4c, 0x04, 0x02,
-	0x00, 0x65, 0xac, 0x10,
-	0x04, 0x64, 0x8f, 0x18,
-	0x04, 0xa0, 0xa0, 0x00,
-	0x00, 0x65, 0xac, 0x10,
-	0x02, 0x64, 0x92, 0x18,
-	0x00, 0x65, 0x14, 0x17,
-	0x00, 0x65, 0xac, 0x10,
-	0x03, 0x64, 0x95, 0x18,
-	0x00, 0x65, 0x0c, 0x17,
-	0x00, 0x65, 0xac, 0x10,
-	0x80, 0x64, 0x9d, 0x1e,
-	0x78, 0x64, 0xa8, 0x1a,
-	0x00, 0x64, 0xfd, 0x16,
-	0x80, 0x35, 0xac, 0x1a,
-	0x04, 0xa0, 0xa0, 0x04,
-	0xc0, 0x6a, 0x34, 0x00,
-	0x00, 0x65, 0x0c, 0x17,
-	0x00, 0x65, 0xac, 0x10,
-	0x07, 0x64, 0xa8, 0x18,
-	0x70, 0x05, 0x6e, 0x02,
-	0xff, 0x6e, 0x64, 0x02,
-	0x00, 0x4f, 0xac, 0x1e,
-	0x00, 0x65, 0x42, 0x17,
-	0xff, 0x65, 0x66, 0x02,
-	0xff, 0x6a, 0x6d, 0x02,
-	0xff, 0x64, 0x64, 0x04,
-	0x00, 0x4f, 0x4f, 0x02,
-	0xff, 0x6a, 0x04, 0x02,
-	0x00, 0x65, 0xac, 0x10,
-	0x10, 0x4e, 0x65, 0x00,
-	0x00, 0x65, 0x52, 0x17,
-	0x11, 0x6a, 0x91, 0x00,
-	0x07, 0x6a, 0xb5, 0x16,
-	0x00, 0x65, 0xca, 0x16,
-	0x00, 0x65, 0x18, 0x10,
-	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x6a, 0x4e, 0x02,
-	0x00, 0x65, 0x00, 0x10,
-	0xff, 0x6c, 0x6d, 0x02,
-	0xff, 0x64, 0x64, 0x06,
-	0x00, 0x6a, 0xb1, 0x18,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x40, 0x6a, 0x60, 0x00,
-	0x80, 0x35, 0xba, 0x1a,
-	0x80, 0x6a, 0x35, 0x00,
-	0x01, 0x6a, 0x36, 0x00,
-	0xff, 0x65, 0x37, 0x02,
-	0xff, 0x6a, 0x60, 0x02,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x02, 0x0b, 0xbc, 0x1e,
-	0xff, 0x65, 0x66, 0x02,
-	0x00, 0x65, 0xd6, 0x16,
-	0xff, 0x06, 0x6d, 0x02,
-	0x04, 0x0b, 0xc0, 0x1e,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x65, 0x66, 0x02,
-	0xff, 0x12, 0x6d, 0x03,
-	0xff, 0x65, 0x66, 0x02,
-	0x00, 0x65, 0xd6, 0x16,
-	0xff, 0x06, 0x6a, 0x02,
-	0x04, 0x0b, 0xc7, 0x1e,
-	0x02, 0x0b, 0xc8, 0x1e,
-	0xff, 0x12, 0x6d, 0x03,
-	0x00, 0x65, 0xd6, 0x16,
-	0xff, 0x06, 0x6a, 0x02,
-	0x04, 0x0b, 0xcc, 0x1e,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x02, 0x0b, 0xce, 0x1e,
-	0x00, 0x65, 0xd6, 0x16,
-	0x80, 0x30, 0xd3, 0x1e,
-	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x6a, 0x30, 0x02,
-	0xff, 0x65, 0x06, 0x02,
-	0x04, 0x0b, 0xd4, 0x1e,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x6a, 0x0a, 0x02,
-	0xff, 0x6a, 0x09, 0x02,
-	0x01, 0x6a, 0x08, 0x01,
-	0xff, 0x65, 0x93, 0x02,
-	0x01, 0x0b, 0xdc, 0x1a,
-	0x10, 0x0c, 0xda, 0x1e,
-	0x04, 0x65, 0xe0, 0x1a,
-	0xfe, 0x65, 0x65, 0x02,
-	0x02, 0x65, 0x93, 0x00,
-	0x02, 0x93, 0xdf, 0x1a,
-	0xff, 0x6a, 0x93, 0x02,
-	0x38, 0x93, 0xe1, 0x1a,
-	0x03, 0x6a, 0x64, 0x00,
-	0xaf, 0x6a, 0x66, 0x00,
-	0x08, 0x6a, 0xb1, 0x16,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x6a, 0x1f, 0x02,
-	0xf0, 0x65, 0x05, 0x02,
-	0x07, 0x5a, 0x64, 0x02,
-	0x00, 0x05, 0x05, 0x00,
-	0xff, 0x6a, 0x30, 0x02,
-	0xff, 0x6a, 0x4e, 0x02,
-	0x0a, 0x6a, 0x01, 0x00,
-	0x38, 0x5a, 0x64, 0x02,
-	0x04, 0x64, 0x02, 0x00,
-	0x84, 0x6a, 0x11, 0x00,
-	0x00, 0x65, 0x0c, 0x17,
-	0x00, 0x65, 0x42, 0x17,
-	0xff, 0x6c, 0x04, 0x02,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x80, 0x34, 0xf7, 0x1e,
-	0x40, 0x34, 0xf7, 0x1a,
-	0x21, 0x6a, 0x91, 0x00,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x70, 0x65, 0x6e, 0x02,
-	0xff, 0x6e, 0x64, 0x02,
-	0x00, 0x32, 0xfc, 0x1e,
-	0xff, 0x6a, 0x64, 0x03,
-	0x40, 0x6a, 0x64, 0x01,
-	0x07, 0x65, 0x64, 0x02,
-	0x00, 0x19, 0x64, 0x00,
-	0xf7, 0x64, 0x64, 0x02,
-	0xff, 0x6a, 0x65, 0x02,
-	0xff, 0x65, 0x90, 0x02,
-	0x00, 0xa1, 0x05, 0x19,
-	0x04, 0xa0, 0x05, 0x1f,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x01, 0x65, 0x65, 0x06,
-	0x04, 0x65, 0x01, 0x19,
-	0x31, 0x6a, 0x91, 0x00,
-	0x06, 0x6a, 0xb5, 0x16,
-	0x10, 0x4e, 0x65, 0x00,
-	0x00, 0x65, 0x52, 0x17,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0xa2, 0x51, 0x02,
-	0x04, 0x6a, 0x64, 0x00,
-	0x52, 0x6a, 0x66, 0x00,
-	0xa3, 0x6a, 0xb1, 0x16,
-	0x80, 0x6a, 0x50, 0x00,
-	0x10, 0xa0, 0x13, 0x1b,
-	0xff, 0x6a, 0x50, 0x02,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x51, 0xa2, 0x02,
-	0x04, 0x6a, 0x64, 0x00,
-	0xa3, 0x6a, 0x66, 0x00,
-	0x52, 0x6a, 0xb1, 0x16,
-	0xef, 0xa0, 0xa0, 0x02,
-	0x80, 0x50, 0x1b, 0x1f,
-	0x10, 0xa0, 0xa0, 0x00,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x51, 0x33, 0x1f,
-	0x80, 0x50, 0x33, 0x1b,
-	0xff, 0x6a, 0x8e, 0x02,
-	0xff, 0x6a, 0x8d, 0x02,
-	0x0c, 0x6a, 0x8c, 0x00,
-	0x04, 0x6a, 0x64, 0x00,
-	0x88, 0x6a, 0x66, 0x00,
-	0x52, 0x6a, 0xb1, 0x16,
-	0x0d, 0x6a, 0x93, 0x00,
-	0x08, 0x94, 0x25, 0x1f,
-	0xff, 0x6a, 0x93, 0x02,
-	0x08, 0x93, 0x27, 0x1b,
-	0xff, 0x99, 0xb3, 0x02,
-	0xff, 0x99, 0xb4, 0x02,
-	0xff, 0x99, 0xb5, 0x02,
-	0xff, 0x99, 0xb6, 0x02,
-	0xff, 0x99, 0x6a, 0x02,
-	0xff, 0x99, 0x6a, 0x02,
-	0xff, 0x99, 0x6a, 0x02,
-	0xff, 0x99, 0x6a, 0x02,
-	0xff, 0x99, 0xb7, 0x02,
-	0xff, 0x99, 0xb8, 0x02,
-	0xff, 0x6a, 0xb9, 0x02,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x51, 0x41, 0x1f,
-	0xff, 0x08, 0x40, 0x1b,
-	0xff, 0x09, 0x40, 0x1b,
-	0xff, 0x0a, 0x40, 0x1b,
-	0xff, 0x6a, 0x50, 0x02,
-	0xff, 0x51, 0x51, 0x06,
-	0xff, 0x6a, 0x64, 0x02,
-	0x0c, 0x52, 0x52, 0x06,
-	0x00, 0x53, 0x53, 0x08,
-	0x00, 0x54, 0x54, 0x08,
-	0x00, 0x55, 0x55, 0x08,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x80, 0x6a, 0x50, 0x00,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x4c, 0x05, 0x64, 0x0a,
-	0x07, 0x64, 0x64, 0x02,
-	0x20, 0x64, 0x65, 0x06,
-	0x70, 0x05, 0x6e, 0x02,
-	0xff, 0x6e, 0x64, 0x03,
-	0xff, 0x65, 0x66, 0x02,
-	0x00, 0x65, 0x42, 0x17,
-	0x00, 0x4f, 0x4b, 0x1b,
-	0xff, 0x6a, 0x6a, 0x03,
-	0x01, 0x6a, 0x6d, 0x00,
-	0x03, 0x6a, 0x6d, 0x00,
-	0x01, 0x6a, 0x6d, 0x00,
-	0x19, 0x6a, 0x6d, 0x00,
-	0x0f, 0x6a, 0x6d, 0x00,
-	0xc9, 0x66, 0x36, 0x06,
-	0xff, 0x6a, 0x6a, 0x03,
-	0xff, 0x65, 0x4e, 0x02,
-	0xff, 0x65, 0x03, 0x03,
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aic7770.c linux/drivers/scsi/aic7770.c
--- v1.3.3/linux/drivers/scsi/aic7770.c	Tue Nov  1 19:36:55 1994
+++ linux/drivers/scsi/aic7770.c	Mon Jun 26 12:42:52 1995
@@ -1,5 +1,5 @@
 /*
- * Adaptec 274x device driver for Linux.
+ * Adaptec 274x/284x/294x device driver for Linux.
  * Copyright (c) 1994 The University of Calgary Department of Computer Science.
  * 
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v1.3.3/linux/drivers/scsi/aic7xxx.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/aic7xxx.c	Mon Jun 26 12:47:36 1995
@@ -0,0 +1,1715 @@
+/*
+ *  @(#)aic7xxx.c 1.34 94/11/30 jda
+ *
+ *  Adaptec 274x/284x/294x device driver for Linux.
+ *  Copyright (c) 1994 The University of Calgary Department of Computer Science.
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Sources include the Adaptec 1740 driver (aha1740.c), the
+ *  Ultrastor 24F driver (ultrastor.c), various Linux kernel
+ *  source, the Adaptec EISA config file (!adp7771.cfg), the
+ *  Adaptec AHA-2740A Series User's Guide, the Linux Kernel
+ *  Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ *  the Adaptec 1542 driver (aha1542.c), the Adaptec EISA
+ *  overlay file (adp7770.ovl), the Adaptec AHA-2740 Series
+ *  Technical Reference Manual, the Adaptec AIC-7770 Data
+ *  Book, the ANSI SCSI specification, the ANSI SCSI-2
+ *  specification (draft 10c), ...
+ *
+ *  On a twin-bus adapter card, channel B is ignored.  Rationale:
+ *  it would greatly complicate the sequencer and host driver code,
+ *  and both busses are multiplexed on to the EISA bus anyway.  So
+ *  I don't really see any technical advantage to supporting both.
+ *
+ *  As well, multiple adapter card using the same IRQ level are
+ *  not supported.  It doesn't make sense to configure the cards
+ *  this way from a performance standpoint.  Not to mention that
+ *  the kernel would have to support two devices per registered IRQ.
+ */
+
+#include <stdarg.h>
+#include <asm/io.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "../block/blk.h"
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "aic7xxx.h"
+
+/*
+ *  There should be a specific return value for this in scsi.h, but
+ *  it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW	DID_ERROR
+
+/* EISA/VL-bus stuff */
+
+#define MINSLOT		1
+#define MAXSLOT		15
+#define SLOTBASE(x)	((x) << 12)
+
+#define MAXIRQ		15
+
+/* AIC-7770 offset definitions */
+
+#define O_MINREG(x)	((x) + 0xc00)		/* i/o range to reserve */
+#define O_MAXREG(x)	((x) + 0xcbf)
+
+#define O_SCSISEQ(x)	((x) + 0xc00)		/* scsi sequence control */
+#define O_SCSISIGI(x)	((x) + 0xc03)		/* scsi control signal read */
+#define O_SCSISIGO(x)	((x) + 0xc03)		/* scsi control signal write */
+#define O_SCSIID(x)	((x) + 0xc05)		/* scsi id */
+#define O_SSTAT0(x)	((x) + 0xc0b)		/* scsi status register 0 */
+#define O_CLRSINT1(x)	((x) + 0xc0c)		/* clear scsi interrupt 1 */
+#define O_SSTAT1(x)	((x) + 0xc0c)		/* scsi status register 1 */
+#define O_SELID(x)	((x) + 0xc19)		/* [re]selection id */
+#define O_SBLKCTL(x)	((x) + 0xc1f)		/* scsi block control */
+#define O_SEQCTL(x)	((x) + 0xc60)		/* sequencer control */
+#define O_SEQRAM(x)	((x) + 0xc61)		/* sequencer ram data */
+#define O_SEQADDR(x)	((x) + 0xc62)		/* sequencer address (W) */
+#define O_BIDx(x)	((x) + 0xc80)		/* board id */
+#define O_BCTL(x)	((x) + 0xc84)		/* board control */
+#define O_HCNTRL(x)	((x) + 0xc87)		/* host control */
+#define O_SCBPTR(x)	((x) + 0xc90)		/* scb pointer */
+#define O_INTSTAT(x)	((x) + 0xc91)		/* interrupt status */
+#define O_ERROR(x)	((x) + 0xc92)		/* hard error */
+#define O_CLRINT(x)	((x) + 0xc92)		/* clear interrupt status */
+#define O_SCBCNT(x)	((x) + 0xc9a)		/* scb auto increment */
+#define O_QINFIFO(x)	((x) + 0xc9b)		/* queue in fifo */
+#define O_QINCNT(x)	((x) + 0xc9c)		/* queue in count */
+#define O_QOUTFIFO(x)	((x) + 0xc9d)		/* queue out fifo */
+#define O_QOUTCNT(x)	((x) + 0xc9e)		/* queue out count */
+#define O_SCBARRAY(x)	((x) + 0xca0)		/* scb array start */
+
+/* AIC-7870-only definitions */
+
+#define O_DSPCISTATUS(x) ((x) + 0xc86)		/* ??? */
+
+/* host adapter offset definitions */
+
+#define HA_REJBYTE(x)	((x) + 0xc31)		/* 1st message in byte */
+#define HA_MSG_FLAGS(x)	((x) + 0xc35)		/* outgoing message flag */
+#define HA_MSG_LEN(x)	((x) + 0xc36)		/* outgoing message length */
+#define HA_MSG_START(x)	((x) + 0xc37)		/* outgoing message body */
+#define HA_ARG_1(x)	((x) + 0xc4c)		/* sdtr <-> rate parameters */
+#define HA_ARG_2(x)	((x) + 0xc4d)
+#define HA_RETURN_1(x)	((x) + 0xc4c)
+#define HA_RETURN_2(x)	((x) + 0xc4d)
+#define HA_SIGSTATE(x)	((x) + 0xc4e)		/* value in SCSISIGO */
+#define HA_NEEDSDTR(x)	((x) + 0xc4f)		/* synchronous negotiation? */
+#define HA_SCBCOUNT(x)	((x) + 0xc56)		/* number of hardware SCBs */
+
+#define HA_SCSICONF(x)	((x) + 0xc5a)		/* SCSI config register */
+#define HA_INTDEF(x)	((x) + 0xc5c)		/* interrupt def'n register */
+#define HA_HOSTCONF(x)	((x) + 0xc5d)		/* host config def'n register */
+
+/* debugging code */
+
+/*
+#define AIC7XXX_DEBUG
+*/
+
+/*
+ *  If a parity error occurs during a data transfer phase, run the
+ *  command to completion - it's easier that way - making a note
+ *  of the error condition in this location.  This then will modify
+ *  a DID_OK status into a DID_PARITY one for the higher-level SCSI
+ *  code.
+ */
+#define aic7xxx_parity(cmd)	((cmd)->SCp.Status)
+
+/*
+ *  Since the sequencer code DMAs the scatter-gather structures
+ *  directly from memory, we use this macro to assert that the
+ *  kernel structure hasn't changed.
+ */
+#define SG_STRUCT_CHECK(sg) \
+	((char *)&(sg).address - (char *)&(sg) != 0 ||	\
+	 (char *)&(sg).length  - (char *)&(sg) != 8 ||	\
+	 sizeof((sg).address) != 4 ||			\
+	 sizeof((sg).length)  != 4 ||			\
+	 sizeof(sg)	      != 12)
+
+/*
+ *  "Static" structures.  Note that these are NOT initialized
+ *  to zero inside the kernel - we have to initialize them all
+ *  explicitly.
+ *
+ *  We support a maximum of one adapter card per IRQ level (see the
+ *  rationale for this above).  On an interrupt, use the IRQ as an
+ *  index into aic7xxx_boards[] to locate the card information.
+ */
+static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
+
+/*
+ *  The maximum number of SCBs we could have for ANY type
+ *  of card.  DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ *  SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB	16
+
+struct aic7xxx_host {
+	int base;					/* card base address */
+	int maxscb;					/* hardware SCBs */
+	int startup;					/* intr type check */
+	int extended;					/* extended xlate? */
+	volatile int unpause;				/* value for HCNTRL */
+	volatile Scsi_Cmnd *SCB_array[AIC7XXX_MAXSCB];	/* active commands */
+};
+
+struct aic7xxx_host_config {
+	int irq;					/* IRQ number */
+	int base;					/* I/O base */
+	int maxscb;					/* hardware SCBs */
+	int unpause;					/* value for HCNTRL */
+	int scsi_id;					/* host SCSI id */
+	int extended;					/* extended xlate? */
+};
+
+struct aic7xxx_scb {
+	unsigned char control;
+	unsigned char target_channel_lun;		/* 4/1/3 bits */
+	unsigned char SG_segment_count;
+	unsigned char SG_list_pointer[4];
+	unsigned char SCSI_cmd_pointer[4];
+	unsigned char SCSI_cmd_length;
+	unsigned char RESERVED[2];			/* must be zero */
+	unsigned char target_status;
+	unsigned char residual_data_count[3];
+	unsigned char residual_SG_segment_count;
+	unsigned char data_pointer[4];
+	unsigned char data_count[3];
+#if 0
+	/*
+	 *  No real point in transferring this to the
+	 *  SCB registers.
+	 */
+	unsigned char RESERVED[6];
+#endif
+};
+
+/*
+ *  NB.  This table MUST be ordered shortest period first.
+ */
+static struct {
+	short period;
+	short rate;
+	char *english;
+} aic7xxx_synctab[] = {
+	100,	0,	"10.0",
+	125,	1,	"8.0",
+	150,	2,	"6.67",
+	175,	3,	"5.7",
+	200,	4,	"5.0",
+	225,	5,	"4.4",
+	250,	6,	"4.0",
+	275,	7,	"3.6"
+};
+
+static int aic7xxx_synctab_max =
+	sizeof(aic7xxx_synctab) / sizeof(aic7xxx_synctab[0]);
+
+enum aha_type {
+	T_NONE,
+	T_274X,
+	T_284X,
+	T_294X,
+	T_MAX
+};
+
+#ifdef AIC7XXX_DEBUG
+
+	extern int vsprintf(char *, const char *, va_list);
+
+	static
+	void debug(const char *fmt, ...)
+	{
+		va_list ap;
+		char buf[256];
+
+		va_start(ap, fmt);
+		  vsprintf(buf, fmt, ap);
+		  printk(buf);
+		va_end(ap);
+	}
+
+	static
+	void debug_config(enum aha_type type, struct aic7xxx_host_config *p)
+	{
+		int ioport2, ioport3;
+
+		static char *BRT[T_MAX][16] = {
+			{ },					/* T_NONE */
+			{
+				"2",   "???", "???", "12",	/* T_274X */
+				"???", "???", "???", "28",
+				"???", "???", "???", "44",
+				"???", "???", "???", "60"
+			},
+			{
+				"2",  "4",  "8",  "12",		/* T_284X */
+				"16", "20", "24", "28",
+				"32", "36", "40", "44",
+				"48", "52", "56", "60"
+			},
+			{
+				"???", "???", "???", "???",	/* T_294X */
+				"???", "???", "???", "???",
+				"???", "???", "???", "???",
+				"???", "???", "???", "???"
+			}
+		};
+		static int DFT[4] = {
+			0, 50, 75, 100
+		};
+		static int SST[4] = {
+			256, 128, 64, 32
+		};
+
+		ioport2 = inb(HA_HOSTCONF(p->base));
+		ioport3 = inb(HA_SCSICONF(p->base));
+
+		switch (type) {
+		    case T_274X:
+			printk("AHA274X AT EISA SLOT %d:\n", p->base >> 12);
+			break;
+		    case T_284X:
+			printk("AHA284X AT SLOT %d:\n", p->base >> 12);
+			break;
+		    case T_294X:
+			printk("AHA294X (PCI-bus):\n");
+			break;
+		    default:
+			panic("aic7xxx debug_config: internal error\n");
+		}
+
+		printk("    irq %d\n"
+		       "    bus release time %s bclks\n"
+		       "    data fifo threshold %d%%\n",
+		       p->irq,
+		       BRT[type][(ioport2 >> 2) & 0xf],
+		       DFT[(ioport2 >> 6) & 0x3]);
+
+		printk("    SCSI CHANNEL A:\n"
+		       "        scsi id %d\n"
+		       "        scsi bus parity check %sabled\n"
+		       "        scsi selection timeout %d ms\n"
+		       "        scsi bus reset at power-on %sabled\n",
+		       ioport3 & 0x7,
+		       (ioport3 & 0x20) ? "en" : "dis",
+		       SST[(ioport3 >> 3) & 0x3],
+		       (ioport3 & 0x40) ? "en" : "dis");
+
+		if (type == T_274X) {
+			printk("        scsi bus termination %sabled\n",
+			       (ioport3 & 0x80) ? "en" : "dis");
+		}
+	}
+
+	static
+	void debug_rate(int base, int rate)
+	{
+		int target = inb(O_SCSIID(base)) >> 4;
+
+		if (rate) {
+			printk("aic7xxx: target %d now synchronous at %sMb/s\n",
+			       target,
+			       aic7xxx_synctab[(rate >> 4) & 0x7].english);
+		} else {
+			printk("aic7xxx: target %d using asynchronous mode\n",
+			       target);
+		}
+	}
+
+#else
+
+#	define debug(fmt, args...)
+#	define debug_config(x)
+#	define debug_rate(x,y)
+
+#endif AIC7XXX_DEBUG
+
+/*
+ *  XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *	  cards in the system.  This should be fixed, but then,
+ *	  does anyone really have more than one in a machine?
+ */
+static int aic7xxx_extended = 0;		/* extended translation on? */
+
+void aic7xxx_setup(char *s, int *dummy)
+{
+	int i;
+	char *p;
+
+	static struct {
+		char *name;
+		int *flag;
+	} options[] = {
+		"extended",	&aic7xxx_extended,
+		NULL
+	};
+
+	for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
+		for (i = 0; options[i].name; i++)
+			if (!strcmp(options[i].name, p))
+				*(options[i].flag) = !0;
+	}
+}
+
+static
+void aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
+{
+	/*
+	 *  This is almost identical to aic7xxx_putscb().
+	 */
+	outb(0x80, O_SCBCNT(base));	/* SCBAUTO */
+
+	asm volatile("cld\n\t"
+		     "rep\n\t"
+		     "insb"
+		     : /* no output */
+		     :"D" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
+		     :"di", "cx", "dx");
+
+	outb(0, O_SCBCNT(base));
+}
+
+/*
+ *  How much data should be transferred for this SCSI command?  Stop
+ *  at segment sg_last if it's a scatter-gather command so we can
+ *  compute underflow easily.
+ */
+static
+unsigned aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
+{
+	int i, segments;
+	unsigned length;
+	struct scatterlist *sg;
+
+	segments = cmd->use_sg - sg_last;
+	sg = (struct scatterlist *)cmd->buffer;
+
+	if (cmd->use_sg) {
+		for (i = length = 0;
+		     i < cmd->use_sg && i < segments;
+		     i++)
+		{
+			length += sg[i].length;
+		}
+	} else
+		length = cmd->request_bufflen;
+
+	return(length);
+}
+
+static
+void aic7xxx_sg_check(Scsi_Cmnd *cmd)
+{
+	int i;
+	struct scatterlist *sg = (struct scatterlist *)cmd->buffer;
+
+	if (cmd->use_sg) {
+		for (i = 0; i < cmd->use_sg; i++)
+			if ((unsigned)sg[i].length > 0xffff)
+				panic("aic7xxx_sg_check: s/g segment > 64k\n");
+	}
+}
+
+static
+void aic7xxx_to_scsirate(unsigned char *rate,
+			 unsigned char transfer,
+			 unsigned char offset)
+{
+	int i;
+
+	transfer *= 4;
+
+	for (i = 0; i < aic7xxx_synctab_max-1; i++) {
+
+		if (transfer == aic7xxx_synctab[i].period) {
+			*rate = (aic7xxx_synctab[i].rate << 4) | (offset & 0xf);
+			return;
+		}
+
+		if (transfer > aic7xxx_synctab[i].period &&
+		    transfer < aic7xxx_synctab[i+1].period)
+		{
+			*rate = (aic7xxx_synctab[i+1].rate << 4) |
+				(offset & 0xf);
+			return;
+		}
+	}
+	*rate = 0;
+}
+
+/*
+ *  Pause the sequencer and wait for it to actually stop - this
+ *  is important since the sequencer can disable pausing for critical
+ *  sections.
+ */
+#define PAUSE_SEQUENCER(p)	\
+	do {								\
+		outb(0xe, O_HCNTRL(p->base));	/* IRQMS|PAUSE|INTEN */	\
+									\
+		while ((inb(O_HCNTRL(p->base)) & 0x4) == 0)		\
+			;						\
+	} while (0)
+
+/*
+ *  Unpause the sequencer.  Unremarkable, yet done often enough to
+ *  warrant an easy way to do it.
+ */
+#define UNPAUSE_SEQUENCER(p)	\
+	outb(p->unpause, O_HCNTRL(p->base))	/* IRQMS|INTEN */
+
+/*
+ *  See comments in aic7xxx_loadram() wrt this.
+ */
+#define RESTART_SEQUENCER(p)	\
+	do {							\
+		do {						\
+			outb(0x2, O_SEQCTL(p->base));		\
+								\
+		} while (inb(O_SEQADDR(p->base)) != 0 &&	\
+			 inb(O_SEQADDR(p->base) + 1) != 0);	\
+								\
+		UNPAUSE_SEQUENCER(p);				\
+	} while (0)
+
+/*
+ *  Since we declared this using SA_INTERRUPT, interrupts should
+ *  be disabled all through this function unless we say otherwise.
+ */
+static
+void aic7xxx_isr(int irq)
+{
+	int base, intstat;
+	struct aic7xxx_host *p;
+	
+	p = (struct aic7xxx_host *)aic7xxx_boards[irq]->hostdata;
+	base = p->base;
+
+	/*
+	 *  Check the startup flag - if no commands have been queued,
+	 *  we probably have the interrupt type set wrong.  Reverse
+	 *  the stored value and the active one in the host control
+	 *  register.
+	 */
+	if (p->startup) {
+		p->unpause ^= 0x8;
+		outb(inb(O_HCNTRL(p->base)) ^ 0x8, O_HCNTRL(p->base));
+		return;
+	}
+
+	/*
+	 *  Handle all the interrupt sources - especially for SCSI
+	 *  interrupts, we won't get a second chance at them.
+	 */
+	intstat = inb(O_INTSTAT(base));
+
+	if (intstat & 0x8) {				/* BRKADRINT */
+
+		panic("aic7xxx_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
+		      inb(O_ERROR(base)), inw(O_SEQADDR(base)));
+	}
+
+	if (intstat & 0x4) {				/* SCSIINT */
+
+		int scbptr = inb(O_SCBPTR(base));
+		int status = inb(O_SSTAT1(base));
+		Scsi_Cmnd *cmd;
+
+		cmd = (Scsi_Cmnd *)p->SCB_array[scbptr];
+		if (!cmd) {
+			printk("aic7xxx_isr: no command for scb (scsiint)\n");
+			/*
+			 *  Turn off the interrupt and set status
+			 *  to zero, so that it falls through the
+			 *  reset of the SCSIINT code.
+			 */
+			outb(status, O_CLRSINT1(base));
+			UNPAUSE_SEQUENCER(p);
+			outb(0x4, O_CLRINT(base));	/* undocumented */
+			status = 0;
+		}
+		p->SCB_array[scbptr] = NULL;
+
+		/*
+		 *  Only the SCSI Status 1 register has information
+		 *  about exceptional conditions that we'd have a
+		 *  SCSIINT about; anything in SSTAT0 will be handled
+		 *  by the sequencer.  Note that there can be multiple
+		 *  bits set.
+		 */
+		if (status & 0x80) {			/* SELTO */
+			/*
+			 *  Hardware selection timer has expired.  Turn
+			 *  off SCSI selection sequence.
+			 */
+			outb(0, O_SCSISEQ(base));
+			cmd->result = DID_TIME_OUT << 16;
+
+			/*
+			 *  If there's an active message, it belongs to the
+			 *  command that is getting punted - remove it.
+			 */
+			outb(0, HA_MSG_FLAGS(base));
+
+			/*
+			 *  Shut off the offending interrupt sources, reset
+			 *  the sequencer address to zero and unpause it,
+			 *  then call the high-level SCSI completion routine.
+			 *
+			 *  WARNING!  This is a magic sequence!  After many
+			 *  hours of guesswork, turning off the SCSI interrupts
+			 *  in CLRSINT? does NOT clear the SCSIINT bit in
+			 *  INTSTAT.  By writing to the (undocumented, unused
+			 *  according to the AIC-7770 manual) third bit of
+			 *  CLRINT, you can clear INTSTAT.  But, if you do it
+			 *  while the sequencer is paused, you get a BRKADRINT
+			 *  with an Illegal Host Address status, so the
+			 *  sequencer has to be restarted first.
+			 */
+			outb(0x80, O_CLRSINT1(base));	/* CLRSELTIMO */
+			RESTART_SEQUENCER(p);
+
+			outb(0x4, O_CLRINT(base));	/* undocumented */
+			cmd->scsi_done(cmd);
+		}
+
+		if (status & 0x4) {			/* SCSIPERR */
+			/*
+			 *  A parity error has occurred during a data
+			 *  transfer phase.  Flag it and continue.
+			 */
+			printk("aic7xxx: parity error on target %d, lun %d\n",
+			       cmd->target,
+			       cmd->lun);
+			aic7xxx_parity(cmd) = DID_PARITY;
+
+			/*
+			 *  Clear interrupt and resume as above.
+			 */
+			outb(0x4, O_CLRSINT1(base));	/* CLRSCSIPERR */
+			UNPAUSE_SEQUENCER(p);
+
+			outb(0x4, O_CLRINT(base));	/* undocumented */
+		}
+
+		if ((status & (0x8|0x4)) == 0 && status) {
+			/*
+			 *  We don't know what's going on.  Turn off the
+			 *  interrupt source and try to continue.
+			 */
+			printk("aic7xxx_isr: sstat1 = 0x%x\n", status);
+			outb(status, O_CLRSINT1(base));
+			UNPAUSE_SEQUENCER(p);
+			outb(0x4, O_CLRINT(base));	/* undocumented */
+		}
+	}
+
+	if (intstat & 0x2) {				/* CMDCMPLT */
+
+		int complete, old_scbptr;
+		struct aic7xxx_scb scb;
+		unsigned actual;
+		Scsi_Cmnd *cmd;
+
+		/*
+		 *  The sequencer will continue running when it
+		 *  issues this interrupt.  There may be >1 commands
+		 *  finished, so loop until we've processed them all.
+		 */
+		do {
+			complete = inb(O_QOUTFIFO(base));
+
+			cmd = (Scsi_Cmnd *)p->SCB_array[complete];
+			if (!cmd) {
+				printk("aic7xxx warning: "
+				       "no command for scb (cmdcmplt)\n");
+				continue;
+			}
+			p->SCB_array[complete] = NULL;
+			
+			PAUSE_SEQUENCER(p);
+
+			/*
+			 *  After pausing the sequencer (and waiting
+			 *  for it to stop), save its SCB pointer, then
+			 *  write in our completed one and read the SCB
+			 *  registers.  Afterwards, restore the saved
+			 *  pointer, unpause the sequencer and call the
+			 *  higher-level completion function - unpause
+			 *  first since we have no idea how long done()
+			 *  will take.
+			 */
+			old_scbptr = inb(O_SCBPTR(base));
+			outb(complete, O_SCBPTR(base));
+
+			aic7xxx_getscb(base, &scb);
+			outb(old_scbptr, O_SCBPTR(base));
+
+			UNPAUSE_SEQUENCER(p);
+
+			cmd->result = scb.target_status |
+				     (aic7xxx_parity(cmd) << 16);
+
+			/*
+			 *  Did we underflow?  At this time, there's only
+			 *  one other driver that bothers to check for this,
+			 *  and cmd->underflow seems to be set rather half-
+			 *  heartedly in the higher-level SCSI code.
+			 */
+			actual = aic7xxx_length(cmd,
+						scb.residual_SG_segment_count);
+
+			actual -= ((scb.residual_data_count[2] << 16) |
+				   (scb.residual_data_count[1] <<  8) |
+				   (scb.residual_data_count[0]));
+
+			if (actual < cmd->underflow) {
+				printk("aic7xxx: target %d underflow - "
+				       "wanted (at least) %u, got %u\n",
+				       cmd->target, cmd->underflow, actual);
+
+				cmd->result = scb.target_status |
+					     (DID_UNDERFLOW << 16);
+			}
+
+			cmd->scsi_done(cmd);
+
+			/*
+			 *  Clear interrupt status before checking
+			 *  the output queue again.  This eliminates
+			 *  a race condition whereby a command could
+			 *  complete between the queue poll and the
+			 *  interrupt clearing, so notification of the
+			 *  command being complete never made it back
+			 *  up to the kernel.
+			 */
+			outb(0x2, O_CLRINT(base));	/* CLRCMDINT */
+
+		} while (inb(O_QOUTCNT(base)));
+	}
+
+	if (intstat & 0x1) {				/* SEQINT */
+
+		unsigned char transfer, offset, rate;
+
+		/*
+		 *  Although the sequencer is paused immediately on
+		 *  a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
+		 *  condition will have unpaused the sequencer before
+		 *  this point.
+		 */
+		PAUSE_SEQUENCER(p);
+
+		switch (intstat & 0xf0) {
+		    case 0x00:
+			panic("aic7xxx_isr: unknown scsi bus phase\n");
+		    case 0x10:
+			debug("aic7xxx_isr warning: "
+			      "issuing message reject, 1st byte 0x%x\n",
+			      inb(HA_REJBYTE(base)));
+			break;
+		    case 0x20:
+			panic("aic7xxx_isr: reconnecting target %d "
+			      "didn't issue IDENTIFY message\n",
+			      (inb(O_SELID(base)) >> 4) & 0xf);
+		    case 0x30:
+			debug("aic7xxx_isr: sequencer couldn't find match "
+			      "for reconnecting target %d - issuing ABORT\n",
+			      (inb(O_SELID(base)) >> 4) & 0xf);
+			break;
+		    case 0x40:
+			transfer = inb(HA_ARG_1(base));
+			offset = inb(HA_ARG_2(base));
+			aic7xxx_to_scsirate(&rate, transfer, offset);
+			outb(rate, HA_RETURN_1(base));
+			debug_rate(base, rate);
+			break;
+		    default:
+			debug("aic7xxx_isr: seqint, "
+			      "intstat = 0x%x, scsisigi = 0x%x\n",
+			      intstat, inb(O_SCSISIGI(base)));
+			break;
+		}
+
+		outb(0x1, O_CLRINT(base));		/* CLRSEQINT */
+		UNPAUSE_SEQUENCER(p);
+	}
+}
+
+/*
+ *  Probing for EISA boards: it looks like the first two bytes
+ *  are a manufacturer code - three characters, five bits each:
+ *
+ *		 BYTE 0   BYTE 1   BYTE 2   BYTE 3
+ *		?1111122 22233333 PPPPPPPP RRRRRRRR
+ *
+ *  The characters are baselined off ASCII '@', so add that value
+ *  to each to get the real ASCII code for it.  The next two bytes
+ *  appear to be a product and revision number, probably vendor-
+ *  specific.  This is what is being searched for at each port,
+ *  and what should probably correspond to the ID= field in the
+ *  ECU's .cfg file for the card - if your card is not detected,
+ *  make sure your signature is listed in the array.
+ *
+ *  The fourth byte's lowest bit seems to be an enabled/disabled
+ *  flag (rest of the bits are reserved?).
+ */
+
+static
+enum aha_type aic7xxx_probe(int slot, int s_base)
+{
+	int i;
+	unsigned char buf[4];
+
+	static struct {
+		int n;
+		unsigned char signature[sizeof(buf)];
+		enum aha_type type;
+	} S[] = {
+		4, { 0x04, 0x90, 0x77, 0x71 }, T_274X,	/* host adapter 274x */
+		4, { 0x04, 0x90, 0x77, 0x70 }, T_274X,	/* motherboard 274x  */
+		4, { 0x04, 0x90, 0x77, 0x56 }, T_284X,	/* 284x, BIOS enabled */
+	};
+
+	for (i = 0; i < sizeof(buf); i++) {
+		/*
+		 *  The VL-bus cards need to be primed by
+		 *  writing before a signature check.
+		 */
+		outb(0x80 + i, s_base);
+		buf[i] = inb(s_base + i);
+	}
+
+	for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
+		if (!memcmp(buf, S[i].signature, S[i].n)) {
+			/*
+			 *  Signature match on enabled card?
+			 */
+			if (inb(s_base + 4) & 1)
+				return(S[i].type);
+			printk("aic7xxx disabled at slot %d, ignored\n", slot);
+		}
+	}
+	return(T_NONE);
+}
+
+/*
+ *  Return ' ' for plain 274x, 'T' for twin-channel, 'W' for
+ *  wide channel, '?' for anything else.
+ */
+
+static
+char aic7xxx_type(int base)
+{
+	/*
+	 *  AIC-7770/7870s can be wired so that, on chip reset,
+	 *  the SCSI Block Control register indicates how many
+	 *  busses the chip is configured for.  The two high bits
+	 *  set indicate a 294x.
+	 */
+	switch (inb(O_SBLKCTL(base))) {
+	    case 0:
+	    case 0xc0:
+		return(' ');
+	    case 2:
+	    case 0xc2:
+		return('W');
+	    case 8:
+		return('T');
+	    default:
+		printk("aic7xxx has unknown bus configuration\n");
+		return('?');
+	}
+}
+
+static
+void aic7xxx_loadram(int base)
+{
+	static unsigned char seqprog[] = {
+		/*
+		 *  Each sequencer instruction is 29 bits
+		 *  long (fill in the excess with zeroes)
+		 *  and has to be loaded from least -> most
+		 *  significant byte, so this table has the
+		 *  byte ordering reversed.
+		 */
+#		include "aic7xxx_seq.h"
+	};
+
+	/*
+	 *  When the AIC-7770 is paused (as on chip reset), the
+	 *  sequencer address can be altered and a sequencer
+	 *  program can be loaded by writing it, byte by byte, to
+	 *  the sequencer RAM port - the Adaptec documentation
+	 *  recommends using REP OUTSB to do this, hence the inline
+	 *  assembly.  Since the address autoincrements as we load
+	 *  the program, reset it back to zero afterward.  Disable
+	 *  sequencer RAM parity error detection while loading, and
+	 *  make sure the LOADRAM bit is enabled for loading.
+	 */
+	outb(0x83, O_SEQCTL(base));	/* PERRORDIS|SEQRESET|LOADRAM */
+
+	asm volatile("cld\n\t"
+		     "rep\n\t"
+		     "outsb"
+		     : /* no output */
+		     :"S" (seqprog), "c" (sizeof(seqprog)), "d" (O_SEQRAM(base))
+		     :"si", "cx", "dx");
+
+	/*
+	 *  WARNING!  This is a magic sequence!  After extensive
+	 *  experimentation, it seems that you MUST turn off the
+	 *  LOADRAM bit before you play with SEQADDR again, else
+	 *  you will end up with parity errors being flagged on
+	 *  your sequencer program.  (You would also think that
+	 *  turning off LOADRAM and setting SEQRESET to reset the
+	 *  address to zero would work, but you need to do it twice
+	 *  for it to take effect on the address.  Timing problem?)
+	 */
+	outb(0, O_SEQCTL(base));
+	do {
+		/*
+		 *  Actually, reset it until
+		 *  the address shows up as
+		 *  zero just to be safe..
+		 */
+		outb(0x2, O_SEQCTL(base));	/* SEQRESET */
+
+	} while (inb(O_SEQADDR(base)) != 0 && inb(O_SEQADDR(base) + 1) != 0);
+}
+
+static
+void aha274x_config(struct aic7xxx_host_config *p, va_list ap)
+{
+	int base = va_arg(ap, int);
+
+	/*
+	 *  Give the AIC-7770 a reset - reading the 274x's registers
+	 *  returns zeroes unless you do.  This forces a pause of the
+	 *  Sequencer.
+	 */
+	outb(1, O_HCNTRL(base));	/* CHIPRST */
+
+	p->base = base;
+	p->irq = inb(HA_INTDEF(base)) & 0xf;
+	p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+
+	/*
+	 *  This value for HCNTRL may be changed in the ISR if we
+	 *  catch a spurious interrupt right away.
+	 */
+	p->unpause = 0xa;
+
+	/*
+	 *  XXX - these are values that I don't know how to query
+	 *	  the hardware for.  Apparently some revision E
+	 *	  '7770s can have more SCBs, and I don't know how
+	 *	  to get the "extended translation" flag from the
+	 *	  EISA data area.
+	 */
+	p->maxscb = 4;
+	p->extended = aic7xxx_extended;
+
+	/*
+	 *  A reminder until this can be detected automatically.
+	 */
+	printk("aha274x: extended translation %sabled\n",
+		p->extended ? "en" : "dis");
+}
+
+static
+void aha284x_config(struct aic7xxx_host_config *p, va_list ap)
+{
+	int base = va_arg(ap, int);
+
+	/*
+	 *  Give the AIC-7770 a reset - this forces a pause of the
+	 *  Sequencer and returns everything to default values.
+	 */
+	outb(1, O_HCNTRL(base));	/* CHIPRST */
+
+	p->base = base;
+	p->unpause = 0x2;
+	p->irq = inb(HA_INTDEF(base)) & 0xf;
+	p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+
+	/*
+	 *  XXX - these are values that I don't know how to query
+	 *	  the hardware for.  Apparently some revision E
+	 *	  '7770s can have more SCBs, and I don't know how
+	 *	  to get the "extended translation" flag from the
+	 *	  onboard memory.
+	 */
+	p->maxscb = 4;
+	p->extended = aic7xxx_extended;
+
+	/*
+	 *  A reminder until this can be detected automatically.
+	 */
+	printk("aha284x: extended translation %sabled\n",
+		p->extended ? "en" : "dis");
+}
+
+static
+void aha294x_config(struct aic7xxx_host_config *p, va_list ap)
+{
+	int error;
+	unsigned long io_port;
+	unsigned char bus, device_fn, irq;
+
+	bus = va_arg(ap, unsigned char);
+	device_fn = va_arg(ap, unsigned char);
+
+	/*
+	 *  Read esundry information from PCI BIOS.
+	 */
+	error = pcibios_read_config_dword(bus,
+					  device_fn,
+					  PCI_BASE_ADDRESS_0,
+					  &io_port);
+	if (error) {
+		panic("aha294x_config: error %s reading i/o port\n",
+		      pcibios_strerror(error));
+	}
+
+	error = pcibios_read_config_byte(bus,
+					 device_fn,
+					 PCI_INTERRUPT_LINE,
+					 &irq);
+	if (error) {
+		panic("aha294x_config: error %s reading irq\n",
+		      pcibios_strerror(error));
+	}
+
+	/*
+	 *  Make the base I/O register look like EISA and VL-bus.
+	 */
+	p->base = io_port - 0xc01;
+
+	/*
+	 *  Give the AIC-7870 a reset - this forces a pause of the
+	 *  Sequencer and returns everything to default values.
+	 */
+	outb(1, O_HCNTRL(p->base));	/* CHIPRST */
+
+	p->irq = irq;
+	p->maxscb = 16;
+	p->unpause = 0xa;
+
+	/*
+	 *  XXX - these are values that I don't know how to query
+	 *	  the hardware for, so for now the SCSI host ID is
+	 *	  hardwired to 7, and the "extended translation"
+	 *	  flag is taken from boot-time flags.
+	 */
+	p->scsi_id = 7;
+	p->extended = aic7xxx_extended;
+
+	/*
+	 *  XXX - force data fifo threshold to 100%.  Why does this
+	 *	  need to be done?
+	 */
+#	define	DFTHRESH	3
+
+	outb(DFTHRESH << 6, O_DSPCISTATUS(p->base));
+	outb(p->scsi_id | (DFTHRESH << 6), HA_SCSICONF(p->base));
+
+	/*
+	 *  A reminder until this can be detected automatically.
+	 */
+	printk("aha294x: extended translation %sabled\n",
+		p->extended ? "en" : "dis");
+}
+
+static
+int aic7xxx_register(Scsi_Host_Template *template, enum aha_type type, ...)
+{
+	va_list ap;
+	int i, base;
+	struct Scsi_Host *host;
+	struct aic7xxx_host *p;
+	struct aic7xxx_host_config config;
+
+	va_start(ap, type);
+	
+	switch (type) {
+	    case T_274X:
+		aha274x_config(&config, ap);
+		break;
+	    case T_284X:
+		aha284x_config(&config, ap);
+		break;
+	    case T_294X:
+		aha294x_config(&config, ap);
+		break;
+	    default:
+		panic("aic7xxx_register: internal error\n");
+	}
+	va_end(ap);
+
+	base = config.base;
+
+	/*
+	 *  The IRQ level in i/o port 4 maps directly onto the real
+	 *  IRQ number.  If it's ok, register it with the kernel.
+	 *
+	 *  NB. the Adaptec documentation says the IRQ number is only
+	 *	in the lower four bits; the ECU information shows the
+	 *	high bit being used as well.  Which is correct?
+	 */
+	if (config.irq < 9 || config.irq > 15) {
+		printk("aic7xxx uses unsupported IRQ level, ignoring\n");
+		return(0);
+	}
+	
+	/*
+	 *  Lock out other contenders for our i/o space.
+	 */
+	snarf_region(O_MINREG(base), O_MAXREG(base)-O_MINREG(base));
+
+	/*
+	 *  Any card-type-specific adjustments before we register
+	 *  the scsi host(s).
+	 */
+	switch (aic7xxx_type(base)) {
+	    case 'T':
+		printk("aic7xxx warning: ignoring channel B of 274x-twin\n");
+		break;
+	    case ' ':
+		break;
+	    default:
+		printk("aic7xxx is an unsupported type, ignoring\n");
+		return(0);
+	}
+
+	/*
+	 *  Before registry, make sure that the offsets of the
+	 *  struct scatterlist are what the sequencer will expect,
+	 *  otherwise disable scatter-gather altogether until someone
+	 *  can fix it.  This is important since the sequencer will
+	 *  DMA elements of the SG array in while executing commands.
+	 */
+	if (template->sg_tablesize != SG_NONE) {
+		struct scatterlist sg;
+
+		if (SG_STRUCT_CHECK(sg)) {
+			printk("aic7xxx warning: kernel scatter-gather "
+			       "structures changed, disabling it\n");
+			template->sg_tablesize = SG_NONE;
+		}
+	}
+	
+	/*
+	 *  Register each "host" and fill in the returned Scsi_Host
+	 *  structure as best we can.  Some of the parameters aren't
+	 *  really relevant for bus types beyond ISA, and none of the
+	 *  high-level SCSI code looks at it anyway.. why are the fields
+	 *  there?  Also save the pointer so that we can find the
+	 *  information when an IRQ is triggered.
+	 */
+	host = scsi_register(template, sizeof(struct aic7xxx_host));
+	host->can_queue = config.maxscb;
+	host->this_id = config.scsi_id;
+	host->irq = config.irq;
+
+	aic7xxx_boards[config.irq] = host;
+	
+	p = (struct aic7xxx_host *)host->hostdata;
+	for (i = 0; i < AIC7XXX_MAXSCB; i++)
+		p->SCB_array[i] = NULL;
+
+	p->base = config.base;
+	p->maxscb = config.maxscb;
+	p->extended = config.extended;
+
+	/*
+	 *  The interrupt trigger is different depending
+	 *  on whether the card is EISA or VL-bus - sometimes.
+	 *  The startup variable will be cleared once the first
+	 *  command is queued, and is checked in the isr to
+	 *  try and detect when the interrupt type is set
+	 *  incorrectly, triggering an interrupt immediately.
+	 *  This is now just set on a per-card-type basis.
+	 */
+	p->unpause = config.unpause;
+	p->startup = !0;
+
+	/*
+	 *  Register IRQ with the kernel _after_ the host information
+	 *  is set up, in case we take an interrupt right away, due to
+	 *  the interrupt type being set wrong.
+	 */
+	if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx")) {
+		printk("aic7xxx couldn't register irq %d, ignoring\n",
+		       config.irq);
+		return(0);
+	}
+
+	/*
+	 *  Print out debugging information before re-enabling
+	 *  the card - a lot of registers on it can't be read
+	 *  when the sequencer is active.
+	 */
+#ifdef AIC7XXX_DEBUG
+	debug_config(type, &config);
+#endif
+
+	/*
+	 *  Load the sequencer program, then re-enable the board -
+	 *  resetting the AIC-7770 disables it, leaving the lights
+	 *  on with nobody home.  On the PCI bus you *may* be home,
+	 *  but then your mailing address is dynamically assigned
+	 *  so no one can find you anyway :-)
+	 */
+	aic7xxx_loadram(base);
+	if (type != T_294X)
+		outb(1, O_BCTL(base));	/* ENABLE */
+
+	/*
+	 *  Set the host adapter registers to indicate that synchronous
+	 *  negotiation should be attempted the first time the targets
+	 *  are communicated with.  Also initialize the active message
+	 *  flag to indicate that there is no message.
+	 */
+	outb(0xff, HA_NEEDSDTR(base));
+	outb(0, HA_MSG_FLAGS(base));
+
+	/*
+	 *  For reconnecting targets, the sequencer code needs to
+	 *  know how many SCBs it has to search through.
+	 */
+	outb(config.maxscb, HA_SCBCOUNT(base));
+
+	/*
+	 *  Unpause the sequencer before returning and enable
+	 *  interrupts - we shouldn't get any until the first
+	 *  command is sent to us by the high-level SCSI code.
+	 */
+	UNPAUSE_SEQUENCER(p);
+	return(1);
+}
+
+int aic7xxx_detect(Scsi_Host_Template *template)
+{
+	enum aha_type type;
+	int found = 0, slot, base;
+
+	/*
+	 *  EISA/VL-bus card signature probe.
+	 */
+	for (slot = MINSLOT; slot <= MAXSLOT; slot++) {
+
+		base = SLOTBASE(slot);
+		
+		if (check_region(O_MINREG(base),
+				 O_MAXREG(base)-O_MINREG(base)))
+		{
+			/*
+			 *  Some other driver has staked a
+			 *  claim to this i/o region already.
+			 */
+			continue;
+		}
+
+		type = aic7xxx_probe(slot, O_BIDx(base));
+
+		if (type != T_NONE) {
+			/*
+			 *  We "find" a 274x if we locate the card
+			 *  signature and we can set it up and register
+			 *  it with the kernel without incident.
+			 */
+			found += aic7xxx_register(template, type, base);
+		}
+	}
+
+	/*
+	 *  PCI-bus probe.
+	 */
+	if (pcibios_present()) {
+		int index = 0;
+		unsigned char bus, device_fn;
+
+		while (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+					    PCI_DEVICE_ID_ADAPTEC_2940,
+					    index,
+					    &bus,
+					    &device_fn))
+		{
+			found += aic7xxx_register(template, T_294X,
+						  bus, device_fn);
+			index += 1;
+		}
+	}
+
+	template->name = (char *)aic7xxx_info(NULL);
+	return(found);
+}
+
+const char *aic7xxx_info(struct Scsi_Host *notused)
+{
+	return("Adaptec AHA274x/284x/294x (EISA/VL-bus/PCI -> Fast SCSI) "
+	       AIC7XXX_SEQ_VERSION "/"
+	       AIC7XXX_H_VERSION "/"
+	       "1.34");
+}
+
+static
+void aic7xxx_buildscb(struct aic7xxx_host *p,
+		      Scsi_Cmnd *cmd,
+		      struct aic7xxx_scb *scb)
+{
+	void *addr;
+	unsigned length;
+
+	memset(scb, 0, sizeof(*scb));
+
+	/*
+	 *  NB. channel selection (bit 3) is always zero.
+	 */
+	scb->target_channel_lun = ((cmd->target << 4) & 0xf0) |
+				   (cmd->lun & 0x7);
+
+	/*
+	 *  The interpretation of request_buffer and request_bufflen
+	 *  changes depending on whether or not use_sg is zero; a
+	 *  non-zero use_sg indicates the number of elements in the
+	 *  scatter-gather array.
+	 *
+	 *  The AIC-7770 can't support transfers of any sort larger
+	 *  than 2^24 (three-byte count) without backflips.  For what
+	 *  the kernel is doing, this shouldn't occur.  I hope.
+	 */
+	length = aic7xxx_length(cmd, 0);
+
+	/*
+	 *  The sequencer code cannot yet handle scatter-gather segments
+	 *  larger than 64k (two-byte length).  The 1.1.x kernels, however,
+	 *  have a four-byte length field in the struct scatterlist, so
+	 *  make sure we don't exceed 64k on these kernels for now.
+	 */
+	aic7xxx_sg_check(cmd);
+
+	if (length > 0xffffff) {
+		panic("aic7xxx_buildscb: can't transfer > 2^24 - 1 bytes\n");
+	}
+
+	/*
+	 *  XXX - this relies on the host data being stored in a
+	 *	  little-endian format.
+	 */
+	addr = cmd->cmnd;
+	scb->SCSI_cmd_length = cmd->cmd_len;
+	memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+
+	if (cmd->use_sg) {
+#if 0
+		debug("aic7xxx_buildscb: SG used, %d segments, length %u\n",
+		      cmd->use_sg,
+		      length);
+#endif
+		scb->SG_segment_count = cmd->use_sg;
+		memcpy(scb->SG_list_pointer,
+		       &cmd->request_buffer,
+		       sizeof(scb->SG_list_pointer));
+	} else {
+		scb->SG_segment_count = 0;
+		memcpy(scb->data_pointer,
+		       &cmd->request_buffer,
+		       sizeof(scb->data_pointer));
+		memcpy(scb->data_count,
+		       &cmd->request_bufflen,
+		       sizeof(scb->data_count));
+	}
+}
+
+static
+void aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
+{
+	/*
+	 *  By turning on the SCB auto increment, any reference
+	 *  to the SCB I/O space postincrements the SCB address
+	 *  we're looking at.  So turn this on and dump the relevant
+	 *  portion of the SCB to the card.
+	 */
+	outb(0x80, O_SCBCNT(base));	/* SCBAUTO */
+
+	asm volatile("cld\n\t"
+		     "rep\n\t"
+		     "outsb"
+		     : /* no output */
+		     :"S" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
+		     :"si", "cx", "dx");
+
+	outb(0, O_SCBCNT(base));
+}
+
+int aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+	long flags;
+	int empty, old_scbptr;
+	struct aic7xxx_host *p;
+	struct aic7xxx_scb scb;
+
+#if 0
+	debug("aic7xxx_queue: cmd 0x%x (size %u), target %d, lun %d\n",
+	      cmd->cmnd[0],
+	      cmd->cmd_len,
+	      cmd->target,
+	      cmd->lun);
+#endif
+
+	p = (struct aic7xxx_host *)cmd->host->hostdata;
+
+	/*
+	 *  Construct the SCB beforehand, so the sequencer is
+	 *  paused a minimal amount of time.
+	 */
+	aic7xxx_buildscb(p, cmd, &scb);
+
+	/*
+	 *  Clear the startup flag - we can now legitimately
+	 *  expect interrupts.
+	 */
+	p->startup = 0;
+
+	/*
+	 *  This is a critical section, since we don't want the
+	 *  interrupt routine mucking with the host data or the
+	 *  card.  Since the kernel documentation is vague on
+	 *  whether or not we are in a cli/sti pair already, save
+	 *  the flags to be on the safe side.
+	 */
+	save_flags(flags);
+	cli();
+
+	/*
+	 *  Find a free slot in the SCB array to load this command
+	 *  into.  Since can_queue is set to the maximum number of
+	 *  SCBs for the card, we should always find one.
+	 */
+	for (empty = 0; empty < p->maxscb; empty++)
+		if (!p->SCB_array[empty])
+			break;
+	if (empty == p->maxscb)
+		panic("aic7xxx_queue: couldn't find a free scb\n");
+
+	/*
+	 *  Pause the sequencer so we can play with its registers -
+	 *  wait for it to acknowledge the pause.
+	 *
+	 *  XXX - should the interrupts be left on while doing this?
+	 */
+	PAUSE_SEQUENCER(p);
+
+	/*
+	 *  Save the SCB pointer and put our own pointer in - this
+	 *  selects one of the four banks of SCB registers.  Load
+	 *  the SCB, then write its pointer into the queue in FIFO
+	 *  and restore the saved SCB pointer.
+	 */
+	old_scbptr = inb(O_SCBPTR(p->base));
+	outb(empty, O_SCBPTR(p->base));
+	
+	aic7xxx_putscb(p->base, &scb);
+
+	outb(empty, O_QINFIFO(p->base));
+	outb(old_scbptr, O_SCBPTR(p->base));
+
+	/*
+	 *  Make sure the Scsi_Cmnd pointer is saved, the struct it
+	 *  points to is set up properly, and the parity error flag
+	 *  is reset, then unpause the sequencer and watch the fun
+	 *  begin.
+	 */
+	cmd->scsi_done = fn;
+	p->SCB_array[empty] = cmd;
+	aic7xxx_parity(cmd) = DID_OK;
+
+	UNPAUSE_SEQUENCER(p);
+
+	restore_flags(flags);
+	return(0);
+}
+
+/* return values from aic7xxx_kill */
+
+enum k_state {
+	k_ok,				/* scb found and message sent */
+	k_busy,				/* message already present */
+	k_absent,			/* couldn't locate scb */
+	k_disconnect,			/* scb found, but disconnected */
+};
+
+/*
+ *  This must be called with interrupts disabled - it's going to
+ *  be messing around with the host data, and an interrupt being
+ *  fielded in the middle could get ugly.
+ *
+ *  Since so much of the abort and reset code is shared, this
+ *  function performs more magic than it really should.  If the
+ *  command completes ok, then it will call scsi_done with the
+ *  result code passed in.  The unpause parameter controls whether
+ *  or not the sequencer gets unpaused - the reset function, for
+ *  instance, may want to do something more aggressive.
+ *
+ *  Note that the command is checked for in our SCB_array first
+ *  before the sequencer is paused, so if k_absent is returned,
+ *  then the sequencer is NOT paused.
+ */
+
+static
+enum k_state aic7xxx_kill(Scsi_Cmnd *cmd, unsigned char message,
+			  unsigned int result, int unpause)
+{
+	struct aic7xxx_host *p;
+	int i, scb, found, queued;
+	unsigned char scbsave[AIC7XXX_MAXSCB];
+
+	p = (struct aic7xxx_host *)cmd->host->hostdata;
+
+	/*
+	 *  If we can't find the command, assume it just completed
+	 *  and shrug it away.
+	 */
+	for (scb = 0; scb < p->maxscb; scb++)
+		if (p->SCB_array[scb] == cmd)
+			break;
+
+	if (scb == p->maxscb)
+		return(k_absent);
+
+	PAUSE_SEQUENCER(p);
+
+	/*
+	 *  This is the best case, really.  Check to see if the
+	 *  command is still in the sequencer's input queue.  If
+	 *  so, simply remove it.  Reload the queue afterward.
+	 */
+	queued = inb(O_QINCNT(p->base));
+	
+	for (i = found = 0; i < queued; i++) {
+		scbsave[i] = inb(O_QINFIFO(p->base));
+
+		if (scbsave[i] == scb) {
+			found = 1;
+			i -= 1;
+		}
+	}
+
+	queued -= found;
+	for (i = 0; i < queued; i++)
+		outb(scbsave[i], O_QINFIFO(p->base));
+
+	if (found)
+		goto complete;
+
+	/*
+	 *  Check the current SCB bank.  If it's not the one belonging
+	 *  to the command we want to kill, assume that the command
+	 *  is disconnected.  It's rather a pain to force a reconnect
+	 *  and send a message to the target, so we abdicate responsibility
+	 *  in this case.
+	 */
+	if (inb(O_SCBPTR(p->base)) != scb) {
+		if (unpause)
+			UNPAUSE_SEQUENCER(p);
+		return(k_disconnect);
+	}
+
+	/*
+	 *  Presumably at this point our target command is active.  Check
+	 *  to see if there's a message already in effect.  If not, place
+	 *  our message in and assert ATN so the target goes into MESSAGE
+	 *  OUT phase.
+	 */
+	if (inb(HA_MSG_FLAGS(p->base)) & 0x80) {
+		if (unpause)
+			UNPAUSE_SEQUENCER(p);
+		return(k_busy);
+	}
+
+	outb(0x80, HA_MSG_FLAGS(p->base));		/* active message */
+	outb(1, HA_MSG_LEN(p->base));			/* length = 1 */
+	outb(message, HA_MSG_START(p->base));		/* message body */
+
+	/*
+	 *  Assert ATN.  Use the value of SCSISIGO saved by the
+	 *  sequencer code so we don't alter its contents radically
+	 *  in the middle of something critical.
+	 */
+	outb(inb(HA_SIGSTATE(p->base)) | 0x10, O_SCSISIGO(p->base));
+
+	/*
+	 *  The command has been killed.  Do the bookkeeping, unpause
+	 *  the sequencer, and notify the higher-level SCSI code.
+	 */
+complete:
+	p->SCB_array[scb] = NULL;
+	if (unpause)
+		UNPAUSE_SEQUENCER(p);
+
+	cmd->result = result << 16;
+	cmd->scsi_done(cmd);
+	return(k_ok);
+}
+
+int aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+	int rv;
+	long flags;
+
+	save_flags(flags);
+	cli();
+
+	switch (aic7xxx_kill(cmd, ABORT, DID_ABORT, !0)) {
+	    case k_ok:		rv = SCSI_ABORT_SUCCESS;	break;
+	    case k_busy:	rv = SCSI_ABORT_BUSY;		break;
+	    case k_absent:	rv = SCSI_ABORT_NOT_RUNNING;	break;
+	    case k_disconnect:	rv = SCSI_ABORT_SNOOZE;		break;
+	    default:
+		panic("aic7xxx_do_abort: internal error\n");
+	}
+
+	restore_flags(flags);
+	return(rv);
+}
+
+/*
+ *  Resetting the bus always succeeds - is has to, otherwise the
+ *  kernel will panic!  Try a surgical technique - sending a BUS
+ *  DEVICE RESET message - on the offending target before pulling
+ *  the SCSI bus reset line.
+ */
+
+int aic7xxx_reset(Scsi_Cmnd *cmd)
+{
+	int i;
+	long flags;
+	Scsi_Cmnd *reset;
+	struct aic7xxx_host *p;
+
+	p = (struct aic7xxx_host *)cmd->host->hostdata;
+	save_flags(flags);
+	cli();
+
+	switch (aic7xxx_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0)) {
+
+	    case k_ok:
+		/*
+		 *  The RESET message was sent to the target
+		 *  with no problems.  Flag that target as
+		 *  needing a SDTR negotiation on the next
+		 *  connection and restart the sequencer.
+		 */
+		outb((1 << cmd->target), HA_NEEDSDTR(p->base));
+		UNPAUSE_SEQUENCER(p);
+		break;
+
+	    case k_absent:
+		/*
+		 *  The sequencer will not be paused if aic7xxx_kill()
+		 *  couldn't find the command.
+		 */
+		PAUSE_SEQUENCER(p);
+		/* falls through */
+
+	    case k_busy:
+	    case k_disconnect:
+		/*
+		 *  Do a hard reset of the SCSI bus.  According to the
+		 *  SCSI-2 draft specification, reset has to be asserted
+		 *  for at least 25us.  I'm invoking the kernel delay
+		 *  function for 30us since I'm not totally trusting of
+		 *  the busy loop timing.
+		 *
+		 *  XXX - I'm not convinced this works.  I tried resetting
+		 *	  the bus before, trying to get the devices on the
+		 *	  bus to revert to asynchronous transfer, and it
+		 *	  never seemed to work.
+		 */
+		debug("aic7xxx: attempting to reset scsi bus and card\n");
+
+		outb(1, O_SCSISEQ(p->base));		/* SCSIRSTO */
+		udelay(30);
+		outb(0, O_SCSISEQ(p->base));		/* !SCSIRSTO */
+
+		outb(0xff, HA_NEEDSDTR(p->base));
+		UNPAUSE_SEQUENCER(p);
+
+		/*
+		 *  Locate the command and return a "reset" status
+		 *  for it.  This is not completely correct and will
+		 *  probably return to haunt me later.
+		 */
+		for (i = 0; i < p->maxscb; i++) {
+			if (cmd == p->SCB_array[i]) {
+				reset = (Scsi_Cmnd *)p->SCB_array[i];
+				p->SCB_array[i] = NULL;
+				reset->result = DID_RESET << 16;
+				reset->scsi_done(reset);
+				break;
+			}
+		}
+		break;
+
+	    default:
+		panic("aic7xxx_reset: internal error\n");
+	}
+
+	restore_flags(flags);
+	return(SCSI_RESET_SUCCESS);
+}
+
+int aic7xxx_biosparam(Disk *disk, int devno, int geom[])
+{
+	int heads, sectors, cylinders;
+	struct aic7xxx_host *p;
+	
+	p = (struct aic7xxx_host *)disk->device->host->hostdata;
+
+	/*
+	 *  XXX - if I could portably find the card's configuration
+	 *	  information, then this could be autodetected instead
+	 *	  of left to a boot-time switch.
+	 */
+	heads = 64;
+	sectors = 32;
+	cylinders = disk->capacity / (heads * sectors);
+
+	if (p->extended && cylinders > 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = disk->capacity / (255 * 63);
+	}
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return(0);
+}
+
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h
--- v1.3.3/linux/drivers/scsi/aic7xxx.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/aic7xxx.h	Mon Jun 26 12:42:52 1995
@@ -0,0 +1,63 @@
+/* @(#)aic7xxx.h 1.14 94/11/30 jda */
+
+/*
+ * Adaptec 274x/284x/294x device driver for Linux.
+ * Copyright (c) 1994 The University of Calgary Department of Computer Science.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef aic7xxx_h
+#define aic7xxx_h
+
+#define AIC7XXX_H_VERSION	"1.14"
+
+/*
+ *  Scsi_Host_Template (see hosts.h) for 274x - some fields
+ *  to do with card config are filled in after the card is
+ *  detected.
+ */
+#define AIC7XXX	{						\
+	NULL,							\
+	NULL,							\
+	NULL,							\
+	aic7xxx_detect,						\
+	NULL,							\
+	aic7xxx_info,						\
+	NULL,							\
+	aic7xxx_queue,						\
+	aic7xxx_abort,						\
+	aic7xxx_reset,						\
+	NULL,							\
+	aic7xxx_biosparam,					\
+	-1,			/* max simultaneous cmds      */\
+	-1,			/* scsi id of host adapter    */\
+	SG_ALL,			/* max scatter-gather cmds    */\
+	1,			/* cmds per lun (linked cmds) */\
+	0,			/* number of 274x's present   */\
+	0,			/* no memory DMA restrictions */\
+	DISABLE_CLUSTERING					\
+}
+
+extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+extern int aic7xxx_biosparam(Disk *, int, int[]);
+extern int aic7xxx_detect(Scsi_Host_Template *);
+extern int aic7xxx_command(Scsi_Cmnd *);
+extern int aic7xxx_abort(Scsi_Cmnd *);
+extern int aic7xxx_reset(Scsi_Cmnd *);
+
+extern const char *aic7xxx_info(struct Scsi_Host *);
+
+#endif
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
--- v1.3.3/linux/drivers/scsi/aic7xxx.seq	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/aic7xxx.seq	Mon Jun 26 12:42:52 1995
@@ -0,0 +1,1029 @@
+# @(#)aic7xxx.seq 1.32 94/11/29 jda
+#
+# Adaptec 274x/284x/294x device driver for Linux.
+# Copyright (c) 1994 The University of Calgary Department of Computer Science.
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+VERSION AIC7XXX_SEQ_VERSION 1.32
+
+SCBMASK		= 0x1f
+
+SCSISEQ		= 0x00
+SXFRCTL0	= 0x01
+SXFRCTL1	= 0x02
+SCSISIGI	= 0x03
+SCSISIGO	= 0x03
+SCSIRATE	= 0x04
+SCSIID		= 0x05
+SCSIDATL	= 0x06
+STCNT		= 0x08
+STCNT+0		= 0x08
+STCNT+1		= 0x09
+STCNT+2		= 0x0a
+SSTAT0		= 0x0b
+CLRSINT1	= 0x0c
+SSTAT1		= 0x0c
+SIMODE1		= 0x11
+SCSIBUSL	= 0x12
+SHADDR		= 0x14
+SELID		= 0x19
+SBLKCTL		= 0x1f
+SEQCTL		= 0x60
+A		= 0x64				# == ACCUM
+SINDEX		= 0x65
+DINDEX		= 0x66
+ALLZEROS	= 0x6a
+NONE		= 0x6a
+SINDIR		= 0x6c
+DINDIR		= 0x6d
+FUNCTION1	= 0x6e
+HADDR		= 0x88
+HCNT		= 0x8c
+HCNT+0		= 0x8c
+HCNT+1		= 0x8d
+HCNT+2		= 0x8e
+SCBPTR		= 0x90
+INTSTAT		= 0x91
+DFCNTRL		= 0x93
+DFSTATUS	= 0x94
+DFDAT		= 0x99
+QINFIFO		= 0x9b
+QINCNT		= 0x9c
+QOUTFIFO	= 0x9d
+
+SCSICONF	= 0x5a
+
+#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
+#  zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
+#  to indicate whether or not to reload scatter-gather parameters after
+#  a disconnect.
+#
+SCBARRAY+0	= 0xa0
+SCBARRAY+1	= 0xa1
+SCBARRAY+2	= 0xa2
+SCBARRAY+3	= 0xa3
+SCBARRAY+7	= 0xa7
+SCBARRAY+11	= 0xab
+SCBARRAY+14	= 0xae
+SCBARRAY+15	= 0xaf
+SCBARRAY+16	= 0xb0
+SCBARRAY+17	= 0xb1
+SCBARRAY+18	= 0xb2
+SCBARRAY+19	= 0xb3
+SCBARRAY+20	= 0xb4
+SCBARRAY+21	= 0xb5
+SCBARRAY+22	= 0xb6
+SCBARRAY+23	= 0xb7
+SCBARRAY+24	= 0xb8
+SCBARRAY+25	= 0xb9
+
+SIGNAL_0	= 0x01				# unknown scsi bus phase
+SIGNAL_1	= 0x11				# message reject
+SIGNAL_2	= 0x21				# no IDENTIFY after reconnect
+SIGNAL_3	= 0x31				# no cmd match for reconnect
+SIGNAL_4	= 0x41				# SDTR -> SCSIRATE conversion
+
+#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
+#  device information, 32-33 and 5a-5f as well.  Since we don't support
+#  wide or twin-bus SCSI, 28-2f can be reclaimed.  As it turns out, the
+#  BIOS trashes 20-27 anyway, writing the synchronous negotiation results
+#  on top of the BIOS values, so we re-use those for our per-target
+#  scratchspace (actually a value that can be copied directly into
+#  SCSIRATE).  This implies, since we can't get the BIOS config values,
+#  that all targets will be negotiated with for synchronous transfer.
+#  NEEDSDTR has one bit per target indicating if an SDTR message is
+#  needed for that device - this will be set initially, as well as
+#  after a bus reset condition.
+#
+#  The high bit of DROPATN is set if ATN should be dropped before the ACK
+#  when outb is called.  REJBYTE contains the first byte of a MESSAGE IN
+#  message, so the driver can report an intelligible error if a message is
+#  rejected.
+#
+#  RESELECT's high bit is true if we are currently handling a reselect;
+#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
+#  from the reselecting target.  If we haven't had IDENTIFY, then we have
+#  no idea what the lun is, and we can't select the right SCB register
+#  bank, so force a kernel panic if the target attempts a data in/out or
+#  command phase instead of corrupting something.
+#
+#  Note that SG_NEXT occupies four bytes.
+#
+SYNCNEG		= 0x20
+DISC_DSB_A	= 0x32
+
+DROPATN		= 0x30
+REJBYTE		= 0x31
+RESELECT	= 0x34
+
+MSG_FLAGS	= 0x35
+MSG_LEN		= 0x36
+MSG_START+0	= 0x37
+MSG_START+1	= 0x38
+MSG_START+2	= 0x39
+MSG_START+3	= 0x3a
+MSG_START+4	= 0x3b
+MSG_START+5	= 0x3c
+-MSG_START+0	= 0xc9				# 2's complement of MSG_START+0
+
+ARG_1		= 0x4c				# sdtr conversion args & return
+ARG_2		= 0x4d
+RETURN_1	= 0x4c
+
+SIGSTATE	= 0x4e				# value written to SCSISIGO
+NEEDSDTR	= 0x4f				# send SDTR message, 1 bit/trgt
+
+SG_SIZEOF	= 12				# sizeof(struct scatterlist)
+SG_NOLOAD	= 0x50				# load SG pointer/length?
+SG_COUNT	= 0x51				# working value of SG count
+SG_NEXT		= 0x52				# working value of SG pointer
+SG_NEXT+0	= 0x52
+SG_NEXT+1	= 0x53
+SG_NEXT+2	= 0x54
+SG_NEXT+3	= 0x55
+
+SCBCOUNT	= 0x56				# the actual number of SCBs
+
+#  Poll QINCNT for work - the lower bits contain
+#  the number of entries in the Queue In FIFO.
+#
+start:
+	test	SCSISIGI,0x4	jnz reselect	# BSYI
+	test	QINCNT,SCBMASK	jz start
+
+#  We have at least one queued SCB now.  Set the SCB pointer
+#  from the FIFO so we see the right bank of SCB registers,
+#  then set SCSI options and set the initiator and target
+#  SCSI IDs.
+#
+	mov	SCBPTR,QINFIFO
+	mov	SCBARRAY+1	call initialize
+	clr	SG_NOLOAD
+	clr	RESELECT
+
+#  As soon as we get a successful selection, the target should go
+#  into the message out phase since we have ATN asserted.  Prepare
+#  the message to send, locking out the device driver.  If the device
+#  driver hasn't beaten us with an ABORT or RESET message, then tack
+#  on a SDTR negotiation if required.
+#
+#  Messages are stored in scratch RAM starting with a flag byte (high bit
+#  set means active message), one length byte, and then the message itself.
+#
+	mov	SCBARRAY+1	call disconnect	# disconnect ok?
+
+	and	SINDEX,0x7,SCBARRAY+1		# lun
+	or	SINDEX,A			# return value from disconnect
+	or	SINDEX,0x80	call mk_mesg	# IDENTIFY message
+
+	mov	A,SINDEX
+	cmp	MSG_START+0,A	jne !message	# did driver beat us?
+	mvi	MSG_START+1	call mk_sdtr	# build SDTR message if needed
+
+!message:
+
+#  Enable selection phase as an initiator, and do automatic ATN
+#  after the selection.
+#
+	mvi	SCSISEQ,0x48			# ENSELO|ENAUTOATNO
+
+#  Wait for successful arbitration.  The AIC-7770 documentation says
+#  that SELINGO indicates successful arbitration, and that it should
+#  be used to look for SELDO.  However, if the sequencer is paused at
+#  just the right time - a parallel fsck(8) on two drives did it for
+#  me - then SELINGO can flip back to false before we've seen it.  This
+#  makes the sequencer sit in the arbitration loop forever.  This is
+#  Not Good.
+#
+#  Therefore, I've added a check in the arbitration loop for SELDO
+#  too.  This could arguably be made a critical section by disabling
+#  pauses, but I don't want to make a potentially infinite loop a CS.
+#  I suppose you could fold it into the select loop, too, but since
+#  I've been hunting this bug for four days it's kinda like a trophy.
+#
+arbitrate:
+	test	SSTAT0,0x40	jnz *select	# SELDO
+	test	SSTAT0,0x10	jz arbitrate	# SELINGO
+
+#  Wait for a successful selection.  If the hardware selection
+#  timer goes off, then the driver gets the interrupt, so we don't
+#  need to worry about it.
+#
+select:
+	test	SSTAT0,0x40	jz select	# SELDO
+	jmp	*select
+
+#  Reselection is being initiated by a target - we've seen the BSY
+#  line driven active, and we didn't do it!  Enable the reselection
+#  hardware, and wait for it to finish.  Make a note that we've been
+#  reselected, but haven't seen an IDENTIFY message from the target
+#  yet.
+#
+reselect:
+	mvi	SCSISEQ,0x10			# ENRSELI
+
+reselect1:
+	test	SSTAT0,0x20	jz reselect1	# SELDI
+	mov	SELID		call initialize
+
+	mvi	RESELECT,0x80			# reselected, no IDENTIFY
+
+#  After the [re]selection, make sure that the [re]selection enable
+#  bit is off.  This chip is flaky enough without extra things
+#  turned on.  Also clear the BUSFREE bit in SSTAT1 since we'll be
+#  using it shortly.
+#
+*select:
+	clr	SCSISEQ
+	mvi	CLRSINT1,0x8			# CLRBUSFREE
+
+#  Main loop for information transfer phases.  If BSY is false, then
+#  we have a bus free condition, expected or not.  Otherwise, wait
+#  for the target to assert REQ before checking MSG, C/D and I/O
+#  for the bus phase.
+#
+#  We can't simply look at the values of SCSISIGI here (if we want
+#  to do synchronous data transfer), because the target won't assert
+#  REQ if it's already sent us some data that we haven't acknowledged
+#  yet.
+#
+ITloop:
+	test	SSTAT1,0x8	jnz p_busfree	# BUSFREE
+	test	SSTAT1,0x1	jz ITloop	# REQINIT
+
+	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
+
+	cmp	ALLZEROS,A	je p_dataout
+	cmp	A,0x40		je p_datain
+	cmp	A,0x80		je p_command
+	cmp	A,0xc0		je p_status
+	cmp	A,0xa0		je p_mesgout
+	cmp	A,0xe0		je p_mesgin
+
+	mvi	INTSTAT,SIGNAL_0		# unknown - signal driver
+
+p_dataout:
+	mvi	0		call scsisig	# !CDO|!IOO|!MSGO
+	call	assert
+	call	sg_load
+
+	mvi	A,3
+	mvi	DINDEX,HCNT
+	mvi	SCBARRAY+23	call bcopy
+
+	mvi	A,3
+	mvi	DINDEX,STCNT
+	mvi	SCBARRAY+23	call bcopy
+
+	mvi	A,4
+	mvi	DINDEX,HADDR
+	mvi	SCBARRAY+19	call bcopy
+
+	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
+						#   DIRECTION|FIFORESET
+
+#  After a DMA finishes, save the final transfer pointer and count
+#  back into the SCB, in case a device disconnects in the middle of
+#  a transfer.  Use SHADDR and STCNT instead of HADDR and HCNT, since
+#  it's a reflection of how many bytes were transferred on the SCSI
+#  (as opposed to the host) bus.
+#
+	mvi	A,3
+	mvi	DINDEX,SCBARRAY+23
+	mvi	STCNT		call bcopy
+
+	mvi	A,4
+	mvi	DINDEX,SCBARRAY+19
+	mvi	SHADDR		call bcopy
+
+	call	sg_advance
+	mov	SCBARRAY+18,SG_COUNT		# residual S/G count
+
+	jmp	ITloop
+
+p_datain:
+	mvi	0x40		call scsisig	# !CDO|IOO|!MSGO
+	call	assert
+	call	sg_load
+
+	mvi	A,3
+	mvi	DINDEX,HCNT
+	mvi	SCBARRAY+23	call bcopy
+
+	mvi	A,3
+	mvi	DINDEX,STCNT
+	mvi	SCBARRAY+23	call bcopy
+
+	mvi	A,4
+	mvi	DINDEX,HADDR
+	mvi	SCBARRAY+19	call bcopy
+
+	mvi	0x39		call dma	# SCSIEN|SDMAEN|HDMAEN|
+						#   !DIRECTION|FIFORESET
+	mvi	A,3
+	mvi	DINDEX,SCBARRAY+23
+	mvi	STCNT		call bcopy
+
+	mvi	A,4
+	mvi	DINDEX,SCBARRAY+19
+	mvi	SHADDR		call bcopy
+
+	call	sg_advance
+	mov	SCBARRAY+18,SG_COUNT		# residual S/G count
+
+	jmp	ITloop
+
+#  Command phase.  Set up the DMA registers and let 'er rip - the
+#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
+#  so we can copy those three bytes directly into HCNT.
+#
+p_command:
+	mvi	0x80		call scsisig	# CDO|!IOO|!MSGO
+	call	assert
+
+	mvi	A,3
+	mvi	DINDEX,HCNT
+	mvi	SCBARRAY+11	call bcopy
+
+	mvi	A,3
+	mvi	DINDEX,STCNT
+	mvi	SCBARRAY+11	call bcopy
+
+	mvi	A,4
+	mvi	DINDEX,HADDR
+	mvi	SCBARRAY+7	call bcopy
+
+	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
+						#   DIRECTION|FIFORESET
+	jmp	ITloop
+
+#  Status phase.  Wait for the data byte to appear, then read it
+#  and store it into the SCB.
+#
+p_status:
+	mvi	0xc0		call scsisig	# CDO|IOO|!MSGO
+
+	mvi	SCBARRAY+14	call inb
+	jmp	ITloop
+
+#  Message out phase.  If there is no active message, but the target
+#  took us into this phase anyway, build a no-op message and send it.
+#
+p_mesgout:
+	mvi	0xa0		call scsisig	# CDO|!IOO|MSGO
+	mvi	0x8		call mk_mesg	# build NOP message
+
+#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
+#  SXFRCTL0 (SPIOEN) is already on.
+#
+	mvi	SINDEX,MSG_START+0
+	mov	DINDEX,MSG_LEN
+	clr	A
+
+#  When target asks for a byte, drop ATN if it's the last one in
+#  the message.  Otherwise, keep going until the message is exhausted.
+#  (We can't use outb for this since it wants the input in SINDEX.)
+#
+#  Keep an eye out for a phase change, in case the target issues
+#  a MESSAGE REJECT.
+#
+p_mesgout2:
+	test	SSTAT0,0x2	jz p_mesgout2	# SPIORDY
+	test	SSTAT1,0x10	jnz p_mesgout6	# PHASEMIS
+
+	cmp	DINDEX,1	jne p_mesgout3	# last byte?
+	mvi	CLRSINT1,0x40			# CLRATNO - drop ATN
+
+#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
+#  send ACKs in automatic PIO or DMA mode unless you make sure that the
+#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
+#  behaviour is completely undocumented and caused me several days of
+#  grief.
+#
+#  After plugging in different drives to test with and using a longer
+#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
+#  especially when transferring >1 byte.  It seems to be much more stable
+#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
+#  polled for transfer completion - for both output _and_ input.  The
+#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
+#  is accessed (like the documentation says it does), and that on a longer
+#  cable run, the sequencer code was fast enough to loop back and see
+#  an SPIORDY that hadn't dropped yet.
+#
+p_mesgout3:
+	call	one_stcnt
+	mov	SCSIDATL,SINDIR
+
+p_mesgout4:
+	test	SSTAT0,0x4	jz p_mesgout4	# SDONE
+	dec	DINDEX
+	inc	A
+	cmp	MSG_LEN,A	jne p_mesgout2
+
+#  If the next bus phase after ATN drops is a message out, it means
+#  that the target is requesting that the last message(s) be resent.
+#
+p_mesgout5:
+	test	SSTAT1,0x8	jnz p_mesgout6	# BUSFREE
+	test	SSTAT1,0x1	jz p_mesgout5	# REQINIT
+
+	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
+	cmp	A,0xa0		jne p_mesgout6
+	mvi	0x10		call scsisig	# ATNO - re-assert ATN
+
+	jmp	ITloop
+
+p_mesgout6:
+	mvi	CLRSINT1,0x40			# CLRATNO - in case of PHASEMIS
+	clr	MSG_FLAGS			# no active msg
+	jmp	ITloop
+
+#  Message in phase.  Bytes are read using Automatic PIO mode, but not
+#  using inb.  This alleviates a race condition, namely that if ATN had
+#  to be asserted under Automatic PIO mode, it had to beat the SCSI
+#  circuitry sending an ACK to the target.  This showed up under heavy
+#  loads and really confused things, since ABORT commands wouldn't be
+#  seen by the drive after an IDENTIFY message in until it had changed
+#  to a data I/O phase.
+#
+p_mesgin:
+	mvi	0xe0		call scsisig	# CDO|IOO|MSGO
+	mvi	A		call inb_first	# read the 1st message byte
+	mvi	REJBYTE,A			# save it for the driver
+
+	cmp	ALLZEROS,A	jne p_mesgin1
+
+#  We got a "command complete" message, so put the SCB pointer
+#  into the Queue Out, and trigger a completion interrupt.
+#
+	mov	QOUTFIFO,SCBPTR
+	mvi	INTSTAT,0x2			# CMDCMPLT
+	jmp	p_mesgin_done
+
+#  Is it an extended message?  We only support the synchronous data
+#  transfer request message, which will probably be in response to
+#  an SDTR message out from us.  If it's not an SDTR, reject it -
+#  apparently this can be done after any message in byte, according
+#  to the SCSI-2 spec.
+#
+#  XXX - we should really reject this if we didn't initiate the SDTR
+#	 negotiation; this may cause problems with unusual devices.
+#
+p_mesgin1:
+	cmp	A,1		jne p_mesgin2	# extended message code?
+	
+	mvi	A		call inb_next
+	cmp	A,3		jne p_mesginN	# extended mesg length = 3
+	mvi	A		call inb_next
+	cmp	A,1		jne p_mesginN	# SDTR code
+
+	mvi	ARG_1		call inb_next	# xfer period
+	mvi	ARG_2		call inb_next	# REQ/ACK offset
+	mvi	INTSTAT,SIGNAL_4		# call driver to convert
+
+	call	ndx_sdtr			# index sync config for target
+	mov	DINDEX,SINDEX
+	mov	DINDIR,RETURN_1			# save returned value
+
+	not	A				# turn off "need sdtr" flag
+	and	NEEDSDTR,A
+
+#  Even though the SCSI-2 specification says that a device responding
+#  to our SDTR message should honor our parameters for transmitting
+#  to us, it doesn't seem to work too well in real life.  In particular,
+#  a lot of CD-ROM and tape units don't function: try using the SDTR
+#  parameters the device sent us for both transmitting and receiving.
+#
+	mov	SCSIRATE,RETURN_1
+	jmp	p_mesgin_done
+
+#  Is it a disconnect message?  Set a flag in the SCB to remind us
+#  and await the bus going free.
+#
+p_mesgin2:
+	cmp	A,4		jne p_mesgin3	# disconnect code?
+
+	or	SCBARRAY+0,0x4			# set "disconnected" bit
+	jmp	p_mesgin_done
+
+#  Save data pointers message?  Copy working values into the SCB,
+#  usually in preparation for a disconnect.
+#
+p_mesgin3:
+	cmp	A,2		jne p_mesgin4	# save data pointers code?
+
+	call	sg_ram2scb
+	jmp	p_mesgin_done
+
+#  Restore pointers message?  Data pointers are recopied from the
+#  SCB anyway at the start of any DMA operation, so the only thing
+#  to copy is the scatter-gather values.
+#
+p_mesgin4:
+	cmp	A,3		jne p_mesgin5	# restore pointers code?
+
+	call	sg_scb2ram
+	jmp	p_mesgin_done
+
+#  Identify message?  For a reconnecting target, this tells us the lun
+#  that the reconnection is for - find the correct SCB and switch to it,
+#  clearing the "disconnected" bit so we don't "find" it by accident later.
+#
+p_mesgin5:
+	test	A,0x80		jz p_mesgin6	# identify message?
+
+	test	A,0x78		jnz p_mesginN	# !DiscPriv|!LUNTAR|!Reserved
+
+	mov	A		call findSCB	# switch to correct SCB
+
+#  If a active message is present after calling findSCB, then either it
+#  or the driver is trying to abort the command.  Either way, something
+#  untoward has happened and we should just leave it alone.
+#
+	test	MSG_FLAGS,0x80	jnz p_mesgin_done
+
+	xor	SCBARRAY+0,0x4			# clear disconnect bit in SCB
+	mvi	RESELECT,0xc0			# make note of IDENTIFY
+
+	call	sg_scb2ram			# implied restore pointers
+						#   required on reselect
+	jmp	p_mesgin_done
+
+#  Message reject?  If we have an outstanding SDTR negotiation, assume
+#  that it's a response from the target selecting asynchronous transfer,
+#  otherwise just ignore it since we have no clue what it pertains to.
+#
+#  XXX - I don't have a device that responds this way.  Does this code
+#	 actually work?
+#
+p_mesgin6:
+	cmp	A,7		jne p_mesgin7	# message reject code?
+
+	and	FUNCTION1,0x70,SCSIID		# outstanding SDTR message?
+	mov	A,FUNCTION1
+	test	NEEDSDTR,A	jz p_mesgin_done  # no - ignore rejection
+
+	call	ndx_sdtr			# note use of asynch xfer
+	mov	DINDEX,SINDEX
+	clr	DINDIR
+
+	not	A				# turn off "active sdtr" flag
+	and	NEEDSDTR,A
+
+	clr	SCSIRATE			# select asynch xfer
+	jmp	p_mesgin_done
+
+#  [ ADD MORE MESSAGE HANDLING HERE ]
+#
+p_mesgin7:
+
+#  We have no idea what this message in is, and there's no way
+#  to pass it up to the kernel, so we issue a message reject and
+#  hope for the best.  Since we're now using manual PIO mode to
+#  read in the message, there should no longer be a race condition
+#  present when we assert ATN.  In any case, rejection should be a
+#  rare occurrence - signal the driver when it happens.
+#
+p_mesginN:
+	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
+	call	scsisig
+	mvi	INTSTAT,SIGNAL_1		# let driver know
+
+	mvi	0x7		call mk_mesg	# MESSAGE REJECT message
+
+p_mesgin_done:
+	call	inb_last			# ack & turn auto PIO back on
+	jmp	ITloop
+
+#  Bus free phase.  It might be useful to interrupt the device
+#  driver if we aren't expecting this.  For now, make sure that
+#  ATN isn't being asserted and look for a new command.
+#
+p_busfree:
+	mvi	CLRSINT1,0x40			# CLRATNO
+	clr	SIGSTATE
+	jmp	start
+
+#  Bcopy: number of bytes to transfer should be in A, DINDEX should
+#  contain the destination address, and SINDEX should contain the
+#  source address.  All input parameters are trashed on return.
+#
+bcopy:
+	mov	DINDIR,SINDIR
+	dec	A
+	cmp	ALLZEROS,A	jne bcopy
+	ret
+
+#  Locking the driver out, build a one-byte message passed in SINDEX
+#  if there is no active message already.  SINDEX is returned intact.
+#
+mk_mesg:
+	mvi	SEQCTL,0x40			# PAUSEDIS
+	test	MSG_FLAGS,0x80	jnz mk_mesg1	# active message?
+
+	mvi	MSG_FLAGS,0x80			# if not, there is now
+	mvi	MSG_LEN,1			# length = 1
+	mov	MSG_START+0,SINDEX		# 1-byte message
+
+mk_mesg1:
+	clr	SEQCTL				# !PAUSEDIS
+	ret
+
+#  Input byte in Automatic PIO mode.  The address to store the byte
+#  in should be in SINDEX.  DINDEX will be used by this routine.
+#
+inb:
+	test	SSTAT0,0x2	jz inb		# SPIORDY
+	mov	DINDEX,SINDEX
+	call	one_stcnt			# xfer one byte
+	mov	DINDIR,SCSIDATL
+inb1:
+	test	SSTAT0,0x4	jz inb1		# SDONE - wait to "finish"
+	ret
+
+#  Carefully read data in Automatic PIO mode.  I first tried this using
+#  Manual PIO mode, but it gave me continual underrun errors, probably
+#  indicating that I did something wrong, but I feel more secure leaving
+#  Automatic PIO on all the time.
+#
+#  According to Adaptec's documentation, an ACK is not sent on input from
+#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+#  latched (the usual way), then read the data byte directly off the bus
+#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+#  spec guarantees that the target will hold the data byte on the bus until
+#  we send our ACK.
+#
+#  The assumption here is that these are called in a particular sequence,
+#  and that REQ is already set when inb_first is called.  inb_{first,next}
+#  use the same calling convention as inb.
+#
+inb_first:
+	mov	DINDEX,SINDEX
+	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
+
+inb_next:
+	mov	DINDEX,SINDEX			# save SINDEX
+
+	call	one_stcnt			# xfer one byte
+	mov	NONE,SCSIDATL			# dummy read from latch to ACK
+inb_next1:
+	test	SSTAT0,0x4	jz inb_next1	# SDONE
+inb_next2:
+	test	SSTAT0,0x2	jz inb_next2	# SPIORDY - wait for next byte
+	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
+
+inb_last:
+	call	one_stcnt			# ACK with dummy read
+	mov	NONE,SCSIDATL
+inb_last1:
+	test	SSTAT0,0x4	jz inb_last1	# wait for completion
+	ret
+
+#  Output byte in Automatic PIO mode.  The byte to output should be
+#  in SINDEX.  If DROPATN's high bit is set, then ATN will be dropped
+#  before the byte is output.
+#
+outb:
+	test	SSTAT0,0x2	jz outb		# SPIORDY
+	call	one_stcnt			# xfer one byte
+
+	test	DROPATN,0x80	jz outb1
+	mvi	CLRSINT1,0x40			# CLRATNO
+	clr	DROPATN
+outb1:
+	mov	SCSIDATL,SINDEX
+outb2:
+	test	SSTAT0,0x4	jz outb2	# SDONE
+	ret
+
+#  Write the value "1" into the STCNT registers, for Automatic PIO
+#  transfers.
+#
+one_stcnt:
+	clr	STCNT+2
+	clr	STCNT+1
+	mvi	STCNT+0,1	ret
+
+#  DMA data transfer.  HADDR and HCNT must be loaded first, and
+#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
+#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+#  during initialization.
+#
+dma:
+	mov	DFCNTRL,SINDEX
+dma1:
+dma2:
+	test	SSTAT0,0x1	jnz dma3	# DMADONE
+	test	SSTAT1,0x10	jz dma1		# PHASEMIS, ie. underrun
+
+#  We will be "done" DMAing when the transfer count goes to zero, or
+#  the target changes the phase (in light of this, it makes sense that
+#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+#  doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+#  magically on STCNT=0 or a phase change, so just wait for FIFO empty
+#  status.
+#
+dma3:
+	test	SINDEX,0x4	jnz dma5	# DIRECTION
+dma4:
+	test	DFSTATUS,0x1	jz dma4		# !FIFOEMP
+
+#  Now shut the DMA enables off, and copy STCNT (ie. the underrun
+#  amount, if any) to the SCB registers; SG_COUNT will get copied to
+#  the SCB's residual S/G count field after sg_advance is called.  Make
+#  sure that the DMA enables are actually off first lest we get an ILLSADDR.
+#
+dma5:
+	clr	DFCNTRL				# disable DMA
+dma6:
+	test	DFCNTRL,0x38	jnz dma6	# SCSIENACK|SDMAENACK|HDMAENACK
+
+	mvi	A,3
+	mvi	DINDEX,SCBARRAY+15
+	mvi	STCNT		call bcopy
+
+	ret
+
+#  Common SCSI initialization for selection and reselection.  Expects
+#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
+#  contents are stomped on return.
+#
+initialize:
+	clr	SBLKCTL				# channel A, !wide
+	and	SCSIID,0xf0,SINDEX		# target ID
+	and	A,0x7,SCSICONF			# SCSI_ID_A[210]
+	or	SCSIID,A
+
+#  Esundry initialization.
+#
+	clr	DROPATN
+	clr	SIGSTATE
+
+#  Turn on Automatic PIO mode now, before we expect to see an REQ
+#  from the target.  It shouldn't hurt anything to leave it on.  Set
+#  CLRCHN here before the target has entered a data transfer mode -
+#  with synchronous SCSI, if you do it later, you blow away some
+#  data in the SCSI FIFO that the target has already sent to you.
+#
+#  DFON is a 7870 bit enabling digital filtering of REQ and ACK signals.
+#
+	mvi	SXFRCTL0,0x8a			# DFON|SPIOEN|CLRCHN
+
+#  Set SCSI bus parity checking and the selection timeout value,
+#  and enable the hardware selection timer.  Set the SELTO interrupt
+#  to signal the driver.
+#
+#  STPWEN is 7870-specific, enabling an external termination power source.
+#
+	and	A,0x38,SCSICONF			# PARITY_ENB_A|SEL_TIM_A[10]
+	or	SXFRCTL1,0x5,A			# ENSTIMER|STPWEN
+	mvi	SIMODE1,0x84			# ENSELTIMO|ENSCSIPERR
+	
+#  Initialize scatter-gather pointers by setting up the working copy
+#  in scratch RAM.
+#
+	call	sg_scb2ram
+
+#  Initialize SCSIRATE with the appropriate value for this target.
+#
+	call	ndx_sdtr
+	mov	SCSIRATE,SINDIR
+	ret
+
+#  Assert that if we've been reselected, then we've seen an IDENTIFY
+#  message.
+#
+assert:
+	test	RESELECT,0x80	jz assert1	# reselected?
+	test	RESELECT,0x40	jnz assert1	# seen IDENTIFY?
+
+	mvi	INTSTAT,SIGNAL_2		# no - cause a kernel panic
+
+assert1:
+	ret
+
+#  Find out if disconnection is ok from the information the BIOS has left
+#  us.  The target ID should be in the upper four bits of SINDEX; A will
+#  contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
+#  on exit.
+#
+#  This is the only place the target ID is limited to three bits, so we
+#  can use the FUNCTION1 register.
+#
+disconnect:
+	and	FUNCTION1,0x70,SINDEX		# strip off extra just in case
+	mov	A,FUNCTION1
+	test	DISC_DSB_A,A	jz disconnect1	# bit nonzero if DISabled
+
+	clr	A		ret
+disconnect1:
+	mvi	A,0x40		ret
+
+#  Locate the SCB matching the target ID in SELID and the lun in the lower
+#  three bits of SINDEX, and switch the SCB to it.  Have the kernel print
+#  a warning message if it can't be found, and generate an ABORT message
+#  to the target.
+#
+findSCB:
+	and	A,0x7,SINDEX			# lun in lower three bits
+	or	A,A,SELID			# can I do this?
+	and	A,0xf7				# only channel A implemented
+	mov	DINDEX,A			# save in DINDEX for later
+
+	clr	SINDEX
+
+findSCB1:
+	mov	A,DINDEX			# reload A after 1st iteration
+	mov	SCBPTR,SINDEX			# switch to new SCB
+	cmp	SCBARRAY+1,A	jne findSCB2	# target ID/channel/lun match?
+	test	SCBARRAY+0,0x4	jz findSCB2	# should be disconnected
+
+	ret
+
+findSCB2:
+	inc	SINDEX
+	mov	A,SCBCOUNT
+	cmp	SINDEX,A	jne findSCB1
+
+	mvi	INTSTAT,SIGNAL_3		# not found - signal kernel
+	mvi	0x6		call mk_mesg	# ABORT message
+
+	or	SINDEX,0x10,SIGSTATE		# assert ATNO
+	call	scsisig
+	ret
+
+#  Make a working copy of the scatter-gather parameters in the SCB.
+#
+sg_scb2ram:
+	mov	SG_COUNT,SCBARRAY+2
+
+	mvi	A,4
+	mvi	DINDEX,SG_NEXT
+	mvi	SCBARRAY+3	call bcopy
+
+	mvi	SG_NOLOAD,0x80
+	test	SCBARRAY+0,0x10	jnz sg_scb2ram1	# don't reload s/g?
+	clr	SG_NOLOAD
+
+sg_scb2ram1:
+	ret
+
+#  Copying RAM values back to SCB, for Save Data Pointers message.
+#
+sg_ram2scb:
+	mov	SCBARRAY+2,SG_COUNT
+
+	mvi	A,4
+	mvi	DINDEX,SCBARRAY+3
+	mvi	SG_NEXT		call bcopy
+
+	and	SCBARRAY+0,0xef,SCBARRAY+0
+	test	SG_NOLOAD,0x80	jz sg_ram2scb1	# reload s/g?
+	or	SCBARRAY+0,0x10
+
+sg_ram2scb1:
+	ret
+
+#  Load a struct scatter if needed and set up the data address and
+#  length.  If the working value of the SG count is nonzero, then
+#  we need to load a new set of values.
+#
+#  This, like the above DMA, assumes a little-endian host data storage.
+#
+sg_load:
+	test	SG_COUNT,0xff	jz sg_load3	# SG being used?
+	test	SG_NOLOAD,0x80	jnz sg_load3	# don't reload s/g?
+
+	clr	HCNT+2
+	clr	HCNT+1
+	mvi	HCNT+0,SG_SIZEOF
+
+	mvi	A,4
+	mvi	DINDEX,HADDR
+	mvi	SG_NEXT		call bcopy
+
+	mvi	DFCNTRL,0xd			# HDMAEN|DIRECTION|FIFORESET
+
+#  Wait for DMA from host memory to data FIFO to complete, then disable
+#  DMA and wait for it to acknowledge that it's off.
+#
+sg_load1:
+	test	DFSTATUS,0x8	jz sg_load1	# HDONE
+
+	clr	DFCNTRL				# disable DMA
+sg_load2:
+	test	DFCNTRL,0x8	jnz sg_load2	# HDMAENACK
+
+#  Copy data from FIFO into SCB data pointer and data count.  This assumes
+#  that the struct scatterlist has this structure (this and sizeof(struct
+#  scatterlist) == 12 are asserted in aic7xxx.c):
+#
+#	struct scatterlist {
+#		char *address;		/* four bytes, little-endian order */
+#		...			/* four bytes, ignored */
+#		unsigned short length;	/* two bytes, little-endian order */
+#	}
+#
+	mov	SCBARRAY+19,DFDAT		# new data address
+	mov	SCBARRAY+20,DFDAT
+	mov	SCBARRAY+21,DFDAT
+	mov	SCBARRAY+22,DFDAT
+
+	mov	NONE,DFDAT			# throw away four bytes
+	mov	NONE,DFDAT
+	mov	NONE,DFDAT
+	mov	NONE,DFDAT
+
+	mov	SCBARRAY+23,DFDAT
+	mov	SCBARRAY+24,DFDAT
+	clr	SCBARRAY+25
+
+sg_load3:
+	ret
+
+#  Advance the scatter-gather pointers only IF NEEDED.  If SG is enabled,
+#  and the SCSI transfer count is zero (note that this should be called
+#  right after a DMA finishes), then move the working copies of the SG
+#  pointer/length along.  If the SCSI transfer count is not zero, then
+#  presumably the target is disconnecting - do not reload the SG values
+#  next time.
+#
+sg_advance:
+	test	SG_COUNT,0xff	jz sg_advance2	# s/g enabled?
+
+	test	STCNT+0,0xff	jnz sg_advance1	# SCSI transfer count nonzero?
+	test	STCNT+1,0xff	jnz sg_advance1
+	test	STCNT+2,0xff	jnz sg_advance1
+
+	clr	SG_NOLOAD			# reload s/g next time
+	dec	SG_COUNT			# one less segment to go
+
+	clr	A				# add sizeof(struct scatter)
+	add	SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
+	adc	SG_NEXT+1,A,SG_NEXT+1
+	adc	SG_NEXT+2,A,SG_NEXT+2
+	adc	SG_NEXT+3,A,SG_NEXT+3
+
+	ret
+
+sg_advance1:
+	mvi	SG_NOLOAD,0x80			# don't reload s/g next time
+sg_advance2:
+	ret
+
+#  Add the array base SYNCNEG to the target offset (the target address
+#  is in SCSIID), and return the result in SINDEX.  The accumulator
+#  contains the 3->8 decoding of the target ID on return.
+#
+ndx_sdtr:
+	shr	A,SCSIID,4
+	and	A,0x7
+	add	SINDEX,SYNCNEG,A
+
+	and	FUNCTION1,0x70,SCSIID		# 3-bit target address decode
+	mov	A,FUNCTION1	ret
+
+#  If we need to negotiate transfer parameters, build the SDTR message
+#  starting at the address passed in SINDEX.  DINDEX is modified on return.
+#
+mk_sdtr:
+	mov	DINDEX,SINDEX			# save SINDEX
+
+	call	ndx_sdtr
+	test	NEEDSDTR,A	jnz mk_sdtr1	# do we need negotiation?
+	ret
+
+mk_sdtr1:
+	mvi	DINDIR,1			# extended message
+	mvi	DINDIR,3			# extended message length = 3
+	mvi	DINDIR,1			# SDTR code
+	mvi	DINDIR,25			# REQ/ACK transfer period
+	mvi	DINDIR,15			# REQ/ACK offset
+
+	add	MSG_LEN,-MSG_START+0,DINDEX	# update message length
+	ret
+
+#  Set SCSI bus control signal state.  This also saves the last-written
+#  value into a location where the higher-level driver can read it - if
+#  it has to send an ABORT or RESET message, then it needs to know this
+#  so it can assert ATN without upsetting SCSISIGO.  The new value is
+#  expected in SINDEX.  Change the actual state last to avoid contention
+#  from the driver.
+#
+scsisig:
+	mov	SIGSTATE,SINDEX
+	mov	SCSISIGO,SINDEX	ret
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v1.3.3/linux/drivers/scsi/fdomain.c	Fri Jun  9 08:03:26 1995
+++ linux/drivers/scsi/fdomain.c	Mon Jun 26 09:40:25 1995
@@ -1,10 +1,10 @@
 /* fdomain.c -- Future Domain TMC-16x0 SCSI driver
  * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Mon Jun  5 09:21:54 1995 by faith@cs.unc.edu
+ * Revised: Fri Jun 23 17:07:09 1995 by r.faith@ieee.org
  * Author: Rickard E. Faith, faith@cs.unc.edu
  * Copyright 1992, 1993, 1994, 1995 Rickard E. Faith
  *
- * $Id: fdomain.c,v 5.28 1995/06/05 13:21:57 faith Exp $
+ * $Id: fdomain.c,v 5.31 1995/06/23 21:07:16 faith Exp $
 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -145,6 +145,11 @@
  (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective
  work on the Quantum RAM layout.
 
+ Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for
+ providing patches for proper PCI BIOS32-mediated detection of the TMC-3260
+ card (a PCI bus card with the 36C70 chip).  Please send James PCI-related
+ bug reports.
+ 
  All of the alpha testers deserve much thanks.
 
 
@@ -193,8 +198,10 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
 
-#define VERSION          "$Revision: 5.28 $"
+#define VERSION          "$Revision: 5.31 $"
 
 /* START OF USER DEFINABLE OPTIONS */
 
@@ -411,17 +418,22 @@
    printk( " at 0x%x using scsi id %d\n",
 	   (unsigned)bios_base, shpnt->this_id );
 
+				/* If this driver works for later FD PCI
+                                   boards, we will have to modify banner
+                                   for additional PCI cards, but for now if
+                                   it's PCI it's a TMC-3260 - JTM */
    printk( "scsi%d <fdomain>: %s chip at 0x%x irq ",
 	   shpnt->host_no,
 	   chip == tmc1800 ? "TMC-1800"
 	   : (chip == tmc18c50 ? "TMC-18C50"
-	      : (chip == tmc18c30 ? "TMC-18C30" : "Unknown")),
+	      : (chip == tmc18c30 ?
+		 (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30")
+		 : "Unknown")),
 	   port_base );
 
    if (interrupt_level) printk( "%d", interrupt_level );
    else                 printk( "<none>" );
 
-   if (PCI_bus)         printk( " (PCI bus)" );
    printk( "\n" );
 }
 
@@ -444,8 +456,6 @@
 
 static int fdomain_is_valid_port( int port )
 {
-   int options;
-
 #if DEBUG_DETECT 
    printk( " (%x%x),",
 	   inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
@@ -473,9 +483,9 @@
 				   we'll use the other method.) */
 
       outb( 0x80, port + IO_Control );
-      if (inb( port + Configuration2 ) & 0x80 == 0x80) {
+      if ((inb( port + Configuration2 ) & 0x80) == 0x80) {
 	 outb( 0x00, port + IO_Control );
-	 if (inb( port + Configuration2 ) & 0x80 == 0x00) {
+	 if ((inb( port + Configuration2 ) & 0x80) == 0x00) {
 	    chip = tmc18c30;
 	    FIFO_Size = 0x800;	/* 2k FIFO */
 	 }
@@ -494,31 +504,6 @@
 				/* If that failed, we are an 18c50. */
    }
 
-   /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
-      Now, check to be sure the bios_base matches these ports.  If someone
-      was unlucky enough to have purchased more than one Future Domain
-      board, then they will have to modify this code, as we only detect one
-      board here.  [The one with the lowest bios_base.]  */
-
-   options = inb( port + Configuration1 );
-
-#if DEBUG_DETECT
-   printk( " Options = %x\n", options );
-#endif
-
-				/* Check for board with lowest bios_base --
-				   this isn't valid for the 18c30 or for
-				   boards on the PCI bus, so just assume we
-				   have the right board. */
-
-   if (chip != tmc18c30
-       && !PCI_bus
-       && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
-
-				/* Get the IRQ from the options. */
-
-   interrupt_level = ints[ (options & 0x0e) >> 1 ];
-
    return 1;
 }
 
@@ -536,48 +521,45 @@
    return 0;
 }
 
-int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
+/* fdomain_get_irq assumes that we have a valid MCA ID for a
+   TMC-1660/TMC-1680 Future Domain board.  Now, check to be sure the
+   bios_base matches these ports.  If someone was unlucky enough to have
+   purchased more than one Future Domain board, then they will have to
+   modify this code, as we only detect one board here.  [The one with the
+   lowest bios_base.]
+
+   Note that this routine is only used for systems without a PCI BIOS32
+   (e.g., ISA bus).  For PCI bus systems, this routine will likely fail
+   unless one of the IRQs listed in the ints array is used by the board.
+   Sometimes it is possible to use the computer's BIOS setup screen to
+   configure a PCI system so that one of these IRQs will be used by the
+   Future Domain card. */
+
+static int fdomain_get_irq( int base )
 {
-   int              i, j;
-   int              flag = 0;
-   int              retcode;
-   struct Scsi_Host *shpnt;
-#if DO_DETECT
-   const int        buflen = 255;
-   Scsi_Cmnd        SCinit;
-   unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
-   unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };
-   unsigned char    do_read_capacity[] = { READ_CAPACITY,
-					   0, 0, 0, 0, 0, 0, 0, 0, 0 };
-   unsigned char    buf[buflen];
-#endif
+   int options = inb( base + Configuration1 );
 
 #if DEBUG_DETECT
-   printk( "fdomain_16x0_detect()," );
+   printk( " Options = %x\n", options );
 #endif
+   
+				/* Check for board with lowest bios_base --
+				   this isn't valid for the 18c30 or for
+				   boards on the PCI bus, so just assume we
+				   have the right board. */
 
-   for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
-#if DEBUG_DETECT
-      printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
-#endif
-      for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
-	 if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
-		      signatures[j].signature, signatures[j].sig_length )) {
-	    bios_major = signatures[j].major_bios_version;
-	    bios_minor = signatures[j].minor_bios_version;
-	    PCI_bus    = (signatures[j].flag == 1);
-	    Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
-	    bios_base  = addresses[i];
-	 }
-      }
-   }
+   if (chip != tmc18c30
+       && !PCI_bus
+       && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
 
-   if (!bios_base) {
-#if DEBUG_DETECT
-      printk( " FAILED: NO BIOS\n" );
-#endif
-      return 0;
-   }
+   return ints[ (options & 0x0e) >> 1 ];
+}
+
+static int fdomain_isa_detect( int *irq, int *iobase )
+{
+   int i;
+   int base;
+   int flag = 0;
 
    if (bios_major == 2) {
       /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
@@ -591,95 +573,299 @@
       switch (Quantum) {
       case 2:			/* ISA_200S */
       case 3:			/* ISA_250MG */
-	 port_base = *((char *)bios_base + 0x1fa2)
+	 base = *((char *)bios_base + 0x1fa2)
 	       + (*((char *)bios_base + 0x1fa3) << 8);
 	 break;
       case 4:			/* ISA_200S (another one) */
-	 port_base = *((char *)bios_base + 0x1fa3)
+	 base = *((char *)bios_base + 0x1fa3)
 	       + (*((char *)bios_base + 0x1fa4) << 8);
 	 break;
       default:
-	 port_base = *((char *)bios_base + 0x1fcc)
+	 base = *((char *)bios_base + 0x1fcc)
 	       + (*((char *)bios_base + 0x1fcd) << 8);
 	 break;
       }
    
 #if DEBUG_DETECT
-      printk( " %x,", port_base );
+      printk( " %x,", base );
 #endif
 
       for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
-	 if (port_base == ports[i])
+	 if (base == ports[i])
 	       ++flag;
       }
 
-      if (flag)
-	    flag = fdomain_is_valid_port( port_base );
-   }
-
-   if (!flag) {			/* Cannot get port base from BIOS RAM */
+      if (flag && fdomain_is_valid_port( base )) {
+	 *irq    = fdomain_get_irq( base );
+	 *iobase = base;
+	 return 1;
+      }
       
       /* This is a bad sign.  It usually means that someone patched the
 	 BIOS signature list (the signatures variable) to contain a BIOS
-	 signature for a board *OTHER THAN* the TMC-1660/TMC-1680.  It
-	 also means that we don't have a Version 2.0 BIOS :-)
-       */
+	 signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */
       
 #if DEBUG_DETECT
-      if (bios_major != 2) printk( " RAM FAILED, " );
+      printk( " RAM FAILED, " );
+#endif
+   }
+
+   /* Anyway, the alternative to finding the address in the RAM is to just
+      search through every possible port address for one that is attached
+      to the Future Domain card.  Don't panic, though, about reading all
+      these random port addresses -- there are rumors that the Future
+      Domain BIOS does something very similar.
+
+      Do not, however, check ports which the kernel knows are being used by
+      another driver. */
+
+   for (i = 0; i < PORT_COUNT; i++) {
+      base = ports[i];
+      if (check_region( base, 0x10 )) {
+#if DEBUG_DETECT
+	 printk( " (%x inuse),", base );
+#endif
+	 continue;
+      }
+#if DEBUG_DETECT
+      printk( " %x,", base );
 #endif
+      if ((flag = fdomain_is_valid_port( base ))) break;
+   }
+
+   if (!flag) return 0;		/* iobase not found */
+
+   *irq    = fdomain_get_irq( base );
+   *iobase = base;
+
+   return 1;			/* success */
+}
 
-      /* Anyway, the alternative to finding the address in the RAM is to
-	 just search through every possible port address for one that is
-	 attached to the Future Domain card.  Don't panic, though, about
-	 reading all these random port addresses -- there are rumors that
-	 the Future Domain BIOS does something very similar.
+static int fdomain_pci_nobios_detect( int *irq, int *iobase )
+{
+   int i;
+   int flag = 0;
 
-	 Do not, however, check ports which the kernel knows are being used
-	 by another driver. */
+   /* The proper way of doing this is to use ask the PCI bus for the device
+      IRQ and interrupt level.  But we can't do that if PCI BIOS32 support
+      isn't compiled into the kernel, or if a PCI BIOS32 isn't present.
+
+      Instead, we scan down a bunch of addresses (Future Domain tech
+      support says we will probably find the address before we get to
+      0xf800).  This works fine on some systems -- other systems may have
+      to scan more addresses.  If you have to modify this section for your
+      installation, please send mail to faith@cs.unc.edu. */
 
-      if (!PCI_bus) {
-	 for (i = 0; !flag && i < PORT_COUNT; i++) {
-	    port_base = ports[i];
-	    if (check_region( port_base, 0x10 )) {
+   for (i = 0xfff8; i > 0xe000; i -= 8) {
+      if (check_region( i, 0x10 )) {
 #if DEBUG_DETECT
-	       printk( " (%x inuse),", port_base );
+	 printk( " (%x inuse)," , i );
 #endif
-	       continue;
-	    }
+	 continue;
+      }
+      if ((flag = fdomain_is_valid_port( i ))) break;
+   }
+
+   if (!flag) return 0;		/* iobase not found */
+
+   *irq    = fdomain_get_irq( i );
+   *iobase = i;
+
+   return 1;			/* success */
+}
+
+/* PCI detection function: int fdomain_36c70_detect(int* irq, int* iobase)
+   This function gets the Interrupt Level and I/O base address from the PCI
+   configuration registers.  The I/O base address is masked with 0xfff8
+   since on my card the address read from the PCI config registers is off
+   by one from the actual I/O base address necessary for accessing the
+   status and control registers on the card (PCI config register gives
+   0xf801, actual address is 0xf800).  This is likely a bug in the FD
+   config code that writes to the PCI registers, however using a mask
+   should be safe since I think the scan done by the card to determine the
+   I/O base is done in increments of 8 (i.e., 0xf800, 0xf808, ...), at
+   least the old scan code we used to use to get the I/O base did...  Also,
+   the device ID from the PCI config registers is 0x0 and should be 0x60e9
+   as it is in the status registers (offset 5 from I/O base).  If this is
+   changed in future hardware/BIOS changes it will need to be fixed in this
+   detection function.  Comments, bug reports, etc... on this function
+   should be sent to mckinley@msupa.pa.msu.edu - James T. McKinley.  */
+
+#ifdef PCI_CONFIG
+static int fdomain_36c70_detect( int *irq, int *iobase )
+{
+   int              error;
+   unsigned char    pci_bus, pci_dev_fn;    /* PCI bus & device function */
+   unsigned char    pci_irq;                /* PCI interrupt line */
+   unsigned long    pci_base;               /* PCI I/O base address */
+   unsigned short   pci_vendor, pci_device; /* PCI vendor & device IDs */
+
+   /* If the PCI BIOS doesn't exist, use the old-style detection routines.
+      Otherwise, get the I/O base address and interrupt from the PCI config
+      registers. */
+   
+   if (!pcibios_present()) return fdomain_pci_detect( irq, iobase );
+
 #if DEBUG_DETECT
-	    printk( " %x,", port_base );
-#endif
-	    flag = fdomain_is_valid_port( port_base );
+   /* Tell how to print a list of the known PCI devices from bios32 and
+      list vendor and device IDs being used if in debug mode.  */
+      
+   printk( "\nINFO: cat /proc/pci to see list of PCI devices from bios32\n" );
+   printk( "\nTMC-3260 detect:"
+	   " Using PCI Vendor ID: 0x%x, PCI Device ID: 0x%x\n",
+	   PCI_VENDOR_ID_FD, 
+	   PCI_DEVICE_ID_FD_36C70 );
+#endif 
+
+   /* We will have to change this if more than 1 PCI bus is present and the
+      FD scsi host is not on the first bus (i.e., a PCI to PCI bridge,
+      which is not supported by bios32 right now anyway).  This should
+      probably be done by a call to pcibios_find_device but I can't get it
+      to work...  Also the device ID reported from the PCI config registers
+      does not match the device ID quoted in the tech manual or available
+      from offset 5 from the I/O base address.  It should be 0x60E9, but it
+      is 0x0 if read from the PCI config registers.  I guess the FD folks
+      neglected to write it to the PCI registers...  This loop is necessary
+      to get the device function (at least until someone can get
+      pcibios_find_device to work, I cannot but 53c7,8xx.c uses it...). */
+    
+   pci_bus = 0;
+
+   for (pci_dev_fn = 0x0; pci_dev_fn < 0xff; pci_dev_fn++) {
+      pcibios_read_config_word( pci_bus,
+				pci_dev_fn,
+				PCI_VENDOR_ID,
+				&pci_vendor );
+
+      if (pci_vendor == PCI_VENDOR_ID_FD) {
+	 pcibios_read_config_word( pci_bus,
+				   pci_dev_fn,
+				   PCI_DEVICE_ID,
+				   &pci_device );
+
+	 if (pci_device == PCI_DEVICE_ID_FD_36C70) {
+	    /* Break out once we have the correct device.  If other FD
+	       PCI devices are added to this driver we will need to add
+	       an or of the other PCI_DEVICE_ID_FD_XXXXX's here. */
+	    break;
+	 } else {
+	    /* If we can't find an FD scsi card we give up. */
+	    return 0;
 	 }
-      } else {
+      }
+   }
+       
+#if DEBUG_DETECT
+   printk( "Future Domain 36C70 : at PCI bus %u, device %u, function %u\n",
+	   pci_bus,
+	   (pci_dev_fn & 0xf8) >> 3, 
+	   pci_dev_fn & 7 );
+#endif
+
+   /* We now have the appropriate device function for the FD board so we
+      just read the PCI config info from the registers.  */
+
+   if ((error = pcibios_read_config_dword( pci_bus,
+					   pci_dev_fn, 
+					   PCI_BASE_ADDRESS_0,
+					   &pci_base ))
+       || (error = pcibios_read_config_byte( pci_bus,
+					     pci_dev_fn, 
+					     PCI_INTERRUPT_LINE,
+					     &pci_irq ))) {
+      printk ( "PCI ERROR: Future Domain 36C70 not initializing"
+	       " due to error reading configuration space\n" );
+      return 0;
+   } else {
+#if DEBUG_DETECT
+      printk( "TMC-3260 PCI: IRQ = %u, I/O base = 0x%lx\n", 
+	      pci_irq, pci_base );
+#endif
+
+      /* Now we have the I/O base address and interrupt from the PCI
+	 configuration registers.  Unfortunately it seems that the I/O base
+	 address is off by one on my card so I mask it with 0xfff8.  This
+	 must be some kind of goof in the FD code that does the autoconfig
+	 and writes to the PCI registers (or maybe I just don't understand
+	 something).  If they fix it in later versions of the card or BIOS
+	 we may have to adjust the address based on the signature or
+	 something...  */
+
+      *irq    = pci_irq;
+      *iobase = (pci_base & 0xfff8);
+
+#if DEBUG_DETECT
+      printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" ); 
+      printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase );
+#endif
 
-	 /* The proper way of doing this is to use ask the PCI bus for the
-            device IRQ and interrupt level.
+      if (!fdomain_is_valid_port( *iobase )) return 0;
+      return 1;
+   }
+   return 0;
+}
+#endif
 
-	    Until the Linux kernel supports this sort of PCI bus query, we
-	    scan down a bunch of addresses (Future Domain tech support says
-	    we will probably find the address before we get to 0xf800).
-	    This works fine on some systems -- other systems may have to
-	    scan more addresses.  If you have to modify this section for
-	    your installation, please send mail to faith@cs.unc.edu. */
-
-	 for (i = 0xfff8; !flag && i > 0xe000; i -= 8) {
-	    port_base = i;
-	    if (check_region( port_base, 0x10 )) {
-#if DEBUG_DETECT
-	       printk( " (%x inuse)," , port_base );
-#endif
-	       continue;
-	    }
-	    flag = fdomain_is_valid_port( port_base );
+int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
+{
+   int              i, j;
+   int              flag = 0;
+   int              retcode;
+   struct Scsi_Host *shpnt;
+#if DO_DETECT
+   const int        buflen = 255;
+   Scsi_Cmnd        SCinit;
+   unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
+   unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };
+   unsigned char    do_read_capacity[] = { READ_CAPACITY,
+					   0, 0, 0, 0, 0, 0, 0, 0, 0 };
+   unsigned char    buf[buflen];
+#endif
+
+#if DEBUG_DETECT
+   printk( "fdomain_16x0_detect()," );
+#endif
+
+   for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
+#if DEBUG_DETECT
+      printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
+#endif
+      for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
+	 if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
+		      signatures[j].signature, signatures[j].sig_length )) {
+	    bios_major = signatures[j].major_bios_version;
+	    bios_minor = signatures[j].minor_bios_version;
+	    PCI_bus    = (signatures[j].flag == 1);
+	    Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
+	    bios_base  = addresses[i];
 	 }
       }
    }
 
+   if (!bios_base) {
+#if DEBUG_DETECT
+      printk( " FAILED: NO BIOS\n" );
+#endif
+      return 0;
+   }
+
+   if (!PCI_bus) {
+      flag = fdomain_isa_detect( &interrupt_level, &port_base );
+   } else {
+#ifdef PCI_CONFIG
+      flag = fdomain_pci_bios_detect( &interrupt_level, &port_base );
+#else
+      flag = fdomain_pci_nobios_detect( &interrupt_level, &port_base );
+#endif
+   }
+	 
    if (!flag) {
 #if DEBUG_DETECT
       printk( " FAILED: NO PORT\n" );
+#endif
+#ifdef PCI_CONFIG
+      printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" );
+      printk( "Send mail to mckinley@msupa.pa.msu.edu.\n" );
 #endif
       return 0;		/* Cannot find valid set of ports */
    }
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.3.3/linux/drivers/scsi/hosts.c	Sun Feb 19 11:33:14 1995
+++ linux/drivers/scsi/hosts.c	Mon Jun 26 12:42:52 1995
@@ -44,8 +44,8 @@
 #include "aha1740.h"
 #endif
 
-#ifdef CONFIG_SCSI_AHA274X
-#include "aha274x.h"
+#ifdef CONFIG_SCSI_AIC7XXX
+#include "aic7xxx.h"
 #endif
 
 #ifdef CONFIG_SCSI_BUSLOGIC
@@ -160,8 +160,8 @@
 #ifdef CONFIG_SCSI_AHA1740
 	AHA1740,
 #endif
-#ifdef CONFIG_SCSI_AHA274X
-	AHA274X,
+#ifdef CONFIG_SCSI_AIC7XXX
+	AIC7XXX,
 #endif
 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
 	FDOMAIN_16X0,
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/script_asm.pl linux/drivers/scsi/script_asm.pl
--- v1.3.3/linux/drivers/scsi/script_asm.pl	Mon Feb  6 20:45:15 1995
+++ linux/drivers/scsi/script_asm.pl	Mon Jun 26 11:32:58 1995
@@ -763,6 +763,8 @@
 
 @label_patches = ();
 
+@external_patches = ();
+
 @absolute = sort @absolute;
 
 foreach $i (@absolute) {
@@ -854,7 +856,7 @@
 open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
 open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
 
-print OUTPUT "unsigned long ".$prefix."SCRIPT[] = {\n";
+print OUTPUT "u32 ".$prefix."SCRIPT[] = {\n";
 $instructions = 0;
 for ($i = 0; $i < $#code; ) {
     if ($list_in_array) {
@@ -863,14 +865,16 @@
     printf OUTPUT "\t0x%08x,", $code[$i];
     printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
     if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
-	printf OUTPUT "((unsigned long)&%s)%s,", $1, $2
+	push (@external_patches, $i+1, $1);
+	printf OUTPUT "0%s,", $2
     } else {
 	printf OUTPUT "0x%08x,",$code[$i+1];
     }
 
     if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
 	if ($code[$i + 2] =~ /$identifier/) {
-	    printf OUTPUT "(unsigned long)&%s,\n",$code[$i+2];
+	    push (@external_patches, $i+2, $code[$i+2]);
+	    printf OUTPUT "0,\n";
 	} else {
 	    printf OUTPUT "0x%08x,\n",$code[$i+2];
 	}
@@ -891,7 +895,7 @@
     }
     printf OUTPUTU "#undef A_$i\n";
 
-    printf OUTPUT "unsigned long A_".$i."_used\[\] = {\n";
+    printf OUTPUT "u32 A_".$i."_used\[\] = {\n";
 printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
     foreach $j (split (/\s+/,$symbol_references{$i})) {
 	$j =~ /(ABS|REL),(.*),(.*)/;
@@ -913,15 +917,27 @@
 # NCR assembler outputs label patches in the form of indices into 
 # the code.
 #
-printf OUTPUT "unsigned long ".$prefix."LABELPATCHES[] = {\n";
+printf OUTPUT "u32 ".$prefix."LABELPATCHES[] = {\n";
 for $patch (sort {$a <=> $b} @label_patches) {
     printf OUTPUT "\t0x%08x,\n", $patch;
 }
 printf OUTPUT "};\n\n";
 
-printf OUTPUT "unsigned long ".$prefix."INSTRUCTIONS\t= 0x%08x;\n", 
+$num_external_patches = 0;
+printf OUTPUT "struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
+    "} ".$prefix."EXTERNAL_PATCHES[] = {\n";
+while ($ident = pop(@external_patches)) {
+    $off = pop(@external_patches);
+    printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
+    ++$num_external_patches;
+}
+printf OUTPUT "};\n\n";
+
+printf OUTPUT "u32 ".$prefix."INSTRUCTIONS\t= %d;\n", 
     $instructions;
-printf OUTPUT "unsigned long ".$prefix."PATCHES\t= 0x%08x;\n", 
+printf OUTPUT "u32 ".$prefix."PATCHES\t= %d;\n", 
     $#label_patches+1;
+printf OUTPUT "u32 ".$prefix."EXTERNAL_PATCHES_LEN\t= %d;\n",
+    $num_external_patches;
 close OUTPUT;
 close OUTPUTU;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.3/linux/drivers/scsi/scsi.c	Fri Jun 16 22:02:55 1995
+++ linux/drivers/scsi/scsi.c	Thu Jun 22 10:32:41 1995
@@ -1900,7 +1900,7 @@
 
   save_flags(flags);
   cli();
-  if(dma_malloc_freelist[page] & (mask << sector) != (mask<<sector))
+  if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
     panic("Trying to free unused memory");
 
   dma_free_sectors += nbits;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.3/linux/drivers/scsi/scsi.h	Tue Apr 11 07:56:25 1995
+++ linux/drivers/scsi/scsi.h	Mon Jun 26 11:32:58 1995
@@ -349,7 +349,11 @@
      unsigned int length;
      };
 
-#define ISA_DMA_THRESHOLD (0x00ffffff)
+#ifdef __alpha__
+# define ISA_DMA_THRESHOLD (~0UL)
+#else
+# define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif
 #define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
 
 
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v1.3.3/linux/drivers/scsi/scsi_ioctl.c	Sun Feb 19 11:33:14 1995
+++ linux/drivers/scsi/scsi_ioctl.c	Mon Jun 26 11:06:52 1995
@@ -33,7 +33,7 @@
 	const char * string;
 	
 	if ((temp = host->hostt->present) && buffer) {
-		len = get_fs_long ((unsigned long *) buffer);
+		len = get_user ((unsigned int *) buffer);
 		if(host->hostt->info)
 		  string = host->hostt->info(host);
 		else 
@@ -157,11 +157,11 @@
 	if (!buffer)
 		return -EINVAL;
 	
-	inlen = get_fs_long((unsigned long *) buffer);
-	outlen = get_fs_long( ((unsigned long *) buffer) + 1);
+	inlen = get_user((unsigned int *) buffer);
+	outlen = get_user( ((unsigned int *) buffer) + 1);
 
 	cmd_in = (char *) ( ((int *)buffer) + 2);
-	opcode = get_fs_byte(cmd_in); 
+	opcode = get_user(cmd_in); 
 
 	needed = buf_needed = (inlen > outlen ? inlen : outlen);
 	if(buf_needed){
@@ -249,8 +249,8 @@
 	switch (cmd) {
 	        case SCSI_IOCTL_GET_IDLUN:
 	                verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-			put_fs_long(dev->id + (dev->lun << 8) + 
-				    (dev->host->host_no << 16), (unsigned long *) arg);
+			put_user(dev->id + (dev->lun << 8) + 
+				 (dev->host->host_no << 16), (unsigned int *) arg);
 			return 0;
 		case SCSI_IOCTL_TAGGED_ENABLE:
 			if(!suser())  return -EACCES;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c
--- v1.3.3/linux/drivers/scsi/sd_ioctl.c	Sun Feb 19 11:33:14 1995
+++ linux/drivers/scsi/sd_ioctl.c	Mon Jun 26 11:06:52 1995
@@ -37,22 +37,18 @@
 			      host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
 							  dev,
 							  &diskinfo[0]);
-			put_fs_byte(diskinfo[0],
-				(char *) &loc->heads);
-			put_fs_byte(diskinfo[1],
-				(char *) &loc->sectors);
-			put_fs_word(diskinfo[2],
-				(short *) &loc->cylinders);
-			put_fs_long(sd[MINOR(inode->i_rdev)].start_sect,
-				(long *) &loc->start);
+			put_user(diskinfo[0], &loc->heads);
+			put_user(diskinfo[1], &loc->sectors);
+			put_user(diskinfo[2], &loc->cylinders);
+			put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
 			return 0;
          	case BLKGETSIZE:   /* Return device size */
 			if (!arg)  return -EINVAL;
 			error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 			if (error)
 				return error;
-			put_fs_long(sd[MINOR(inode->i_rdev)].nr_sects,
-				(long *) arg);
+			put_user(sd[MINOR(inode->i_rdev)].nr_sects,
+				 (long *) arg);
 			return 0;
 		case BLKRASET:
 			if(!suser())  return -EACCES;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v1.3.3/linux/drivers/scsi/sg.c	Sun Feb 19 11:33:14 1995
+++ linux/drivers/scsi/sg.c	Mon Jun 26 11:06:52 1995
@@ -71,7 +71,7 @@
   switch(cmd_in)
    {
     case SG_SET_TIMEOUT:
-     scsi_generics[dev].timeout=get_fs_long((int *) arg);
+     scsi_generics[dev].timeout=get_user((int *) arg);
      return 0;
     case SG_GET_TIMEOUT:
      return scsi_generics[dev].timeout;
@@ -289,7 +289,7 @@
   /* now issue command */
   SCpnt->request.dev=dev;
   SCpnt->sense_buffer[0]=0;
-  opcode = get_fs_byte(buf);
+  opcode = get_user(buf);
   size=COMMAND_SIZE(opcode);
   if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
   SCpnt->cmd_len = size;
diff -u --recursive --new-file v1.3.3/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v1.3.3/linux/drivers/scsi/sr_ioctl.c	Mon Feb 20 08:49:05 1995
+++ linux/drivers/scsi/sr_ioctl.c	Tue Jun 20 18:37:03 1995
@@ -261,9 +261,10 @@
 			return result;
 
 		case CDROMEJECT:
-			if (scsi_CDs[target].device -> access_count == 1)
-			  sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+			if (scsi_CDs[target].device -> access_count != 1)
+				return -EBUSY;
 
+			sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
 		        sr_cmd[0] = START_STOP;
 			sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
 			sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
diff -u --recursive --new-file v1.3.3/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.3.3/linux/fs/binfmt_elf.c	Tue Jun 20 09:10:32 1995
+++ linux/fs/binfmt_elf.c	Mon Jun 26 11:49:19 1995
@@ -65,15 +65,16 @@
 
 static void padzero(unsigned long elf_bss)
 {
-	unsigned long fpnt, nbyte;
+	unsigned long nbyte;
+	char * fpnt;
   
 	nbyte = elf_bss & (PAGE_SIZE-1);
 	if (nbyte) {
 		nbyte = PAGE_SIZE - nbyte;
 		verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-		fpnt = elf_bss;
+		fpnt = (char *) elf_bss;
 		do {
-			put_fs_byte(0, fpnt++);
+			put_user(0, fpnt++);
 		} while (--nbyte);
 	}
 }
@@ -115,8 +116,8 @@
 	sp -= argc+1;
 	argv = sp;
 	if (!ibcs) {
-		put_fs_long((unsigned long)envp,--sp);
-		put_fs_long((unsigned long)argv,--sp);
+		put_user(envp,--sp);
+		put_user(argv,--sp);
 	}
 
 	/* The constant numbers (0-9) that we are writing here are
@@ -125,29 +126,29 @@
 	if(exec) { /* Put this here for an ELF program interpreter */
 	  struct elf_phdr * eppnt;
 	  eppnt = (struct elf_phdr *) exec->e_phoff;
-	  put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
-	  put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
-	  put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
-	  put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
-	  put_fs_long(7,dlinfo++); put_fs_long(interp_load_addr,dlinfo++);
-	  put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
-	  put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
-	  put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
+	  put_user(3,dlinfo++); put_user(load_addr + exec->e_phoff,dlinfo++);
+	  put_user(4,dlinfo++); put_user(sizeof(struct elf_phdr),dlinfo++);
+	  put_user(5,dlinfo++); put_user(exec->e_phnum,dlinfo++);
+	  put_user(9,dlinfo++); put_user((unsigned long) exec->e_entry,dlinfo++);
+	  put_user(7,dlinfo++); put_user(interp_load_addr,dlinfo++);
+	  put_user(8,dlinfo++); put_user(0,dlinfo++);
+	  put_user(6,dlinfo++); put_user(PAGE_SIZE,dlinfo++);
+	  put_user(0,dlinfo++); put_user(0,dlinfo++);
 	}
 
-	put_fs_long((unsigned long)argc,--sp);
+	put_user((unsigned long)argc,--sp);
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
-		put_fs_long((unsigned long) p,argv++);
-		while (get_fs_byte(p++)) /* nothing */ ;
+		put_user(p,argv++);
+		while (get_user(p++)) /* nothing */ ;
 	}
-	put_fs_long(0,argv);
+	put_user(0,argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
-		put_fs_long((unsigned long) p,envp++);
-		while (get_fs_byte(p++)) /* nothing */ ;
+		put_user(p,envp++);
+		while (get_user(p++)) /* nothing */ ;
 	}
-	put_fs_long(0,envp);
+	put_user(0,envp);
 	current->mm->env_end = (unsigned long) p;
 	return sp;
 }
@@ -739,7 +740,7 @@
 	if(k > elf_bss) elf_bss = k;
 	
 	SYS(close)(fd);
-	if (error != elf_phdata->p_vaddr & 0xfffff000) {
+	if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
 	        kfree(elf_phdata);
 		MOD_DEC_USE_COUNT;
 		return error;
diff -u --recursive --new-file v1.3.3/linux/fs/block_dev.c linux/fs/block_dev.c
--- v1.3.3/linux/fs/block_dev.c	Mon Jan 23 23:04:09 1995
+++ linux/fs/block_dev.c	Mon Jun 26 11:06:52 1995
@@ -289,8 +289,8 @@
 				brelse(*bhe);
 				buf += chars;
 			} else {
-				while (chars-->0)
-					put_fs_byte(0,buf++);
+				while (chars-- > 0)
+					put_user(0,buf++);
 			}
 			offset = 0;
 			if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.3/linux/fs/buffer.c	Tue Jun 13 15:40:17 1995
+++ linux/fs/buffer.c	Tue Jun 20 18:59:31 1995
@@ -1340,8 +1340,12 @@
  * Priority tells the routine how hard to try to shrink the
  * buffers: 3 means "don't bother too much", while a value
  * of 0 means "we'd better get some free pages now".
+ *
+ * "limit" is meant to limit the shrink-action only to pages
+ * that are in the 0 - limit address range, for DMA re-allocations.
+ * We ignore that right now.
  */
-int shrink_buffers(unsigned int priority)
+int shrink_buffers(unsigned int priority, unsigned long limit)
 {
 	if (priority < 2) {
 		sync_buffers(0,0);
diff -u --recursive --new-file v1.3.3/linux/fs/exec.c linux/fs/exec.c
--- v1.3.3/linux/fs/exec.c	Fri Jun 16 22:02:55 1995
+++ linux/fs/exec.c	Mon Jun 26 11:06:52 1995
@@ -330,13 +330,13 @@
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		put_user(p,argv++);
-		while (get_fs_byte(p++)) /* nothing */ ;
+		while (get_user(p++)) /* nothing */ ;
 	}
 	put_user(NULL,argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		put_user(p,envp++);
-		while (get_fs_byte(p++)) /* nothing */ ;
+		while (get_user(p++)) /* nothing */ ;
 	}
 	put_user(NULL,envp);
 	current->mm->env_end = (unsigned long) p;
@@ -358,7 +358,7 @@
 		error = verify_area(VERIFY_READ, tmp, sizeof(char *));
 		if (error)
 			return error;
-		while ((p = (char *) get_user(tmp++)) != NULL) {
+		while ((p = get_user(tmp++)) != NULL) {
 			i++;
 			error = verify_area(VERIFY_READ, p, 1);
 			if (error)
@@ -401,14 +401,14 @@
 	while (argc-- > 0) {
 		if (from_kmem == 1)
 			set_fs(new_fs);
-		if (!(tmp = (char *)get_user(argv+argc)))
+		if (!(tmp = get_user(argv+argc)))
 			panic("VFS: argc is wrong");
 		if (from_kmem == 1)
 			set_fs(old_fs);
 		len=0;		/* remember zero-padding */
 		do {
 			len++;
-		} while (get_fs_byte(tmp++));
+		} while (get_user(tmp++));
 		if (p < len) {	/* this shouldn't happen - 128kB */
 			set_fs(old_fs);
 			return 0;
@@ -427,7 +427,7 @@
 					set_fs(new_fs);
 
 			}
-			*(pag + offset) = get_fs_byte(tmp);
+			*(pag + offset) = get_user(tmp);
 		}
 	}
 	if (from_kmem==2)
diff -u --recursive --new-file v1.3.3/linux/fs/ext/file.c linux/fs/ext/file.c
--- v1.3.3/linux/fs/ext/file.c	Mon Apr 18 11:38:16 1994
+++ linux/fs/ext/file.c	Mon Jun 26 11:06:52 1995
@@ -170,7 +170,7 @@
 				buf += chars;
 			} else {
 				while (chars-->0)
-					put_fs_byte(0,buf++);
+					put_user(0,buf++);
 			}
 			offset = 0;
 			if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/ext/symlink.c linux/fs/ext/symlink.c
--- v1.3.3/linux/fs/ext/symlink.c	Mon May  2 18:34:26 1994
+++ linux/fs/ext/symlink.c	Mon Jun 26 11:06:52 1995
@@ -101,7 +101,7 @@
 	i = 0;
 	while (i<buflen && (c = bh->b_data[i])) {
 		i++;
-		put_fs_byte(c,buffer++);
+		put_user(c,buffer++);
 	}
 	brelse(bh);
 	return i;
diff -u --recursive --new-file v1.3.3/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v1.3.3/linux/fs/ext2/file.c	Wed Mar 22 10:33:59 1995
+++ linux/fs/ext2/file.c	Mon Jun 26 11:06:52 1995
@@ -202,7 +202,7 @@
 				buf += chars;
 			} else {
 				while (chars-- > 0)
-					put_fs_byte (0, buf++);
+					put_user (0, buf++);
 			}
 			offset = 0;
 			if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v1.3.3/linux/fs/ext2/symlink.c	Wed Mar 22 10:33:59 1995
+++ linux/fs/ext2/symlink.c	Mon Jun 26 11:06:52 1995
@@ -119,7 +119,7 @@
 	i = 0;
 	while (i < buflen && (c = link[i])) {
 		i++;
-		put_fs_byte (c, buffer++);
+		put_user (c, buffer++);
 	}
 	iput (inode);
 	if (bh)
diff -u --recursive --new-file v1.3.3/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v1.3.3/linux/fs/hpfs/hpfs_fs.c	Mon Jun 12 17:05:30 1995
+++ linux/fs/hpfs/hpfs_fs.c	Mon Jun 26 11:06:52 1995
@@ -981,7 +981,7 @@
 		unsigned c = *in++;
 		if (c == '\r' && (len == 0 || *in == '\n'));
 		else
-			put_fs_byte(c, out++);
+			put_user(c, out++);
 	}
 
 	return out - start;
diff -u --recursive --new-file v1.3.3/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v1.3.3/linux/fs/isofs/file.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/isofs/file.c	Mon Jun 26 11:06:52 1995
@@ -88,7 +88,7 @@
 			if(mode == ISOFS_FILE_TEXT_M) outchar = 0x0a;
 			if(mode == ISOFS_FILE_TEXT) outchar = ' ';
 		}
-		put_fs_byte(outchar, outbuf++);
+		put_user(outchar, outbuf++);
 		buffer++;
 	}
 }
@@ -240,7 +240,7 @@
 		    buf += chars;
 		  } else {
 		    while (chars-->0)
-		      put_fs_byte(0,buf++);
+		      put_user(0,buf++);
 		  }
 		  offset = 0;
 		  if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c
--- v1.3.3/linux/fs/isofs/symlink.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/isofs/symlink.c	Mon Jun 26 11:06:52 1995
@@ -103,7 +103,7 @@
 
 	while (i<buflen && (c = pnt[i])) {
 		i++;
-		put_fs_byte(c,buffer++);
+		put_user(c,buffer++);
 	}
 	kfree(pnt);
 	return i;
diff -u --recursive --new-file v1.3.3/linux/fs/minix/file.c linux/fs/minix/file.c
--- v1.3.3/linux/fs/minix/file.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/minix/file.c	Mon Jun 26 11:06:52 1995
@@ -168,7 +168,7 @@
 				buf += chars;
 			} else {
 				while (chars-->0)
-					put_fs_byte(0,buf++);
+					put_user(0,buf++);
 			}
 			offset = 0;
 			if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/minix/symlink.c linux/fs/minix/symlink.c
--- v1.3.3/linux/fs/minix/symlink.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/minix/symlink.c	Mon Jun 26 11:06:52 1995
@@ -99,7 +99,7 @@
 	i = 0;
 	while (i<buflen && (c = bh->b_data[i])) {
 		i++;
-		put_fs_byte(c,buffer++);
+		put_user(c,buffer++);
 	}
 	brelse(bh);
 	return i;
diff -u --recursive --new-file v1.3.3/linux/fs/msdos/dir.c linux/fs/msdos/dir.c
--- v1.3.3/linux/fs/msdos/dir.c	Fri Jun  9 12:16:46 1995
+++ linux/fs/msdos/dir.c	Mon Jun 26 09:51:17 1995
@@ -89,7 +89,8 @@
 		return -ENOENT;
 	bh = NULL;
 	while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
-		if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
+		if (!IS_FREE(de->name)
+			&& !(de->attr & (ATTR_VOLUME|ATTR_SYS|ATTR_HIDDEN))) {
 			char bufname[12];
 			char *ptname = bufname;
 			for (i = last = 0; i < 8; i++) {
diff -u --recursive --new-file v1.3.3/linux/fs/msdos/file.c linux/fs/msdos/file.c
--- v1.3.3/linux/fs/msdos/file.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/msdos/file.c	Mon Jun 26 11:06:52 1995
@@ -247,7 +247,7 @@
 					filp->f_pos = inode->i_size;
 					break;
 				}else if (ch != '\r'){
-					put_fs_byte(ch,buf++);
+					put_user(ch,buf++);
 				}
 			}
 		}
@@ -330,7 +330,7 @@
 				carry = 0;
 			}
 			for (size = 0; size < count && left; size++) {
-				if ((ch = get_fs_byte(buf++)) == '\n') {
+				if ((ch = get_user(buf++)) == '\n') {
 					*to++ = '\r';
 					left--;
 				}
diff -u --recursive --new-file v1.3.3/linux/fs/namei.c linux/fs/namei.c
--- v1.3.3/linux/fs/namei.c	Fri Jun  2 19:19:06 1995
+++ linux/fs/namei.c	Mon Jun 26 11:06:52 1995
@@ -65,7 +65,7 @@
 		error = -ENAMETOOLONG;
 		i = PAGE_SIZE;
 	}
-	c = get_fs_byte(filename++);
+	c = get_user(filename++);
 	if (!c)
 		return -ENOENT;
 	if(!(page = __get_free_page(GFP_KERNEL)))
@@ -73,7 +73,7 @@
 	*result = tmp = (char *) page;
 	while (--i) {
 		*(tmp++) = c;
-		c = get_fs_byte(filename++);
+		c = get_user(filename++);
 		if (!c) {
 			*tmp = '\0';
 			return 0;
diff -u --recursive --new-file v1.3.3/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v1.3.3/linux/fs/nfs/symlink.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/nfs/symlink.c	Mon Jun 26 11:06:52 1995
@@ -112,7 +112,7 @@
 	iput(inode);
 	if (! error) {
 		memcpy_tofs(buffer, res, len);
-		put_fs_byte('\0', buffer + len);
+		put_user('\0', buffer + len);
 		error = len;
 	}
 	kfree(mem);
diff -u --recursive --new-file v1.3.3/linux/fs/open.c linux/fs/open.c
--- v1.3.3/linux/fs/open.c	Mon Jun 12 16:49:41 1995
+++ linux/fs/open.c	Mon Jun 26 11:06:52 1995
@@ -157,8 +157,8 @@
 			iput(inode);
 			return error;
 		}
-		actime = get_fs_long((unsigned long *) &times->actime);
-		modtime = get_fs_long((unsigned long *) &times->modtime);
+		actime = get_user(&times->actime);
+		modtime = get_user(&times->modtime);
 		newattrs.ia_ctime = CURRENT_TIME;
 		flags = ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
diff -u --recursive --new-file v1.3.3/linux/fs/pipe.c linux/fs/pipe.c
--- v1.3.3/linux/fs/pipe.c	Fri Jun  2 16:15:08 1995
+++ linux/fs/pipe.c	Mon Jun 26 11:06:52 1995
@@ -135,7 +135,7 @@
 		case FIONREAD:
 			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
 			if (!error)
-				put_fs_long(PIPE_SIZE(*pino),(int *) arg);
+				put_user(PIPE_SIZE(*pino),(int *) arg);
 			return error;
 		default:
 			return -EINVAL;
diff -u --recursive --new-file v1.3.3/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.3/linux/fs/proc/array.c	Fri Jun  2 14:21:40 1995
+++ linux/fs/proc/array.c	Mon Jun 26 11:06:52 1995
@@ -87,7 +87,7 @@
 	}
 
 	while (p < 2*PAGE_SIZE && count > 0) {
-		put_fs_byte(0,buf);
+		put_user(0,buf);
 		buf++;
 		p++;
 		count--;
@@ -135,7 +135,7 @@
     read = 0;
 
     while (p < sizeof(unsigned long) && count > 0) {
-        put_fs_byte(*((char *)(&sample_step)+p),buf);
+        put_user(*((char *)(&sample_step)+p),buf);
 		buf++; p++; count--; read++;
     }
     pnt = (char *)prof_buffer + p - sizeof(unsigned long);
diff -u --recursive --new-file v1.3.3/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v1.3.3/linux/fs/proc/inode.c	Fri Jun 16 22:02:55 1995
+++ linux/fs/proc/inode.c	Mon Jun 26 16:18:15 1995
@@ -196,7 +196,7 @@
 		return;
 	}
 	ino &= 0x0000ffff;
-	if (p->dumpable) {
+	if (p->dumpable && p->uid == p->euid && p->gid == p->egid) {
 		inode->i_uid = p->uid;
 		inode->i_gid = p->gid;
 	}
diff -u --recursive --new-file v1.3.3/linux/fs/proc/link.c linux/fs/proc/link.c
--- v1.3.3/linux/fs/proc/link.c	Mon Jan 23 23:04:10 1995
+++ linux/fs/proc/link.c	Mon Jun 26 11:06:52 1995
@@ -191,6 +191,6 @@
 		buflen = i;
 	i = 0;
 	while (i < buflen)
-		put_fs_byte(buf[i++],buffer++);
+		put_user(buf[i++],buffer++);
 	return i;
 }
diff -u --recursive --new-file v1.3.3/linux/fs/read_write.c linux/fs/read_write.c
--- v1.3.3/linux/fs/read_write.c	Mon Jun  5 12:31:10 1995
+++ linux/fs/read_write.c	Tue Jun 20 19:52:08 1995
@@ -65,7 +65,15 @@
 	if ((err = verify_area(VERIFY_WRITE, result, sizeof(loff_t))))
 		return err;
 	offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
-/* there is no fs specific llseek handler */
+
+	/* if there is a fs-specific handler, we can't just ignore it.. */
+	/* accept llseek() only for the signed long subset of long long */
+	if (file->f_op && file->f_op->lseek) {
+		if (offset != (long) offset)
+			return -EINVAL;
+		return file->f_op->lseek(file->f_inode,file,offset,origin);
+	}
+
 	switch (origin) {
 		case 0:
 			tmp = offset;
@@ -81,9 +89,11 @@
 	}
 	if (tmp < 0)
 		return -EINVAL;
-	file->f_pos = tmp;
-	file->f_reada = 0;
-	file->f_version = ++event;
+	if (tmp != file->f_pos) {
+		file->f_pos = tmp;
+		file->f_reada = 0;
+		file->f_version = ++event;
+	}
 	memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
 	return 0;
 }
diff -u --recursive --new-file v1.3.3/linux/fs/readdir.c linux/fs/readdir.c
--- v1.3.3/linux/fs/readdir.c	Tue Jun 20 09:10:32 1995
+++ linux/fs/readdir.c	Thu Jun 22 14:36:55 1995
@@ -36,7 +36,7 @@
 	int count;
 };
 
-static int fillonedir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
 {
 	struct readdir_callback * buf = (struct readdir_callback *) __buf;
 	struct old_linux_dirent * dirent;
@@ -92,7 +92,7 @@
 	int error;
 };
 
-static int filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
 {
 	struct linux_dirent * dirent;
 	struct getdents_callback * buf = (struct getdents_callback *) __buf;
diff -u --recursive --new-file v1.3.3/linux/fs/select.c linux/fs/select.c
--- v1.3.3/linux/fs/select.c	Fri Jun 16 22:02:55 1995
+++ linux/fs/select.c	Mon Jun 26 11:06:53 1995
@@ -227,8 +227,8 @@
 		i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
 		if (i)
 			return i;
-		timeout = ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ));
-		timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
+		timeout = ROUND_UP(get_user(&tvp->tv_usec),(1000000/HZ));
+		timeout += get_user(&tvp->tv_sec) * (unsigned long) HZ;
 		if (timeout)
 			timeout += jiffies + 1;
 	}
@@ -239,10 +239,10 @@
 	if ((long) timeout < 0)
 		timeout = 0;
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
+		put_user(timeout/HZ, &tvp->tv_sec);
 		timeout %= HZ;
 		timeout *= (1000000/HZ);
-		put_fs_long(timeout, (unsigned long *) &tvp->tv_usec);
+		put_user(timeout, &tvp->tv_usec);
 	}
 	if (i < 0)
 		return i;
diff -u --recursive --new-file v1.3.3/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v1.3.3/linux/fs/sysv/file.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/sysv/file.c	Mon Jun 26 11:06:53 1995
@@ -176,7 +176,7 @@
 				buf += chars;
 			} else {
 				while (chars-- > 0)
-					put_fs_byte(0,buf++);
+					put_user(0,buf++);
 			}
 			offset = 0;
 			if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- v1.3.3/linux/fs/sysv/symlink.c	Mon Jan 23 10:38:30 1995
+++ linux/fs/sysv/symlink.c	Mon Jun 26 11:06:53 1995
@@ -107,7 +107,7 @@
 	i = 0;
 	while (i<buflen && (c = bh_data[i])) {
 		i++;
-		put_fs_byte(c,buffer++);
+		put_user(c,buffer++);
 	}
 	brelse(bh);
 	return i;
diff -u --recursive --new-file v1.3.3/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v1.3.3/linux/fs/umsdos/dir.c	Wed Mar 22 10:31:42 1995
+++ linux/fs/umsdos/dir.c	Mon Jun 26 09:51:17 1995
@@ -36,14 +36,43 @@
 {
 	return -EISDIR;
 }
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
+
+struct UMSDOS_DIR_ONCE {
+	void *dirbuf;
+	filldir_t filldir;
+	int count;
+	int stop;
+};
+
+/*
+	Record a single entry the first call.
+	Return -EINVAL the next one.
+*/
+static int umsdos_dir_once(
+	void * buf,
+	char * name,
+	int name_len,
+	off_t offset,
+	ino_t ino)
+{
+	int ret = -EINVAL;
+	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
+	if (d->count == 0){
+		char zname[100];
+		memcpy (zname,name,name_len);
+		zname[name_len] = '\0';
+		PRINTK (("dir_once :%s: offset %ld\n",zname,offset));
+		ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
+		d->stop = ret < 0;
+		d->count = 1;
+	}
+	return ret;
+}
 
 /*
 	Read count directory entries from directory filp
 	Return a negative value from linux/errno.h.
-	Return > 0 if success (The amount of byte written in
-	dirent round_up to a word size (32 bits).
+	Return > 0 if success (The amount of byte written by filldir).
 
 	This function is used by the normal readdir VFS entry point and by
 	some function who try to find out info on a file from a pure MSDOS
@@ -52,19 +81,19 @@
 static int umsdos_readdir_x(
 	struct inode *dir,		/* Point to a description of the super block */
 	struct file *filp,		/* Point to a directory which is read */
-    struct dirent *dirent,	/* Will hold count directory entry */
-	int dirent_in_fs,		/* dirent point in user's space ? */
-	int count,
+    void *dirbuf,			/* Will hold count directory entry */
+							/* but filled by the filldir function */
+	int internal_read,		/* Called for internal purpose */
 	struct umsdos_dirent *u_entry,	/* Optional umsdos entry */
 	int follow_hlink,
-	off_t *pt_f_pos)		/* will hold the offset of the entry in EMD */
+	filldir_t filldir)
 {
 	int ret = 0;
 	
 	umsdos_startlookup(dir);	
 	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
 		&& dir == pseudo_root
-		&& dirent_in_fs){
+		&& !internal_read){
 		/*
 			We don't need to simulate this pseudo directory
 			when umsdos_readdir_x is called for internal operation
@@ -75,13 +104,10 @@
 			linux root), it simulate a directory /DOS which points to
 			the real root of the file system.
 		*/
-		put_fs_long(dir->i_sb->s_mounted->i_ino,&dirent->d_ino);
-		memcpy_tofs (dirent->d_name,"DOS",3);
-		put_fs_byte(0,dirent->d_name+3);
-		put_fs_word (3,&dirent->d_reclen);
-		if (u_entry != NULL) u_entry->flags = 0;
-		ret = ROUND_UP(NAME_OFFSET(dirent) + 3 + 1);
-		filp->f_pos++;
+		if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
+			,dir->i_sb->s_mounted->i_ino) == 0){
+			filp->f_pos++;
+		}
 	}else if (filp->f_pos < 2
 		|| (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
 		/* #Specification: readdir / . and ..
@@ -116,15 +142,26 @@
 			EMD, we are back at offset 64. So we set the offset
 			to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
 			.. entry from msdos.
+			
+			Now (linux 1.3), umsdos_readdir can read more than one
+			entry even if we limit (umsdos_dir_once) to only one:
+			It skips over hidden file. So we switch to
+			UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
+			the .. entry.
 		*/
-		ret = msdos_readdir(dir,filp,dirent,count);
-		if (filp->f_pos == 64) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
+		int last_f_pos = filp->f_pos;	
+		struct UMSDOS_DIR_ONCE bufk;
+		bufk.dirbuf = dirbuf;
+		bufk.filldir = filldir;
+		bufk.count = 0;
+		ret = msdos_readdir(dir,filp,&bufk,umsdos_dir_once);
+		if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
 		if (u_entry != NULL) u_entry->flags = 0;
 	}else{
 		struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
 		if (emd_dir != NULL){
 			if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
-			PRINTK (("f_pos %ld i_size %d\n",filp->f_pos,emd_dir->i_size));
+			PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size));
 			ret = 0;
 			while (filp->f_pos < emd_dir->i_size){
 				struct umsdos_dirent entry;
@@ -156,7 +193,6 @@
 					int lret;
 					umsdos_parse (entry.name,entry.name_len,&info);
 					info.f_pos = cur_f_pos;
-					*pt_f_pos = cur_f_pos;
 					umsdos_manglename (&info);
 					lret = umsdos_real_lookup (dir,info.fake.fname
 						,info.fake.len,&inode);
@@ -177,29 +213,16 @@
 							infinite recursion /DOS/linux/DOS/linux while
 							walking the file system.
 						*/
-						if (inode != pseudo_root){
-							PRINTK (("Trouve ino %d ",inode->i_ino));
-							if (dirent_in_fs){
-								put_fs_long(inode->i_ino,&dirent->d_ino);
-								memcpy_tofs (dirent->d_name,entry.name
-									,entry.name_len);
-								put_fs_byte(0,dirent->d_name+entry.name_len);
-								put_fs_word (entry.name_len
-									,&dirent->d_reclen);
-								/* In this case, the caller only needs */
-								/* flags */
-								if (u_entry != NULL){
-									u_entry->flags = entry.flags;
-								}
-							}else{
-								dirent->d_ino = inode->i_ino;
-								memcpy (dirent->d_name,entry.name
-									,entry.name_len);
-								dirent->d_name[entry.name_len] = '\0';
-								dirent->d_reclen = entry.name_len;
-								if (u_entry != NULL) *u_entry = entry;
+						if (inode != pseudo_root
+							&& (internal_read
+								|| !(entry.flags & UMSDOS_HIDDEN))){
+							if (filldir (dirbuf 
+								,entry.name,entry.name_len
+								,cur_f_pos, inode->i_ino) < 0){
+								filp->f_pos = cur_f_pos;
 							}
-							ret = ROUND_UP(NAME_OFFSET(dirent) + entry.name_len + 1);
+							PRINTK (("Trouve ino %ld ",inode->i_ino));
+							if (u_entry != NULL) *u_entry = entry;
 							iput (inode);
 							break;
 						}
@@ -217,11 +240,18 @@
 					}
 				}
 			}
+			/*
+				If the fillbuf has failed, f_pos is back to 0.
+				To avoid getting back into the . and .. state
+				(see comments at the beginning), we put back
+				the special offset.
+			*/
+			if (filp->f_pos == 0) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
 			iput(emd_dir);
 		}
 	}
 	umsdos_endlookup(dir);	
-	PRINTK (("read dir %p pos %d ret %d\n",dir,filp->f_pos,ret));
+	PRINTK (("read dir %p pos %lu ret %d\n",dir,filp->f_pos,ret));
 	return ret;
 }
 /*
@@ -232,17 +262,26 @@
 static int UMSDOS_readdir(
 	struct inode *dir,		/* Point to a description of the super block */
 	struct file *filp,		/* Point to a directory which is read */
-    struct dirent *dirent,	/* Will hold count directory entry */
-	int count)
+	void *dirbuf,			/* Will hold directory entries  */
+	filldir_t filldir)
 {
-	int ret = -ENOENT;
-	while (1){
+	int ret = 0;
+	int count = 0;
+	struct UMSDOS_DIR_ONCE bufk;
+	bufk.dirbuf = dirbuf;
+	bufk.filldir = filldir;
+	bufk.stop = 0;
+	PRINTK (("UMSDOS_readdir in\n"));
+	while (ret == 0 && bufk.stop == 0){
 		struct umsdos_dirent entry;
-		off_t f_pos;
-		ret = umsdos_readdir_x (dir,filp,dirent,1,count,&entry,1,&f_pos);
-		if (ret <= 0 || !(entry.flags & UMSDOS_HIDDEN)) break;
+		bufk.count = 0;
+		ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
+		if (bufk.count == 0) break;
+		count += bufk.count;
 	}
-	return ret;
+	PRINTK (("UMSDOS_readdir out %d count %d pos %lu\n",ret,count
+		,filp->f_pos));
+	return count == 0 ? -ENOENT : ret;
 }
 /*
 	Complete the inode content with info from the EMD file
@@ -331,6 +370,53 @@
 if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
 	}
 }
+struct UMSDOS_DIRENT_K{
+	off_t f_pos; /* will hold the offset of the entry in EMD */
+	ino_t ino;
+};
+
+/*
+	Just to record the offset of one entry.
+*/
+static int umsdos_filldir_k(
+	void * buf,
+	char * name,
+	int name_len,
+	off_t offset,
+	ino_t ino)
+{
+	struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
+	d->f_pos = offset;
+	d->ino = ino;
+	return 0;
+}
+
+struct UMSDOS_DIR_SEARCH{
+	struct umsdos_dirent *entry;
+	int found;
+	ino_t search_ino;
+};
+
+static int umsdos_dir_search (
+	void * buf,
+	char * name,
+	int name_len,
+	off_t offset,
+	ino_t ino)
+{
+	int ret = 0;
+	struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
+	if (d->search_ino == ino){
+		d->found = 1;
+		memcpy (d->entry->name,name,name_len);
+		d->entry->name[name_len] = '\0';
+		d->entry->name_len = name_len;
+		ret = 1;	/* So msdos_readdir will terminate */
+	}
+	return ret;
+}
+
+
 /*
 	Locate entry of an inode in a directory.
 	Return 0 or a negative error code.
@@ -357,24 +443,18 @@
 		iput (emddir);
 		if (emddir == NULL){
 			/* This is a DOS directory */
+			struct UMSDOS_DIR_SEARCH bufk;
 			struct file filp;
 			filp.f_reada = 1;
 			filp.f_pos = 0;
-			while (1){
-				struct dirent dirent;
-				if (umsdos_readdir_kmem (dir,&filp,&dirent,1) <= 0){
-					printk ("UMSDOS: can't locate inode %ld in DOS directory???\n"
-						,inode->i_ino);
-				}else if (dirent.d_ino == inode->i_ino){
-					ret = 0;
-					memcpy (entry->name,dirent.d_name,dirent.d_reclen);
-					entry->name[dirent.d_reclen] = '\0';
-					entry->name_len = dirent.d_reclen;
-					inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-					inode->u.umsdos_i.i_emd_owner = 0;
-					umsdos_setup_dir_inode(inode);
-					break;
-				}
+			bufk.entry = entry;
+			bufk.search_ino = inode->i_ino;
+			msdos_readdir (dir,&filp,&bufk,umsdos_dir_search);
+			if (bufk.found){
+				ret = 0;
+				inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+				inode->u.umsdos_i.i_emd_owner = 0;
+				umsdos_setup_dir_inode(inode);
 			}
 		}else{
 			/* skip . and .. see umsdos_readdir_x() */
@@ -382,16 +462,15 @@
 			filp.f_reada = 1;
 			filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
 			while (1){
-				struct dirent dirent;
-				off_t f_pos;
-				if (umsdos_readdir_x(dir,&filp,&dirent
-					,0,1,entry,0,&f_pos) <= 0){
+				struct UMSDOS_DIRENT_K bufk;
+				if (umsdos_readdir_x(dir,&filp,&bufk
+					,1,entry,0,umsdos_filldir_k) < 0){
 					printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
 						,inode->i_ino);
 					break;
-				}else if (dirent.d_ino == inode->i_ino){
+				}else if (bufk.ino == inode->i_ino){
 					ret = 0;
-					umsdos_lookup_patch (dir,inode,entry,f_pos);
+					umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
 					break;
 				}
 			}
@@ -411,7 +490,7 @@
 	int ret;
 	umsdos_patch_inode (dir,NULL,0);
 	ret = umsdos_real_lookup (dir,"..",2,result);
-	PRINTK (("result %d %x ",ret,*result));
+	PRINTK (("result %d %p ",ret,*result));
 	if (ret == 0){
 		struct inode *adir = *result;
 		ret = umsdos_inode2entry (adir,dir,entry);
@@ -560,7 +639,7 @@
 		struct umsdos_info info;
 		ret = umsdos_parse (name,len,&info);
 		if (ret == 0) ret = umsdos_findentry (dir,&info,0);
-		PRINTK (("lookup %s pos %d ret %d len %d ",info.fake.fname,info.f_pos,ret
+		PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret
 			,info.fake.len));
 		if (ret == 0){
 			/* #Specification: umsdos / lookup
@@ -581,7 +660,7 @@
 				umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
 			}else{
 				umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-				PRINTK (("lookup ino %d flags %d\n",inode->i_ino
+				PRINTK (("lookup ino %ld flags %d\n",inode->i_ino
 					,info.entry.flags));
 				if (info.entry.flags & UMSDOS_HLINK){
 					ret = umsdos_hlink2inode (inode,result);
diff -u --recursive --new-file v1.3.3/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v1.3.3/linux/fs/umsdos/emd.c	Mon Jan 23 10:38:30 1995
+++ linux/fs/umsdos/emd.c	Mon Jun 26 09:51:17 1995
@@ -22,19 +22,6 @@
 #define PRINTK(x)
 #define Printk(x) printk x
 
-int umsdos_readdir_kmem(
-	struct inode *inode,
-	struct file *filp,
-	struct dirent *dirent,
-	int count)
-{
-	int ret;
-	int old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	ret = msdos_readdir(inode,filp,dirent,count);
-	set_fs (old_fs);
-	return ret;
-}
 /*
 	Read a file into kernel space memory
 */
@@ -102,7 +89,8 @@
 	filp->f_flags = 0;
 	sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count);
 	if (sizeread != count){
-		printk ("UMSDOS: problem with EMD file. Can't read\n");
+		printk ("UMSDOS: problem with EMD file. Can't read pos = %ld (%d != %d)\n"
+			,filp->f_pos,sizeread,count);
 		ret = -EIO;
 	}
 	return ret;
diff -u --recursive --new-file v1.3.3/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v1.3.3/linux/fs/umsdos/ioctl.c	Tue Jan 31 09:36:21 1995
+++ linux/fs/umsdos/ioctl.c	Mon Jun 26 09:51:18 1995
@@ -20,6 +20,37 @@
 #define PRINTK(x)
 #define Printk(x) printk x
 
+struct UMSDOS_DIR_ONCE {
+	struct dirent *ent;
+	int count;
+};
+
+/*
+	Record a single entry the first call.
+	Return -EINVAL the next one.
+*/
+static int umsdos_ioctl_fill(
+	void * buf,
+	char * name,
+	int name_len,
+	off_t offset,
+	ino_t ino)
+{
+	int ret = -EINVAL;
+	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
+	if (d->count == 0){
+		memcpy_tofs (d->ent->d_name,name,name_len);
+		put_user ('\0',d->ent->d_name+name_len);
+		put_user (name_len,&d->ent->d_reclen);
+		put_user (ino,&d->ent->d_ino);
+		put_user (offset,&d->ent->d_off);
+		d->count = 1;
+		ret = 0;
+	}
+	return ret;
+}
+
+
 /*
 	Perform special function on a directory
 */
@@ -80,7 +111,11 @@
 
 				Return > 0 if success.
 			*/
-			ret = msdos_readdir(dir,filp,&idata->dos_dirent,1);
+			struct UMSDOS_DIR_ONCE bufk;
+			bufk.count = 0;
+			bufk.ent = &idata->dos_dirent;
+			msdos_readdir(dir,filp,&bufk,umsdos_ioctl_fill);
+			ret = bufk.count == 1 ? 1 : 0;
 		}else if (cmd == UMSDOS_READDIR_EMD){
 			/* #Specification: ioctl / UMSDOS_READDIR_EMD
 				One entry is read from the EMD at the current
diff -u --recursive --new-file v1.3.3/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v1.3.3/linux/fs/umsdos/rdir.c	Wed Mar 22 10:31:43 1995
+++ linux/fs/umsdos/rdir.c	Mon Jun 26 09:51:18 1995
@@ -28,42 +28,55 @@
 
 extern struct inode *pseudo_root;
 
-static int UMSDOS_rreaddir (
-	struct inode *dir,
-	struct file *filp,
-    struct dirent *dirent,
-	int count)
+struct RDIR_FILLDIR {
+	void *dirbuf;
+	filldir_t filldir;
+	int real_root;
+};
+
+static int rdir_filldir(
+	void * buf,
+	char * name,
+	int name_len,
+	off_t offset,
+	ino_t ino)
 {
 	int ret = 0;
-	while (1){
-		int len = -1;
-		ret = msdos_readdir(dir,filp,dirent,count);
-		if (ret > 0) len = get_fs_word(&dirent->d_reclen);
-		if (len == 5
-			&& pseudo_root != NULL
-			&& dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){
-			/*
-				In pseudo root mode, we must eliminate logically
-				the directory linux from the real root.
-			*/
-			char name[5];
-			memcpy_fromfs (name,dirent->d_name,5);
-			if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break;
-		}else{
-			if (pseudo_root != NULL
-				&& len == 2
-				&& dir == dir->i_sb->s_mounted
-				&& dir == pseudo_root->i_sb->s_mounted){
-				char name[2];
-				memcpy_fromfs (name,dirent->d_name,2);
-				if (name[0] == '.' && name[1] == '.'){
-					put_fs_long (pseudo_root->i_ino,&dirent->d_ino);
-				}
+	struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
+	if (d->real_root){
+		/* real root of a pseudo_rooted partition */
+		if (name_len != UMSDOS_PSDROOT_LEN
+			|| memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
+			/* So it is not the /linux directory */
+			if (name_len == 2
+				&& name[0] == '.'
+				&& name[1] == '.'){
+				/* Make sure the .. entry points back to the pseudo_root */
+				ino = pseudo_root->i_ino;
 			}
-			break;
+			ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
 		}
+	}else{
+		/* Any DOS directory */
+		ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
 	}
 	return ret;
+}
+
+
+static int UMSDOS_rreaddir (
+	struct inode *dir,
+	struct file *filp,
+    void *dirbuf,
+	filldir_t filldir)
+{
+	struct RDIR_FILLDIR bufk;
+	bufk.filldir = filldir;
+	bufk.dirbuf = dirbuf;
+	bufk.real_root = pseudo_root != NULL
+		&& dir == dir->i_sb->s_mounted
+		&& dir == pseudo_root->i_sb->s_mounted;
+	return msdos_readdir(dir,filp,&bufk,rdir_filldir);
 }
 
 /*
diff -u --recursive --new-file v1.3.3/linux/fs/xiafs/file.c linux/fs/xiafs/file.c
--- v1.3.3/linux/fs/xiafs/file.c	Mon Jan 23 10:38:30 1995
+++ linux/fs/xiafs/file.c	Mon Jun 26 11:06:53 1995
@@ -166,7 +166,7 @@
 		buf += chars;
 	    } else {
 	        while (chars-->0)
-		    put_fs_byte(0,buf++);
+		    put_user(0,buf++);
 	    }
 	    offset = 0;
 	    if (++bhe == &buflist[NBUF])
diff -u --recursive --new-file v1.3.3/linux/fs/xiafs/symlink.c linux/fs/xiafs/symlink.c
--- v1.3.3/linux/fs/xiafs/symlink.c	Mon Jan 23 10:38:30 1995
+++ linux/fs/xiafs/symlink.c	Mon Jun 26 11:06:53 1995
@@ -69,9 +69,9 @@
     if (!bh)
         return 0;
     for (i=0; i < buflen && (c=bh->b_data[i]); i++)
-      put_fs_byte(c, buffer++);
+      put_user(c, buffer++);
     if (i < buflen-1)
-      put_fs_byte((char)0, buffer);
+      put_user('\0', buffer);
     brelse(bh);
     return i;
 }
diff -u --recursive --new-file v1.3.3/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h
--- v1.3.3/linux/include/asm-alpha/dma.h	Fri Jun  2 13:51:16 1995
+++ linux/include/asm-alpha/dma.h	Tue Jun 20 08:58:27 1995
@@ -74,7 +74,7 @@
 #define MAX_DMA_CHANNELS	8
 
 /* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS		0x1000000
+#define MAX_DMA_ADDRESS		(~0UL)
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff -u --recursive --new-file v1.3.3/linux/include/asm-alpha/pal.h linux/include/asm-alpha/pal.h
--- v1.3.3/linux/include/asm-alpha/pal.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/pal.h	Mon Jun 26 11:06:53 1995
@@ -0,0 +1,50 @@
+#ifndef __ALPHA_PAL_H
+#define __ALPHA_PAL_H
+
+/*
+ * Common PAL-code
+ */
+#define PAL_halt	  0
+#define PAL_cflush	  1
+#define PAL_draina	  2
+#define PAL_cobratt	  9
+#define PAL_bpt		128
+#define PAL_bugchk	129
+#define PAL_chmk	131
+#define PAL_callsys	131
+#define PAL_imb		134
+#define PAL_rduniq	158
+#define PAL_wruniq	159
+#define PAL_gentrap	170
+#define PAL_nphalt	190
+
+/*
+ * VMS specific PAL-code
+ */
+#define PAL_swppal	10
+#define PAL_mfpr_vptb	41
+
+/*
+ * OSF specific PAL-code
+ */
+#define PAL_rdmces	16
+#define PAL_wrmces	17
+#define PAL_wrfen	43
+#define PAL_wrvptptr	45
+#define PAL_jtopal	46
+#define PAL_swpctx	48
+#define PAL_wrval	49
+#define PAL_rdval	50
+#define PAL_tbi		51
+#define PAL_wrent	52
+#define PAL_swpipl	53
+#define PAL_rdps	54
+#define PAL_wrkgp	55
+#define PAL_wrusp	56
+#define PAL_wrperfmon	57
+#define PAL_rdusp	58
+#define PAL_whami	60
+#define PAL_rtsys	61
+#define PAL_rti		63
+
+#endif /* __ALPHA_PAL_H */
diff -u --recursive --new-file v1.3.3/linux/include/asm-alpha/segment.h linux/include/asm-alpha/segment.h
--- v1.3.3/linux/include/asm-alpha/segment.h	Thu Jun  8 11:41:19 1995
+++ linux/include/asm-alpha/segment.h	Mon Jun 26 11:06:53 1995
@@ -9,7 +9,7 @@
  * pointer type..
  */
 #define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) __get_user((ptr),sizeof(*(ptr)))
+#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
 
 /*
  * This is a silly but good way to make sure that
@@ -40,7 +40,7 @@
 }
 
 /* I should make this use unaligned transfers etc.. */
-static inline unsigned long __get_user(void * y, int size)
+static inline unsigned long __get_user(const void * y, int size)
 {
 	switch (size) {
 		case 1:
diff -u --recursive --new-file v1.3.3/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v1.3.3/linux/include/asm-alpha/system.h	Fri Jun  2 13:51:17 1995
+++ linux/include/asm-alpha/system.h	Mon Jun 26 11:06:53 1995
@@ -1,6 +1,8 @@
 #ifndef __ALPHA_SYSTEM_H
 #define __ALPHA_SYSTEM_H
 
+#include <asm/pal.h>	/* for backwards compatibility... */
+
 /*
  * System defines.. Note that this is included both from .c and .S
  * files, so it does only defines, not any C code.
@@ -27,58 +29,14 @@
 #define START_ADDR	0xfffffc0000310000
 #define START_SIZE	(2*1024*1024)
 
-/*
- * Common PAL-code
- */
-#define PAL_halt	  0
-#define PAL_cflush	  1
-#define PAL_draina	  2
-#define PAL_cobratt	  9
-#define PAL_bpt		128
-#define PAL_bugchk	129
-#define PAL_chmk	131
-#define PAL_callsys	131
-#define PAL_imb		134
-#define PAL_rduniq	158
-#define PAL_wruniq	159
-#define PAL_gentrap	170
-#define PAL_nphalt	190
-
-/*
- * VMS specific PAL-code
- */
-#define PAL_swppal	10
-#define PAL_mfpr_vptb	41
-
-/*
- * OSF specific PAL-code
- */
-#define PAL_rdmces	16
-#define PAL_wrmces	17
-#define PAL_wrfen	43
-#define PAL_wrvptptr	45
-#define PAL_jtopal	46
-#define PAL_swpctx	48
-#define PAL_wrval	49
-#define PAL_rdval	50
-#define PAL_tbi		51
-#define PAL_wrent	52
-#define PAL_swpipl	53
-#define PAL_rdps	54
-#define PAL_wrkgp	55
-#define PAL_wrusp	56
-#define PAL_wrperfmon	57
-#define PAL_rdusp	58
-#define PAL_whami	60
-#define PAL_rtsys	61
-#define PAL_rti		63
-
 #ifndef __ASSEMBLY__
 
 extern void wrent(void *, unsigned long);
 extern void wrkgp(unsigned long);
 extern void wrusp(unsigned long);
 extern unsigned long rdusp(void);
+extern unsigned long rdmces (void);
+extern void wrmces (unsigned long);
 
 #define halt() __asm__ __volatile__(".long 0");
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-alpha/termios.h linux/include/asm-alpha/termios.h
--- v1.3.3/linux/include/asm-alpha/termios.h	Fri Jun 16 22:02:55 1995
+++ linux/include/asm-alpha/termios.h	Mon Jun 26 11:06:53 1995
@@ -60,6 +60,8 @@
 
 #define TIOCSWINSZ	_IOW('t', 103, struct winsize)
 #define TIOCGWINSZ	_IOR('t', 104, struct winsize)
+#define	TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
+#define	TIOCSTOP	_IO('t', 111)		/* stop output, like ^S */
 #define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
 
 #define TIOCGLTC	_IOR('t', 116, struct ltchars)
@@ -154,8 +156,8 @@
 #define VSTOP 13
 #define VLNEXT 14
 #define VDISCARD 15
-#define VTIME 17
 #define VMIN 16
+#define VTIME 17
 
 /*
  * ..and the same for c_cc in the termio structure.. 
@@ -173,13 +175,13 @@
 #define _VSWTC	7
 
 #ifdef __KERNEL__
-/*	intr=^C		quit=^|		erase=del	kill=^U
-	eof=^D		vtime=\0	vmin=\1		sxtc=\0
-	start=^Q	stop=^S		susp=^Z		eol=\0
-	reprint=^R	discard=^U	werase=^W	lnext=^V
-	eol2=\0
+/*	eof=^D		eol=\0		eol2=\0		erase=del
+	werase=^W	kill=^U		reprint=^R	sxtc=\0
+	intr=^C		quit=^\		susp=^Z		<OSF/1 VDSUSP>
+	start=^Q	stop=^S		lnext=^V	discard=^U
+	vmin=\1		vtime=\0
 */
-#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\000\001"
+#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000"
 #endif
 
 /* c_iflag bits */
diff -u --recursive --new-file v1.3.3/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v1.3.3/linux/include/asm-i386/bitops.h	Mon Aug 22 21:38:32 1994
+++ linux/include/asm-i386/bitops.h	Tue Jun 20 09:40:08 1995
@@ -25,7 +25,7 @@
 
 	__asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
 		:"=r" (oldbit),"=m" (ADDR)
-		:"r" (nr));
+		:"ir" (nr));
 	return oldbit;
 }
 
@@ -35,7 +35,7 @@
 
 	__asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
 		:"=r" (oldbit),"=m" (ADDR)
-		:"r" (nr));
+		:"ir" (nr));
 	return oldbit;
 }
 
@@ -45,7 +45,7 @@
 
 	__asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
 		:"=r" (oldbit),"=m" (ADDR)
-		:"r" (nr));
+		:"ir" (nr));
 	return oldbit;
 }
 
@@ -59,7 +59,7 @@
 
 	__asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
 		:"=r" (oldbit)
-		:"m" (ADDR),"r" (nr));
+		:"m" (ADDR),"ir" (nr));
 	return oldbit;
 }
 
@@ -75,20 +75,18 @@
 	__asm__("
 		cld
 		movl $-1,%%eax
+		xorl %%edx,%%edx
 		repe; scasl
 		je 1f
+		xorl -4(%%edi),%%eax
 		subl $4,%%edi
-		movl (%%edi),%%eax
-		notl %%eax
 		bsfl %%eax,%%edx
-		jmp 2f
-1:		xorl %%edx,%%edx
-2:		subl %%ebx,%%edi
+1:		subl %%ebx,%%edi
 		shll $3,%%edi
 		addl %%edi,%%edx"
 		:"=d" (res)
 		:"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
-		:"ax", "bx", "cx", "di");
+		:"ax", "cx", "di");
 	return res;
 }
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- v1.3.3/linux/include/asm-i386/io.h	Fri Jun  2 15:56:28 1995
+++ linux/include/asm-i386/io.h	Mon Jun 26 15:39:10 1995
@@ -60,6 +60,34 @@
 #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.
+ */
+extern inline unsigned long readb(unsigned long addr)
+{ return *(unsigned char *) addr; }
+
+extern inline unsigned long readw(unsigned long addr)
+{ return *(unsigned short *) addr; }
+
+extern inline unsigned long readl(unsigned long addr)
+{ return *(unsigned int *) addr; }
+
+extern inline void writeb(unsigned char b, unsigned long addr)
+{ *(unsigned char *) addr = b; }
+
+extern inline void writew(unsigned short b, unsigned long addr)
+{ *(unsigned short *) addr = b; }
+
+extern inline void writel(unsigned int b, unsigned long addr)
+{ *(unsigned int *) addr = b; }
+
+#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+/*
  * Talk about misusing macros..
  */
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-i386/segment.h linux/include/asm-i386/segment.h
--- v1.3.3/linux/include/asm-i386/segment.h	Fri Jun 16 22:02:55 1995
+++ linux/include/asm-i386/segment.h	Mon Jun 26 11:06:53 1995
@@ -15,7 +15,7 @@
  * pointer type..
  */
 #define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) __get_user((ptr),sizeof(*(ptr)))
+#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
 
 /*
  * This is a silly but good way to make sure that
@@ -127,21 +127,27 @@
 
 static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n)
 {
-__asm__("cld\n\t"
-	"push %%es\n\t"
-	"push %%fs\n\t"
-	"pop %%es\n\t"
-	"testb $1,%%cl\n\t"
-	"je 1f\n\t"
-	"movsb\n"
-	"1:\ttestb $2,%%cl\n\t"
-	"je 2f\n\t"
-	"movsw\n"
-	"2:\tshrl $2,%%ecx\n\t"
-	"rep ; movsl\n\t"
-	"pop %%es"
-	: /* no outputs */
-	:"c" (n),"D" ((long) to),"S" ((long) from)
+    __asm__ volatile
+	("	cld
+		push %%es
+		movw %%fs,%%cx
+		movw %%cx,%%es
+		cmpl $3,%0
+		jbe 1f
+		movl %%edi,%%ecx
+		negl %%ecx
+		andl $3,%%ecx
+		subl %%ecx,%0
+		rep; movsb
+		movl %0,%%ecx
+		shrl $2,%%ecx
+		rep; movsl
+		andl $3,%0
+	1:	movl %0,%%ecx
+		rep; movsb
+		pop %%es"
+	:"=abd" (n)
+	:"0" (n),"D" ((long) to),"S" ((long) from)
 	:"cx","di","si");
 }
 
@@ -210,18 +216,24 @@
 
 static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
-__asm__("cld\n\t"
-	"testb $1,%%cl\n\t"
-	"je 1f\n\t"
-	"fs ; movsb\n"
-	"1:\ttestb $2,%%cl\n\t"
-	"je 2f\n\t"
-	"fs ; movsw\n"
-	"2:\tshrl $2,%%ecx\n\t"
-	"rep ; fs ; movsl"
-	: /* no outputs */
-	:"c" (n),"D" ((long) to),"S" ((long) from)
-	:"cx","di","si","memory");
+    __asm__ volatile
+	("	cld
+		cmpl $3,%0
+		jbe 1f
+		movl %%edi,%%ecx
+		negl %%ecx
+		andl $3,%%ecx
+		subl %%ecx,%0
+		fs; rep; movsb
+		movl %0,%%ecx
+		shrl $2,%%ecx
+		fs; rep; movsl
+		andl $3,%0
+	1:	movl %0,%%ecx
+		fs; rep; movsb"
+	:"=abd" (n)
+	:"0" (n),"D" ((long) to),"S" ((long) from)
+	:"cx","di","si", "memory");
 }
 
 static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
diff -u --recursive --new-file v1.3.3/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v1.3.3/linux/include/asm-i386/string.h	Mon Jun 12 12:59:55 1995
+++ linux/include/asm-i386/string.h	Tue Jun 20 09:40:08 1995
@@ -342,15 +342,15 @@
 __asm__ __volatile__(
 	"cld\n\t"
 	"rep ; movsl\n\t"
-	"testb $2,%%dl\n\t"
+	"testb $2,%b1\n\t"
 	"je 1f\n\t"
 	"movsw\n"
-	"1:\ttestb $1,%%dl\n\t"
+	"1:\ttestb $1,%b1\n\t"
 	"je 2f\n\t"
 	"movsb\n"
 	"2:"
 	: /* no output */
-	:"c" (n/4), "d" (n),"D" ((long) to),"S" ((long) from)
+	:"c" (n/4), "q" (n),"D" ((long) to),"S" ((long) from)
 	: "cx","di","si","memory");
 return (to);
 }
@@ -424,21 +424,7 @@
 return dest;
 }
 
-extern inline int memcmp(const void * cs,const void * ct,size_t count)
-{
-register int __res;
-__asm__ __volatile__(
-	"cld\n\t"
-	"repe\n\t"
-	"cmpsb\n\t"
-	"je 1f\n\t"
-	"sbbl %%eax,%%eax\n\t"
-	"orb $1,%%al\n"
-	"1:"
-	:"=a" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
-	:"si","di","cx");
-return __res;
-}
+#define memcmp __builtin_memcmp
 
 extern inline void * memchr(const void * cs,int c,size_t count)
 {
@@ -482,15 +468,15 @@
 __asm__ __volatile__(
 	"cld\n\t"
 	"rep ; stosl\n\t"
-	"testb $2,%%dl\n\t"
+	"testb $2,%b1\n\t"
 	"je 1f\n\t"
 	"stosw\n"
-	"1:\ttestb $1,%%dl\n\t"
+	"1:\ttestb $1,%b1\n\t"
 	"je 2f\n\t"
 	"stosb\n"
 	"2:"
 	: /* no output */
-	:"a" (c), "d" (count), "c" (count/4), "D" ((long) s)
+	:"a" (c), "q" (count), "c" (count/4), "D" ((long) s)
 	:"cx","di","memory");
 return (s);	
 }
diff -u --recursive --new-file v1.3.3/linux/include/asm-i386/types.h linux/include/asm-i386/types.h
--- v1.3.3/linux/include/asm-i386/types.h	Fri Jun 16 22:02:55 1995
+++ linux/include/asm-i386/types.h	Mon Jun 26 11:34:01 1995
@@ -48,8 +48,8 @@
 typedef __signed__ short __s16;
 typedef unsigned short __u16;
 
-typedef __signed__ long __s32;
-typedef unsigned long __u32;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
 
 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 typedef __signed__ long long __s64;
@@ -67,8 +67,8 @@
 typedef signed short s16;
 typedef unsigned short u16;
 
-typedef signed long s32;
-typedef unsigned long u32;
+typedef signed int s32;
+typedef unsigned int u32;
 
 typedef signed long long s64;
 typedef unsigned long long u64;
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/asi.h linux/include/asm-sparc/asi.h
--- v1.3.3/linux/include/asm-sparc/asi.h	Sun Feb 26 20:46:20 1995
+++ linux/include/asm-sparc/asi.h	Tue Jun 20 08:19:38 1995
@@ -2,18 +2,18 @@
 #define _SPARC_ASI_H
 
 /* asi.h:  Address Space Identifier values for the sparc.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Pioneer work for sun4m: Paul Hatchman (paul@sfe.com.au)
+ * Joint edition for sun4c+sun4m: Pete A. Zaitcev <zaitcev@ipmce.su>
+ */
 
 /* These are sun4c, beware on other architectures. Although things should
  * be similar under regular sun4's.
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_SUN4M
-#include "asi4m.h"
-#else
 
 #define ASI_NULL1        0x0
 #define ASI_NULL2        0x1
@@ -24,6 +24,7 @@
 #define ASI_PTE              0x4
 #define ASI_HWFLUSHSEG       0x5      /* These are to initiate hw flushes of the cache */
 #define ASI_HWFLUSHPAGE      0x6
+#define ASI_REGMAP           0x6      /* Top level segmaps on Sun4's with MUTANT MMU */
 #define ASI_HWFLUSHCONTEXT   0x7
 
 
@@ -38,6 +39,243 @@
 #define ASI_FLUSHPG      0xd
 #define ASI_FLUSHCTX     0xe
 
+/* The following are now not so SS5 specific any more, it is pretty
+ * much a complete generic sun4m/V8 ASI assignment listing now.
+ *
+ * -- davem@caip.rutgers.edu
+ */
+
+/* SPARCstation-5: only 6 bits are decoded. */
+/* wo = Write Only, rw = Read Write;        */
+/* ss = Single Size, as = All Sizes;        */
+#define ASI_M_RES00         0x00   /* Don't touch... */
+#define ASI_M_UNA01         0x01   /* Same here... */
+#define ASI_M_MXCC          0x02   /* Access to TI VIKING MXCC registers */
+#define ASI_M_FLUSH_PROBE   0x03   /* Reference MMU Flush/Probe; rw, ss */
+#define ASI_M_MMUREGS       0x04   /* MMU Registers; rw, ss */
+#define ASI_M_TLBDIAG       0x05   /* MMU TLB only Diagnostics */
+#define ASI_M_DIAGS         0x06   /* Reference MMU Diagnostics */
+#define ASI_M_IODIAG        0x07   /* MMU I/O TLB only Diagnostics */
+#define ASI_M_USERTXT       0x08   /* Same as ASI_USERTXT; rw, as */
+#define ASI_M_KERNELTXT     0x09   /* Same as ASI_KERNELTXT; rw, as */
+#define ASI_M_USERDATA      0x0A   /* Same as ASI_USERDATA; rw, as */
+#define ASI_M_KERNELDATA    0x0B   /* Same as ASI_KERNELDATA; rw, as */
+#define ASI_M_TXTC_TAG      0x0C   /* Instruction Cache Tag; rw, ss */
+#define ASI_M_TXTC_DATA     0x0D   /* Instruction Cache Data; rw, ss */
+#define ASI_M_DATAC_TAG     0x0E   /* Data Cache Tag; rw, ss */
+#define ASI_M_DATAC_DATA    0x0F   /* Data Cache Data; rw, ss */
+
+/* The following cache flushing ASIs work only with the 'sta'
+ * instruction results are unpredictable for 'swap' and 'ldstuba' etc.
+ * So don't do it.
+ */
+
+/* These ASI flushes affect external caches too. */
+#define ASI_M_FLUSH_PAGE    0x10   /* Flush I&D Cache Line (page); wo, ss */
+#define ASI_M_FLUSH_SEG     0x11   /* Flush I&D Cache Line (seg); wo, ss */
+#define ASI_M_FLUSH_REGION  0x12   /* Flush I&D Cache Line (region); wo, ss */
+#define ASI_M_FLUSH_CTX     0x13   /* Flush I&D Cache Line (context); wo, ss */
+#define ASI_M_FLUSH_USER    0x14   /* Flush I&D Cache Line (user); wo, ss */
+
+/* Block-copy operations are available on certain V8 cpus */
+#define ASI_M_BCOPY         0x17   /* Block copy */
+
+/* These affect only the ICACHE and are Ross HyperSparc specific. */
+#define ASI_M_IFLUSH_PAGE   0x18   /* Flush I Cache Line (page); wo, ss */
+#define ASI_M_IFLUSH_SEG    0x19   /* Flush I Cache Line (seg); wo, ss */
+#define ASI_M_IFLUSH_REGION 0x1A   /* Flush I Cache Line (region); wo, ss */
+#define ASI_M_IFLUSH_CTX    0x1B   /* Flush I Cache Line (context); wo, ss */
+#define ASI_M_IFLUSH_USER   0x1C   /* Flush I Cache Line (user); wo, ss */
+
+/* Block-fill operations are available on certain V8 cpus */
+#define ASI_M_BFILL         0x1F
+
+/* This allows direct access to main memory, actually 0x20 to 0x2f are
+ * the available ASI's for physical ram pass-through, but I don't have
+ * any idea what the other ones do....
+ */
+
+#define ASI_M_BYPASS       0x20   /* Reference MMU bypass; rw, as */
+#define ASI_M_FBMEM        0x29   /* Graphics card frame buffer access */
+#define ASI_M_VMEUS        0x2A   /* VME user 16-bit access */
+#define ASI_M_VMEPS        0x2B   /* VME priv 16-bit access */
+#define ASI_M_VMEUT        0x2C   /* VME user 32-bit access */
+#define ASI_M_VMEPT        0x2D   /* VME priv 32-bit access */
+#define ASI_M_SBUS         0x2E   /* Direct SBus access */
+#define ASI_M_CTL          0x2F   /* Control Space (ECC and MXCC are here) */
+
+
+/* This is ROSS HyperSparc only. */
+#define ASI_M_FLUSH_IWHOLE 0x31   /* Flush entire ICACHE; wo, ss */
+
+#define ASI_M_DCDR         0x39   /* Data Cache Diagnostics Registerl rw, ss */
+
+/* Sparc V9 TI UltraSparc ASI's */
+
+/* ASIs 0x0-0x7f are Supervisor Only.  0x80-0xff are for anyone. */
+
+/* You will notice that there are a lot of places where if a normal
+ * ASI is available on the V9, there is also a little-endian version.
+ */
+
+#define ASI_V9_RESV0       0x00   /* Don't touch... */
+#define ASI_V9_RESV1       0x01   /* Not here */
+#define ASI_V9_RESV2       0x02   /* Or here */
+#define ASI_V9_RESV3       0x03   /* nor here. */
+#define ASI_V9_NUCLEUS     0x04   /* Impl-dep extra virtual access context */
+#define ASI_V9_NUCLEUSL    0x0C   /* Nucleus context, little-endian */
+#define ASI_V9_USER_PRIM   0x10   /* User primary address space */
+#define ASI_V9_USER_SEC    0x11   /* User secondary address space */
+
+#define ASI_V9_MMUPASS     0x14   /* OBMEM (external cache, no data cache) */
+#define ASI_V9_IOPASS      0x15   /* Like MMUPASS but for I/O areas (uncached) */
+#define ASI_V9_USER_PRIML  0x18   /* User primary address space, little-endian. */
+#define ASI_V9_USER_SECL   0x19   /* User secondary address space, little-endian. */
+#define ASI_V9_MMUPASSL    0x1C   /* OBMEM little-endian */
+#define ASI_V9_IOPASSL     0x1D   /* Like IOPASS but little-endian */
+#define ASI_V9_ATOMICQ     0x24   /* Atomic 128-bit load address space */
+#define ASI_V9_ATOMICQL    0x2C   /* Atomic 128-bit load little-endian */
+#define ASI_V9_LSTORECTL   0x45   /* ld/st control unit */
+#define ASI_V9_DCACHE_ENT  0x46   /* Data cache entries */
+#define ASI_V9_DCACHE_TAG  0x47   /* Data cache tags */
+#define ASI_V9_IRQDISPS    0x48   /* IRQ dispatch status registers */
+#define ASI_V9_IRQRECVS    0x49   /* IRQ receive status registers */
+#define ASI_V9_MMUREGS     0x4A   /* Spitfire MMU control register */
+#define ASI_V9_ESTATE      0x4B   /* Error state enable register */
+#define ASI_V9_ASYNC_FSR   0x4C   /* Asynchronous Fault Status reg */
+#define ASI_V9_ASYNC_FAR   0x4D   /* Asynchronous Fault Address reg */
+
+#define ASI_V9_ECACHE_DIAG 0x4E   /* External Cache diagnostics */
+
+#define ASI_V9_TXTMMU      0x50   /* MMU for program text */
+#define ASI_V9_TXTMMU_D1   0x51   /* XXX */
+#define ASI_V9_TXTMMU_D2   0x52   /* XXX */
+#define ASI_V9_TXTMMU_TDI  0x54   /* Text MMU TLB data in */
+#define ASI_V9_TXTMMU_TDA  0x55   /* Text MMU TLB data access */
+#define ASI_V9_TXTMMU_TTR  0x56   /* Text MMU TLB tag read */
+#define ASI_V9_TXTMMU_TDM  0x57   /* Text MMU TLB de-map */
+
+#define ASI_V9_DATAMMU     0x58   /* MMU for program data */
+#define ASI_V9_DATAMMU_D1  0x59   /* XXX */
+#define ASI_V9_DATAMMU_D2  0x5A   /* XXX */
+#define ASI_V9_DATAMMU_DD  0x5B   /* XXX */
+#define ASI_V9_DATAMMU_TDI 0x5C   /* Data MMU TLB data in */
+#define ASI_V9_DATAMMU_TDA 0x5D   /* Data MMU TLB data access */
+#define ASI_V9_DATAMMU_TTR 0x5E   /* Data MMU TLB tag read */
+#define ASI_V9_DATAMMU_TDM 0x5F   /* Data MMU TLB de-map */
+
+#define ASI_V9_ICACHE_D    0x66   /* Instruction cache data */
+#define ASI_V9_ICACHE_T    0x67   /* Instruction cache tags */
+#define ASI_V9_ICACHE_DEC  0x6E   /* Instruction cache decode */
+#define ASI_V9_ICACHE_NXT  0x6F   /* Instruction cache next ent */
+
+#define ASI_V9_HUH1        0x70   /* XXX */
+#define ASI_V9_HUH2        0x71   /* XXX */
+
+#define ASI_V9_ECACHE_ACC  0x76   /* External cache registers */
+
+#define ASI_V9_INTR_DISP   0x77   /* Interrupt dispatch registers */
+#define ASI_V9_HUH1L       0x78   /* XXX */
+#define ASI_V9_HUH2L       0x79   /* XXX */
+#define ASI_V9_INTR_RECV   0x7f   /* Interrupt Receive registers */
+
+#define ASI_V9_PRIMARY      0x80   /* Primary address space */
+#define ASI_V9_SECONDARY    0x81   /* Secondary address space */
+#define ASI_V9_PRIMARY_NF   0x82   /* Primary address space -- No Fault */
+#define ASI_V9_SECONDARY_NF 0x83   /* Secondary address space -- No Fault */
+
+#define ASI_V9_PRIMARYL      0x80   /* Primary address space, little-endian */
+#define ASI_V9_SECONDARYL    0x81   /* Secondary address space, little-endian  */
+#define ASI_V9_PRIMARY_NFL   0x82   /* Primary address space, No Fault, l-endian  */
+#define ASI_V9_SECONDARY_NFL 0x83   /* Secondary address space, No Fault, l-endian  */
+
+#define ASI_V9_XXX1        0xC0   /* XXX */
+#define ASI_V9_XXX2        0xC1   /* XXX */
+#define ASI_V9_XXX3        0xC2   /* XXX */
+#define ASI_V9_XXX4        0xC3   /* XXX */
+#define ASI_V9_XXX5        0xC4   /* XXX */
+#define ASI_V9_XXX6        0xC5   /* XXX */
+#define ASI_V9_XXX7        0xC8   /* XXX */
+#define ASI_V9_XXX8        0xC9   /* XXX */
+#define ASI_V9_XXX9        0xCA   /* XXX */
+#define ASI_V9_XXX10       0xCB   /* XXX */
+#define ASI_V9_XXX11       0xCC   /* XXX */
+#define ASI_V9_XXX12       0xCD   /* XXX */
+
+#define ASI_V9_XXX13       0xD0   /* XXX */
+#define ASI_V9_XXX14       0xD1   /* XXX */
+#define ASI_V9_XXX15       0xD2   /* XXX */
+#define ASI_V9_XXX16       0xD3   /* XXX */
+#define ASI_V9_XXX17       0xD8   /* XXX */
+#define ASI_V9_XXX18       0xD9   /* XXX */
+#define ASI_V9_XXX19       0xDA   /* XXX */
+#define ASI_V9_XXX20       0xDB   /* XXX */
+
+#define ASI_V9_XXX21       0xE0   /* XXX */
+#define ASI_V9_XXX22       0xE1   /* XXX */
+#define ASI_V9_XXX23       0xF0   /* XXX */
+#define ASI_V9_XXX24       0xF1   /* XXX */
+#define ASI_V9_XXX25       0xF8   /* XXX */
+#define ASI_V9_XXX26       0xF9   /* XXX */
+
+#ifndef __ASSEMBLY__
+
+/* Better to do these inline with gcc __asm__ statements. */
+
+/* The following allow you to access physical memory directly without
+ * translation by the SRMMU.  The only other way to do this is to
+ * turn off the SRMMU completely, and well... thats not good.
+ *
+ * TODO: For non-MBus SRMMU units we have to perform the following
+ *       using this sequence.
+ * 1) Turn off traps
+ * 2) Turn on AC bit in SRMMU control register
+ * 3) Do our direct physical memory access
+ * 4) Restore old SRMMU control register value
+ * 5) Restore old %psr value 
+ */
+
+extern __inline__ unsigned int
+ldb_sun4m_bypass(unsigned int addr)
+{
+  unsigned int retval;
+
+  __asm__("lduba [%2] %1, %0\n\t" :
+          "=r" (retval) :
+          "i" (ASI_M_BYPASS), "r" (addr));
+
+  return retval;
+}
+
+extern __inline__ unsigned int
+ldw_sun4m_bypass(unsigned int addr)
+{
+  unsigned int retval;
+
+  __asm__("lda [%2] %1, %0\n\t" :
+          "=r" (retval) :
+          "i" (ASI_M_BYPASS), "r" (addr));
+
+  return retval;
+}
+
+extern __inline__ void
+stb_sun4m_bypass(unsigned char value, unsigned int addr)
+{
+  __asm__("stba %0, [%2] %1\n\t" : :
+          "r" (value), "i" (ASI_M_BYPASS), "r" (addr) :
+	  "memory");
+}
+
+extern __inline__ void
+stw_sun4m_bypass(unsigned int value, unsigned int addr)
+{
+  __asm__("sta %0, [%2] %1\n\t" : :
+          "r" (value), "i" (ASI_M_BYPASS), "r" (addr) :
+	  "memory");
+}
+
+#endif /* !(__ASSEMBLY__) */
+
 
-#endif /* CONFIG_SUN4M */
 #endif /* _SPARC_ASI_H */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h
--- v1.3.3/linux/include/asm-sparc/auxio.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/auxio.h	Thu Jun  8 23:41:46 1995
@@ -0,0 +1,35 @@
+/* auxio.h:  Definitons and code for the Auxiliary I/O register.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_AUXIO_H
+#define _SPARC_AUXIO_H
+
+/* This defines the register as I know it on the Sun4c, it may be
+ * different or not exist at all on sun4m's.
+ */
+
+#define AUXIO_IOADDR  0xf7400000  /* Physical address is IO space */
+
+/* This register is an unsigned char in IO space.  It does two things.
+ * First, it is used to control the front panel LED light on machines
+ * that have it (good for testing entry points to trap handlers and irq's)
+ * Secondly, it controls various floppy drive parameters on machines that
+ * have a drive.
+ */
+
+#define AUXIO_ORMEIN      0xf0    /* All writes must set these bits. */
+#define AUXIO_FLPY_DENS   0x20    /* Floppy density, high if set. */
+#define AUXIO_FLPY_DCHG   0x10    /* A disk change occurred. */
+#define AUXIO_FLPY_DSEL   0x08    /* Drive select, 0 'a drive' 1 'b drive'. */
+#define AUXIO_FLPY_TCNT   0x04    /* Floppy terminal count... ??? */
+#define AUXIO_FLPY_EJCT   0x02    /* Eject floppy disk. */
+#define AUXIO_LED         0x01    /* On if set, off if unset. */
+
+#define AUXREG ((volatile unsigned char *)(AUXIO_VADDR + 3))
+
+#define TURN_ON_LED  *AUXREG = AUXIO_ORMEIN | AUXIO_FLPY_EJCT | AUXIO_LED
+#define TURN_OFF_LED *AUXREG = AUXIO_ORMEIN | AUXIO_FLPY_EJCT
+#define FLIP_LED     *AUXREG = (*AUXREG | AUXIO_ORMEIN) ^ AUXIO_LED
+
+#endif /* !(_SPARC_AUXIO_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v1.3.3/linux/include/asm-sparc/bitops.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/bitops.h	Sun Jun 25 09:56:23 1995
@@ -1,8 +1,11 @@
 #ifndef _SPARC_BITOPS_H
 #define _SPARC_BITOPS_H
 
+#include <linux/kernel.h>
+#include <asm/system.h>
+
 /*
- * Copyright 1994, David S. Miller (davem@caip.rutgers.edu).
+ * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
  */
 
 
@@ -17,105 +20,259 @@
  * for sun4m (ie. SMP) no doubt.
  */
 
-extern __inline__ unsigned int set_bit(unsigned int nr, void *addr)
+/* These routines now do things in little endian byte order. */
+
+/* Our unsigned long accesses on the Sparc look like this:
+ * Big Endian:
+ *    byte 0    byte 1      byte 2    byte 3
+ *  0000 0000  0000 0000  0000 0000  0000 0000
+ *  31     24  23     16  15      8  7       0
+ *
+ * We want to set the bits in a little-endian fashion:
+ * Little Endian:
+ *    byte 3    byte 2      byte 1    byte 0
+ *  0000 0000  0000 0000  0000 0000  0000 0000
+ *  31     24  23     16  15      8  7       0
+ */
+
+/* #define LITTLE_ENDIAN_BITOPS */
+
+extern __inline__ unsigned int set_bit(unsigned int nr, void *vaddr)
 {
-  register unsigned long retval, tmp, mask, psr;
 
-  __asm__ __volatile__("or %%g0, 0x1, %3\n\t"     /* produce the mask */
-		       "sll %3, %4, %3\n\t"
-		       "rd %%psr, %5\n\t"         /* read the psr */
-		       "wr %5, 0x20, %%psr\n\t"   /* traps disabled */
-		       "ld [%1], %2\n\t"          /* critical section */
-		       "and %3, %2, %0\n\t"
-		       "or  %3, %2, %2\n\t"
-		       "st  %2, [%1]\n\t"
-		       "wr %5, 0x0, %%psr\n\t" :  /* re-enable traps */
-                       "=r" (retval) :
-                       "r" (addr), "r" (tmp=0), "r" (mask=0),
-                       "r" (nr), "r" (psr=0));
 
-  return retval; /* confuse gcc :-) */
+#ifdef LITTLE_ENDIAN_BITOPS
+
+
+        int retval;
+        unsigned char *addr = (unsigned char *)vaddr;
+	unsigned char mask;
+#ifndef TEST_BITOPS
+        unsigned long flags;
+#endif
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 0x7);
+
+#ifndef TEST_BITOPS
+	save_flags(flags);
+	cli();
+#endif
+
+        retval = (mask & *addr) != 0;
+        *addr |= mask;
+
+#ifndef TEST_BITOPS
+	restore_flags(flags);
+#endif
+
+        return retval;
+
+#else  /* BIG ENDIAN BITOPS */
+
+
+	int retval;
+	unsigned long *addr = vaddr;
+	unsigned long mask;
+#ifndef TEST_BITOPS
+	unsigned long flags;
+#endif
 
+	addr += nr>>5;
+	mask = 1 << (nr&31);
+
+#ifndef TEST_BITOPS
+	save_flags(flags);
+	cli();
+#endif
+
+	retval = (mask & *addr) != 0;
+	*addr |= mask;
+
+#ifndef TEST_BITOPS
+	restore_flags(flags);
+#endif
+
+	return retval;
+
+
+#endif
 }
 
-extern __inline__ unsigned int clear_bit(unsigned int nr, void *addr)
+extern __inline__ unsigned int clear_bit(unsigned int nr, void *vaddr)
 {
-  register unsigned long retval, tmp, mask, psr;
+#ifdef LITTLE_ENDIAN_BITOPS
+
+
+        int retval;
+        unsigned char *addr = (unsigned char *)vaddr;
+	unsigned char mask;
+#ifndef TEST_BITOPS
+        unsigned long flags;
+#endif
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 7);
+
+#ifndef TEST_BITOPS
+	save_flags(flags);
+	cli();
+#endif
+
+        retval = (mask & *addr) != 0;
+        *addr &= ~mask;
+
+#ifndef TEST_BITOPS
+	restore_flags(flags);
+#endif
+
+        return retval;
+
 
-  __asm__ __volatile__("or %%g0, 0x1, %3\n\t"
-		       "sll %3, %4, %3\n\t"
-		       "rd %%psr, %5\n\t"
-		       "wr %5, 0x20, %%psr\n\t"   /* disable traps */
-                       "ld [%1], %2\n\t"
-		       "and %2, %3, %0\n\t"       /* get old bit */
-		       "andn %2, %3, %2\n\t"      /* set new val */
-		       "st  %2, [%1]\n\t"
-		       "wr %5, 0x0, %%psr\n\t" :  /* enable traps */
-		       "=r" (retval) :
-		       "r" (addr), "r" (tmp=0), "r" (mask=0),
-		       "r" (nr), "r" (psr=0));
+#else   /* BIG ENDIAN BITOPS */
 
-  return retval; /* confuse gcc ;-) */
 
+	int retval;
+	unsigned long *addr = vaddr;
+	unsigned long mask;
+#ifndef TEST_BITOPS
+	unsigned long flags;
+#endif
+
+	addr += nr>>5;
+	mask = 1 << (nr&31);
+
+#ifndef TEST_BITOPS
+	save_flags(flags);
+	cli();
+#endif
+
+	retval = (mask & *addr) != 0;
+	*addr &= ~mask;
+
+#ifndef TEST_BITOPS
+	restore_flags(flags);
+#endif
+
+	return retval;
+
+
+#endif
 }
 
-extern __inline__ unsigned int change_bit(unsigned int nr, void *addr)
+extern __inline__ unsigned int change_bit(unsigned int nr, void *vaddr)
 {
-  register unsigned long retval, tmp, mask, psr;
+#ifdef LITTLE_ENDIAN_BITOPS
+
+
+        int retval;
+        unsigned char *addr = (unsigned char *)vaddr;
+	unsigned char mask;
+#ifndef TEST_BITOPS
+        unsigned long flags;
+#endif
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 7);
+
+#ifndef TEST_BITOPS
+	save_flags(flags);
+	cli();
+#endif
+
+        retval = (mask & *addr) != 0;
+        *addr ^= mask;
+
+#ifndef TEST_BITOPS
+	restore_flags(flags);
+#endif
+
+        return retval;
 
-  __asm__ __volatile__("or %%g0, 0x1, %3\n\t"
-		       "sll %3, %4, %3\n\t"
-		       "rd %%psr, %5\n\t"
-		       "wr %5, 0x20, %%psr\n\t"   /* disable traps */
-                       "ld [%1], %2\n\t"
-		       "and %3, %2, %0\n\t"       /* get old bit val */
-		       "xor %3, %2, %2\n\t"       /* set new val */
-		       "st  %2, [%1]\n\t"
-		       "wr %5, 0x0, %%psr\n\t" :  /* enable traps */
-		       "=r" (retval) :
-		       "r" (addr), "r" (tmp=0), "r" (mask=0),
-		       "r" (nr), "r" (psr=0));
 
-  return retval; /* confuse gcc ;-) */
+#else   /* BIG ENDIAN BITOPS */
 
+
+	int retval;
+	unsigned long *addr = vaddr;
+	unsigned long mask;
+#ifndef TEST_BITOPS
+	unsigned long flags;
+#endif
+
+	addr += nr>>5;
+	mask = 1 << (nr&31);
+
+#ifndef TEST_BITOPS
+	save_flags(flags);
+	cli();
+#endif
+
+	retval = (mask & *addr) != 0;
+	*addr ^= mask;
+
+#ifndef TEST_BITOPS
+	restore_flags(flags);
+#endif
+
+	return retval;
+
+
+#endif
 }
 
 /* The following routine need not be atomic. */
 
-extern __inline__ unsigned int test_bit(int nr, void *addr)
+extern __inline__ unsigned int test_bit(int nr, void *vaddr)
 {
-  register unsigned long retval, tmp;
+#ifdef LITTLE_ENDIAN_BITOPS
+
+        unsigned char mask;
+        unsigned char *addr = (unsigned char *)vaddr;
+
+        addr += nr >> 3;
+        mask = 1 << (nr & 7);
+        return ((mask & *addr) != 0);
+
+#else   /* BIG ENDIAN BITOPS */
 
-  __asm__ __volatile__("ld [%1], %2\n\t"
-		       "or %%g0, 0x1, %0\n\t"
-		       "sll %0, %3, %0\n\t"
-		       "and %0, %2, %0\n\t" :
-		       "=r" (retval) :
-		       "r" (addr), "r" (tmp=0),
-		       "r" (nr));
+	unsigned long mask;
+	unsigned long *addr = vaddr;
 
-  return retval; /* confuse gcc :> */
+	addr += (nr>>5);
+	mask = 1 << (nr&31);
+	return ((mask & *addr) != 0);
 
+#endif
 }
 
 /* There has to be a faster way to do this, sigh... */
 
 extern __inline__ unsigned long ffz(unsigned long word)
 {
-  register unsigned long cnt, tmp, tmp2;
+  register unsigned long cnt;
 
   cnt = 0;
 
-  __asm__("or %%g0, %3, %2\n\t"
-	  "1: and %2, 0x1, %1\n\t"
-	  "srl %2, 0x1, %2\n\t"
-	  "cmp %1, 0\n\t"
-	  "bne,a 1b\n\t"
-	  "add %0, 0x1, %0\n\t" :
-	  "=r" (cnt) :
-	  "r" (tmp=0), "r" (tmp2=0), "r" (word));
+#ifdef LITTLE_ENDIAN_BITOPS
 
+  for(int byte_bit = 24; byte_bit >=0; byte_bit -= 8)
+	  for(int bit = 0; bit<8; bit++)
+		  if((word>>(byte_bit+bit))&1)
+			  cnt++;
+		  else
+			  return cnt;
+
+#else /* BIT ENDIAN BITOPS */
+  while(cnt<32) {
+	  if(!((word>>cnt)&1))
+		  return cnt;
+	  else
+		  cnt++;
+  }
   return cnt;
+#endif
+
 }
 
 /* find_next_zero_bit() finds the first zero bit in a bit string of length
@@ -123,42 +280,49 @@
  * on Linus's ALPHA routines, which are pretty portable BTW.
  */
 
-extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+extern __inline__ unsigned long
+find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
-  unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
-  unsigned long result = offset & ~31UL;
-  unsigned long tmp;
-
-  if (offset >= size)
-    return size;
-  size -= result;
-  offset &= 31UL;
-  if (offset) 
-    {
-      tmp = *(p++);
-      tmp |= ~0UL >> (32-offset);
-      if (size < 32)
-	goto found_first;
-      if (~tmp)
-	goto found_middle;
-      size -= 32;
-      result += 32;
-    }
-  while (size & ~32UL) 
-    {
-      if (~(tmp = *(p++)))
-	goto found_middle;
-      result += 32;
-      size -= 32;
-    }
-  if (!size)
-    return result;
-  tmp = *p;
+#ifdef LITTLE_ENDIAN_BITOPS
+
+	/* FOO, needs to be written */
+
+#else   /* BIG ENDIAN BITOPS */
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long result = offset & ~31UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 31UL;
+	if (offset) 
+	{
+		tmp = *(p++);
+		tmp |= ~0UL >> (32-offset);
+		if (size < 32)
+			goto found_first;
+		if (~tmp)
+			goto found_middle;
+		size -= 32;
+		result += 32;
+	}
+	while (size & ~32UL) 
+	{
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
 
 found_first:
-  tmp |= ~0UL << size;
+	tmp |= ~0UL << size;
 found_middle:
-  return result + ffz(tmp);
+	return result + ffz(tmp);
+#endif
 }
 
 /* Linus sez that gcc can optimize the following correctly, we'll see if this
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/bugs.h linux/include/asm-sparc/bugs.h
--- v1.3.3/linux/include/asm-sparc/bugs.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/bugs.h	Thu Jun  8 23:42:22 1995
@@ -13,9 +13,9 @@
 #define CONFIG_BUGSPARC
 
 #include <asm/openprom.h>
+#include <asm/page.h>
 
-extern struct linux_romvec *romvec;
-extern int tbase_needs_unmapping;   /* We do the bug workaround in pagetables.c */
+extern pgd_t swapper_pg_dir[16384];
 
 static void check_mmu(void)
 {
@@ -26,15 +26,16 @@
   lvec = romvec;
 
   root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
-  tbase_needs_unmapping=0;
 
   present = 0;
   (*(romvec->pv_nodeops->no_getprop))(root_node, "buserr-type", 
 				      (char *) &present);
   if(present == 1)
     {
-      tbase_needs_unmapping=1;
-      printk("MMU bug found: not allowing trapbase to be cached\n");
+      printk("MMU bug found: uncaching trap table\n");
+      for(present = (unsigned long) &trapbase; present < (unsigned long)
+	  &swapper_pg_dir; present+=PAGE_SIZE)
+	      put_pte(present, (get_pte(present) | PTE_NC));
     }
 
   return;
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/cache.h linux/include/asm-sparc/cache.h
--- v1.3.3/linux/include/asm-sparc/cache.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/cache.h	Wed Jun 14 11:44:50 1995
@@ -0,0 +1,128 @@
+/* cache.h:  Cache specific code for the Sparc.  These include flushing
+ *           and direct tag/data line access.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_CACHE_H
+#define _SPARC_CACHE_H
+
+#include <asm/asi.h>
+
+/* Direct access to the instruction cache is provided through and
+ * alternate address space.  The IDC bit must be off in the ICCR on
+ * HyperSparcs for these accesses to work.  The code below does not do
+ * any checking, the caller must do so.  These routines are for
+ * diagnostics only, but coule end up being useful.  Use with care.
+ * Also, you are asking for trouble if you execute these in one of the
+ * three instructions following a %asr/%psr access or modification.
+ */
+
+/* First, cache-tag access. */
+extern inline unsigned int get_icache_tag(int setnum, int tagnum)
+{
+	unsigned int vaddr, retval;
+
+	vaddr = ((setnum&1) << 12) | ((tagnum&0x7f) << 5);
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (vaddr), "i" (ASI_M_TXTC_TAG));
+	return retval;
+}
+
+extern inline void put_icache_tag(int setnum, int tagnum, unsigned int entry)
+{
+	unsigned int vaddr;
+
+	vaddr = ((setnum&1) << 12) | ((tagnum&0x7f) << 5);
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (entry), "r" (vaddr), "i" (ASI_M_TXTC_TAG) :
+			     "memory");
+	return;
+}
+
+/* Second cache-data access.  The data is returned two-32bit quantities
+ * at a time.
+ */
+extern inline void get_icache_data(int setnum, int tagnum, int subblock,
+			      unsigned int *data)
+{
+	unsigned int value1, value2, vaddr;
+
+	vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | ((subblock&0x3) << 3);
+	__asm__ __volatile__("ldda [%2] %3, %%g2\n\t"
+			     "or %%g0, %%g2, %0\n\t"
+			     "or %%g0, %%g3, %1\n\t" :
+			     "=r" (value1), "=r" (value2) :
+			     "r" (vaddr), "i" (ASI_M_TXTC_DATA) :
+			     "g2", "g3");
+	data[0] = value1; data[1] = value2;
+	return;
+}
+
+extern inline void put_icache_data(int setnum, int tagnum, int subblock,
+			      unsigned int *data)
+{
+	unsigned int value1, value2, vaddr;
+
+	vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | ((subblock&0x3) << 3);
+	value1 = data[0]; value2 = data[1];
+	__asm__ __volatile__("or %%g0, %0, %%g2\n\t"
+			     "or %%g0, %1, %%g3\n\t"
+			     "stda %%g2, [%2] %3\n\t" : :
+			     "r" (value1), "r" (value2), 
+			     "r" (vaddr), "i" (ASI_M_TXTC_DATA) :
+			     "g2", "g3", "memory" /* no joke */);
+	return;
+}
+
+/* Different types of flushes with the ICACHE.  Some of the flushes
+ * affect both the ICACHE and the external cache.  Others only clear
+ * the ICACHE entries on the cpu itself.  V8's (most) allow
+ * granularity of flushes on the packet (element in line), whole line,
+ * and entire cache (ie. all lines) level.  The ICACHE only flushes are
+ * ROSS HyperSparc specific and are in ross.h
+ */
+
+/* Flushes which clear out both the on-chip and external caches */
+extern inline void flush_ei_page(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_PAGE) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_ei_seg(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_SEG) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_ei_region(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_REGION) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_ei_ctx(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_CTX) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_ei_user(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_USER) :
+			     "memory");
+	return;
+}
+
+#endif /* !(_SPARC_CACHE_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/clock.h linux/include/asm-sparc/clock.h
--- v1.3.3/linux/include/asm-sparc/clock.h	Mon Feb 20 08:59:52 1995
+++ linux/include/asm-sparc/clock.h	Thu Jun  8 23:42:52 1995
@@ -1,53 +1,10 @@
-/* clock.h:  Definitions for the clock/timer chips on the Sparc.
+/* clock.h:  Definitions for clock operations on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
+#ifndef _SPARC_CLOCK_H
+#define _SPARC_CLOCK_H
 
-/* Clock timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one.  Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10.  There is another one available that can fire at
- * IRQ 14. If I can think of some creative uses for it this may
- * change. It might make a nice kernel/user profiler etc.
- */
-
-struct sparc_timer_info {
-  unsigned int cur_count10;
-  unsigned int timer_limit10;
-  unsigned int cur_count14;
-  unsigned int timer_limit14;
-};
-
-struct sparc_clock_info {
-  unsigned char hsec;
-  unsigned char hr;
-  unsigned char min;
-  unsigned char sec;
-  unsigned char mon;
-  unsigned char day;
-  unsigned char yr;
-  unsigned char wkday;
-  unsigned char ram_hsec;
-  unsigned char ram_hr;
-  unsigned char ram_min;
-  unsigned char ram_sec;
-  unsigned char ram_mon;
-  unsigned char ram_day;
-  unsigned char ram_year;
-  unsigned char ram_wkday;
-  unsigned char intr_reg;
-  unsigned char cmd_reg;
-  unsigned char foo[14];
-};
-
-#define TIMER_PHYSADDR   0xf3000000
-
-/* YUCK YUCK YUCK, grrr... */
-#define  TIMER_STRUCT  ((struct sparc_timer_info *)((struct sparc_clock_info *) TIMER_VADDR))
+/* Foo for now. */
 
+#endif /* !(_SPARC_CLOCK_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/contregs.h linux/include/asm-sparc/contregs.h
--- v1.3.3/linux/include/asm-sparc/contregs.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/contregs.h	Tue Jun 20 03:40:38 1995
@@ -2,18 +2,48 @@
 #define _SPARC_CONTREGS_H
 
 /* contregs.h:  Addresses of registers in the ASI_CONTROL alternate address
-                space. These are for the mmu's context register, etc.
+ *              space. These are for the mmu's context register, etc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+/* 4 = sun4 (as in sun4 sysmaint student book), c = sun4c (according to davem) */
 
-#define AC_CONTEXT    0x30000000    /* current mmu-context, handy for invalidate()'s ;-)   */
-#define AC_SENABLE    0x40000000    /* system dvma/cache enable, plus special reset poking */
-#define AC_CACHETAGS  0x80000000    /* direct access to the VAC cache, unused...          */
-#define AC_SYNC_ERR   0x60000000    /* what type of synchronous memory error happened      */
-#define AC_SYNC_VA    0x60000004    /* what virtual address caused the error to occur      */
-#define AC_ASYNC_ERR  0x60000008    /* what type of asynchronous mem-error happened        */
-#define AC_ASYNC_VA   0x6000000c    /* what virtual address caused the async-err to happen */
-#define AC_CACHEDDATA 0x90000000    /* where the actual VAC cached data sits               */
+#define AC_IDPROM     0x00000000    /* 4  ID PROM, R/O, byte, 32 bytes                        */
+#define AC_CONTEXT    0x30000000    /* 4c current mmu-context, handy for invalidate()'s ;-)   */
+#define AC_SENABLE    0x40000000    /* 4c system dvma/cache enable, plus special reset poking */
+#define AC_UDVMA_ENB  0x50000000    /* 4  Not used on Sun boards, byte                        */
+#define AC_BUS_ERROR  0x60000000    /* 4  Cleared on read, byte. Probably same as sun4c.      */
+#define AC_SYNC_ERR   0x60000000    /*  c what type of synchronous memory error happened      */
+#define AC_SYNC_VA    0x60000004    /*  c what virtual address caused the error to occur      */
+#define AC_ASYNC_ERR  0x60000008    /*  c what type of asynchronous mem-error happened        */
+#define AC_ASYNC_VA   0x6000000c    /*  c what virtual address caused the async-err to happen */
+#define AC_LEDS       0x70000000    /* 4  Zero turns on LEDs, byte                            */
+#define AC_CACHETAGS  0x80000000    /* 4c direct access to the VAC cache, unused...           */
+#define AC_CACHEDDATA 0x90000000    /*  c where the actual VAC cached data sits               */
+#define AC_UDVMA_MAP  0xD0000000    /* 4  Not used on Sun boards, byte                        */
+#define AC_VME_VECTOR 0xE0000000    /* 4  For non-Autovector VME, byte                        */
+#define AC_BOOT_SCC   0xF0000000    /* 4  To bypass MMU and access Zilog 8530 on boot. byte.  */
+
+/* SPARCstation-5. I changed Paul's names to the hardware guy's ones. --P3 */
+#define AC_M_PCR      0x0000        /* 5  Processor Control Register */
+#define AC_M_CTPR     0x0100        /* 5  Context Table Pointer Register  */
+#define AC_M_CXR      0x0200        /* 5  Context Register */
+#define AC_M_SFSR     0x0300        /* 5  Synchronous Fault Status Register */
+#define AC_M_SFAR     0x0400        /* 5  Synchronous Fault Address Register */
+#define AC_M_AFSR     0x0500        /* 5  Asynchronous Fault Status Register */
+#define AC_M_AFAR     0x0600        /* 5  Asynchronous Fault Address Register */
+#define AC_M_RESET    0x0700        /* 5  Reset Register  Aieee! */
+#define AC_M_RPR      0x1000        /* 5  Root Pointer Register */
+#define AC_M_TSUTRCR  0x1000        /* 5  TLB Replacement Control Reg on Tsunami */
+#define AC_M_IAPTP    0x1100        /* 5  Instruction Access PTP */
+#define AC_M_DAPTP    0x1200        /* 5  Data Access PTP */
+#define AC_M_ITR      0x1300        /* 5  Index Tag Register */
+#define AC_M_TRCR     0x1400        /* 5  TLB Replacement Control Register */
+
+/* The following are Ross HyperSparc only. */
+#define AC_M_RPR1     0x1500        /* 5  Root Pointer Register (entry 2) */
+#define AC_M_IAPTP1   0x1600        /* 5  Instruction Access PTP (entry 2) */
+#define AC_M_DAPTP1   0x1700        /* 5  Data Access PTP (entry 2) */
 
 #endif /* _SPARC_CONTREGS_H */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/cypress.h linux/include/asm-sparc/cypress.h
--- v1.3.3/linux/include/asm-sparc/cypress.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/cypress.h	Thu Jun 22 12:11:59 1995
@@ -0,0 +1,51 @@
+/* cypress.h: Cypress module specific definitions and defines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_CYPRESS_H
+#define _SPARC_CYPRESS_H
+
+/* Cypress chips have %psr 'impl' of '0001' and 'vers' of '0001'. */
+
+/* The MMU control register fields on the Sparc Cypress 604/605 MMU's.
+ *
+ * ---------------------------------------------------------------
+ * |implvers| MCA | MCM |MV| MID |BM| C|RSV|MR|CM|CL|CE|RSV|NF|ME|
+ * ---------------------------------------------------------------
+ *  31    24 23-22 21-20 19 18-15 14 13  12 11 10  9  8 7-2  1  0
+ *
+ * MCA: MultiChip Access -- Used for configuration of multiple
+ *      CY7C604/605 cache units.
+ * MCM: MultiChip Mask -- Again, for multiple cache unit config.
+ * MV: MultiChip Valid -- Indicates MCM and MCA have valid settings.
+ * MID: ModuleID -- Unique processor ID for MBus transactions. (605 only)
+ * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode
+ * C: Cacheable -- Indicates whether accesses are cacheable while
+ *    the MMU is off.  0=no 1=yes
+ * MR: MemoryReflection -- Indicates whether the bus attacted to the
+ *     MBus supports memory reflection. 0=no 1=yes (605 only)
+ * CM: CacheMode -- Indicates whether the cache is operating in write
+ *     through or copy-back mode. 0=write-through 1=copy-back
+ * CL: CacheLock -- Indicates if the entire cache is locked or not.
+ *     0=not-locked 1=locked  (604 only)
+ * CE: CacheEnable -- Is the virtual cache on? 0=no 1=yes
+ * NF: NoFault -- Do faults generate traps? 0=yes 1=no
+ * ME: MmuEnable -- Is the MMU doing translations? 0=no 1=yes
+ */
+
+/* NEEDS TO BE FIXED */
+#define CYPRESS_MCABITS   0x01800000
+#define CYPRESS_MCMBITS   0x00600000
+#define CYPRESS_MVALID    0x00040000
+#define CYPRESS_MIDMASK   0x0003c000   /* Only on 605 */
+#define CYPRESS_BMODE     0x00002000
+#define CYPRESS_ACENABLE  0x00001000
+#define CYPRESS_MRFLCT    0x00000800   /* Only on 605 */
+#define CYPRESS_CMODE     0x00000400
+#define CYPRESS_CLOCK     0x00000200   /* Only on 604 */
+#define CYPRESS_CENABLE   0x00000100
+#define CYPRESS_NFAULT    0x00000002
+#define CYPRESS_MENABLE   0x00000001
+
+#endif /* !(_SPARC_CYPRESS_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/delay.h linux/include/asm-sparc/delay.h
--- v1.3.3/linux/include/asm-sparc/delay.h	Mon Feb 20 08:59:52 1995
+++ linux/include/asm-sparc/delay.h	Thu Jun  8 23:44:03 1995
@@ -23,10 +23,8 @@
 {
   usecs *= 0x000010c6;         /* Sparc is 32-bit just like ix86 */
 
-  __asm__("sethi %hi(_loops_per_sec), %o1\n\t"
-	  "ld [%o1 + %lo(_loops_per_sec)], %o1\n\t"
-	  "call ___delay\n\t"
-	  "umul %o1, %o0, %o0\n\t");
+  __delay(loops_per_sec*usecs);
+
 }
 
 /* calibrate_delay() wants this... */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h
--- v1.3.3/linux/include/asm-sparc/dma.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/dma.h	Wed Jun  7 10:30:19 1995
@@ -5,16 +5,148 @@
  * on the Sparc. It may end up being real hairy to plug
  * into this code, maybe not, we'll see.
  *
- * Copyright (C) David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
  */
 
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
 #include <asm/vac-ops.h>  /* for invalidate's, etc. */
+#include <asm/sbus.h>
+#include <asm/delay.h>
+#include <asm/oplib.h>
+
+/* DMA probing routine */
+extern unsigned long probe_dma(unsigned long);
 
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
 #define MAX_DMA_CHANNELS 8
 #define MAX_DMA_ADDRESS  0x0
 
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+  volatile unsigned long cond_reg;   /* DMA condition register */
+  volatile char * st_addr;           /* Start address of this transfer */
+  volatile unsigned long cnt;        /* How many bytes to transfer */
+  volatile unsigned long dma_test;   /* DMA test register */
+};
+
+/* Linux DMA information structure, filled during probe. */
+struct Linux_SBus_DMA {
+  struct linux_sbus_device *SBus_dev;   /* pointer to sbus device struct */
+  struct sparc_dma_registers *DMA_regs; /* Pointer to DMA regs in IO space */
+
+  /* Status, misc info */
+  int node;                /* Prom node for this DMA device */
+  int dma_running;         /* Are we using the DMA now? */
+
+  /* DMA revision: 0=REV0 1=REV1 2=REV2 3=DMA_PLUS */
+  int dma_rev;
+};
+
+extern struct Linux_SBus_DMA Sparc_DMA;
+
+/* Main routines in dma.c */
+extern void dump_dma_regs(struct sparc_dma_registers *);
+extern unsigned long probe_dma(unsigned long);
+extern void sparc_dma_init_transfer(struct sparc_dma_registers *,
+				    unsigned long, int, int);
+extern int sparc_dma_interrupt(struct sparc_dma_registers *);
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An interrupt needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take care of an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_ST_WRITE     0x00000100        /* If set, write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Read is pending */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_BRST_SZ      0x000c0000        /* SBUS transfer r/w burst size */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer equals 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer equals 3 clock ticks */
+#define DMA_CNTR_DISAB   0x00800000        /* No intr's when DMA_TERM_CNTR is set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto next address" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+
+/* Only 24-bits of the byte count are significant */
+#define DMA_BYTE_CNT_MASK  0x00ffffff
+
+/* Pause until counter runs out or BIT isn't set in the DMA condition
+ * register.
+ */
+extern inline void sparc_dma_pause(struct sparc_dma_registers *dma_regs,
+				   unsigned long bit)
+{
+  int ctr = 50000;   /* Let's find some bugs ;) */
+
+  /* Busy wait until the bit is not set any more */
+  while((dma_regs->cond_reg&bit) && (ctr>0)) {
+    ctr--;
+    __delay(1);
+  }
+
+  /* Check for bogus outcome. */
+  if(ctr==0) {
+    printk("DMA Grrr:  I tried for wait for the assertion of bit %08xl to clear",
+	   (unsigned int) bit);
+    printk("           in the DMA condition register and it did not!\n");
+    printk("Cannot continue, halting...\n");
+    prom_halt();
+  }
+
+  return;
+}
+
+/* Enable DMA interrupts */
+extern inline void sparc_dma_enable_interrupts(struct sparc_dma_registers *dma_regs)
+{
+  dma_regs->cond_reg |= DMA_INT_ENAB;
+}
+
+/* Disable DMA interrupts from coming in */
+extern inline void sparc_dma_disable_interrupts(struct sparc_dma_registers *dma_regs)
+{
+  dma_regs->cond_reg &= ~(DMA_INT_ENAB);
+}
+
+/* Reset the DMA module. */
+extern inline void sparc_dma_reset(struct sparc_dma_registers *dma_regs)
+{
+  /* Let the current FIFO drain itself */
+  sparc_dma_pause(dma_regs, (DMA_FIFO_ISDRAIN));
+
+  /* Reset the logic */
+  dma_regs->cond_reg |= (DMA_RST_SCSI);     /* assert */
+  __delay(400);                             /* let the bits set ;) */
+  dma_regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */
+
+  sparc_dma_enable_interrupts(dma_regs);    /* Re-enable interrupts */
+
+  /* Enable FAST transfers if available */
+  if(Sparc_DMA.dma_rev>1) { dma_regs->cond_reg |= DMA_3CLKS; }
+  Sparc_DMA.dma_running = 0;
 
+  return;
+}
 
 #endif /* !(_ASM_SPARC_DMA_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/ecc.h linux/include/asm-sparc/ecc.h
--- v1.3.3/linux/include/asm-sparc/ecc.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ecc.h	Tue Jun 20 04:18:53 1995
@@ -0,0 +1,121 @@
+/* ecc.h: Definitions and defines for the external cache/memory
+ *        controller on the sun4m.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ECC_H
+#define _SPARC_ECC_H
+
+/* These registers are accessed through the SRMMU passthrough ASI 0x20 */
+#define ECC_ENABLE     0x00000000       /* ECC enable register */
+#define ECC_FSTATUS    0x00000008       /* ECC fault status register */
+#define ECC_FADDR      0x00000010       /* ECC fault address register */
+#define ECC_DIGNOSTIC  0x00000018       /* ECC diagnostics register */
+#define ECC_MBAENAB    0x00000020       /* MBus arbiter enable register */
+#define ECC_DMESG      0x00001000       /* Diagnostic message passing area */
+
+/* ECC MBus Arbiter Enable register:
+ *
+ * ----------------------------------------
+ * |              |SBUS|MOD3|MOD2|MOD1|RSV|
+ * ----------------------------------------
+ *  31           5   4   3    2    1    0
+ *
+ * SBUS: Enable MBus Arbiter on the SBus 0=off 1=on
+ * MOD3: Enable MBus Arbiter on MBus module 3  0=off 1=on
+ * MOD2: Enable MBus Arbiter on MBus module 2  0=off 1=on
+ * MOD1: Enable MBus Arbiter on MBus module 1  0=off 1=on
+ */
+
+#define ECC_MBAE_SBUS     0x00000010
+#define ECC_MBAE_MOD3     0x00000008
+#define ECC_MBAE_MOD2     0x00000004
+#define ECC_MBAE_MOD1     0x00000002 
+
+/* ECC Fault Control Register layout:
+ *
+ * -----------------------------
+ * |    RESV   | ECHECK | EINT |
+ * -----------------------------
+ *  31        2     1       0
+ *
+ * ECHECK:  Enable ECC checking.  0=off 1=on
+ * EINT:  Enable Interrupts for correctable errors. 0=off 1=on
+ */ 
+#define ECC_FCR_CHECK    0x00000002
+#define ECC_FCR_INTENAB  0x00000001
+
+/* ECC Fault Address Register Zero layout:
+ *
+ * -----------------------------------------------------
+ * | MID | S | RSV |  VA   | BM |AT| C| SZ |TYP| PADDR |
+ * -----------------------------------------------------
+ *  31-28  27 26-22  21-14   13  12 11 10-8 7-4   3-0
+ *
+ * MID: ModuleID of the faulting processor. ie. who did it?
+ * S: Supervisor/Privileged access? 0=no 1=yes
+ * VA: Bits 19-12 of the virtual faulting address, these are the
+ *     superset bits in the virtual cache and can be used for
+ *     a flush operation if necessary.
+ * BM: Boot mode? 0=no 1=yes  This is just like the SRMMU boot
+ *     mode bit.
+ * AT: Did this fault happen during an atomic instruction? 0=no
+ *     1=yes.  This means either an 'ldstub' or 'swap' instruction
+ *     was in progress (but not finished) when this fault happened.
+ *     This indicated whether the bus was locked when the fault
+ *     occurred.
+ * C: Did the pte for this access indicate that it was cacheable?
+ *    0=no 1=yes
+ * SZ: The size of the transaction.
+ * TYP: The transaction type.
+ * PADDR: Bits 35-32 of the physical address for the fault.
+ */
+#define ECC_FADDR0_MIDMASK   0xf0000000
+#define ECC_FADDR0_S         0x08000000
+#define ECC_FADDR0_VADDR     0x003fc000
+#define ECC_FADDR0_BMODE     0x00002000
+#define ECC_FADDR0_ATOMIC    0x00001000
+#define ECC_FADDR0_CACHE     0x00000800
+#define ECC_FADDR0_SIZE      0x00000700
+#define ECC_FADDR0_TYPE      0x000000f0
+#define ECC_FADDR0_PADDR     0x0000000f
+
+/* ECC Fault Address Register One layout:
+ *
+ * -------------------------------------
+ * |          Physical Address 31-0    |
+ * -------------------------------------
+ *  31                               0
+ *
+ * You get the upper 4 bits of the physical address from the
+ * PADDR field in ECC Fault Address Zero register.
+ */
+
+/* ECC Fault Status Register layout:
+ *
+ * ----------------------------------------------
+ * | RESV|C2E|MULT|SYNDROME|DWORD|UNC|TIMEO|BS|C|
+ * ----------------------------------------------
+ *  31-18  17  16    15-8    7-4   3    2    1 0
+ *
+ * C2E: A C2 graphics error occurred. 0=no 1=yes (SS10 only)
+ * MULT: Multiple errors occurres ;-O 0=no 1=prom_panic(yes)
+ * SYNDROME: Controller is mentally unstable.
+ * DWORD:
+ * UNC: Uncorrectable error.  0=no 1=yes
+ * TIMEO: Timeout occurred. 0=no 1=yes
+ * BS: C2 graphics bad slot access. 0=no 1=yes (SS10 only)
+ * C: Correctable error? 0=no 1=yes
+ */
+
+#define ECC_FSR_C2ERR    0x00020000
+#define ECC_FSR_MULT     0x00010000
+#define ECC_FSR_SYND     0x0000ff00
+#define ECC_FSR_DWORD    0x000000f0
+#define ECC_FSR_UNC      0x00000008
+#define ECC_FSR_TIMEO    0x00000004
+#define ECC_FSR_BADSLOT  0x00000002
+#define ECC_FSR_C        0x00000001
+
+#endif /* !(_SPARC_ECC_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/eeprom.h linux/include/asm-sparc/eeprom.h
--- v1.3.3/linux/include/asm-sparc/eeprom.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/eeprom.h	Thu Jun  8 23:44:16 1995
@@ -0,0 +1,8 @@
+/* eeprom.h:  Definitions for the Sun eeprom.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* The EEPROM and the Mostek Mk48t02 use the same IO address space
+ * for their registers/data areas.  The IDPROM lives here too.
+ */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h
--- v1.3.3/linux/include/asm-sparc/head.h	Sun Feb 26 20:46:20 1995
+++ linux/include/asm-sparc/head.h	Thu Jun 15 06:48:58 1995
@@ -1,61 +1,75 @@
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
-#define KERNSIZE	134217728   /* this is how much of a mapping the prom promises */
-#define PAGESIZE	4096        /* luckily this is the same on sun4c's and sun4m's */
-#define PAGESHIFT       12
-#define PROM_BASE	-1568768    /* casa 'de PROM */
-#define LOAD_ADDR       0x4000      /* prom jumps to us here */
+#define KERNBASE        0xf0000000  /* First address the kernel will eventually be */
+#define LOAD_ADDR       0x4000      /* prom jumps to us here unless this is elf /boot */
 #define C_STACK         96
 #define SUN4C_SEGSZ     (1 << 18)
-#define USRSTACK        0x0         /* no joke, this is temporary, trust me */
-#define INT_ENABLE_REG_PHYSADR      0xf5000000
-#define INTS_ENAB   0x01
+#define SRMMU_L1_KBASE_OFFSET ((KERNBASE>>24)<<2)  /* Used in boot remapping. */
+#define INTS_ENAB   0x01            /* entry.S uses this. */
 
-#define BOOT_MSG_LEN    61
-#define BOOT_MSG2_LEN   50
+#define NCPUS           4            /* Architectual limit of sun4m. */
 
+#define  SUN4_PROM_VECTOR   0xFFE81000    /* To safely die on a SUN4 */
+#define  SUN4_PRINTF   0x84               /* Offset into SUN4_PROM_VECTOR */
 
 #define WRITE_PAUSE     nop; nop; nop;
 
-#define PAGE_SIZE       4096
+#define NOP_INSN        0x01000000        /* Used to patch sparc_save_state */
 
 /* Here are some trap goodies */
 
-
 /* Generic trap entry. */
-
 #define TRAP_ENTRY(type, label) \
 	mov (type), %l3; b label; rd %psr, %l0; nop;
 
+/* Notice that for the system calls we pull a trick.  We load up a
+ * different pointer to the system call vector table in %l7, but call
+ * the same generic system call low-level entry point.  The trap table
+ * entry sequences are also HyperSparc pipeline friendly ;-)
+ */
+
+/* Software trap for Linux system calls. */
+#define LINUX_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* Software trap for SunOS4.1.x system calls. */
+#define SUNOS_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* Software trap for Slowaris system calls. */
+#define SOLARIS_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* Software trap for Sparc-netbsd system calls. */
+#define NETBSD_SYSCALL_TRAP \
+        sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0;
+
+/* The Get Condition Codes software trap for userland. */
+#define GETCC_TRAP \
+        b getcc_trap_handler; mov %psr, %l0; nop; nop
+
+/* The Set Condition Codes software trap for userland. */
+#define SETCC_TRAP \
+        b setcc_trap_handler; mov %psr, %l0; nop; nop
+
 /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and
  * gets handled with another macro.
  */
-
 #define TRAP_ENTRY_INTERRUPT(int_level) \
-        mov int_level, %l3; b stray_irq_entry; rd %psr, %l0; nop;
+        mov int_level, %l3; b real_irq_entry; rd %psr, %l0; nop;
 
-/* Here is the macro for soft interrupts (ie. not as urgent as hard ones)
- * which need to jump to a different handler.
+/* NMI's (Non Maskable Interrupts) are special, you can't keep them
+ * from coming in, and basically if you get one, the shows over. ;(
  */
-
-#define TRAP_ENTRY_INTERRUPT_SOFT(int_level, ident) \
-        mov int_level, %l3; rd %psr, %l0; b stray_irq_entry; mov ident, %l4;
+#define NMI_TRAP \
+        b linux_trap_nmi; mov %psr, %l0; nop; nop
 
 /* The above two macros are for generic traps. The following is made
  * especially for timer interrupts at IRQ level 14.
  */
-
 #define TRAP_ENTRY_TIMER \
-        mov 10, %l3; rd %psr, %l0; b sparc_timer; nop;
-
-/* Non-maskable interrupt entry macro. You have to turn off all interrupts
- * to not receive this. This is usually due to a asynchronous memory error.
- * All we can really do is stop the show. :-(
- */
-
-#define TRAP_ENTRY_INTERRUPT_NMI(t_type, jmp_to) \
-        mov t_type, %l3; b jmp_to; rd %psr, %l0; nop;
+        rd %psr, %l0; b sparc_timer; nop; nop;
 
 /* Trap entry code in entry.S needs the offsets into task_struct
  * to get at the thread_struct goodies during window craziness.
@@ -65,11 +79,43 @@
  *       See TRAP_WIN_CLEAN in entry.S for details.
  */
 
-#define THREAD_UWINDOWS 0x3bc
-#define THREAD_WIM 0x3c0
-#define THREAD_W_SAVED 0x3c4
-#define THREAD_KSP 0x3c8
-#define THREAD_USP 0x3cc
-#define THREAD_REG_WINDOW 0x3d4
+/* First generic task_struct offsets */
+#define TASK_STATE        0x000
+#define TASK_PRI          0x008
+#define TASK_KSTACK_PG    0x250
+
+#define THREAD_UWINDOWS   0x3b8
+#define THREAD_WIM        0x3bc
+#define THREAD_W_SAVED    0x3c0
+#define THREAD_KSP        0x3c4
+#define THREAD_USP        0x3c8
+#define THREAD_PSR        0x3cc
+#define THREAD_PC         0x3d0
+#define THREAD_NPC        0x3d4
+#define THREAD_Y          0x3d8
+#define THREAD_REG_WINDOW 0x3e0
+
+/* More fun offset macros. These are for pt_regs. */
+
+#define PT_PSR    0x0
+#define PT_PC     0x4
+#define PT_NPC    0x8
+#define PT_Y      0xc
+#define PT_G0     0x10
+#define PT_G1     0x14
+#define PT_G2     0x18
+#define PT_G3     0x1c
+#define PT_G4     0x20
+#define PT_G5     0x24
+#define PT_G6     0x28
+#define PT_G7     0x2c
+#define PT_I0     0x30
+#define PT_I1     0x34
+#define PT_I2     0x38
+#define PT_I3     0x3c
+#define PT_I4     0x40
+#define PT_I5     0x44
+#define PT_I6     0x48
+#define PT_I7     0x4c
 
 #endif __SPARC_HEAD_H
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/idprom.h linux/include/asm-sparc/idprom.h
--- v1.3.3/linux/include/asm-sparc/idprom.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/idprom.h	Thu Jun  8 23:44:28 1995
@@ -3,10 +3,17 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#ifndef _SPARC_IDPROM_H
+#define _SPARC_IDPROM_H
+
 extern struct linux_romvec *romvec;
 
-#define IDPROM_ADDR  (0xffd04000 + 0x7d8)
-#define IDPROM_SIZE  36
+/* Offset into the EEPROM where the id PROM is located on the 4c */
+#define IDPROM_OFFSET  0x7d8
+
+/* On sun4m; physical. */
+/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
+#define IDPROM_OFFSET_M  0xfd8
 
 struct idp_struct
 {
@@ -19,3 +26,8 @@
   unsigned char dummy[16];    /* XXX */
 };
 
+extern struct idp_struct *idprom;
+
+#define IDPROM_SIZE  (sizeof(struct idp_struct))
+
+#endif /* !(_SPARC_IDPROM_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v1.3.3/linux/include/asm-sparc/io.h	Mon Feb 20 08:59:52 1995
+++ linux/include/asm-sparc/io.h	Fri Jun 16 05:01:08 1995
@@ -1,7 +1,10 @@
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
+#include <linux/kernel.h>
+
 #include <asm/page.h>      /* IO address mapping routines need this */
+#include <asm/system.h>
 
 /*
  * Defines for io operations on the Sparc. Whether a memory access is going
@@ -86,15 +89,31 @@
 #define inb_p inb
 #define outb_p outb
 
-extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr)
-{
-  unsigned long page_entry;
-
-  page_entry = physaddr >> PAGE_SHIFT;
-  page_entry |= (PTE_V | PTE_ACC | PTE_NC | PTE_IO);  /* kernel io addr */
+extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly);
+extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly);
 
-  put_pte(virt_addr, page_entry);
-  return;
+extern inline void mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+			     int bus, int rdonly)
+{
+	switch(sparc_cpu_model) {
+	case sun4c:
+		sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly);
+		break;
+	case sun4m:
+	case sun4d:
+	case sun4e:
+		srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly);
+		break;
+	default:
+		printk("mapioaddr: Trying to map IO space for unsupported machine.\n");
+		printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model);
+		printk("mapioaddr: Halting...\n");
+		halt();
+	};
+	return;
 }
+
+extern void *sparc_alloc_io (void *, void *, int, char *, int, int);
+extern void *sparc_dvma_malloc (int, char *);
 
 #endif /* !(__SPARC_IO_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/ipsum.h linux/include/asm-sparc/ipsum.h
--- v1.3.3/linux/include/asm-sparc/ipsum.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ipsum.h	Thu Jun  8 23:44:41 1995
@@ -0,0 +1,49 @@
+#ifndef __SPARC_IPSUM_H
+#define __SPARC_IPSUM_H
+/*  ipsum.h:  IP/UDP/TCP checksum routines on the Sparc.
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ *      This routine computes a UDP checksum. 
+ */
+extern inline unsigned short udp_check(struct udphdr *uh, int len, u32 saddr, u32 daddr)
+{
+        /* uhh.. eventually */
+        return 0;
+}
+
+/*
+ *      This routine computes a TCP checksum. 
+ */
+extern inline unsigned short tcp_check(struct tcphdr *th, int len, u32 saddr, u32 daddr)
+{     
+        /* uhh.. eventually */
+        return 0;
+}
+
+
+/*
+ * This routine does all the checksum computations that don't
+ * require anything special (like copying or special headers).
+ */
+
+extern inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+        /* uhh.. eventually */
+        return 0;
+}
+
+/*
+ *      This is a version of ip_compute_csum() optimized for IP headers, which
+ *      always checksum on 4 octet boundaries.
+ */
+
+static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
+{
+        /* uhh.. eventually */
+        return 0;
+}
+
+#endif /* !(__SPARC_IPSUM_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h
--- v1.3.3/linux/include/asm-sparc/irq.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/irq.h	Sat Jun 10 02:50:43 1995
@@ -4,14 +4,70 @@
 /*
  *	linux/include/asm-sparc/irq.h
  *
- *	Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ *	Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/linkage.h>
 
+#include <asm/system.h>     /* For NCPUS */
+
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
+/* On the sun4m, just like the timers, we have both per-cpu and master
+ * interrupt registers.
+ */
+
+/* These registers are used for sending/receiving irqs from/to
+ * different cpu's.   
+ */
+struct sun4m_intreg_percpu {
+	unsigned int tbt;        /* Interrupts still pending for this cpu. */
+
+	/* These next two registers are WRITE-ONLY and are only
+	 * "on bit" sensitive, "off bits" written have NO affect.
+	 */
+	unsigned int clear;  /* Clear this cpus irqs here. */
+	unsigned int set;    /* Set this cpus irqs here. */
+	unsigned char space[PAGE_SIZE - 12];
+};
+
+struct sun4m_intregs {
+	struct sun4m_intreg_percpu cpu_intregs[NCPUS];
+	unsigned int tbt;                /* IRQ's that are still pending. */
+	unsigned int irqs;               /* Master IRQ bits. */
+
+	/* Again, like the above, two these registers are WRITE-ONLY. */
+	unsigned int clear;              /* Clear master IRQ's by setting bits here. */
+	unsigned int set;                /* Set master IRQ's by setting bits here. */
+
+	/* This register is both READ and WRITE. */
+	unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+};
+
+extern struct sun4m_intregs *sun4m_interrupts;
+
+/* Bit field defines for the interrupt registers on various
+ * Sparc machines.
+ */
+
+/* The sun4c interrupt register. */
+#define SUN4C_INT_ENABLE  0x01     /* Allow interrupts. */
+#define SUN4C_INT_E14     0x80     /* Enable level 14 IRQ. */
+#define SUN4C_INT_E10     0x20     /* Enable level 10 IRQ. */
+#define SUN4C_INT_E8      0x10     /* Enable level 8 IRQ. */
+#define SUN4C_INT_E6      0x08     /* Enable level 6 IRQ. */
+#define SUN4C_INT_E4      0x04     /* Enable level 4 IRQ. */
+#define SUN4C_INT_E1      0x02     /* Enable level 1 IRQ. */
+
+/* The sun4m interrupt registers.  MUST RESEARCH THESE SOME MORE XXX */
+#define SUN4M_INT_ENABLE  0x80000000
+#define SUN4M_INT_E14     0x00000080
+#define SUN4M_INT_E10     0x00080000
+
+#if 0 /* These aren't used on the Sparc (yet), but kept for
+       * future reference, they could come in handy.
+       */
 #define __STR(x) #x
 #define STR(x) __STR(x)
  
@@ -39,5 +95,6 @@
 asmlinkage void FAST_IRQ_NAME(nr); \
 asmlinkage void BAD_IRQ_NAME(nr); \
 asm code comes here
+#endif
 
 #endif
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/kdebug.h linux/include/asm-sparc/kdebug.h
--- v1.3.3/linux/include/asm-sparc/kdebug.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/kdebug.h	Thu Jun  8 23:44:53 1995
@@ -0,0 +1,75 @@
+/* kdebug.h:  Defines and definitions for debugging the Linux kernel
+ *            under various kernel debuggers.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_KDEBUG_H
+#define _SPARC_KDEBUG_H
+
+#include <asm/openprom.h>
+
+/* The debugger lives in 1MB of virtual address space right underneath
+ * the boot prom.
+ */
+
+#define DEBUG_FIRSTVADDR       0xffc00000
+#define DEBUG_LASTVADDR       LINUX_OPPROM_BEGVM
+
+/* Breakpoints are enter through trap table entry 126.  So in sparc assembly
+ * if you want to drop into the debugger you do:
+ *
+ * t DEBUG_BP_TRAP
+ */
+
+#define DEBUG_BP_TRAP     126
+
+#ifndef __ASSEMBLY__
+/* The debug vector is passed in %o1 at boot time.  It is a pointer to
+ * a structure in the debuggers address space.  Here is it's format.
+ */
+
+typedef unsigned int (*debugger_funct)(void);
+
+struct kernel_debug {
+	/* First the entry point into the debugger.  You jump here
+	 * to give control over to the debugger.
+	 */
+	unsigned long kdebug_entry;
+	unsigned long kdebug_trapme;   /* Figure out later... */
+	/* The following is the number of pages that the debugger has
+	 * taken from to total pool.
+	 */
+	unsigned long *kdebug_stolen_pages;
+	/* Ok, after you remap yourself and/or change the trap table
+	 * from what you were left with at boot time you have to call
+	 * this synchronization function so the debugger can check out
+	 * what you have done.
+	 */
+	debugger_funct teach_debugger;
+}; /* I think that is it... */
+
+extern struct kernel_debug *linux_dbvec;
+
+/* Use this macro in C-code to enter the debugger. */
+extern __inline__ void sp_enter_debugger(void)
+{
+	printk("Entering debugger in file %s line %d\n", __FILE__, __LINE__);
+	__asm__ __volatile__("jmpl %0, %%o7\n\t"
+			     "nop\n\t" : :
+			     "r" (linux_dbvec) : "o7", "memory");
+}
+
+#define SP_ENTER_DEBUGGER do { \
+	     if((linux_dbvec!=0) && ((*(short *)linux_dbvec)!=-1)) \
+	       sp_enter_debugger(); \
+		       } while(0)
+
+#endif /* !(__ASSEMBLY__) */
+
+/* Some nice offset defines for assembler code. */
+#define KDEBUG_ENTRY_OFF    0x0
+#define KDEBUG_DUNNO_OFF    0x4
+#define KDEBUG_DUNNO2_OFF   0x8
+#define KDEBUG_TEACH_OFF    0xc
+
+#endif /* !(_SPARC_KDEBUG_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/machines.h linux/include/asm-sparc/machines.h
--- v1.3.3/linux/include/asm-sparc/machines.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/machines.h	Sat Jun 17 08:05:08 1995
@@ -0,0 +1,68 @@
+/* machines.h:  Defines for taking apart the machine type value in the
+ *              idprom and determining the kind of machine we are on.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_MACHINES_H
+#define _SPARC_MACHINES_H
+
+struct Sun_Machine_Models {
+	char *name;
+	unsigned char id_machtype;
+};
+
+/* Current number of machines we know about that has an IDPROM
+ * machtype entry including one entry for the 0x80 OBP machines.
+ */
+#define NUM_SUN_MACHINES   15
+
+extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
+
+/* The machine type in the idprom area looks like this:
+ *
+ * ---------------
+ * | ARCH | MACH |
+ * ---------------
+ *  7    4 3    0
+ *
+ * The ARCH field determines the architecture line (sun4, sun4c, etc).
+ * The MACH field determines the machine make within that architecture.
+ */
+
+#define SM_ARCH_MASK  0xf0
+#define SM_SUN4       0x20
+#define SM_SUN4C      0x50
+#define SM_SUN4M      0x70
+#define SM_SUN4M_OBP  0x80
+
+#define SM_TYP_MASK   0x0f
+/* Sun4 machines */
+#define SM_4_260      0x01    /* Sun 4/200 series */
+#define SM_4_110      0x02    /* Sun 4/100 series */
+#define SM_4_330      0x03    /* Sun 4/300 series */
+#define SM_4_470      0x04    /* Sun 4/400 series */
+
+/* Sun4c machines                Full Name              - PROM NAME */
+#define SM_4C_SS1     0x01    /* Sun4c SparcStation 1   - Sun 4/60  */
+#define SM_4C_IPC     0x02    /* Sun4c SparcStation IPC - Sun 4/40  */
+#define SM_4C_SS1PLUS 0x03    /* Sun4c SparcStation 1+  - Sun 4/65  */
+#define SM_4C_SLC     0x04    /* Sun4c SparcStation SLC - Sun 4/20  */
+#define SM_4C_SS2     0x05    /* Sun4c SparcStation 2   - Sun 4/75  */
+#define SM_4C_ELC     0x06    /* Sun4c SparcStation ELC - Sun 4/25  */
+#define SM_4C_IPX     0x07    /* Sun4c SparcStation IPX - Sun 4/50  */
+
+/* Sun4m machines, these predate the OpenBoot.  These values only mean
+ * something if the value in the ARCH field is SM_SUN4M, if it is
+ * SM_SUN4M_OBP then you have the following situation:
+ * 1) You either have a sun4d, a sun4e, or a recently made sun4m.
+ * 2) You have to consult OpenBoot to determine which machine this is.
+ */
+#define SM_4M_SS60    0x01    /* Sun4m SparcSystem 600                  */
+#define SM_4M_SS50    0x02    /* Sun4m SparcStation 10                  */
+#define SM_4M_SS40    0x03    /* Sun4m SparcStation 5                   */
+
+/* Sun4d machines -- N/A */
+/* Sun4e machines -- N/A */
+/* Sun4u machines -- N/A */
+
+#endif /* !(_SPARC_MACHINES_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/mbus.h linux/include/asm-sparc/mbus.h
--- v1.3.3/linux/include/asm-sparc/mbus.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/mbus.h	Sun Jun 25 05:05:32 1995
@@ -0,0 +1,99 @@
+/* mbus.h:  Various defines for MBUS modules.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_MBUS_H
+#define _SPARC_MBUS_H
+
+#include <asm/ross.h>    /* HyperSparc stuff */
+#include <asm/cypress.h> /* Cypress Chips */
+#include <asm/viking.h>  /* Ugh, bug city... */
+
+enum mbus_module {
+	HyperSparc        = 0,
+	Cypress           = 1,
+	Cypress_vE        = 2,
+	Cypress_vD        = 3,
+	Swift_ok          = 4,
+	Swift_bad_c       = 5,
+	Swift_lots_o_bugs = 6,
+	Tsunami           = 7,
+	Viking_12         = 8,
+	Viking_2x         = 9,
+	Viking_30         = 10,
+	Viking_35         = 11,
+	Viking_new        = 12,
+	SRMMU_INVAL_MOD   = 13,
+};
+
+extern enum mbus_module srmmu_modtype;
+extern unsigned int viking_rev, swift_rev, cypress_rev;
+
+/* HW Mbus module bugs we have to deal with */
+#define HWBUG_COPYBACK_BROKEN        0x00000001
+#define HWBUG_ASIFLUSH_BROKEN        0x00000002
+#define HWBUG_VACFLUSH_BITROT        0x00000004
+#define HWBUG_KERN_ACCBROKEN         0x00000008
+#define HWBUG_KERN_CBITBROKEN        0x00000010
+#define HWBUG_MODIFIED_BITROT        0x00000020
+#define HWBUG_PC_BADFAULT_ADDR       0x00000040
+#define HWBUG_SUPERSCALAR_BAD        0x00000080
+#define HWBUG_PACINIT_BITROT         0x00000100
+
+extern unsigned int hwbug_bitmask;
+
+/* First the module type values. To find out which you have, just load
+ * the mmu control register from ASI_M_MMUREG alternate adress space and
+ * shift the value right 28 bits.
+ */
+/* IMPL field means the company which produced the chip. */
+#define MBUS_VIKING        0x4   /* bleech, Texas Instruments Module */
+#define MBUS_LSI           0x3   /* LSI Logics */
+#define MBUS_ROSS          0x1   /* Ross is nice */
+#define MBUS_FMI           0x0   /* Fujitsu Microelectronics/Swift */
+
+/* Ross Module versions */
+#define ROSS_604_REV_CDE        0x0   /* revisions c, d, and e */
+#define ROSS_604_REV_F          0x1   /* revision f */
+#define ROSS_605                0xf   /* revision a, a.1, and a.2 */
+#define ROSS_605_REV_B          0xe   /* revision b */
+
+/* TI Viking Module versions */
+#define VIKING_REV_12           0x1   /* Version 1.2 or SPARCclassic's CPU */
+#define VIKING_REV_2            0x2   /* Version 2.1, 2.2, 2.3, and 2.4 */
+#define VIKING_REV_30           0x3   /* Version 3.0 */
+#define VIKING_REV_35           0x4   /* Version 3.5 */
+
+/* LSI Logics. */
+#define LSI_L64815		0x0
+
+/* Fujitsu */
+#define FMI_AURORA		0x4   /* MB8690x, a Swift module... */
+
+/* For multiprocessor support we need to be able to obtain the CPU id and
+ * the MBUS Module id.
+ */
+
+/* The CPU ID is encoded in the trap base register, 20 bits to the left of
+ * bit zero, with 2 bits being significant.
+ */
+#define TBR_ID_SHIFT            0x20
+
+extern inline int get_cpuid(void)
+{
+	register int retval;
+	__asm__ __volatile__("rd %%tbr, %0\n\t"
+			     "srl %0, %1, %0\n\t" :
+			     "=r" (retval) :
+			     "i" (TBR_ID_SHIFT));
+	return (retval & 3);
+}
+
+extern inline int get_modid(void)
+{
+	return (get_cpuid() | 0x8);
+}
+
+	
+#endif /* !(_SPARC_MBUS_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/memerr.h linux/include/asm-sparc/memerr.h
--- v1.3.3/linux/include/asm-sparc/memerr.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/memerr.h	Tue Jun 20 10:08:38 1995
@@ -2,11 +2,11 @@
 #define _SPARC_MEMERR_H
 
 /* memerr.h:  Bit fields in the asynchronous and synchronous memory error
-              registers used to determine what 'type' of error has just
-	      induced a trap.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *            registers used to determine what 'type' of error has just
+ *	      induced a trap.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 /* synchronous error register fields come first... */
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/memreg.h linux/include/asm-sparc/memreg.h
--- v1.3.3/linux/include/asm-sparc/memreg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/memreg.h	Thu Jun  8 23:45:24 1995
@@ -0,0 +1,38 @@
+#ifndef _SPARC_MEMREG_H
+#define _SPARC_MEMREG_H
+/* memreg.h:  Definitions of the values found in the synchronous
+ *            and asynchronous memory error registers when a fault
+ *            occurs on the sun4c.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* First the synchronous error codes, these are usually just
+ * normal page faults.
+ */
+
+#define SUN4C_SYNC_WDRESET   0x1  /* watchdog reset, only the prom sees this */
+#define SUN4C_SYNC_SIZE      0x2  /* bad access size? whuz this? */
+#define SUN4C_SYNC_PARITY    0x8  /* bad ram chips caused a parity error */
+#define SUN4C_SYNC_SBUS      0x10 /* the SBUS had some problems... */
+#define SUN4C_SYNC_NOMEM     0x20 /* translation pointed to non-existant ram */
+#define SUN4C_SYNC_PROT      0x40 /* access violated pte protection settings */
+#define SUN4C_SYNC_NPRESENT  0x80 /* pte said that page was not present */
+#define SUN4C_SYNC_BADWRITE  0x8000  /* while writing something went bogus */
+
+/* Now the asynchronous error codes, these are almost always produced
+ * by the cache writing things back to memory and getting a bad translation.
+ * Bad DVMA transactions can cause these faults too.
+ */
+
+#define SUN4C_ASYNC_BADDVMA  0x10 /* error during DVMA access */
+#define SUN4C_ASYNC_NOMEM    0x20 /* write back pointed to bad phys addr */
+#define SUN4C_ASYNC_BADWB    0x80 /* write back points to non-present page */
+
+/* These are the values passed as the first arguement to the fault
+ * entry c-code from the assembly entry points.
+ */
+#define FAULT_ASYNC          0x0
+#define FAULT_SYNC           0x1
+
+#endif /* !(_SPARC_MEMREG_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/mostek.h linux/include/asm-sparc/mostek.h
--- v1.3.3/linux/include/asm-sparc/mostek.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/mostek.h	Thu Jun  8 23:45:31 1995
@@ -0,0 +1,74 @@
+/* mostek.h:  Describes the various Mostek time of day clock registers.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_MOSTEK_H
+#define _SPARC_MOSTEK_H
+
+#include <asm/idprom.h>
+
+/* First the Mostek 48t02 clock chip.  The registers other than the
+ * control register are in binary coded decimal.
+ */
+struct mostek48t02 {
+	char eeprom[2008];            /* This is the eeprom, don't touch! */
+	struct idp_struct idprom;     /* The idprom lives here. */
+	volatile unsigned char creg;  /* Control register */
+	volatile unsigned char sec;   /* Seconds (0-59) */
+	volatile unsigned char min;   /* Minutes (0-59) */
+	volatile unsigned char hour;  /* Hour (0-23) */
+	volatile unsigned char dow;   /* Day of the week (1-7) */
+	volatile unsigned char dom;   /* Day of the month (1-31) */
+	volatile unsigned char mnth;  /* Month of year (1-12) */
+	volatile unsigned char yr;    /* Year (0-99) */
+};
+
+extern struct mostek48t02 *mstk48t02_regs;
+
+/* Control register values. */
+#define MSTK_CREG_WRITE    0x80   /* Must set this before placing values. */
+#define MSTK_CREG_READ     0x40   /* Stop the clock, I want to fetch values. */
+#define MSTK_CREG_SIGN     0x20   /* Grrr... whats this??? */
+
+#define MSTK_YR_ZERO       1968   /* If year reg has zero, it is 1968 */
+#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YR_ZERO)
+
+/* Fun with masks. */
+#define MSTK_SEC_MASK      0x7f
+#define MSTK_MIN_MASK      0x7f
+#define MSTK_HOUR_MASK     0x3f
+#define MSTK_DOW_MASK      0x07
+#define MSTK_DOM_MASK      0x3f
+#define MSTK_MNTH_MASK     0x1f
+#define MSTK_YR_MASK       0xff
+
+/* Conversion routines. */
+#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0xf) + 0xa * ((x) >> 0x4))
+#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0xa) << 0x4) + ((x) % 0xa))
+
+/* Macros to make register access easier on our fingers. These give you
+ * the decimal value of the register requested if applicable.  You pass
+ * the a pointer to a 'struct mostek48t02'.
+ */
+#define MSTK_REG_CREG(ptr)  (ptr->creg)
+#define MSTK_REG_SEC(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->sec & MSTK_SEC_MASK)))
+#define MSTK_REG_MIN(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->min & MSTK_MIN_MASK)))
+#define MSTK_REG_HOUR(ptr)  (MSTK_REGVAL_TO_DECIMAL((ptr->hour & MSTK_HOUR_MASK)))
+#define MSTK_REG_DOW(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->dow & MSTK_DOW_MASK)))
+#define MSTK_REG_DOM(ptr)   (MSTK_REGVAL_TO_DECIMAL((ptr->dom & MSTK_DOM_MASK)))
+#define MSTK_REG_MNTH(ptr)  (MSTK_REGVAL_TO_DECIMAL((ptr->mnth & MSTK_MNTH_MASK)))
+#define MSTK_REG_YR(ptr)    (MSTK_REGVAL_TO_DECIMAL((ptr->yr & MSTK_YR_MASK)))
+
+/* The Mostek 48t02 clock chip.  Found on Sun4m's I think.  It has the
+ * same (basically) layout of the 48t02 chip.
+ */
+struct mostek48t08 {
+	char offset[6*1024];         /* Magic things may be here, who knows? */
+	struct mostek48t02 regs;     /* Here is what we are interested in.   */
+};
+extern struct mostek48t08 *mstk48t08_regs;
+
+enum sparc_clock_type {	MSTK48T02, MSTK48T08, MSTK_INVALID };
+extern enum sparc_clock_type sp_clock_typ;
+
+#endif /* !(_SPARC_MOSTEK_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/mp.h linux/include/asm-sparc/mp.h
--- v1.3.3/linux/include/asm-sparc/mp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/mp.h	Tue Jun 13 08:19:22 1995
@@ -0,0 +1,33 @@
+/* mp.h:  Multiprocessing definitions for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_MP_H
+#define _SPARC_MP_H
+
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/vaddrs.h>
+
+extern int linux_smp_still_initting;
+
+struct sparc_percpu {
+	struct tt_entry trap_table[NUM_SPARC_TRAPS];  /* One page */
+	unsigned int kernel_stack[PAGE_SIZE/4];       /* One page */
+	int cpuid;          /* Who am I? */
+	int cpu_is_alive;   /* Linux has fired it up. */
+	int cpu_is_idling;  /* Is sitting in the idle loop. */
+	/* More to come... */
+	char filler[PERCPU_ENTSIZE-(PAGE_SIZE*2)-0xc];
+};
+
+extern struct sparc_percpu *percpu_table;
+
+struct prom_cpuinfo {
+	int prom_node;
+	int mid;
+};
+
+extern struct prom_cpuinfo linux_cpus[NCPUS];
+
+#endif /* !(_SPARC_MP_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/mpmbox.h linux/include/asm-sparc/mpmbox.h
--- v1.3.3/linux/include/asm-sparc/mpmbox.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/mpmbox.h	Sun Jun  4 13:50:17 1995
@@ -0,0 +1,66 @@
+/* mpmbox.h:  Interface and defines for the OpenProm mailbox
+ *               facilities for MP machines under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_MPMBOX_H
+#define _SPARC_MPMBOX_H
+
+/* The prom allocates, for each CPU on the machine an unsigned
+ * byte in physical ram.  You probe the device tree prom nodes
+ * for these values.  The purpose of this byte is to be able to
+ * pass messages from one cpu to another.
+ */
+
+/* These are the main message types we have to look for in our
+ * Cpu mailboxes, based upon these values we decide what course
+ * of action to take.
+ */
+
+/* The CPU is executing code in the kernel. */
+#define MAILBOX_ISRUNNING     0xf0
+
+/* Another CPU called romvec->pv_exit(), you should call
+ * prom_stopcpu() when you see this in your mailbox.
+ */
+#define MAILBOX_EXIT          0xfb
+
+/* Another CPU called romvec->pv_enter(), you should call
+ * prom_cpuidle() when this is seen.
+ */
+#define MAILBOX_GOSPIN        0xfc
+
+/* Another CPU has hit a breakpoint either into kadb or the prom
+ * itself.  Just like MAILBOX_GOSPIN, you should call prom_cpuidle()
+ * at this point.
+ */
+#define MAILBOX_BPT_SPIN      0xfd
+
+/* Oh geese, some other nitwit got a damn watchdog reset.  The partys
+ * over so go call prom_stopcpu().
+ */
+#define MAILBOX_WDOG_STOP     0xfe
+
+#ifndef __ASSEMBLY__
+
+/* Handy macro's to determine a cpu's state. */
+
+/* Is the cpu still in Power On Self Test? */
+#define MBOX_POST_P(letter)  ((letter) >= 0x00 && (letter) <= 0x7f)
+
+/* Is the cpu at the 'ok' prompt of the PROM? */
+#define MBOX_PROMPROMPT_P(letter) ((letter) >= 0x80 && (letter) <= 0x8f)
+
+/* Is the cpu spinning in the PROM? */
+#define MBOX_PROMSPIN_P(letter) ((letter) >= 0x90 && (letter) <= 0xef)
+
+/* Sanity check... This is junk mail, throw it out. */
+#define MBOX_BOGON_P(letter) ((letter) >= 0xf1 && (letter) <= 0xfa)
+
+/* Is the cpu actively running an application/kernel-code? */
+#define MBOX_RUNNING_P(letter) ((letter) == MAILBOX_ISRUNNING)
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* !(_SPARC_MPMBOX_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/mxcc.h linux/include/asm-sparc/mxcc.h
--- v1.3.3/linux/include/asm-sparc/mxcc.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/mxcc.h	Tue Jun 20 04:11:50 1995
@@ -0,0 +1,82 @@
+/* mxcc.h:  Definitions of the Viking MXCC registers
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_MXCC_H
+#define _SPARC_MXCC_H
+
+/* These registers are accessed through ASI 0x2. */
+#define MXCC_DATSTREAM       0x1C00000  /* Data stream register */
+#define MXCC_SRCSTREAM       0x1C00100  /* Source stream register */
+#define MXCC_DESSTREAM       0x1C00200  /* Destination stream register */
+#define MXCC_RMCOUNT         0x1C00300  /* Count of references and misses */
+#define MXCC_STEST           0x1C00804  /* Internal self-test */
+#define MXCC_CREG            0x1C00A04  /* Control register */
+#define MXCC_SREG            0x1C00B00  /* Status register */
+#define MXCC_RREG            0x1C00C04  /* Reset register */
+#define MXCC_EREG            0x1C00E00  /* Error code register */
+#define MXCC_PREG            0x1C00F04  /* Address port register */
+
+/* The MXCC Control Register:
+ *
+ * ----------------------------------------------------------------------
+ * |                                   | RRC | RSV |PRE|MCE|PARE|ECE|RSV|
+ * ----------------------------------------------------------------------
+ *  31                              10    9    8-6   5   4    3   2  1-0
+ *
+ * RRC: Controls what you read from MXCC_RMCOUNT reg.
+ *      0=Misses 1=References
+ * PRE: Prefetch enable
+ * MCE: Multiple Command Enable
+ * PARE: Parity enable
+ * ECE: External cache enable
+ */
+
+#define MXCC_CTL_RRC   0x00000200
+#define MXCC_CTL_PRE   0x00000020
+#define MXCC_CTL_MCE   0x00000010
+#define MXCC_CTL_PARE  0x00000008
+#define MXCC_CTL_ECE   0x00000004
+
+/* The MXCC Error Register:
+ *
+ * --------------------------------------------------------
+ * |ME| RSV|CE|PEW|PEE|ASE|EIV| MOPC|ECODE|PRIV|RSV|HPADDR|
+ * --------------------------------------------------------
+ *  31   30 29  28  27  26  25 24-15  14-7   6  5-3   2-0
+ *
+ * ME: Multiple Errors have occurred
+ * CE: Cache consistancy Error
+ * PEW: Parity Error during a Write operation
+ * PEE: Parity Error involving the External cache
+ * ASE: ASynchronous Error
+ * EIV: This register is toast
+ * MOPC: MXCC Operation Code for instance causing error
+ * ECODE: The Error CODE
+ * PRIV: A privileged mode error? 0=no 1=yes
+ * HPADDR: High PhysicalADDRess bits (35-32)
+ */
+
+#define MXCC_ERR_ME     0x80000000
+#define MXCC_ERR_CE     0x20000000
+#define MXCC_ERR_PEW    0x10000000
+#define MXCC_ERR_PEE    0x08000000
+#define MXCC_ERR_ASE    0x04000000
+#define MXCC_ERR_EIV    0x02000000
+#define MXCC_ERR_MOPC   0x01FF8000
+#define MXCC_ERR_ECODE  0x00007F80
+#define MXCC_ERR_PRIV   0x00000040
+#define MXCC_ERR_HPADDR 0x0000000f
+
+/* The MXCC Port register:
+ *
+ * -----------------------------------------------------
+ * |                | MID |                            |
+ * -----------------------------------------------------
+ *  31            21 20-18 17                         0
+ *
+ * MID: The moduleID of the cpu your read this from.
+ */
+
+#endif /* !(_SPARC_MXCC_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/openprom.h linux/include/asm-sparc/openprom.h
--- v1.3.3/linux/include/asm-sparc/openprom.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/openprom.h	Mon Jun  5 12:08:38 1995
@@ -2,33 +2,37 @@
 #define __SPARC_OPENPROM_H
 
 /* openprom.h:  Prom structures and defines for access to the OPENBOOT
-                prom routines and data areas.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *              prom routines and data areas.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 /* In the v0 interface of the openboot prom we could traverse a nice
-   little list structure to figure out where in vm-space the prom had
-   mapped itself and how much space it was taking up. In the v2 prom
-   interface we have to rely on 'magic' values. :-( Most of the machines
-   I have checked on have the prom mapped here all the time though.
-*/
+ * little list structure to figure out where in vm-space the prom had
+ * mapped itself and how much space it was taking up. In the v2 prom
+ * interface we have to rely on 'magic' values. :-( Most of the machines
+ * I have checked on have the prom mapped here all the time though.
+ */
+
+#define KADB_DEBUGGER_BEGVM     0xffc00000    /* Where kern debugger is in virt-mem */
+
 #define	LINUX_OPPROM_BEGVM	0xffd00000
 #define	LINUX_OPPROM_ENDVM	0xfff00000
 
 #define	LINUX_OPPROM_MAGIC      0x10010407
 
+#ifndef __ASSEMBLY__
 /* The device functions structure for the v0 prom. Nice and neat, open,
-   close, read & write divvied up between net + block + char devices. We
-   also have a seek routine only usable for block devices. The divide
-   and conquer strategy of this struct becomes unnecessary for v2.
-
-   V0 device names are limited to two characters, 'sd' for scsi-disk,
-   'le' for local-ethernet, etc. Note that it is technically possible
-   to boot a kernel off of a tape drive and use the tape as the root
-   partition! In order to do this you have to have 'magic' formatted
-   tapes from Sun supposedly :-)
-*/
+ * close, read & write divvied up between net + block + char devices. We
+ * also have a seek routine only usable for block devices. The divide
+ * and conquer strategy of this struct becomes unnecessary for v2.
+ *
+ * V0 device names are limited to two characters, 'sd' for scsi-disk,
+ * 'le' for local-ethernet, etc. Note that it is technically possible
+ * to boot a kernel off of a tape drive and use the tape as the root
+ * partition! In order to do this you have to have 'magic' formatted
+ * tapes from Sun supposedly :-)
+ */
 
 struct linux_dev_v0_funcs {
 	int	(*v0_devopen)(char *device_str);
@@ -43,32 +47,32 @@
 };
 
 /* The OpenBoot Prom device operations for version-2 interfaces are both
-   good and bad. They now allow you to address ANY device whatsoever
-   that is in the machine via these funny "device paths". They look like
-   this:
-
-     "/sbus/esp@0,0xf004002c/sd@3,1"
-
-   You can basically reference any device on the machine this way, and
-   you pass this string to the v2 dev_ops. Producing these strings all
-   the time can be a pain in the rear after a while. Why v2 has memory
-   allocations in here are beyond me. Perhaps they figure that if you
-   are going to use only the prom's device drivers then your memory
-   management is either non-existent or pretty sad. :-)
-*/
+ * good and bad. They now allow you to address ANY device whatsoever
+ * that is in the machine via these funny "device paths". They look like
+ * this:
+ *
+ *   "/sbus/esp@0,0xf004002c/sd@3,1"
+ *
+ * You can basically reference any device on the machine this way, and
+ * you pass this string to the v2 dev_ops. Producing these strings all
+ * the time can be a pain in the rear after a while. Why v2 has memory
+ * allocations in here are beyond me. Perhaps they figure that if you
+ * are going to use only the prom's device drivers then your memory
+ * management is either non-existent or pretty sad. :-)
+ */
 
 struct linux_dev_v2_funcs {
-	int	(*v2_aieee)(int d);	/* figure this out later... */
+	int	(*v2_inst2pkg)(int d);	/* Convert ihandle to phandle */
 
 	/* "dumb" prom memory management routines, probably
-	    only safe to use for mapping device address spaces...
-        */
+	 *  only safe to use for mapping device address spaces...
+         */
 
 	char* 	(*v2_dumb_mem_alloc)(char*  va, unsigned sz);
 	void	(*v2_dumb_mem_free)(char*  va, unsigned sz);
 
 	/* "dumb" mmap() munmap(), copy on write? what's that? */
-	char* 	(*v2_dumb_mmap)(char*  virta, int asi, unsigned prot, unsigned sz);
+	char* 	(*v2_dumb_mmap)(char*  virta, int which_io, unsigned paddr, unsigned sz);
 	void	(*v2_dumb_munmap)(char*  virta, unsigned size);
 
 	/* Basic Operations, self-explanatory */
@@ -78,16 +82,16 @@
 	int	(*v2_dev_write)(int d, char*  buf, int nbytes);
 	void	(*v2_dev_seek)(int d, int hi, int lo);
 
-        /* huh? */
+	/* Never issued (multistage load support) */
 	void	(*v2_wheee2)(void);
 	void	(*v2_wheee3)(void);
 };
 
 /* Just like the device ops, they slightly screwed up the mem-list
-   from v0 to v2. Probably easier on the prom-writer dude, sucks for
-   us though. See above comment about prom-vm mapped address space
-   magic numbers. :-(
-*/
+ * from v0 to v2. Probably easier on the prom-writer dude, sucks for
+ * us though. See above comment about prom-vm mapped address space
+ * magic numbers. :-(
+ */
 
 struct linux_mlist_v0 {
 	struct	linux_mlist_v0 *theres_more;
@@ -95,11 +99,12 @@
 	unsigned num_bytes;
 };
 
-/* The linux_mlist_v0's are pointer by this structure. One list
-   per description. This means one list for total physical memory,
-   one for prom's address mapping, and one for physical mem left after
-   the kernel is loaded.
+/* The linux_mlist_v0's are pointed to by this structure. One list
+ * per description. This means one list for total physical memory,
+ * one for prom's address mapping, and one for physical mem left after
+ * the kernel is loaded.
  */
+
 struct linux_mem_v0 {
 	struct	linux_mlist_v0 **v0_totphys;	/* all of physical */
 	struct	linux_mlist_v0 **v0_prommap;	/* addresses map'd by prom */
@@ -120,9 +125,9 @@
 };
 
 /* Prom version-2 gives us the raw strings for boot arguments and
-   boot device path. We also get the stdin and stdout file pseudo
-   descriptors for use with the mungy v2 device functions.
-*/
+ * boot device path. We also get the stdin and stdout file pseudo
+ * descriptors for use with the mungy v2 device functions.
+ */
 struct linux_bootargs_v2 {
 	char	**bootpath;		/* V2: Path to boot device */
 	char	**bootargs;		/* V2: Boot args */
@@ -131,11 +136,12 @@
 };
 
 /* This is the actual Prom Vector from which everything else is accessed
-   via struct and function pointers, etc. The prom when it loads us into
-   memory plops a pointer to this master structure in register %o0 before
-   it jumps to the kernel start address. I will update this soon to cover
-   the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-)
-*/
+ * via struct and function pointers, etc. The prom when it loads us into
+ * memory plops a pointer to this master structure in register %o0 before
+ * it jumps to the kernel start address. I will update this soon to cover
+ * the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-)
+ */
+
 struct linux_romvec {
 	/* Version numbers. */
 	unsigned int	pv_magic_cookie;      /* Magic Mushroom... */
@@ -200,7 +206,7 @@
 	struct	linux_bootargs_v2 pv_v2bootargs;    /* V2: Boot args+std-in/out */
 	struct	linux_dev_v2_funcs pv_v2devops;	    /* V2: device operations */
 
-	int	whatzthis[15];       /* huh? */
+	int	filler[15];
 
 	/*
 	 * The following is machine-dependent.
@@ -222,11 +228,9 @@
 
 	/* v3_cpustart() will start the cpu 'whichcpu' in mmu-context
 	 * 'thiscontext' executing at address 'prog_counter'
-	 *
-	 * XXX Have to figure out what 'cancontext' means.
          */
 
-	int (*v3_cpustart)(unsigned int whichcpu, int cancontext,
+	int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr,
 			   int thiscontext, char* prog_counter);
 
 	/* v3_cpustop() will cause cpu 'whichcpu' to stop executing
@@ -277,11 +281,6 @@
  * are not in the openprom vectors but rather found by indirection from
  * there.  So the taste balances out.
  */
-struct linux_prom_addr {
-	int	oa_space;		/* address space (may be relative) */
-	unsigned int	oa_base;		/* address within space */
-	unsigned int	oa_size;		/* extent (number of bytes) */
-};
 
 struct linux_nodeops {
 	/*
@@ -300,5 +299,32 @@
 	int	(*no_setprop)(int node, char*  name, char*  val, int len);
 	char* 	(*no_nextprop)(int node, char*  name);
 };
+
+/* More fun PROM structures for device probing. */
+#define PROMREG_MAX     16
+#define PROMVADDR_MAX   16
+#define PROMINTR_MAX    15
+
+struct linux_prom_registers {
+  int which_io;         /* is this in OBIO space? */
+  char *phys_addr;      /* The physical address of this register */
+  int reg_size;         /* How many bytes does this register take up? */
+};
+
+struct linux_prom_irqs {
+  int pri;    /* IRQ priority */
+  int vector; /* This is foobar, what does it do? */
+};
+
+/* Element of the "ranges" vector */
+struct linux_prom_ranges {
+	unsigned int	ot_child_space;
+	unsigned int	ot_child_base;		/* Bus feels this */
+	unsigned int	ot_parent_space;
+	unsigned int	ot_parent_base;		/* CPU looks from here */
+	unsigned int	or_size;
+};
+
+#endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC_OPENPROM_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h
--- v1.3.3/linux/include/asm-sparc/oplib.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/oplib.h	Sat Jun 17 04:40:43 1995
@@ -0,0 +1,260 @@
+/* oplib.h:  Describes the interface and available routines in the
+ *           Linux Prom library.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_OPLIB_H
+#define __SPARC_OPLIB_H
+
+#include <asm/openprom.h>
+
+/* The master romvec pointer... */
+extern struct linux_romvec *romvec;
+
+/* Enumeration to describe the prom major version we have detected. */
+enum prom_major_version {
+	PROM_V0,      /* Origional sun4c V0 prom */
+	PROM_V2,      /* sun4c and early sun4m V2 prom */
+	PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
+	PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
+};
+
+extern enum prom_major_version prom_vers;
+/* Revision, and firmware revision. */
+extern unsigned int prom_rev, prom_prev;
+
+/* Root node of the prom device tree, this stays constant after
+ * initialization is complete.
+ */
+extern int prom_root_node;
+
+/* Pointer to prom structure containing the device tree traversal
+ * and usage utility functions.  Only prom-lib should use these,
+ * users use the interface defined by the library only!
+ */
+extern struct linux_nodeops *prom_nodeops;
+
+/* The functions... */
+
+/* You must call prom_init() before using any of the library services,
+ * preferably as early as possible.  Pass it the romvec pointer.
+ */
+extern int prom_init(struct linux_romvec *rom_ptr);
+
+/* Boot argument acquisition, returns the boot command line string. */
+extern char *prom_getbootargs(void);
+
+/* Device utilities. */
+
+/* Map and unmap devices in IO space at virtual addresses. Note that the
+ * virtual address you pass is a request and the prom may put your mappings
+ * somewhere else, so check your return value as that is where your new
+ * mappings really are!
+ *
+ * Another note, these are only available on V2 or higher proms!
+ */
+extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes);
+extern void prom_unmapio(char *virt_addr, unsigned int num_bytes);
+
+/* Device operations. */
+
+/* Open the device described by the passed string.  Note, that the format
+ * of the string is different on V0 vs. V2->higher proms.  The caller must
+ * know what he/she is doing!  Returns the device descriptor, an int.
+ */
+extern int prom_devopen(char *device_string);
+
+/* Close a previously opened device described by the passed integer
+ * descriptor.
+ */
+extern int prom_devclose(int device_handle);
+
+/* Do a seek operation on the device described by the passed integer
+ * descriptor.
+ */
+extern void prom_seek(int device_handle, unsigned int seek_hival,
+		      unsigned int seek_lowval);
+
+/* Machine memory configuration routine. */
+
+/* This function returns a V0 format memory descriptor table, it has three
+ * entries.  One for the total amount of physical ram on the machine, one
+ * for the amount of physical ram available, and one describing the virtual
+ * areas which are allocated by the prom.  So, in a sense the physical
+ * available is a calculation of the total physical minus the physcial mapped
+ * by the prom with virtual mappings.
+ *
+ * These lists are returned pre-sorted, this should make your life easier
+ * since the prom itself is way too lazy to do such nice things.
+ */
+extern struct linux_mem_v0 *prom_meminfo(void);
+
+/* Miscellaneous routines, don't really fit in any category per se. */
+
+/* Reboot the machine with the command line passed. */
+extern void prom_reboot(char *boot_command);
+
+/* Evaluate the forth string passed. */
+extern void prom_feval(char *forth_string);
+
+/* Enter the prom, with possibility of continuation with the 'go'
+ * command in newer proms.
+ */
+extern void prom_halt(void);
+
+/* Enter the prom, with no chance of continuation for the stand-alone
+ * which calls this.
+ */
+extern void prom_die(void);
+
+/* Set the PROM 'sync' callback function to the passed function pointer.
+ * When the user gives the 'sync' command at the prom prompt while the
+ * kernel is still active, the prom will call this routine.
+ *
+ * XXX The arguments are different on V0 vs. V2->higher proms, grrr! XXX
+ */
+typedef void (*sync_func_t)(void);
+extern void prom_setsync(sync_func_t func_ptr);
+
+/* Acquire the IDPROM of the root node in the prom device tree.  This
+ * gets passed a buffer where you would like it stuffed.  The return value
+ * is the format type of this idprom or 0xff on error.
+ */
+extern unsigned char prom_getidp(char *idp_buffer, int idpbuf_size);
+
+/* Get the prom major version. */
+extern int prom_version(void);
+
+/* Get the prom plugin revision. */
+extern int prom_getrev(void);
+
+/* Get the prom firmware revision. */
+extern int prom_getprev(void);
+
+/* Character operations to/from the console.... */
+
+/* Non-blocking get character from console. */
+extern int prom_nbgetchar(void);
+
+/* Non-blocking put character to console. */
+extern int prom_nbputchar(char character);
+
+/* Blocking get character from console. */
+extern char prom_getchar(void);
+
+/* Blocking put character to console. */
+extern void prom_putchar(char character);
+
+/* Prom's internal printf routine, don't use in kernel/boot code. */
+void prom_printf(char *fmt, ...);
+
+/* Multiprocessor operations... */
+
+/* Start the CPU with the given device tree node, context table, and context
+ * at the passed program counter.
+ */
+extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table,
+			 int context, char *program_counter);
+
+/* Stop the CPU with the passed device tree node. */
+extern int prom_stopcpu(int cpunode);
+
+/* Idle the CPU with the passed device tree node. */
+extern int prom_idlecpu(int cpunode);
+
+/* Re-Start the CPU with the passed device tree node. */
+extern int prom_restartcpu(int cpunode);
+
+/* PROM memory allocation facilities... */
+
+/* Allocated at possibly the given virtual address a chunk of the
+ * indicated size.
+ */
+extern char *prom_alloc(char *virt_hint, unsigned int size);
+
+/* Free a previously allocated chunk. */
+extern void prom_free(char *virt_addr, unsigned int size);
+
+/* Sun4/sun4c specific memory-management startup hook. */
+
+/* Map the passed segment in the given context at the passed
+ * virtual address.
+ */
+extern void prom_putsegment(int context, unsigned long virt_addr,
+			    int physical_segment);
+
+/* PROM device tree traversal functions... */
+
+/* Get the child node of the given node, or zero if no child exists. */
+extern int prom_getchild(int parent_node);
+
+/* Get the next sibling node of the given node, or zero if no further
+ * siblings exist.
+ */
+extern int prom_getsibling(int node);
+
+/* Get the length, at the passed node, of the given property type.
+ * Returns -1 on error (ie. no such property at this node).
+ */
+extern int prom_getproplen(int thisnode, char *property);
+
+/* Fetch the requested property using the given buffer.  Returns
+ * the number of bytes the prom put into your buffer or -1 on error.
+ */
+extern int prom_getproperty(int thisnode, char *property,
+			    char *prop_buffer, int propbuf_size);
+
+/* Acquire an integer property. */
+extern int prom_getint(int node, char *property);
+
+/* Acquire an integer property, with a default value. */
+extern int prom_getintdefault(int node, char *property, int defval);
+
+/* Acquire a boolean property, 0=FALSE 1=TRUE. */
+extern int prom_getbool(int node, char *prop);
+
+/* Acquire a string property, null string on error. */
+extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+
+/* Does the passed node have the given "name"? YES=1 NO=0 */
+extern int prom_nodematch(int thisnode, char *name);
+
+/* Search all siblings starting at the passed node for "name" matching
+ * the given string.  Returns the node on success, zero on failure.
+ */
+extern int prom_searchsiblings(int node_start, char *name);
+
+/* Return the first property type, as a string, for the given node.
+ * Returns a null string on error.
+ */
+extern char *prom_firstprop(int node);
+
+/* Returns the next property after the passed property for the given
+ * node.  Returns null string on failure.
+ */
+extern char *prom_nextprop(int node, char *prev_property);
+
+/* Set the indicated property at the given node with the passed value.
+ * Returns the number of bytes of your value that the prom took.
+ */
+extern int prom_setprop(int node, char *prop_name, char *prop_value,
+			int value_size);
+
+/* Dorking with Bus ranges... */
+
+/* Adjust reg values with the passed ranges. */
+extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
+			     struct linux_prom_ranges *rangep, int nranges);
+
+/* Adjust child ranges with the passed parent ranges. */
+extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
+			       struct linux_prom_ranges *pranges, int npranges);
+
+/* Apply promlib probed OBIO ranges to registers. */
+extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
+
+/* Apply promlib probed SBUS ranges to registers. */
+extern void prom_apply_sbus_ranges(struct linux_prom_registers *sbusregs, int nregs);
+
+#endif /* !(__SPARC_OPLIB_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v1.3.3/linux/include/asm-sparc/page.h	Wed Mar  1 09:12:33 1995
+++ linux/include/asm-sparc/page.h	Fri Jun 23 08:00:28 1995
@@ -1,31 +1,32 @@
 /* page.h:  Various defines and such for MMU operations on the Sparc for
-            the Linux kernel.
-
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+ *          the Linux kernel.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
 #include <asm/asi.h>        /* for get/set segmap/pte routines */
 #include <asm/contregs.h>   /* for switch_to_context */
+#include <asm/head.h>       /* for KERNBASE */
 
 #define PAGE_SHIFT   12             /* This is the virtual page... */
-
-#ifndef __ASSEMBLY__
-#define PAGE_SIZE    (1UL << PAGE_SHIFT)
+#define PAGE_OFFSET    KERNBASE
+#define PAGE_SIZE    (1 << PAGE_SHIFT)
 
 /* to mask away the intra-page address bits */
 #define PAGE_MASK         (~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
+#ifndef __ASSEMBLY__
 
 /* The following structure is used to hold the physical
- * memory configuration of the machine.  This is filled
- * in probe_memory() and is later used by mem_init() to
- * set up mem_map[].  We statically allocate 14 of these
- * structs, this is arbitrary.  The entry after the last
- * valid one has num_bytes==0.
+ * memory configuration of the machine.  This is filled in
+ * probe_memory() and is later used by mem_init() to set up
+ * mem_map[].  We statically allocate SPARC_PHYS_BANKS of
+ * these structs, this is arbitrary.  The entry after the
+ * last valid one has num_bytes==0.
  */
 
 struct sparc_phys_banks {
@@ -33,6 +34,10 @@
   unsigned long num_bytes;
 };
 
+#define SPARC_PHYS_BANKS 32
+
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+
 #define CONFIG_STRICT_MM_TYPECHECKS
 
 #ifdef CONFIG_STRICT_MM_TYPECHECKS
@@ -76,16 +81,19 @@
 #endif
 
 /* The current va context is global and known, so all that is needed to
- * do an invalidate is flush the VAC.
+ * do an invalidate is flush the VAC on a sun4c or call the ASI flushing
+ * routines on a SRMMU.
  */
 
-#define invalidate() flush_vac_context()  /* how conveeeiiiiinnnient :> */
+extern void (*invalidate)(void);
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-#define PAGE_OFFSET    0
-#define MAP_NR(addr) (((unsigned long)(addr)) >> PAGE_SHIFT)
+/* We now put the free page pool mapped contiguously in high memory above
+ * the kernel.
+ */
+#define MAP_NR(addr) ((((unsigned long)addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED (1<<15)
 
 
@@ -114,21 +122,144 @@
 #define PTE_RESV  0x00f80000   /* reserved bits */
 #define PTE_PHYPG 0x0007ffff   /* phys pg number, sun4c only uses 16bits */
 
+/* SRMMU defines */
+/* The fields in an srmmu virtual address when it gets translated.
+ *
+ *  -------------------------------------------------------------
+ *  |   INDEX 1   |   INDEX 2   |   INDEX 3   |   PAGE OFFSET   |
+ *  -------------------------------------------------------------
+ *  31          24 23        18  17         12  11              0
+ */
+#define SRMMU_IDX1_SHIFT      24
+#define SRMMU_IDX1_MASK       0xff000000
+#define SRMMU_IDX2_SHIFT      18
+#define SRMMU_IDX2_MASK       0x00fc0000
+#define SRMMU_IDX3_SHIFT      12
+#define SRMMU_IDX3_MASK       0x0003f000
+
+#define SRMMU_PGOFFSET_MASK   0x00000fff
+/* The page table sizes for the various levels in bytes. */
+#define SRMMU_LV1_PTSIZE      1024
+#define SRMMU_LV2_PTSIZE      256
+#define SRMMU_LV3_PTSIZE      256
+
+/* Definition of the values in the ET field of PTD's and PTE's */
+#define SRMMU_ET_INVALID      0x0
+#define SRMMU_ET_PTD          0x1
+#define SRMMU_ET_PTE          0x2
+#define SRMMU_ET_RESV         0x3
+#define SRMMU_ET_PTDBAD       0x3   /* Upward compatability my butt. */
+
+/* Page table directory bits.
+ *
+ * ----------------
+ * |  PTP    | ET |
+ * ----------------
+ * 31       2 1  0
+ *
+ * PTP:  The physical page table pointer.  This value appears on
+ *       bits 35->6 on the physical address bus during translation.
+ *
+ * ET:   Entry type field.  Must be 1 for a PTD.
+ */
+
+#define SRMMU_PTD_PTP_SHIFT         0x2
+#define SRMMU_PTD_PTP_MASK          0xfffffffc
+#define SRMMU_PTD_PTP_PADDR_SHIFT   0x4
+#define SRMMU_PTD_ET_SHIFT          0x0
+#define SRMMU_PTD_ET_MASK           0x00000003
+
+/* Page table entry bits.
+ *
+ * -------------------------------------------------
+ * |  Physical Page Number  | C | M | R | ACC | ET |
+ * -------------------------------------------------
+ * 31                     8   7   6   5  4   2  1  0
+ *
+ * PPN: Physical page number, high order 24 bits of the 36-bit
+ *      physical address, thus is you mask off all the non
+ *      PPN bits you have the physical address of your page.
+ *      No shifting necessary.
+ *
+ * C:   Whether the page is cacheable in the mmu TLB or not.  If
+ *      not set the CPU cannot cache values to these addresses. For
+ *      IO space translations this bit should be clear.
+ *
+ * M:   Modified.  This tells whether the page has been written to
+ *      since the bit was last cleared.  NOTE: this does not include
+ *      accesses via the ASI physical page pass through since that does
+ *      not use the MMU.
+ *
+ * R:   References.  This tells whether the page has been referenced
+ *      in any way shape or form since the last clearing of the bit.
+ *      NOTE: this does not include accesses via the ASI physical page
+ *      pass through since that does not use the MMU.
+ *
+ * ACC: Access permissions for this page.  This is further explained below
+ *      with appropriate macros.
+ */
+
+#define SRMMU_PTE_PPN_SHIFT         0x8
+#define SRMMU_PTE_PPN_MASK          0xffffff00
+#define SRMMU_PTE_PPN_PADDR_SHIFT   0x4
+#define SRMMU_PTE_C_SHIFT           0x7
+#define SRMMU_PTE_C_MASK            0x00000080
+#define SRMMU_PTE_M_SHIFT           0x6
+#define SRMMU_PTE_M_MASK            0x00000040
+#define SRMMU_PTE_R_SHIFT           0x5
+#define SRMMU_PTE_R_MASK            0x00000020
+#define SRMMU_PTE_ACC_SHIFT         0x2
+#define SRMMU_PTE_ACC_MASK          0x0000001c
+#define SRMMU_PTE_ET_SHIFT          0x0
+#define SRMMU_PTE_ET_MASK           0x00000003
+
+/* SRMMU pte access bits.
+ *
+ * BIT    USER ACCESS          SUPERVISOR ACCESS
+ * ---    --------------       -----------------
+ * 0x0    read only            read only
+ * 0x1    read&write           read&write
+ * 0x2    read&execute         read&execute
+ * 0x3    read&write&execute   read&write&execute
+ * 0x4    execute only         execute only
+ * 0x5    read only            read&write
+ * 0x6    ACCESS DENIED        read&execute
+ * 0x7    ACCESS DENIED        read&write&execute
+ *
+ * All these values are shifted left two bits.
+ */
+
+#define SRMMU_ACC_US_RDONLY      0x00
+#define SRMMU_ACC_US_RDWR        0x04
+#define SRMMU_ACC_US_RDEXEC      0x08
+#define SRMMU_ACC_US_RDWREXEC    0x0c
+#define SRMMU_ACC_US_EXECONLY    0x10
+#define SRMMU_ACC_U_RDONLY       0x14
+#define SRMMU_ACC_S_RDWR         0x14
+#define SRMMU_ACC_U_ACCDENIED    0x18
+#define SRMMU_ACC_S_RDEXEC       0x18
+#define SRMMU_ACC_U_ACCDENIED2   0x1c
+#define SRMMU_ACC_S_RDWREXEC     0x1c
+
+#ifndef __ASSEMBLY__
+
+/* SUN4C pte, segmap, and context manipulation */
 extern __inline__ unsigned long get_segmap(unsigned long addr)
 {
   register unsigned long entry;
 
-  __asm__ __volatile__("lduba [%1] 0x3, %0" : 
+  __asm__ __volatile__("lduba [%1] %2, %0" : 
 		       "=r" (entry) :
-		       "r" (addr));
+		       "r" (addr), "i" (ASI_SEGMAP));
 
-  return (entry&0x7f);
+  return (entry&0xff);
 }
 
 extern __inline__ void put_segmap(unsigned long addr, unsigned long entry)
 {
 
-  __asm__ __volatile__("stba %1, [%0] 0x3" : : "r" (addr), "r" (entry&0x7f));
+  __asm__ __volatile__("stba %1, [%0] %2" : : "r" (addr), "r" (entry&0xff),
+		       "i" (ASI_SEGMAP));
 
   return;
 }
@@ -137,42 +268,37 @@
 {
   register unsigned long entry;
 
-  __asm__ __volatile__("lda [%1] 0x4, %0" : 
+  __asm__ __volatile__("lda [%1] %2, %0" : 
 		       "=r" (entry) :
-		       "r" (addr));
+		       "r" (addr), "i" (ASI_PTE));
   return entry;
 }
 
 extern __inline__ void put_pte(unsigned long addr, unsigned long entry)
 {
-  __asm__ __volatile__("sta %1, [%0] 0x4" : :
+  __asm__ __volatile__("sta %1, [%0] %2" : :
 		       "r" (addr), 
-		       "r" (entry));
+		       "r" (entry), "i" (ASI_PTE));
 
   return;
 }
 
-extern __inline__ void switch_to_context(int context)
-{
-  __asm__ __volatile__("stba %0, [%1] 0x2" : :
-		       "r" (context),
-		       "r" (0x30000000));		       
-
-  return;
-}
+extern void (*switch_to_context)(int);
 
 extern __inline__ int get_context(void)
 {
   register int ctx;
 
-  __asm__ __volatile__("lduba [%1] 0x2, %0" :
+  __asm__ __volatile__("lduba [%1] %2, %0" :
 		       "=r" (ctx) :
-		       "r" (0x30000000));
+		       "r" (AC_CONTEXT), "i" (ASI_CONTROL));
 
   return ctx;
 }
 
 typedef unsigned short mem_map_t;
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v1.3.3/linux/include/asm-sparc/pgtable.h	Wed Mar  1 09:12:33 1995
+++ linux/include/asm-sparc/pgtable.h	Mon Jun 12 02:55:37 1995
@@ -7,76 +7,73 @@
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define PMD_SHIFT       18
-#define PMD_SIZE        (1UL << PMD_SHIFT)
-#define PMD_MASK        (~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT       18
-#define PGDIR_SIZE        (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK        (~(PGDIR_SIZE-1))
-#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&PGDIR_MASK)
+#include <linux/mm.h>
+#include <asm/asi.h>
+#include <asm/pgtsun4c.h>
+#include <asm/pgtsrmmu.h>
+
+extern void load_mmu(void);
+
+extern unsigned int pmd_shift;
+extern unsigned int pmd_size;
+extern unsigned int pmd_mask;
+extern unsigned int (*pmd_align)(unsigned int);
+
+extern unsigned int pgdir_shift;
+extern unsigned int pgdir_size;
+extern unsigned int pgdir_mask;
+extern unsigned int (*pgdir_align)(unsigned int);
+
+extern unsigned int ptrs_per_pte;
+extern unsigned int ptrs_per_pmd;
+extern unsigned int ptrs_per_pgd;
+
+extern unsigned int ptrs_per_page;
+
+extern unsigned long (*(vmalloc_start))(void);
+
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_START vmalloc_start()
+
+extern pgprot_t page_none;
+extern pgprot_t page_shared;
+extern pgprot_t page_copy;
+extern pgprot_t page_readonly;
+extern pgprot_t page_kernel;
+extern pgprot_t page_invalid;
+
+#define PMD_SHIFT      (pmd_shift)
+#define PMD_SIZE       (pmd_size)
+#define PMD_MASK       (pmd_mask)
+#define PMD_ALIGN      (pmd_align)
+#define PGDIR_SHIFT    (pgdir_shift)
+#define PGDIR_SIZE     (pgdir_size)
+#define PGDIR_MASK     (pgdir_mask)
+#define PGDIR_ALIGN    (pgdir_align)
+#define PTRS_PER_PTE   (ptrs_per_pte)
+#define PTRS_PER_PMD   (ptrs_per_pmd)
+#define PTRS_PER_PGD   (ptrs_per_pgd)
+
+#define PAGE_NONE      (page_none)
+#define PAGE_SHARED    (page_shared)
+#define PAGE_COPY      (page_copy)
+#define PAGE_READONLY  (page_readonly)
+#define PAGE_KERNEL    (page_kernel)
+#define PAGE_INVALID   (page_invalid)
 
-/*
- * Just following the i386 lead, because it works on the Sparc sun4c
- * machines.  Two-level, therefore there is no real PMD.
+/* Top-level page directory */
+extern pgd_t swapper_pg_dir[1024];
+
+/* Page table for 0-4MB for everybody, on the Sparc this
+ * holds the same as on the i386.
  */
+extern unsigned long pg0[1024];
 
-#define PTRS_PER_PTE    1024
-#define PTRS_PER_PMD    1
-#define PTRS_PER_PGD    1024
+extern unsigned long ptr_in_current_pgd;
 
 /* the no. of pointers that fit on a page: this will go away */
 #define PTRS_PER_PAGE   (PAGE_SIZE/sizeof(void*))
 
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_OFFSET  (8*1024*1024)
-#define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
-
-/*
- * Sparc page table fields.
- */
-
-#define _PAGE_VALID     0x80000000   /* valid page */
-#define _PAGE_WRITE     0x40000000   /* can be written to */
-#define _PAGE_PRIV      0x20000000   /* bit to signify privileged page */
-#define _PAGE_NOCACHE   0x10000000   /* non-cacheable page */
-#define _PAGE_REF       0x02000000   /* Page has been accessed/referenced */
-#define _PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
-#define _PAGE_COW       0x00800000   /* COW page, hardware ignores this bit (untested) */
-
-
-/* Sparc sun4c mmu has only a writable bit. Thus if a page is valid it can be
- * read in a load, and executed as code automatically. Although, the memory fault
- * hardware does make a distinction between date-read faults and insn-read faults
- * which is determined by which trap happened plus magic sync/async fault register
- * values which must be checked in the actual fault handler.
- */
-
-/* We want the swapper not to swap out page tables, thus dirty and writable
- * so that the kernel can change the entries as needed. Also valid for
- * obvious reasons.
- */
-#define _PAGE_TABLE     (_PAGE_VALID | _PAGE_WRITE | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_REF | _PAGE_DIRTY)
-
-#define PAGE_NONE       __pgprot(_PAGE_VALID | _PAGE_REF)
-#define PAGE_SHARED     __pgprot(_PAGE_VALID | _PAGE_WRITE | _PAGE_REF)
-#define PAGE_COPY       __pgprot(_PAGE_VALID | _PAGE_REF | _PAGE_COW)
-#define PAGE_READONLY   __pgprot(_PAGE_VALID | _PAGE_REF)
-#define PAGE_KERNEL     __pgprot(_PAGE_VALID | _PAGE_WRITE | _PAGE_NOCACHE | _PAGE_REF | _PAGE_PRIV)
-#define PAGE_INVALID    __pgprot(_PAGE_PRIV)
-
-#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | _PAGE_REF | (x))
-
 /* I define these like the i386 does because the check for text or data fault
  * is done at trap time by the low level handler. Maybe I can set these bits
  * then once determined. I leave them like this for now though.
@@ -99,8 +96,39 @@
 #define __S110	PAGE_SHARED
 #define __S111	PAGE_SHARED
 
+/* Contexts on the Sparc. */
+#define MAX_CTXS 256
+#define NO_CTX   0xffff     /* In tss.context means task has no context currently */
+extern struct task_struct * ctx_tasks[MAX_CTXS];
+extern int ctx_tasks_last_frd;
+
+extern int num_contexts;
+
+/* This routine allocates a new context.  And 'p' must not be 'current'! */
+extern inline int alloc_mmu_ctx(struct task_struct *p)
+{
+	int i;
+
+	for(i=0; i<num_contexts; i++)
+		if(ctx_tasks[i] == NULL) break;
+
+	if(i<num_contexts) {
+		p->tss.context = i;
+		ctx_tasks[i] = p;
+		return i;
+	}
 
-extern unsigned long pg0[1024];
+	/* Have to free one up */
+	ctx_tasks_last_frd++;
+	if(ctx_tasks_last_frd >= num_contexts) ctx_tasks_last_frd=0;
+	/* Right here is where we invalidate the user mappings that were
+	 * present.  TODO
+	 */
+        ctx_tasks[ctx_tasks_last_frd]->tss.context = NO_CTX;
+	ctx_tasks[ctx_tasks_last_frd] = p;
+	p->tss.context = ctx_tasks_last_frd;
+	return ctx_tasks_last_frd;
+}
 
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
@@ -120,7 +148,7 @@
 #define ZERO_PAGE __zero_page()
 
 /* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR      (8*sizeof(unsigned long))   /* better check this stuff */
+#define BITS_PER_PTR      (8*sizeof(unsigned long))
 
 /* to align the pointer to a pointer address */
 #define PTR_MASK          (~(sizeof(void*)-1))
@@ -128,6 +156,9 @@
 
 #define SIZEOF_PTR_LOG2   2
 
+extern unsigned long (*pte_page)(pte_t);
+extern unsigned long (*pmd_page)(pmd_t);
+extern unsigned long (*pgd_page)(pgd_t);
 
 /* to set the page-dir
  *
@@ -135,208 +166,187 @@
  * Therefore there is no global idea of 'the' page directory, although we
  * make a virtual one in kernel memory so that we can keep the stats on
  * all the pages since not all can be loaded at once in the mmu.
+ *
+ * Actually on the SRMMU things do work exactly like the i386, the
+ * page tables live in real physical ram, no funky TLB buisness.  But
+ * we have to do lots of flushing. And we have to update the root level
+ * page table pointer for this process if it has a context.
  */
 
-#define SET_PAGE_DIR(tsk,pgdir)
+extern void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
 
+#define SET_PAGE_DIR(tsk,pgdir) \
+do { sparc_update_rootmmu_dir(tsk, pgdir); } while (0)
+       
 /* to find an entry in a page-table */
 #define PAGE_PTR(address) \
 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
 extern unsigned long high_memory;
 
-extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] > 1; }
-extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-extern inline void pte_reuse(pte_t *ptep)
-{
-  if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
-    mem_map[MAP_NR(ptep)]++;
-}
-
-extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
-extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
-extern inline int pmd_inuse(pmd_t *pmdp)        { return 0; }
-extern inline void pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)      { }
-
-extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
-extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
-extern inline int pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] > 1; }
-extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
-extern inline void pgd_reuse(pgd_t *pgdp)
-{
-  if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
-    mem_map[MAP_NR(pgdp)]++;
-}
+extern int (*pte_none)(pte_t);
+extern int (*pte_present)(pte_t);
+extern int (*pte_inuse)(pte_t *);
+extern void (*pte_clear)(pte_t *);
+extern void (*pte_reuse)(pte_t *);
+
+extern int (*pmd_none)(pmd_t);
+extern int (*pmd_bad)(pmd_t);
+extern int (*pmd_present)(pmd_t);
+extern int (*pmd_inuse)(pmd_t *);
+extern void (*pmd_clear)(pmd_t *);
+extern void (*pmd_reuse)(pmd_t *);
+
+extern int (*pgd_none)(pgd_t);
+extern int (*pgd_bad)(pgd_t);
+extern int (*pgd_present)(pgd_t);
+extern int (*pgd_inuse)(pgd_t *);
+extern void (*pgd_clear)(pgd_t *);
+extern void (*pgd_reuse)(pgd_t *);
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_WRITE; }
-extern inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_REF; }
-extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_REF; }
-extern inline int pte_cow(pte_t pte)		{ return pte_val(pte) & _PAGE_COW; }
-
-extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_WRITE; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_VALID; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_VALID; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_REF; return pte; }
-extern inline pte_t pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_PAGE_COW; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _PAGE_WRITE; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) |= _PAGE_VALID; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) |= _PAGE_VALID; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_REF; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
+extern int (*pte_read)(pte_t);
+extern int (*pte_write)(pte_t);
+extern int (*pte_exec)(pte_t);
+extern int (*pte_dirty)(pte_t);
+extern int (*pte_young)(pte_t);
+extern int (*pte_cow)(pte_t);
+
+extern pte_t (*pte_wrprotect)(pte_t);
+extern pte_t (*pte_rdprotect)(pte_t);
+extern pte_t (*pte_exprotect)(pte_t);
+extern pte_t (*pte_mkclean)(pte_t);
+extern pte_t (*pte_mkold)(pte_t);
+extern pte_t (*pte_uncow)(pte_t);
+extern pte_t (*pte_mkwrite)(pte_t);
+extern pte_t (*pte_mkread)(pte_t);
+extern pte_t (*pte_mkexec)(pte_t);
+extern pte_t (*pte_mkdirty)(pte_t);
+extern pte_t (*pte_mkyoung)(pte_t);
+extern pte_t (*pte_mkcow)(pte_t);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline unsigned long pte_page(pte_t pte)	{ return pte_val(pte) & PAGE_MASK; }
+extern pte_t (*mk_pte)(unsigned long, pgprot_t);
 
-extern inline unsigned long pmd_page(pmd_t pmd) { return pmd_val(pmd) & PAGE_MASK; }
+extern void (*pgd_set)(pgd_t *, pte_t *);
 
-extern inline unsigned long pgd_page(pgd_t pgd)	{ return pgd_val(pgd) & PAGE_MASK; }
-
-extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
-{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
-
-/* to find an entry in a page-table-directory */
-#define PAGE_DIR_OFFSET(tsk,address) \
-((((unsigned long)(address)) >> 22) + (pgd_t *) (tsk)->tss.cr3)
+extern pte_t (*pte_modify)(pte_t, pgprot_t);
 
 /* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct task_struct * tsk, unsigned long address)
-{
-	return (pgd_t *) tsk->tss.cr3 + (address >> PGDIR_SHIFT);
-}
+extern pgd_t * (*pgd_offset)(struct task_struct *, unsigned long);
 
 /* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
-{
-	return (pmd_t *) dir;
-}
+extern pmd_t * (*pmd_offset)(pgd_t *, unsigned long);
 
 /* Find an entry in the third-level page table.. */ 
-extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
-	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
-
+extern pte_t * (*pte_offset)(pmd_t *, unsigned long);
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
-extern inline void pte_free_kernel(pte_t * pte)
-{
-	mem_map[MAP_NR(pte)] = 1;
-	free_page((unsigned long) pte);
-}
+extern void (*pte_free_kernel)(pte_t *);
 
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
-				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
-				return page + address;
-			}
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
+extern pte_t * (*pte_alloc_kernel)(pmd_t *, unsigned long);
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-extern inline void pmd_free_kernel(pmd_t * pmd)
-{
-}
+extern void (*pmd_free_kernel)(pmd_t *);
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
-{
-	return (pmd_t *) pgd;
-}
+extern pmd_t * (*pmd_alloc_kernel)(pgd_t *, unsigned long);
 
-extern inline void pte_free(pte_t * pte)
-{
-	free_page((unsigned long) pte);
-}
+extern void (*pte_free)(pte_t *);
 
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
-				return page + address;
-			}
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
+extern pte_t * (*pte_alloc)(pmd_t *, unsigned long);
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-extern inline void pmd_free(pmd_t * pmd)
-{
-}
+extern void (*pmd_free)(pmd_t *);
+
+extern pmd_t * (*pmd_alloc)(pgd_t *, unsigned long);
+
+extern void (*pgd_free)(pgd_t *);
 
-extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+/* A page directory on the sun4c needs 16k, thus we request an order of
+ * two.
+ *
+ * I need 16k for a sun4c page table, so I use kmalloc since kmalloc_init()
+ * is called before pgd_alloc ever is (I think).
+ */
+
+extern pgd_t * (*pgd_alloc)(void);
+
+extern int invalid_segment;
+
+/* Sun4c specific routines.  They can stay inlined. */
+extern inline int alloc_sun4c_pseg(void)
 {
-	return (pmd_t *) pgd;
+	int oldseg, i;
+	/* First see if any are free already */
+	for(i=0; i<PSEG_ENTRIES; i++)
+		if(phys_seg_map[i]==PSEG_AVL) return i;
+
+	/* Uh-oh, gotta unallocate a TLB pseg */
+	oldseg=0;
+	for(i=0; i<PSEG_ENTRIES; i++) {
+		/* Can not touch PSEG_KERNEL and PSEG_RSV segmaps */
+		if(phys_seg_map[i]!=PSEG_USED) continue;
+		/* Ok, take a look at it's lifespan */
+		oldseg = (phys_seg_life[i]>oldseg) ? phys_seg_life[i] : oldseg;
+	}
+	phys_seg_life[oldseg]=PSEG_BORN;
+	return oldseg;
 }
 
-extern inline void pgd_free(pgd_t *pgd)
+/* Age all psegs except pseg_skip */
+extern inline void age_sun4c_psegs(int pseg_skip)
 {
-  free_page((unsigned long) pgd);
+	int i;
+
+	for(i=0; i<pseg_skip; i++) phys_seg_life[i]++;
+	i++;
+	while(i<PSEG_ENTRIES) phys_seg_life[i++]++;
+	return;
 }
-extern inline pgd_t *pgd_alloc(void)
+
+/*
+ * This is only ever called when the sun4c page fault routines run
+ * so we can keep this here as the srmmu code will never get to it.
+ */
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+	unsigned long address, pte_t pte)
 {
-  return (pgd_t *) get_free_page(GFP_KERNEL);
-}
+  unsigned long clr_addr;
+  int segmap;
 
-extern pgd_t swapper_pg_dir[1024];
+  segmap = (int) get_segmap(address & SUN4C_REAL_PGDIR_MASK);
+  if(segmap == invalid_segment) {
+    segmap = alloc_sun4c_pseg();
+    put_segmap((address & SUN4C_REAL_PGDIR_MASK), segmap);
+    phys_seg_map[segmap] = PSEG_USED;
+
+    /* We got a segmap, clear all the pte's in it. */
+    for(clr_addr=(address&SUN4C_REAL_PGDIR_MASK); clr_addr<((address&SUN4C_REAL_PGDIR_MASK) + SUN4C_REAL_PGDIR_SIZE); 
+	clr_addr+=PAGE_SIZE)
+	    put_pte(clr_addr, 0);
+  }
+
+  /* Do aging */
+  age_sun4c_psegs(segmap);
+  put_pte((address & PAGE_MASK), pte_val(pte));
+  return;
+
+}
 
 #endif /* !(_SPARC_PGTABLE_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/pgtsfmmu.h linux/include/asm-sparc/pgtsfmmu.h
--- v1.3.3/linux/include/asm-sparc/pgtsfmmu.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/pgtsfmmu.h	Sat Jun 17 08:25:16 1995
@@ -0,0 +1,29 @@
+/* pgtsfmmu.h:  Spitfire V9 MMU support goes here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_PGTSFMMU_H
+#define _SPARC_PGTSFMMU_H
+
+/* Spitfire is four-level.... I think... It also has a seperate TLB for
+ * data and instruction mappings.
+ */
+#define SFMMU_PMD_SHIFT       16
+#define SFMMU_PMD_SIZE        (1UL << SFMMU_PMD_SHIFT)
+#define SFMMU_PMD_MASK        (~(SFMMU_PMD_SIZE-1))
+#define SFMMU_PMD_ALIGN(addr) (((addr)+SFMMU_PMD_SIZE-1)&SFMMU_PMD_MASK)
+
+#define SFMMU_PGDIR_SHIFT     19
+#define SFMMU_PGDIR_SIZE        (1UL << SFMMU_PGDIR_SHIFT)
+#define SFMMU_PGDIR_MASK        (~(SFMMU_PGDIR_SIZE-1))
+#define SFMMU_PGDIR_ALIGN(addr) (((addr)+SFMMU_PGDIR_SIZE-1)&SFMMU_PGDIR_MASK)
+
+#define SFMMU_PGMAP_SHIFT     22
+#define SFMMU_PGDIR_SIZE        (1UL << SFMMU_PGDIR_SHIFT)
+#define SFMMU_PGDIR_MASK        (~(SFMMU_PGDIR_SIZE-1))
+#define SFMMU_PGDIR_ALIGN(addr) (((addr)+SFMMU_PGDIR_SIZE-1)&SFMMU_PGDIR_MASK)
+
+
+#endif /* !(_SPARC_PGTSFMMU_H) */
+
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/pgtsrmmu.h linux/include/asm-sparc/pgtsrmmu.h
--- v1.3.3/linux/include/asm-sparc/pgtsrmmu.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/pgtsrmmu.h	Sat Jun 24 12:27:58 1995
@@ -0,0 +1,424 @@
+/* pgtsrmmu.h:  SRMMU page table defines and code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/page.h>  /* just in case */
+
+#ifndef _SPARC_PGTSRMMU_H
+#define _SPARC_PGTSRMMU_H
+
+#define SRMMU_PAGE_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PMD_TABLE_SIZE  0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PGD_TABLE_SIZE  0x400 /* 256 entries, 4 bytes a piece */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define SRMMU_PMD_SHIFT       18
+#define SRMMU_PMD_SIZE        (1UL << SRMMU_PMD_SHIFT)
+#define SRMMU_PMD_MASK        (~(SRMMU_PMD_SIZE-1))
+#define SRMMU_PMD_ALIGN(addr) (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define SRMMU_PGDIR_SHIFT       24
+#define SRMMU_PGDIR_SIZE        (1UL << SRMMU_PGDIR_SHIFT)
+#define SRMMU_PGDIR_MASK        (~(SRMMU_PGDIR_SIZE-1))
+#define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK)
+
+/*
+ * Three-level on SRMMU.
+ */
+
+#define SRMMU_PTRS_PER_PTE    64
+#define SRMMU_PTRS_PER_PMD    64
+#define SRMMU_PTRS_PER_PGD    256
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define SRMMU_VMALLOC_OFFSET  (8*1024*1024)
+#define SRMMU_VMALLOC_START ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1))
+
+/*
+ * Sparc SRMMU page table fields.
+ */
+
+#define _SRMMU_PAGE_VALID      (SRMMU_ET_PTE)
+#define _SRMMU_PMD_VALID       (SRMMU_ET_PTD)
+#define _SRMMU_PGD_VALID       (SRMMU_ET_PTD)
+#define _SRMMU_PAGE_WRITE_USR  (SRMMU_ACC_US_RDWR)
+#define _SRMMU_PAGE_WRITE_KERN (SRMMU_ACC_S_RDWR)
+#define _SRMMU_PAGE_EXEC       (SRMMU_ACC_US_RDEXEC)
+#define _SRMMU_PAGE_RDONLY     (SRMMU_ACC_US_RDONLY)
+#define _SRMMU_PAGE_NOREAD     (SRMMU_ACC_U_ACCDENIED)
+#define _SRMMU_PAGE_NOCACHE    (~SRMMU_PTE_C_MASK)
+#define _SRMMU_PAGE_PRIV       (SRMMU_ACC_S_RDWREXEC)
+#define _SRMMU_PAGE_REF        (SRMMU_PTE_R_MASK)
+#define _SRMMU_PAGE_DIRTY      (SRMMU_PTE_M_MASK)
+#define _SRMMU_PAGE_COW        (SRMMU_ACC_U_RDONLY)
+#define _SRMMU_PAGE_UNCOW      (SRMMU_ACC_US_RDWR)
+
+/* We want the swapper not to swap out page tables, thus dirty and writable
+ * so that the kernel can change the entries as needed. Also valid for
+ * obvious reasons.
+ */
+#define _SRMMU_PAGE_TABLE     (_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_KERN | _SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY)
+#define _SRMMU_PAGE_CHG_MASK  (_SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY | SRMMU_ET_PTE)
+#define _SRMMU_PMD_CHG_MASK   (SRMMU_ET_PTD)
+#define _SRMMU_PGD_CHG_MASK   (SRMMU_ET_PTD)
+
+#define SRMMU_PAGE_NONE       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF)
+#define SRMMU_PAGE_SHARED     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_USR | _SRMMU_PAGE_REF)
+#define SRMMU_PAGE_COPY       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | _SRMMU_PAGE_COW)
+#define SRMMU_PAGE_READONLY   __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | SRMMU_ACC_US_RDONLY)
+#define SRMMU_PAGE_KERNEL     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_PRIV | SRMMU_PTE_C_MASK)
+#define SRMMU_PAGE_INVALID    __pgprot(SRMMU_ET_INVALID)
+
+#define _SRMMU_PAGE_NORMAL(x) __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | (x))
+
+/* SRMMU Register addresses */
+#define SRMMU_CTRL_REG           0x00000000
+#define SRMMU_CTXTBL_PTR         0x00000100
+#define SRMMU_CTX_REG            0x00000200
+#define SRMMU_FAULT_STATUS       0x00000300
+#define SRMMU_FAULT_ADDR         0x00000400
+#define SRMMU_AFAULT_STATUS      0x00000500
+#define SRMMU_AFAULT_ADDR        0x00000600
+
+/* The SRMMU control register fields:
+ * -------------------------------------------------------------------
+ * | IMPL  |  VERS  |    SysControl | PSO | Resv | No Fault | Enable |
+ * -------------------------------------------------------------------
+ * 31    28 27    24 23            8   7    6   2      1        0
+ *
+ * IMPL:  Indicates the implementation of this SRMMU, read-only.
+ * VERS:  The version of this implementation, again read-only.
+ * SysControl:  This is an implementation specific field, the SRMMU
+ *              specification does not define anything for this field.
+ * PSO: This determines whether the memory model as seen by the CPU
+ *      is Partial Store Order (PSO=1) or Total Store Ordering (PSO=0).
+ * Resv: Don't touch these bits ;)
+ * No Fault: If zero, any fault acts as expected where the fault status
+ *           and address registers are updated and a trap hits the CPU.
+ *           When this bit is one, on any fault other than in ASI 9, the
+ *           MMU updates the status and address fault registers but does
+ *           not signal the CPU with a trap.  This is useful to beat
+ *           race conditions in low-level code when we have to throw
+ *           a register window onto the stack in a spill/fill handler
+ *           on multiprocessors.
+ * Enable: If one the MMU is doing translations, if zero the addresses
+ *         given to the bus are pure physical.
+ */
+
+#define SRMMU_CTREG_IMPL_MASK        0xf0000000
+#define SRMMU_CTREG_IMPL_SHIFT       28
+#define SRMMU_CTREG_VERS_MASK        0x0f000000
+#define SRMMU_CTREG_VERS_SHIFT       24
+#define SRMMU_CTREG_SYSCNTRL_MASK    0x00ffff00
+#define SRMMU_CTREG_SYSCNTRL_SHIFT   8
+#define SRMMU_CTREG_PSO_MASK         0x00000080
+#define SRMMU_CTREG_PSO_SHIFT        7
+#define SRMMU_CTREG_RESV_MASK        0x0000007c
+#define SRMMU_CTREG_RESV_SHIFT       2
+#define SRMMU_CTREG_NOFAULT_MASK     0x00000002
+#define SRMMU_CTREG_NOFAULT_SHIFT    1
+#define SRMMU_CTREG_ENABLE_MASK      0x00000001
+#define SRMMU_CTREG_ENABLE_SHIFT     0
+
+/* Get the MMU control register */
+extern inline unsigned int srmmu_get_mmureg(void)
+{
+        register unsigned int retval;
+	__asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
+			     "=r" (retval) :
+			     "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+/* Set the MMU control register */
+extern inline void srmmu_set_mmureg(unsigned long regval)
+{
+	__asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
+			     "r" (regval), "i" (ASI_M_MMUREGS) : "memory");
+
+	return;
+}
+
+/* The SRMMU Context Table Pointer Register:
+ * ---------------------------------
+ * |  Context Table Pointer | Resv |
+ * ---------------------------------
+ * 31                      2 1    0
+ *
+ * This is where the MMU goes to in physical RAM to fetch the
+ * elements in the context table.  The non-Resv bits of this
+ * address appear in bits 6-35 of the physical bus during miss
+ * processing, then indexed by the value in the Context Register.
+ * This table must be aligned on a boundary equal to the size of
+ * the table, we provide a nice macro for doing this based upon
+ * the significant bits in the context register.
+ */
+#define SRMMU_CTP_ADDR_MASK          0xfffffffc
+#define SRMMU_CTP_ADDR_PADDR_SHIFT   0x4
+#define SRMMU_CTP_RESV_MASK          0x00000003
+
+#define SRMMU_SIGBITS_TO_ALIGNMENT(numbits)  ((1 << (numbits + 2)))
+
+
+/* Set the address of the context table.  You pass this routine
+ * the physical address, we do the magic shifting for you.
+ */
+extern inline void srmmu_set_ctable_ptr(unsigned long paddr)
+{
+	unsigned long ctp;
+
+	ctp = (paddr >> SRMMU_CTP_ADDR_PADDR_SHIFT);
+	ctp &= SRMMU_CTP_ADDR_MASK;
+
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (ctp), "r" (SRMMU_CTXTBL_PTR),
+			     "i" (ASI_M_MMUREGS) :
+			     "memory");
+	return;
+}
+
+
+/* Get the address of the context table.  We return the physical
+ * address of the table, again we do the shifting here.
+ */
+extern inline unsigned long srmmu_get_ctable_ptr(void)
+{
+	register unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (SRMMU_CTXTBL_PTR),
+			     "i" (ASI_M_MMUREGS));
+
+	retval &= SRMMU_CTP_ADDR_MASK;
+	retval = (retval << SRMMU_CTP_ADDR_PADDR_SHIFT);
+	return retval;
+}
+
+/* Set the context on an SRMMU */
+extern inline void srmmu_set_context(int context)
+{
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (context), "r" (SRMMU_CTX_REG),
+			     "i" (ASI_M_MMUREGS) : "memory");
+	return;
+}
+
+/* Get the context on an SRMMU */
+extern inline int srmmu_get_context(void)
+{
+	register int retval;
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (SRMMU_CTX_REG),
+			     "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+/* SRMMU diagnostic register:
+ * --------------------------------------------------------
+ * |   Virtual Address   |   PDC entry   | DiagReg | Resv |
+ * --------------------------------------------------------
+ * 31                  12 11            4 3       2 1    0
+ *
+ * An SRMMU implementation has the choice of providing this register
+ * and I don't know much about it.
+ */
+
+#define SRMMU_DIAG_VADDR_MASK        0xfffff000
+#define SRMMU_DIAG_PDC_MASK          0x00000ff0
+#define SRMMU_DIAG_REG_MASK          0x0000000c
+#define SRMMU_DIAG_RESV_MASK         0x00000003
+
+/* SRMMU Fault Status Register:
+ * -----------------------------------------------------------
+ * | Reserved          | EBE  |  L  |  AT  |  FT  | FAV | OW |
+ * -----------------------------------------------------------
+ *  31               18 17  10  9  8 7    5  4   2   1     0
+ *
+ * WARNING!!! On certain VERY BROKEN Viking Sun4d modules this register
+ * is complete TOAST!  During a fault you cannot trust the values
+ * contained in this register, you must calculate them yourself
+ * by first using the trap program counter to decode the
+ * instruction the code tried to execute (ie. load or store) and
+ * the address they tried to access.  I think the Fault Virtual
+ * Address register may be ok on these chips, but who knows. Grrr.
+ *
+ * Reserved:  These bits must be zero.
+ * EBE: External bus error bits, implementation dependant (at least
+ *      we know what the bits mean on sun4d Viking modules) ;)
+ * L: The level in tree traversal at which the fault occured. The
+ *    values are... 0 = context table
+ *                  1 = level-1 page table
+ *                  2 = level-2 page table
+ *                  3 = level-3 page table
+ * AT: Access type field. This is decoded as follows...
+ *     0 -- Load from user data space
+ *     1 -- Load from supervisor data space
+ *     2 -- Read/Execute from user instruction space
+ *     3 -- Read/Execute from supervisor instruction space
+ *     4 -- Store to user data space
+ *     5 -- Store to supervisor data space
+ *     6 -- Store to user instruction space
+ *     7 -- Store to supervisor instruction space (emacs does this)
+ *     On the Viking --  TOAST!
+ * FT:  This is the fault type field.  It is used to determine what was
+ *      wrong in the attempted translation. It can be one of...
+ *     0 -- None
+ *     1 -- Invalid address error
+ *     2 -- Protection violation error
+ *     3 -- Priviledge violation error
+ *     4 -- Translation error (your tables are fucked up)
+ *     5 -- Bus access error (you lose)
+ *     6 -- Internal error (might as well have a Viking)
+ *     7 -- Reserved (don't touch)
+ * FAV: Fault Address Valid bit.  When set to one the fault address
+ *      register contents are valid.  It need not be valid for text
+ *      faults as the trapped PC tells us this anyway.
+ * OW: The Overwrite Bit, if set to one, this register has been
+ *     written to more than once by the hardware since software did
+ *     a read.  This mean multiple faults have occurred and you have
+ *     to a manual page table tree traversal to continue the handling
+ *     of the first fault. And on the Viking module....
+ *
+ * The Fault Address Register is just a 32-bit register representing the
+ * virtual address which caused the fault.  It's validity is determined
+ * by the following equation:
+ * if(module==VIKING || FSR.FAV==0) forget_it();
+ * It's ok for the FAV to be invalid for a text fault because we can
+ * use the trapped program counter, however for a data fault we are SOL.
+ * I'll probably have to write a workaround for this situation too ;-(
+ */
+
+#define SRMMU_FSR_RESV_MASK      0xfffc0000  /* Reserved bits */
+#define SRMMU_FSR_EBE_MASK       0x0003fc00  /* External Bus Error bits */
+#define SRMMU_FSR_EBE_BERR       0x00000400  /* Bus Error */
+#define SRMMU_FSR_EBE_BTIMEO     0x00000800  /* Bus Time Out */
+#define SRMMU_FSR_EBE_UNCOR      0x00001000  /* Uncorrectable Error */
+#define SRMMU_FSR_EBE_UNDEF      0x00002000  /* Undefined Error */
+#define SRMMU_FSR_EBE_PARITY     0x00004000  /* Parity error */
+#define SRMMU_FSR_EBE_TPARITY    0x00006000  /* Tsunami parity error */
+#define SRMMU_FSR_EBE_SBUF       0x00008000  /* Store Buffer error */
+#define SRMMU_FSR_EBE_CSA        0x00010000  /* Control space access error (bad ASI) */
+#define SRMMU_FSR_EBE_EMRT       0x00020000  /* Viking Emergency Response Team */
+#define SRMMU_FSR_L_MASK         0x00000300  /* Fault level bits */
+#define SRMMU_FSR_L_CTABLE       0x00000000  /* Context table level flt/err */
+#define SRMMU_FSR_L_ONE          0x00000100  /* Level1 ptable flt/err */
+#define SRMMU_FSR_L_TWO          0x00000200  /* Level2 ptable flt/err */
+#define SRMMU_FSR_L_THREE        0x00000300  /* Level3 ptable flt/err */
+#define SRMMU_FSR_AT_MASK        0x000000e0  /* Access Type bits */
+#define SRMMU_FSR_AT_LUD         0x00000000  /* Load from User Data space */
+#define SRMMU_FSR_AT_LSD         0x00000020  /* What I'll need after writing this code */
+#define SRMMU_FSR_AT_RXUI        0x00000040  /* Read/Execute from user text */
+#define SRMMU_FSR_AT_RXSI        0x00000060  /* Read/Execute from supv text */
+#define SRMMU_FSR_AT_SUD         0x00000080  /* Store to user data space */
+#define SRMMU_FSR_AT_SSD         0x000000a0  /* Store to supv data space */
+#define SRMMU_FSR_AT_SUI         0x000000c0  /* Store to user text */
+#define SRMMU_FSR_AT_SSI         0x000000e0  /* Store to supv text */
+#define SRMMU_FSR_FT_MASK        0x0000001c  /* Fault Type bits */
+#define SRMMU_FSR_FT_NONE        0x00000000  /* No fault occurred */
+#define SRMMU_FSR_FT_IADDR       0x00000002  /* Invalid address */
+#define SRMMU_FSR_FT_PROT        0x00000004  /* Protection violation */
+#define SRMMU_FSR_FT_PRIV        0x00000008  /* Privilege violation */
+#define SRMMU_FSR_FT_TRANS       0x0000000a  /* Translation error */
+#define SRMMU_FSR_FT_BACC        0x0000000c  /* Bus Access error */
+#define SRMMU_FSR_FT_IACC        0x0000000e  /* Internal error */
+#define SRMMU_FSR_FT_RESV        0x00000010  /* Reserved, should not get this */
+#define SRMMU_FSR_FAV_MASK       0x00000002  /* Fault Address Valid bits */
+#define SRMMU_FSR_OW_MASK        0x00000001  /* SFSR OverWritten bits */
+
+/* Read the Fault Status Register on the SRMMU */
+extern inline unsigned int srmmu_get_fstatus(void)
+{
+	register unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+/* Read the Fault Address Register on the SRMMU */
+extern inline unsigned int srmmu_get_faddr(void)
+{
+	register unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (SRMMU_FAULT_ADDR), "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+/* SRMMU Asynchronous Fault Status Register:
+ * -----------------------------------------
+ * |  RESERVED |UCE|BTO|BERR|RSV|HFADDR|AFO|
+ * -----------------------------------------
+ *  31       13  12  11  10  9-8  7-4     0
+ *
+ * UCE: UnCorrectable Error
+ * BTO: Bus TimeOut
+ * BERR: Genreic Bus Error
+ * HFADDR: High 4 bits of the faulting address
+ * AFO: Asynchronous Fault Occurred
+ */
+#define SRMMU_AFSR_RESVMASK  0xffffe000
+#define SRMMU_AFSR_UCE       0x00001000
+#define SRMMU_AFSR_BTO       0x00000800
+#define SRMMU_AFSR_BERR      0x00000400
+#define SRMMU_AFSR_HFADDR    0x000000f0
+#define SRMMU_AFSR_AFO       0x00000001
+
+/* Read the asynchronous fault register */
+extern inline unsigned int srmmu_get_afstatus(void)
+{
+	register unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (SRMMU_AFAULT_STATUS), "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+/* Read the Asynchronous Fault Address Register on the SRMMU */
+extern inline unsigned int srmmu_get_afaddr(void)
+{
+	register unsigned int retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (SRMMU_AFAULT_ADDR), "i" (ASI_M_MMUREGS));
+	return retval;
+}
+
+
+/* Flush the entire TLB cache on the SRMMU. */
+extern inline void srmmu_flush_whole_tlb(void)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (0x400),        /* Flush entire TLB!! */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+	return;
+}
+
+/* Probe for an entry in the page-tables of the SRMMU. */
+extern inline unsigned long srmmu_hwprobe(unsigned long vaddr)
+{
+	unsigned long retval;
+
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (retval) :
+			     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
+
+	return retval;
+}
+
+#endif /* !(_SPARC_PGTSRMMU_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/pgtsun4.h linux/include/asm-sparc/pgtsun4.h
--- v1.3.3/linux/include/asm-sparc/pgtsun4.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/pgtsun4.h	Sat Jun 17 08:18:46 1995
@@ -0,0 +1,9 @@
+/* pgtsun4.c:  Regular Sun4 MMU support goes in here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_PGTSUN4_H
+#define _SPARC_PGTSUN4_H
+
+#endif /* !(_SPARC_PGTSUN4_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h
--- v1.3.3/linux/include/asm-sparc/pgtsun4c.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/pgtsun4c.h	Thu Jun  8 23:46:31 1995
@@ -0,0 +1,125 @@
+/* pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_PGTSUN4C_H
+#define _SPARC_PGTSUN4C_H
+
+#define SUN4C_PAGE_TABLE_SIZE 0x100   /* 64 entries, 4 bytes a piece */
+
+/* NOTE:  Now we put the free page pool and the page structures
+ *        up in high memory above the kernel image which itself
+ *        starts at KERNBASE.  Also note PAGE_OFFSET in page.h
+ *        This is just like what Linus does on the ALPHA.
+ */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define SUN4C_PMD_SHIFT       22
+#define SUN4C_PMD_SIZE        (1UL << SUN4C_PMD_SHIFT)
+#define SUN4C_PMD_MASK        (~(SUN4C_PMD_SIZE-1))
+#define SUN4C_PMD_ALIGN(addr) (((addr)+SUN4C_PMD_SIZE-1)&SUN4C_PMD_MASK)
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define SUN4C_PGDIR_SHIFT       22
+#define SUN4C_PGDIR_SIZE        (1UL << SUN4C_PGDIR_SHIFT)
+#define SUN4C_PGDIR_MASK        (~(SUN4C_PGDIR_SIZE-1))
+#define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK)
+
+/* To make sun4c_paging_init() happy, I provide the following macros. */
+#define SUN4C_REAL_PGDIR_SHIFT  18
+#define SUN4C_REAL_PGDIR_SIZE        (1UL << SUN4C_REAL_PGDIR_SHIFT)
+#define SUN4C_REAL_PGDIR_MASK        (~(SUN4C_REAL_PGDIR_SIZE-1))
+#define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK)
+
+/*
+ * To be efficient, and not have to worry about allocating such
+ * a huge pgd, we make the kernel sun4c tables each hold 1024
+ * entries and the pgd similarly.
+ */
+
+#define SUN4C_PTRS_PER_PTE    1024
+#define SUN4C_PTRS_PER_PMD    1
+#define SUN4C_PTRS_PER_PGD    1024
+
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define SUN4C_VMALLOC_OFFSET  (8*1024*1024)
+#define SUN4C_VMALLOC_START ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1))
+
+/*
+ * Sparc SUN4C page table fields. (for now, basically the same as the i386)
+ */
+
+#define _SUN4C_PAGE_VALID     0x80000000   /* valid page */
+#define _SUN4C_PAGE_WRITE     0x40000000   /* can be written to */
+#define _SUN4C_PAGE_USER      0x00000000   /* User page */
+#define _SUN4C_PAGE_NOCACHE   0x10000000   /* non-cacheable page */
+#define _SUN4C_PAGE_PRIV      0x20000000   /* bit to signify privileged page */
+#define _SUN4C_PAGE_REF       0x02000000   /* Page has been accessed/referenced */
+#define _SUN4C_PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
+#define _SUN4C_PAGE_COW       0x00800000   /* COW page */
+
+/* Sparc sun4c mmu has only a writable bit. Thus if a page is valid it can be
+ * read in a load, and executed as code automatically. Although, the memory 
+ * fault hardware does make a distinction between data-read faults and 
+ * insn-read faults which is determined by which trap happened plus magic
+ * sync/async fault register values which must be checked in the actual
+ * fault handler.
+ */
+
+#define _SUN4C_PFN_MASK       0x0000ffff    /* just the page frame number */
+#define _SUN4C_MMU_MASK       0xffff0000    /* just the non-page pte bits */
+
+/* The following are for pgd/pmd's */
+#define _SUN4C_PGD_PFN_MASK   0x00ffffff    /* bits to hold page tables address */
+#define _SUN4C_PGD_MMU_MASK   0xff000000    /* pgd/pfn protection bits          */
+#define _SUN4C_PGD_PAGE_SHIFT 8             /* bits to shift to obtain address  */
+
+/* We want the swapper not to swap out page tables, thus dirty and writable
+ * so that the kernel can change the entries as needed. Also valid for
+ * obvious reasons.
+ */
+#define _SUN4C_PAGE_TABLE     (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PAGE_PRIV | _SUN4C_PAGE_NOCACHE) /* No cache for now */
+#define _SUN4C_PAGE_CHG_MASK  (_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PFN_MASK)
+#define _SUN4C_PGD_CHG_MASK   (_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PGD_PFN_MASK)
+
+#define SUN4C_PAGE_NONE       __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF)
+#define SUN4C_PAGE_SHARED     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_REF)
+#define SUN4C_PAGE_COPY       __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF | _SUN4C_PAGE_COW)
+#define SUN4C_PAGE_READONLY   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF)
+#define SUN4C_PAGE_KERNEL     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_PRIV | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PAGE_NOCACHE)
+#define SUN4C_PAGE_INVALID    __pgprot(0)
+
+#define _SUN4C_PAGE_NORMAL(x) __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF | (x))
+
+/* The Sun4c mmu physical segment map allocation data structure.
+ * For each physical segmap available on the mmu we have one entry,
+ * 127 on the sun4c (except SparcStation 2's which seem to have 255)
+ * and 512 on the sun4.  Each segmap can be in various stages of
+ * allocation.
+ */
+#define PSEG_ENTRIES  513     /* We allocate 513 entries for simplicity */
+extern unsigned int phys_seg_map[PSEG_ENTRIES];
+extern unsigned int phys_seg_life[PSEG_ENTRIES];
+
+/* for phys_seg_map entries */
+#define PSEG_AVL      0x0     /* Physical segment is available/free */
+#define PSEG_USED     0x1     /* A segmap currently being used */
+#define PSEG_RSV      0x2     /* This segmap is reserved (used for proms addr space) */
+#define PSEG_KERNEL   0x3     /* This is a kernel hard segment, cannot deallocate */
+
+/* for phys_seg_life entries */
+/* The idea is, every call to update_mmu_cache we increment all the life
+ * counters.  When we re-allocate or allocate a physical segment for the
+ * first time we set the phys_seg_life entry to PSEG_BORN.  Also, when we
+ * fill a pte for a segment already loaded we *decrease* the life count
+ * by two for that segment.  We'll see how this works.
+ */
+#define PSEG_BORN     0x00     /* Just allocated */
+
+#endif /* !(_SPARC_PGTSUN4C_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v1.3.3/linux/include/asm-sparc/processor.h	Wed Mar  1 09:12:33 1995
+++ linux/include/asm-sparc/processor.h	Sat Jun 10 08:55:58 1995
@@ -6,10 +6,14 @@
 #ifndef __ASM_SPARC_PROCESSOR_H
 #define __ASM_SPARC_PROCESSOR_H
 
+#include <linux/sched.h>  /* For intr_count */
+
+#include <asm/ptrace.h>   /* For pt_regs declaration */
+
 /*
  * Bus types
  */
-#define EISA_bus 1
+#define EISA_bus 0
 #define EISA_bus__is_a_macro /* for versions in ksyms.c */
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
@@ -17,24 +21,30 @@
 /*
  * Write Protection works right in supervisor mode on the Sparc
  */
-
+#if 0  /* Let's try this out ;) */
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
+#else
+extern char wp_works_ok;
+#endif
 
 /*
  * User space process size: 3GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
  *
- * "this is gonna have to change to 1gig for the sparc" - David S. Miller
+ * With the way identity mapping works on the sun4c, this is the best
+ * value to use.
+ *
+ * This has to be looked into for a unified sun4c/sun4m task size.
  */
-#define TASK_SIZE	(0xC0000000UL)
+#define TASK_SIZE	(0xC000000UL)
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
  */
 #define IO_BITMAP_SIZE	32
 
-/* The first five entries here MUST be the first four. This allows me to
+/* The first four entries here MUST be the first four. This allows me to
  * do %lo(offset) loads and stores in entry.S. See TRAP_WIN_CLEAN to see
  * why.
  */
@@ -43,61 +53,32 @@
 	unsigned long uwindows;       /* how many user windows are in the set */
 	unsigned long wim;            /* user's window invalid mask */
 	unsigned long w_saved;        /* how many windows saved in reg_window[] */
-	unsigned long ksp;          /* kernel stack pointer */
-	unsigned long usp;          /* user's sp, throw reg windows here */
-	unsigned long psr;          /* save for condition codes */
-	unsigned long reg_window[16*24];
-	unsigned long cr3;          /* why changed from ptbr? */
-	unsigned int pcc;
-	unsigned int asn;
-	unsigned long unique;
-	unsigned long flags;
-	unsigned long res1, res2;
-	unsigned long pc;           /* program counter */
-	unsigned long npc;          /* next program counter */
+	unsigned long ksp;            /* kernel stack pointer */
+	unsigned long usp;            /* user's sp, throw reg windows here */
+	unsigned long psr;            /* save for condition codes */
+	unsigned long pc;             /* program counter */
+	unsigned long npc;            /* next program counter */
+	unsigned long yreg;
+	unsigned long align;          /* to get 8-byte alignment  XXX  */
+	unsigned long reg_window[16];
+	unsigned long pgd_ptr;
+	int context;                  /* The context allocated to this thread */
 
 /* 8 local registers + 8 in registers * 24 register windows.
- * Most sparcs I know of only have 8 windows implemented,
+ * Most sparcs I know of only have 7 or 8 windows implemented,
  * we determine how many at boot time and store that value
  * in nwindows.
  */
-	unsigned long globl_regs[8];  /* global regs need to be saved too */
-	unsigned long yreg;
 	unsigned long float_regs[64]; /* V8 and below have 32, V9 has 64 */
 };
 
-#define INIT_MMAP { &init_task, 0x0, 0x40000000, \
-		      PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC }
+#define INIT_MMAP { &init_task, (PAGE_OFFSET), (0xff000000UL), \
+		    0x0 , VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_TSS  { \
-	0, 0, 0, 0, 0, 0, \
-        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
-	0, 0, 0, 0, 0, 0, 0, 0, 0, \
-        { 0, 0, 0, 0, 0, 0, 0, 0, }, \
-        0, \
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+	(long) &swapper_pg_dir, -1,  \
         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
@@ -109,16 +90,14 @@
  * spill if things don't go right (bad user stack pointer). In reality
  * it is not per-process per se, it just sits in the kernel stack while
  * the current process is in a handler then it is basically forgotten
- * about.
+ * about the next time flow control goes back to that process.
  */
 
-struct thread_frame {
-  unsigned int thr_psr;
-  unsigned int thr_pc;
-  unsigned int thr_npc;
-  unsigned int thr_y;
-  unsigned int thr_globals[8];
-  unsigned int thr_outs[8];
+/* Sparc stack save area allocated for each save, not very exciting. */
+struct sparc_save_stack {
+  unsigned int locals[8];
+  unsigned int ins[8];
+  unsigned int padd[8];
 };
 
 /*
@@ -128,28 +107,36 @@
  */
 extern inline void start_bh_atomic(void)
 {
-	unsigned long dummy, psr;
-	__asm__ __volatile__("rd %%psr, %2\n\t"
-			     "wr %2, 0x20, %%psr\n\t"  /* disable traps */
-			     "ld %1,%0\n\t"
-			     "add %0,1,%0\n\t"
-			     "st %0,%1\n\t"
-			     "wr %2, 0x0, %%psr\n\t"   /* enable traps */
-			     : "=r" (dummy), "=m" (intr_count)
-			     : "0" (0), "r" (psr=0));
+	__asm__ __volatile__("rd %%psr, %%g2\n\t"
+			     "wr %%g2, 0x20, %%psr\n\t"  /* disable traps */
+			     "ld %0,%%g3\n\t"
+			     "add %%g3,1,%%g3\n\t"
+			     "st %%g3,%0\n\t"
+			     "wr %%g2, 0x0, %%psr\n\t"   /* enable traps */
+			     : "=m" (intr_count)
+			     : : "g2", "g3", "memory");
 }
 
 extern inline void end_bh_atomic(void)
 {
-	unsigned long dummy, psr;
-	__asm__ __volatile__("rd %%psr, %2\n\t"
-			     "wr %2, 0x20, %%psr\n\t"
-			     "ld %1,%0\n\t"
-			     "sub %0,1,%0\n\t"
-			     "st %0,%1\n\t"
-			     "wr %2, 0x0, %%psr\n\t"
-			     : "=r" (dummy), "=m" (intr_count)
-			     : "0" (0), "r" (psr=0));
+	__asm__ __volatile__("rd %%psr, %%g2\n\t"
+			     "wr %%g2, 0x20, %%psr\n\t"
+			     "ld %0,%%g3\n\t"
+			     "sub %%g3,1,%%g3\n\t"
+			     "st %%g3,%0\n\t"
+			     "wr %%g2, 0x0, %%psr\n\t"
+			     : "=m" (intr_count)
+			     : : "g2", "g3", "memory");
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+static inline void start_thread(struct pt_regs * regs, unsigned long sp,
+				unsigned long fp)
+{
+  printk("start_thread called, halting..n");
+  halt();
 }
 
 #endif /* __ASM_SPARC_PROCESSOR_H */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/psr.h linux/include/asm-sparc/psr.h
--- v1.3.3/linux/include/asm-sparc/psr.h	Mon Mar  6 11:22:08 1995
+++ linux/include/asm-sparc/psr.h	Wed Jun  7 11:10:16 1995
@@ -46,6 +46,42 @@
 #define PSR_VERS    0x0f000000         /* cpu-version field          */
 #define PSR_IMPL    0xf0000000         /* cpu-implementation field   */
 
+#ifndef __ASSEMBLY__
+/* Get the %psr register. */
+extern inline unsigned int get_psr(void)
+{
+	unsigned int psr;
+	__asm__ __volatile__("rd %%psr, %0\n\t" :
+			     "=r" (psr));
+	return psr;
+}
+
+extern inline void put_psr(unsigned int new_psr)
+{
+  __asm__("wr %0, 0x0, %%psr\n\t" : :
+	  "r" (new_psr));
+}
+
+/* Get the %fsr register.  Be careful, make sure the floating point
+ * enable bit is set in the %psr when you execute this or you will
+ * incur a trap.
+ */
+
+extern unsigned int fsr_storage;
+
+extern inline unsigned int get_fsr(void)
+{
+	unsigned int fsr = 0;
+
+	__asm__ __volatile__("st %%fsr, %1\n\t"
+			     "ld %1, %0\n\t" :
+			     "=r" (fsr) :
+			     "m" (fsr_storage));
+	return fsr;
+}
+
+#endif /* !(__ASSEMBLY__) */
+
 #endif /* !(__LINUX_SPARC_V8) */
 
 #ifdef __LINUX_SPARC_V9
@@ -80,6 +116,21 @@
 #define PSTATE_CLE   0x200   /* Current Little Endian         */
 
 
+extern inline unsigned int get_v9_pstate(void)
+{
+	unsigned int pstate;
+	__asm__ __volatile__("rdpr %pstate, %0\n\t" :
+			     "=r" (pstate));
+	return pstate;
+}
+
+extern inline void put_v9_pstate(unsigned int pstate)
+{
+	__asm__ __volatile__("wrpr %0, 0x0, %pstate\n\t" : :
+			     "r" (pstate));
+	return;
+}
+
 /* The Version Register holds vendor information for the chip:
 
     ---------------------------------------------------------------------------
@@ -93,6 +144,38 @@
 #define VERS_MAXTL   0x00000000000ff000     /* Maximum Trap-level supported  */
 #define VERS_MASK    0x0000000ff0000000     /* impl. dep. chip mask revision */
 #define VERS_MANUF   0xffff000000000000     /* Manufacturer ID code          */
+
+extern inline unsigned int get_v9_version(void)
+{
+	unsigned int vers;
+	__asm__ __volatile__("rdpr %ver, %0\n\t" :
+			     "=r" (vers));
+	return vers;
+}
+
+extern inline unsigned int get_v9_tstate(void)
+{
+	unsigned int tstate;
+	__asm__ __volatile__("rdpr %tstate, %0\n\t" :
+			     "=r" (pstate));
+	return tstate;
+}
+
+extern inline unsigned int get_v9_pil(void)
+{
+	unsigned int pil;
+	__asm__ __volatile__("rdpr %pil, %0\n\t" :
+			     "=r" (pstate));
+	return pil;
+}
+
+extern inline void put_v9_pil(unsigned int pil)
+{
+	__asm__ __volatile__("wrpr %0, 0x0, %pil\n\t" : :
+			     "r" (pil));
+	return;
+}
+
 
 #endif /* !(__LINUX_SPARC_V9) */
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h
--- v1.3.3/linux/include/asm-sparc/ptrace.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/ptrace.h	Thu Jun  8 23:46:59 1995
@@ -10,22 +10,19 @@
    stack during a system call. */
 
 struct pt_regs {
-	unsigned long ps;    /* previous supervisor, same as alpha I believe */
+	unsigned long psr;   /* for condition codes */
 	unsigned long pc;    /* current and next program counter */
 	unsigned long npc;
-	unsigned long sp;    /* stack and frame pointer */
-	unsigned long fp;
-	unsigned long psr;   /* for condition codes */
-	unsigned long nuwin; /* number of user windows */
+	unsigned long y;
 	/* not sure yet whether all regs are necessary
 	 * but this is how it is traditionally done on the sparc.
 	 */
-	unsigned long u_regs[24*16];
-	unsigned long f_regs[64];    /* yuck yuck yuck */
+	unsigned long u_regs[16]; /* globals and ins */
 };
 
 #ifdef __KERNEL__
-#define user_mode(regs) (0x0)  /* if previous supervisor is 0, came from user */
+/* if previous supervisor is 0, came from user */
+#define user_mode(regs) (0x0)
 extern void show_regs(struct pt_regs *);
 #endif
 
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/ross.h linux/include/asm-sparc/ross.h
--- v1.3.3/linux/include/asm-sparc/ross.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ross.h	Wed Jun 14 11:34:08 1995
@@ -0,0 +1,151 @@
+/* ross.h: Ross module specific definitions and defines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ROSS_H
+#define _SPARC_ROSS_H
+
+/* Ross made Hypersparcs have a %psr 'impl' field of '0001'.  The 'vers'
+ * field has '1111'.
+ */
+
+/* The MMU control register fields on the HyperSparc.
+ *
+ * -----------------------------------------------------------------
+ * |implvers| RSV |CWR|SE|WBE| MID |BM| C|CS|MR|CM|RSV|CE|RSV|NF|ME|
+ * -----------------------------------------------------------------
+ *  31    24 23-22 21  20  19 18-15 14 13 12 11 10  9   8 7-2  1  0
+ *
+ * Phew, lots of fields there ;-)
+ *
+ * CWR: Cache Wrapping Enabled, if one cache wrapping is on.
+ * SE: Snoop Enable, turns on bus snooping for cache activity if one.
+ * WBE: Write Buffer Enable, one turns it on.
+ * MID: The ModuleID of the chip for MBus transactions.
+ * BM: Boot-Mode. One indicates the MMU is in boot mode.
+ * C: Indicates whether accesses are cachable while the MMU is
+ *    disabled.
+ * CS: Cache Size -- 0 = 128k, 1 = 256k
+ * MR: Memory Reflection, one indicates that the memory bus connected
+ *     to the MBus supports memory reflection.
+ * CM: Cache Mode -- 0 = write-through, 1 = copy-back
+ * CE: Cache Enable -- 0 = no caching, 1 = cache is on
+ * NF: No Fault -- 0 = faults trap the CPU from supervisor mode
+ *                 1 = faults from supervisor mode do not generate traps
+ * ME: MMU Enable -- 0 = MMU is off, 1 = MMU is on
+ */
+
+#define HYPERSPARC_CWENABLE   0x00200000
+#define HYPERSPARC_SBENABLE   0x00100000
+#define HYPERSPARC_WBENABLE   0x00080000
+#define HYPERSPARC_MIDMASK    0x00078000
+#define HYPERSPARC_BMODE      0x00004000
+#define HYPERSPARC_ACENABLE   0x00002000
+#define HYPERSPARC_CSIZE      0x00001000
+#define HYPERSPARC_MRFLCT     0x00000800
+#define HYPERSPARC_CMODE      0x00000400
+#define HYPERSPARC_CENABLE    0x00000100
+#define HYPERSPARC_NFAULT     0x00000002
+#define HYPERSPARC_MENABLE    0x00000001
+
+/* Flushes which clear out only the on-chip Ross HyperSparc ICACHE. */
+extern inline void flush_i_page(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_IFLUSH_PAGE) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_i_seg(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_IFLUSH_SEG) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_i_region(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_IFLUSH_REGION) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_i_ctx(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_IFLUSH_CTX) :
+			     "memory");
+	return;
+}
+
+extern inline void flush_i_user(unsigned int addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_IFLUSH_USER) :
+			     "memory");
+	return;
+}
+
+/* Finally, flush the entire ICACHE. */
+extern inline void flush_whole_icache(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_FLUSH_IWHOLE));
+	return;
+}
+
+
+/* The ICCR instruction cache register on the HyperSparc.
+ *
+ * -----------------------------------------------
+ * |                                 | FTD | IDC |
+ * -----------------------------------------------
+ *  31                                  1     0
+ *
+ * This register is accessed using the V8 'wrasr' and 'rdasr'
+ * opcodes, since not all assemblers understand them and those
+ * that do use different semantics I will just hard code the
+ * instruction with a '.word' statement.
+ *
+ * FTD:  If set to one flush instructions executed during an
+ *       instruction cache hit occurs, the corresponding line
+ *       for said cache-hit is invalidated.  If FTD is zero,
+ *       an unimplemented 'flush' trap will occur when any
+ *       flush is executed by the processor.
+ *
+ * ICE:  If set to one, the instruction cache is enabled.  If
+ *       zero, the cache will not be used for instruction fetches.
+ *
+ * All other bits are read as zeros, and writes to them have no
+ * effect.
+ */
+
+extern inline unsigned int get_ross_icr(void)
+{
+	unsigned int icreg;
+
+	__asm__ __volatile__(".word 0xbf402000\n\t" : /* rd %iccr, %g1 */
+			     "=r" (icreg) : :
+			     "g1", "memory");
+
+	return icreg;
+}
+
+extern inline void put_ross_icr(unsigned int icreg)
+{
+	__asm__ __volatile__("or %%g0, %0, %%g1\n\t"
+			     ".word 0xbf802000\n\t" /* wr %g1, 0x0, %iccr */
+			     "nop\n\t"
+			     "nop\n\t"
+			     "nop\n\t" : : 
+			     "r" (icreg) :
+			     "g1", "memory");
+
+	return;
+}
+
+#endif /* !(_SPARC_ROSS_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h
--- v1.3.3/linux/include/asm-sparc/sbus.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/sbus.h	Thu Jun  8 23:47:04 1995
@@ -0,0 +1,76 @@
+/* sbus.h:  Defines for the Sun SBus.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_SBUS_H
+#define _SPARC_SBUS_H
+
+#include <asm/openprom.h>  /* For linux_prom_registers and linux_prom_irqs */
+
+/* We scan which devices are on the SBus using the PROM node device
+ * tree.  SBus devices are described in two different ways.  You can
+ * either get an absolute address at which to access the device, or
+ * you can get a SBus 'slot' number and an offset within that slot.
+ */
+
+/* The base address at which to calculate device OBIO addresses. */
+#define SUN_SBUS_BVADDR        0xf8000000
+#define SBUS_OFF_MASK          0x01ffffff
+
+/* These routines are used to calculate device address from slot
+ * numbers + offsets, and vice versa.
+ */
+
+extern inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
+{
+  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
+}
+
+extern inline int sbus_dev_slot(unsigned long dev_addr)
+{
+  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
+}
+
+extern inline unsigned long sbus_dev_offset(unsigned long dev_addr)
+{
+  return (unsigned long) (((dev_addr)-SUN_SBUS_BVADDR)&SBUS_OFF_MASK);
+}
+
+/* Handy macro */
+#define STRUCT_ALIGN(addr) ((addr+7)&(~7))
+
+/* Linus SBUS device tables */
+struct linux_sbus_device {
+  struct linux_sbus_device *next;      /* next device on this SBus or null */
+  int prom_node;                       /* PROM device tree node for this device */
+  char *prom_name;                     /* PROM device name */
+  char *linux_name;                    /* Name used internally by Linux */
+
+  /* device register addresses */
+  struct linux_prom_registers reg_addrs[PROMREG_MAX];
+  int num_registers;
+
+  /* List of IRQ's this device uses. */
+  struct linux_prom_irqs irqs[PROMINTR_MAX];
+  int num_irqs;
+
+  unsigned long sbus_addr;             /* Absolute base address for device. */
+  unsigned long sbus_vaddrs[PROMVADDR_MAX];
+  unsigned long num_vaddrs;
+  unsigned long offset;                /* Offset given by PROM */
+  int slot;                            /* Device slot number */
+};
+
+/* This struct describes the SBus-es found on this machine. */
+struct linux_sbus {
+  struct linux_sbus *next;             /* next SBus, if more than one SBus */
+  struct linux_sbus_device *devices;   /* Link to devices on this SBus */
+  int prom_node;                       /* PROM device tree node for this SBus */
+  char *prom_name;                     /* Usually "sbus" */
+  int clock_freq;                 /* Speed of this SBus */
+};
+
+extern struct linux_sbus Linux_SBus;
+
+#endif /* !(_SPARC_SBUS_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/segment.h linux/include/asm-sparc/segment.h
--- v1.3.3/linux/include/asm-sparc/segment.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/segment.h	Thu Jun  8 23:47:11 1995
@@ -82,6 +82,10 @@
 
 static inline void set_fs(unsigned long val)
 {
+  unsigned long foo;
+  foo = val;
+
+  return;
 }
 
 #endif /* _ASM_SEGMENT_H */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/smpprim.h linux/include/asm-sparc/smpprim.h
--- v1.3.3/linux/include/asm-sparc/smpprim.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/smpprim.h	Thu Jun  8 23:47:23 1995
@@ -0,0 +1,53 @@
+/*  smpprim.h:  SMP locking primitives on the Sparc
+ *
+ *  God knows we won't be actually using this code for some time
+ *  but I thought I'd write it since I knew how.
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_SMPPRIM_H
+#define __SPARC_SMPPRIM_H
+
+/* Test and set the unsigned byte at ADDR to 1.  Returns the previous
+ * value.  On the Sparc we use the ldstub instruction since it is
+ * atomic.
+ */
+
+extern inline volatile char test_and_set(void *addr)
+{
+	char state = 0;
+
+	__asm__ __volatile__("ldstub [%0], %1         ! test_and_set\n\t"
+			     "=r" (addr), "=r" (state) :
+			     "0" (addr), "1" (state) : "memory");
+
+	return state;
+}
+
+/* Initialize a spin-lock. */
+extern inline volatile smp_initlock(void *spinlock)
+{
+	/* Unset the lock. */
+	*((unsigned char *) spinlock) = 0;
+
+	return;
+}
+
+/* This routine spins until it acquires the lock at ADDR. */
+extern inline volatile smp_lock(void *addr)
+{
+	while(test_and_set(addr) == 0xff)
+		;
+
+	/* We now have the lock */
+	return;
+}
+
+/* This routine releases the lock at ADDR. */
+extern inline volatile smp_unlock(void *addr)
+{
+	*((unsigned char *) addr) = 0;
+}
+
+#endif /* !(__SPARC_SMPPRIM_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h
--- v1.3.3/linux/include/asm-sparc/string.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/string.h	Sun Jun  4 09:36:13 1995
@@ -1,367 +1,205 @@
 /* string.h: External definitions for optimized assembly string
-             routines for the Linux Kernel.
+ *           routines for the Linux Kernel.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
 
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+#ifndef _SPARC_STRING_H
+#define _SPARC_STRING_H
 
-extern inline size_t strlen(const char * str)
+extern __inline__ size_t strlen(const char * str)
 {
-  register size_t retval = 0;
-  register char tmp = 0;
-  register char * lstr;
-
-  lstr = (char *) str;
-
-  __asm__("ldub [%1], %2\n\t"
-	  "or %%g0, %%g0, %0\n\t"
-	  "orcc %2, %%g0, %%g0\n\t"
-	  "be 2f\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "1: ldub [%1], %2\n\t"
-	  "add %0, 0x1, %0\n\t"
-	  "orcc %2, %%g0, %%g0\n\t"
-	  "bne 1b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "2:" :
-	  "=r" (retval), "=r" (lstr), "=r" (tmp) :
-	  "0" (retval), "1" (lstr), "2" (tmp));
+  const char *sc;
 
-  return retval;
+  for (sc = str; *sc != '\0'; ++sc)
+    /* nothing */;
+  return sc - str;
 }
 
 extern __inline__ int strcmp(const char* str1, const char* str2)
 {
-  register unsigned int tmp1=0, tmp2=0;
-  register int retval=0;
+  register signed char __res;
 
-  __asm__("ldub [%1], %3\n\t"
-	  "ldub [%2], %4\n\t"
-	  "1: add %2, 0x1, %2\n\t"
-	  "cmp %3, %4\n\t"
-	  "bne,a 2f\n\t"
-	  "sub %2, 0x1, %2\n\t"
-	  "ldub [%1], %3\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne,a 1b\n\t"
-	  "ldub [%2], %4\n\t"
-	  "b 3f\n\t"
-	  "or %%g0, %%g0, %0\n\t"
-	  "2: ldub [%1], %3\n\t"
-	  "ldub [%2], %4\n\t"
-          "sub %3, %4, %0\n\t"
-	  "3: \n\t" :
-	  "=r" (retval), "=r" (str1), "=r" (str2), "=r" (tmp1), "=r" (tmp2) :
-	  "0" (retval), "1" (str1), "2" (str2),
-	  "3" (tmp1), "4" (tmp2));
+  while (1) {
+    if ((__res = *str1 - *str2++) != 0 || !*str1++)
+      break;
+  }
 
-  return retval;
+  return __res;
 }
 
 extern __inline__ int strncmp(const char* str1, const char* str2, size_t strlen)
 {
-  register int retval=0;
+  register signed char __res = 0;
 
-  __asm__("cmp %3, 0x0\n\t"
-	  "be 2f\n\t"
-	  "ldub [%2], %%g3\n\t"
-	  "1: ldub [%1], %%g2\n\t"
-	  "sub %%g2, %%g3, %0\n\t"
-	  "cmp %0, 0x0\n\t"
-	  "bne 2f\n\t"
-	  "add %2, 0x1, %2\n\t"
-	  "cmp %%g2, 0x0\n\t"
-	  "be 2f\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "addcc %3, -1, %3\n\t"
-	  "bne,a 1b\n\t"
-	  "ldub [%2], %%g3\n\t"
-	  "2: " :
-	  "=r" (retval), "=r" (str1), "=r" (str2), "=r" (strlen) :
-	  "0" (retval), "1" (str1), "2" (str2), "3" (strlen) :
-	  "%g2", "%g3");
+  while (strlen) {
+    if ((__res = *str1 - *str2++) != 0 || !*str1++)
+      break;
+    strlen--;
+  }
 
-  return retval;
+  return __res;
 }
 
 
 extern __inline__ char *strcpy(char* dest, const char* source)
 {
-  register char tmp;
-  register char *retval;
+  char *tmp = dest;
 
-  __asm__("or %%g0, %2, %0\n\t"
-	  "ldub [%1], %3\n\t"
-	  "1: stb %3, [%2]\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne,a 1b\n\t"
-	  "ldub [%1], %3\n\t" :
-	  "=r" (retval), "=r" (source), "=r" (dest), "=r" (tmp) :
-	  "0" (retval), "1" (source), "2" (dest), "3" (tmp));
-
-  return retval;
+  while ((*dest++ = *source++) != '\0')
+    /* nothing */;
+  return tmp;
 }
 
 extern __inline__ char *strncpy(char *dest, const char *source, size_t cpylen)
 {
-  register char tmp;
-  register char *retval;
+  char *tmp = dest;
 
-  __asm__("or %%g0, %1, %0\n\t"
-	  "1: cmp %4, 0x0\n\t"
-	  "be 2f\n\t"
-	  "ldub [%1], %3\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "stb %3, [%2]\n\t"
-	  "sub %4, 0x1, %4\n\t"
-	  "ba 1\n\t"
-	  "add %2, 0x1, %2\n\t" :
-	  "=r" (retval), "=r" (dest), "=r" (source), "=r"(tmp), "=r" (cpylen) :
-	  "0" (retval), "1" (dest), "2" (source), 
-	  "3" (tmp), "4" (cpylen));
+  while (cpylen-- && (*dest++ = *source++) != '\0')
+    /* nothing */;
 
-  return retval;
+  return tmp;
 }
 
 extern __inline__ char *strcat(char *dest, const char *src)
 {
-  register char *retval;
-  register char temp=0;
+  char *tmp = dest;
 
-  __asm__("or %%g0, %1, %0\n\t"
-	  "1: ldub [%1], %3\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne,a 1b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "2: ldub [%2], %3\n\t"
-	  "stb %3, [%1]\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne 2b\n\t"
-	  "add %2, 0x1, %2\n\t" :
-	  "=r" (retval), "=r" (dest), "=r" (src), "=r" (temp) :
-	  "0" (retval), "1" (dest), "2" (src), "3" (temp));
+  while (*dest)
+    dest++;
+  while ((*dest++ = *src++) != '\0')
+    ;
 
-  return retval;
+  return tmp;
 }
 
 extern __inline__ char *strncat(char *dest, const char *src, size_t len)
 {
-  register char *retval;
-  register char temp=0;
+  char *tmp = dest;
 
-  __asm__("or %%g0, %1, %0\n\t"
-	  "1: ldub [%1], %3\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne,a 1b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "2: ldub [%2], %3\n\t"
-	  "stb %3, [%1]\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "add %3, -1, %3\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne 2b\n\t"
-	  "add %2, 0x1, %2\n\t" :
-	  "=r" (retval), "=r" (dest), "=r" (src), "=r" (len), "=r" (temp) :
-	  "0" (retval), "1" (dest), "2" (src), "3" (len), "4" (temp));
+  if (len) {
+    while (*dest)
+      dest++;
+    while ((*dest++ = *src++)) {
+      if (--len == 0)
+	break;
+    }
+  }
 
-  return retval;
+  return tmp;
 }
 
 extern __inline__ char *strchr(const char *src, int c)
 {
-  register char temp=0;
-  register char *trick=0;
-
-  __asm__("1: ldub [%0], %2\n\t"
-	  "cmp %2, %1\n\t"
-	  "bne,a 1b\n\t"
-	  "add %0, 0x1, %0\n\t"
-	  "or %%g0, %0, %3\n\t" :
-	  "=r" (src), "=r" (c), "=r" (temp), "=r" (trick), "=r" (src) :
-	  "0" (src), "1" (c), "2" (temp), "3" (trick), "4" (src));
-
-  return trick;
+  for(; *src != c; ++src)
+    if (*src == '\0')
+      return NULL;
+  return (char *) src;
 }
 
 extern __inline__ char *strpbrk(const char *cs, const char *ct)
 {
-  register char temp1, temp2;
-  register char *scratch;
-  register char *trick;
-
-  __asm__("or %%g0, %1, %4\n\t"
-	  "1: ldub [%0], %2\n\t"
-	  "2: ldub [%1], %3\n\t"
-	  "cmp %3, %2\n\t"
-	  "be 3f\n\t"
-	  "nop\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bne 2b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "or %%g0, %4, %1\n\t"
-	  "b 1b\n\t"
-	  "add %0, 0x1, %0\n\t"
-	  "or %%g0, %0, %5\n\t" :
-	  "=r" (cs) :
-	  "r" (ct), "r" (temp1), "r" (temp2), "r" (scratch), "r" (trick=0),
-	  "0" (cs), "1" (ct));
-
-  return trick;
+  const char *sc1,*sc2;
 
+  for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+    for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+      if (*sc1 == *sc2)
+	return (char *) sc1;
+    }
+  }
+  return NULL;
 }
 
       
 extern __inline__ size_t strspn(const char *s, const char *accept)
 {
-  register char temp1, temp2;
-  register char* scratch;
-  register size_t trick;
-
-  __asm__("or %%g0, %1, %4\n\t"
-	  "1: ldub [%0], %2\n\t"
-	  "2: ldub [%1], %3\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "be 3f\n\t"
-	  "cmp %3, %2"
-	  "bne 2b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "add %0, 0x1, %0\n\t"
-	  "b 1b\n\t"
-	  "add %5, 0x1, %5\n\t"
-	  "3: or %%g0, %0, %4\n\t" :
-	  "=r" (s) :
-	  "r" (accept), "r" (temp1), "r" (temp2), 
-	  "r" (scratch), "r" (trick=0), "0" (s));
-
-  return trick;
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p) {
+    for (a = accept; *a != '\0'; ++a) {
+      if (*p == *a)
+	break;
+    }
+    if (*a == '\0')
+      return count;
+    ++count;
+  }
 
+  return count;
 }
 
 extern __inline__ char *strtok(char *s, const char *ct)
 {
-  static char* old; /* frob this kludge for now */
-  register char *tok;
-
-  if (s == (char *) 0)
-    {
-      if (old == (char *) 0)
-	{
-	  return (char *) 0;
-	}
-      else
-	s = old;
-    }
+  char *sbegin, *send;
 
-  s += strspn(s, ct);
-  if(*s == '\0')
-    {
-      old = (char *) 0;
-      return (char *) 0;
-    }
-
-  tok = s;
-  s = strpbrk(tok, ct);
-  if (s == (char *) 0)
-    old = (char *) 0;
-  else
-    {
-      *s = '\0';
-      old = s + 1;
-    }
-  return tok;
+  sbegin  = s ? s : ___strtok;
+  if (!sbegin) {
+    return NULL;
+  }
+  sbegin += strspn(sbegin,ct);
+  if (*sbegin == '\0') {
+    ___strtok = NULL;
+    return( NULL );
+  }
+  send = strpbrk( sbegin, ct);
+  if (send && *send != '\0')
+    *send++ = '\0';
+  ___strtok = send;
+  return (sbegin);
 }
 	
 
 extern __inline__ void *memset(void *src, int c, size_t count)
 {
-  register void *retval;
+  char *xs = (char *) src;
 
-  __asm__("or %%g0, %1, %0\n\t"
-	  "1: add %1, 0x1, %1\n\t"
-	  "2: add %3, -1, %3\n\t"
-	  "cmp %3, -1\n\t"
-	  "bne,a 1b\n\t"
-	  "stb %2, [%1]\n\t" :
-	  "=r" (retval), "=r" (src), "=r" (c), "=r" (count) :
-	  "0" (retval), "1" (src), "2" (c), "3" (count));
+  while (count--)
+    *xs++ = c;
 
-  return retval;
+  return src;
 }
 
 extern __inline__ void *memcpy(void *dest, const void *src, size_t count)
 {
-  register void *retval;
-  register char tmp;
+  char *tmp = (char *) dest, *s = (char *) src;
 
-  __asm__("or %%g0, %1, %0\n\t"
-	  "add %3, -1, %3\n\t"
-	  "cmp %3, -1\n\t"
-	  "be 2f\n\t"
-	  "1: ldub [%2], %4\n\t"
-	  "add %2, 0x1, %2\n\t"
-	  "add %3, -1, %3\n\t"
-	  "cmp %3, -1\n\t"
-	  "stb %4, [%1]\n\t"
-	  "bne 1b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "2: " :
-	  "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) :
-	  "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp));
+  while (count--)
+    *tmp++ = *s++;
 
-  return retval;
+  return dest;
 }
 
 extern __inline__ void *memmove(void *dest, const void *src, size_t count)
 {
-  register void *retval;
-  register char tmp;
+  char *tmp, *s;
 
-  __asm__("or %%g0, %1, %1\n\t"
-	  "add %3, -1, %3\n\t"
-	  "cmp %3, -1\n\t"
-	  "be 2f\n\t"
-	  "1: ldub [%2], %4\n\t"
-	  "add %2, 0x1, %2\n\t"
-	  "add %3, -1, %3\n\t"
-	  "cmp %3, -1\n\t"
-	  "stb %4, [%1]\n\t"
-	  "bne 1b\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "2: " :
-	  "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) :
-	  "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp));
+  if (dest <= src) {
+    tmp = (char *) dest;
+    s = (char *) src;
+    while (count--)
+      *tmp++ = *s++;
+  }
+  else {
+    tmp = (char *) dest + count;
+    s = (char *) src + count;
+    while (count--)
+      *--tmp = *--s;
+  }
 
-  return retval;
+  return dest;
 }
 
 extern __inline__ int memcmp(const void *cs, const void *ct, size_t count)
 {
-  register int retval;
-  register unsigned long tmp1, tmp2;
-
-  __asm__("or %%g0, %1, %0\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "ble,a 3f\n\t"
-	  "or %%g0, %%g0, %0\n\t"
-	  "1: ldub [%1], %4\n\t"
-	  "ldub [%2], %5\n\t"
-	  "cmp %4, %5\n\t"
-	  "be,a 2f\n\t"
-	  "add %1, 0x1, %1\n\t"
-	  "bgeu 3f\n\t"
-	  "or %%g0, 0x1, %0\n\t"
-	  "b 3f\n\t"
-	  "or %%g0, -1, %0\n\t"
-	  "2: add %3, -1, %3\n\t"
-	  "cmp %3, 0x0\n\t"
-	  "bg 1b\n\t"
-	  "add %2, 0x1, %2\n\t"
-	  "or %%g0, %%g0, %0\n\t"
-	  "3: " :
-	  "=r" (retval) :
-	  "r" (cs), "r" (ct), "r" (count), "r" (tmp1=0), "r" (tmp2=0));
+  const unsigned char *su1, *su2;
+  signed char res = 0;
 
-  return retval;
+  for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+    if ((res = *su1 - *su2) != 0)
+      break;
+  return res;
 }
 
+#endif /* !(_SPARC_STRING_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/sysen.h linux/include/asm-sparc/sysen.h
--- v1.3.3/linux/include/asm-sparc/sysen.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/sysen.h	Thu Jun  8 21:32:31 1995
@@ -1,14 +1,14 @@
-#ifndef _SPARC_SYSEN_H
-#define _SPARC_SYSEN_H
-
 /* sysen.h:  Bit fields within the "System Enable" register accessed via
-             the ASI_CONTROL address space at address AC_SYSENABLE.
+ *           the ASI_CONTROL address space at address AC_SYSENABLE.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
 
-   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
+#ifndef _SPARC_SYSEN_H
+#define _SPARC_SYSEN_H
 
 #define SENABLE_DVMA   0x20   /* enable dvma transfers */
 #define SENABLE_CACHE  0x10   /* enable VAC cache */
-#define SENABLE_RESET  0x04   /* reset the whole machine, danger Will Robinson */
+#define SENABLE_RESET  0x04   /* reset whole machine, danger Will Robinson */
 
 #endif /* _SPARC_SYSEN_H */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v1.3.3/linux/include/asm-sparc/system.h	Sun Feb 26 20:46:20 1995
+++ linux/include/asm-sparc/system.h	Sat Jun 17 09:34:09 1995
@@ -4,50 +4,84 @@
 #include <asm/segment.h>
 
 /*
- * System defines.. Note that this is included both from .c and .S
- * files, so it does only defines, not any C code.
- */
-
-/*
  * I wish the boot time image was as beautiful as the Alpha's
  * but no such luck. The icky PROM loads us at 0x0, and jumps
- * to magic address 0x4000 to start thing going. This means that
- * I can stick the pcb and user/kernel stacks in the area from
- * 0x0-0x4000 and be reasonably sure that this is sane.
+ * to magic address 0x4000 to start things going.
  *
  * Sorry, I can't impress people with cool looking 64-bit values
- * yet. ;-)
+ * yet. Wait till V9 ;-)
  */
 
+#include <asm/page.h>
 #include <asm/openprom.h>
 #include <asm/psr.h>
 
-#define INIT_PCB	0x00011fe0
-#define INIT_STACK	0x00013fe0
-#define START_ADDR	0x00004000
-#define START_SIZE	(32*1024)
-#define EMPTY_PGT	0x00001000
-#define EMPTY_PGE	0x00001000
-#define ZERO_PGE	0x00001000
-
-#define IRQ_ENA_ADR     0x2000        /* This is a bitmap of all activated IRQ's
-				       * which is mapped in head.S during boot.
-				       */
+#define START_ADDR	(0x00004000)
+#define EMPTY_PGT       (&empty_bad_page)
+#define EMPTY_PGE	(&empty_bad_page_table)
+#define ZERO_PGE	(&empty_zero_page)
 
 #ifndef __ASSEMBLY__
 
+/*
+ * Sparc (general) CPU types
+ */
+enum sparc_cpu {
+  sun4        = 0x00,
+  sun4c       = 0x01,
+  sun4m       = 0x02,
+  sun4d       = 0x03,
+  sun4e       = 0x04,
+  sun4u       = 0x05,
+  sun_unknown = 0x06,
+};
+
+extern enum sparc_cpu sparc_cpu_model;
+
+extern unsigned long empty_bad_page;
+extern unsigned long empty_bad_page_table;
+extern unsigned long empty_zero_page;
+
 extern void wrent(void *, unsigned long);
 extern void wrkgp(unsigned long);
 extern struct linux_romvec *romvec;
 
-#define halt() { romvec->pv_halt(); }
+#define halt() do { \
+			 printk("Entering monitor in file %s at line %d\n", __FILE__, __LINE__); \
+romvec->pv_halt(); } while(0)
+
 #define move_to_user_mode() halt()
-#define switch_to(x) halt()
 
 #ifndef stbar  /* store barrier Sparc insn to synchronize stores in PSO */
 #define stbar() __asm__ __volatile__("stbar": : :"memory")
 #endif
 
+/* When a context switch happens we must flush all user windows so that
+ * the windows of the current process are flushed onto it's stack. This
+ * way the windows are all clean for the next process.
+ */
+
+#define flush_user_windows() \
+do { __asm__ __volatile__( \
+			  "save %sp, -64, %sp\n\t" \
+			  "save %sp, -64, %sp\n\t" \
+			  "save %sp, -64, %sp\n\t" \
+			  "save %sp, -64, %sp\n\t" \
+			  "save %sp, -64, %sp\n\t" \
+			  "save %sp, -64, %sp\n\t" \
+			  "save %sp, -64, %sp\n\t" \
+			  "restore\n\t" \
+			  "restore\n\t" \
+			  "restore\n\t" \
+			  "restore\n\t" \
+			  "restore\n\t" \
+			  "restore\n\t" \
+			  "restore\n\t"); } while(0)
+
+extern void sparc_switch_to(void *new_task);
+
+#define switch_to(p) sparc_switch_to(p)
+
 /* Changing the PIL on the sparc is a bit hairy. I'll figure out some
  * more optimized way of doing this soon. This is bletcherous code.
  */
@@ -73,36 +107,6 @@
 #define iret() __asm__ __volatile__ ("jmp %%l1\n\t" \
 				     "rett %%l2\n\t": : :"memory")
 
-#define _set_gate(gate_addr,type,dpl,addr) \
-__asm__ __volatile__ ("nop\n\t")
-
-#define set_intr_gate(n,addr) \
-	_set_gate(&idt[n],14,0,addr)
-
-#define set_trap_gate(n,addr) \
-	_set_gate(&idt[n],15,0,addr)
-
-#define set_system_gate(n,addr) \
-	_set_gate(&idt[n],15,3,addr)
-
-#define set_call_gate(a,addr) \
-	_set_gate(a,12,3,addr)
-
-
-extern inline unsigned int get_psr(void)
-{
-  unsigned int ret_val;
-  __asm__("rd %%psr, %0\n\t" :
-	  "=r" (ret_val));
-  return ret_val;
-}
-
-extern inline void put_psr(unsigned int new_psr)
-{
-  __asm__("wr %0, 0x0, %%psr\n\t" : :
-	  "r" (new_psr));
-}
-
 /* Must this be atomic? */
 
 extern inline void *xchg_u32(int * m, unsigned long val)
@@ -110,7 +114,7 @@
 	unsigned long dummy;
 
 	__asm__ __volatile__(
-		"ld %1,%2   ! xchg_u32() is here\n\t"
+		"ld %1,%2\n\t"
 		"st %0, %1\n\t"
 		"or %%g0, %2, %0"
 		: "=r" (val), "=m" (*m), "=r" (dummy)
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/timer.h linux/include/asm-sparc/timer.h
--- v1.3.3/linux/include/asm-sparc/timer.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/timer.h	Sat Jun 10 04:22:20 1995
@@ -0,0 +1,83 @@
+/* timer.h:  Definitions for the timer chips on the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_TIMER_H
+#define _SPARC_TIMER_H
+
+#include <asm/system.h>  /* For NCPUS */
+
+/* Timer structures. The interrupt timer has two properties which
+ * are the counter (which is handled in do_timer in sched.c) and the limit.
+ * This limit is where the timer's counter 'wraps' around. Oddly enough,
+ * the sun4c timer when it hits the limit wraps back to 1 and not zero
+ * thus when calculating the value at which it will fire a microsecond you
+ * must adjust by one.  Thanks SUN for designing such great hardware ;(
+ */
+
+/* Note that I am only going to use the timer that interrupts at
+ * Sparc IRQ 10.  There is another one available that can fire at
+ * IRQ 14. Currently it is left untouched, we keep the PROM's limit
+ * register value and let the prom take these interrupts.  This allows
+ * L1-A to work.
+ */
+
+struct sun4c_timer_info {
+  volatile unsigned int cur_count10;
+  volatile unsigned int timer_limit10;
+  volatile unsigned int cur_count14;
+  volatile unsigned int timer_limit14;
+};
+
+#define SUN4C_TIMER_PHYSADDR   0xf3000000
+
+/* All accesses to the sun4c timer registers should use this macro. */
+#define  SUN4C_TIMER_STRUCT  ((volatile struct sun4c_timer_info *) TIMER_VADDR)
+
+/* A sun4m has two blocks of registers which are probably of the same
+ * structure. LSI Logic's L64851 is told to _decrement_ from the limit
+ * value. Aurora behaves similarly but its limit value is compacted in
+ * other fashion (it's wider). Documented fields are defined here.
+ */
+
+/* As with the interrupt register, we have two classes of timer registers
+ * which are per-cpu and master.  Per-cpu timers only hit that cpu and are
+ * only level 14 ticks, master timer hits all cpus and is level 10.
+ */
+
+#define SUN4M_PRM_CNT_L       0x80000000
+#define SUN4M_PRM_CNT_LVALUE  0x7FFFFC00
+
+struct sun4m_timer_percpu_info {
+  volatile unsigned int l14_timer_limit;    /* Initial value is 0x009c4000 */
+  volatile unsigned int l14_cur_count;
+
+  /* This register appears to be write only and/or inaccessible
+   * on Uni-Processor sun4m machines.
+   */
+  volatile unsigned int l14_limit_noclear;  /* Data access error is here */
+
+  volatile unsigned int cntrl;            /* =1 after POST on Aurora */
+  volatile unsigned char space[PAGE_SIZE - 16];
+};
+
+struct sun4m_timer_regs {
+	struct sun4m_timer_percpu_info cpu_timers[NCPUS];
+	volatile unsigned int l10_timer_limit;
+	volatile unsigned int l10_cur_count;
+
+	/* Again, this appears to be write only and/or inaccessible
+	 * on uni-processor sun4m machines.
+	 */
+	volatile unsigned int l10_limit_noclear;
+
+	/* This register too, it must be magic. */
+	volatile unsigned int foobar;
+
+	volatile unsigned int cfg;     /* equals zero at boot time... */
+};
+
+extern struct sun4m_timer_regs *sun4m_timers;
+extern volatile unsigned int *master_l10_limit;
+
+#endif /* !(_SPARC_TIMER_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/traps.h linux/include/asm-sparc/traps.h
--- v1.3.3/linux/include/asm-sparc/traps.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/traps.h	Sun Jun 18 02:33:57 1995
@@ -0,0 +1,135 @@
+/* traps.h:  Format of entries for the Sparc trap table.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_TRAPS_H
+#define _SPARC_TRAPS_H
+
+#define NUM_SPARC_TRAPS  255
+
+/* This is for V8 and V9 compliant Sparc CPUS */
+struct tt_entry {
+	unsigned long inst_one;
+	unsigned long inst_two;
+	unsigned long inst_three;
+	unsigned long inst_four;
+};
+
+/* We set this to _start in system setup. */
+extern struct tt_entry *sparc_ttable;
+
+/* This for V9 compliant Sparc CPUS */
+struct tt_v9_entry {
+	unsigned long inst_one;
+	unsigned long inst_two;
+	unsigned long inst_three;
+	unsigned long inst_four;
+	unsigned long inst_five;
+	unsigned long inst_six;
+	unsigned long inst_seven;
+	unsigned long inst_eight;
+};
+
+/* V9 has multiple trap tables, which one is used depends
+ * upon how deep within multiple traps you are.
+ * I believe the UltraSparc supports two levels now.
+ */
+extern struct tt_v9_entry *sparc_v9_ttablel0;
+extern struct tt_v9_entry *sparc_v9_ttablel1;
+
+/* For patching the trap table at boot time, we need to know how to
+ * form various common Sparc instructions.  Thus these macros...
+ */
+
+#define SPARC_MOV_CONST_L3(const) (0xa6102000 | (const&0xfff))
+
+/* The following assumes that the branch lies before the place we
+ * are branching to.  This is the case for a trap vector...
+ * You have been warned.
+ */
+#define SPARC_BRANCH(dest_addr, inst_addr) \
+          (0x10800000 | (((dest_addr-inst_addr)>>2)&0x3fffff))
+
+#define SPARC_RD_PSR_L0  (0xa1480000)
+#define SPARC_NOP (0x01000000)
+
+/* Various interesting trap levels. */
+/* First, hardware traps. */
+#define SP_TRAP_TFLT    0x1          /* Text fault */
+#define SP_TRAP_II      0x2          /* Illegal Instruction */
+#define SP_TRAP_PI      0x3          /* Priviledged Instruction */
+#define SP_TRAP_FPD     0x4          /* Floating Point Disabled */
+#define SP_TRAP_WOVF    0x5          /* Window Overflow */
+#define SP_TRAP_WUNF    0x6          /* Window Underflow */
+#define SP_TRAP_MNA     0x7          /* Memory Address Unaligned */
+#define SP_TRAP_FPE     0x8          /* Floating Point Exception */
+#define SP_TRAP_DFLT    0x9          /* Data Fault */
+#define SP_TRAP_TOF     0xa          /* Tag Overflow */
+#define SP_TRAP_WDOG    0xb          /* Watchpoint Detected */
+#define SP_TRAP_IRQ1    0x11         /* IRQ level 1 */
+#define SP_TRAP_IRQ2    0x12         /* IRQ level 2 */
+#define SP_TRAP_IRQ3    0x13         /* IRQ level 3 */
+#define SP_TRAP_IRQ4    0x14         /* IRQ level 4 */
+#define SP_TRAP_IRQ5    0x15         /* IRQ level 5 */
+#define SP_TRAP_IRQ6    0x16         /* IRQ level 6 */
+#define SP_TRAP_IRQ7    0x17         /* IRQ level 7 */
+#define SP_TRAP_IRQ8    0x18         /* IRQ level 8 */
+#define SP_TRAP_IRQ9    0x19         /* IRQ level 9 */
+#define SP_TRAP_IRQ10   0x1a         /* IRQ level 10 */
+#define SP_TRAP_IRQ11   0x1b         /* IRQ level 11 */
+#define SP_TRAP_IRQ12   0x1c         /* IRQ level 12 */
+#define SP_TRAP_IRQ13   0x1d         /* IRQ level 13 */
+#define SP_TRAP_IRQ14   0x1e         /* IRQ level 14 */
+#define SP_TRAP_IRQ15   0x1f         /* IRQ level 15 Non-maskable */
+#define SP_TRAP_RACC    0x20         /* Register Access Error ??? */
+#define SP_TRAP_IACC    0x21         /* Instruction Access Error */
+#define SP_TRAP_CPDIS   0x24         /* Co-Processor Disabled */
+#define SP_TRAP_BADFL   0x25         /* Unimplemented Flush Instruction */
+#define SP_TRAP_CPEXP   0x28         /* Co-Processor Exception */
+#define SP_TRAP_DACC    0x29         /* Data Access Error */
+#define SP_TRAP_DIVZ    0x2a         /* Divide By Zero */
+#define SP_TRAP_DSTORE  0x2b         /* Data Store Error ??? */
+#define SP_TRAP_DMM     0x2c         /* Data Access MMU Miss ??? */
+#define SP_TRAP_IMM     0x3c         /* Instruction Access MMU Miss ??? */
+
+/* Now the Software Traps... */
+#define SP_TRAP_SUNOS   0x80         /* SunOS System Call */
+#define SP_TRAP_SBPT    0x81         /* Software Breakpoint */
+#define SP_TRAP_SDIVZ   0x82         /* Software Divide-by-Zero trap */
+#define SP_TRAP_FWIN    0x83         /* Flush Windows */
+#define SP_TRAP_CWIN    0x84         /* Clean Windows */
+#define SP_TRAP_RCHK    0x85         /* Range Check */
+#define SP_TRAP_FUNA    0x86         /* Fix Unaligned Access */
+#define SP_TRAP_IOWFL   0x87         /* Integer Overflow */
+#define SP_TRAP_SOLARIS 0x88         /* Solaris System Call */
+#define SP_TRAP_NETBSD  0x89         /* NetBSD System Call */
+#define SP_TRAP_LINUX   0x90         /* Linux System Call */
+
+/* Special traps... */
+#define SP_TRAP_KBPT1   0xfe         /* KADB/PROM Breakpoint one */
+#define SP_TRAP_KBPT2   0xff         /* KADB/PROM Breakpoint two */
+
+/* Handy Macros */
+/* Is this a trap we never expect to get? */
+#define BAD_TRAP_P(level) \
+        ((level > SP_TRAP_WDOG && level < SP_TRAP_IRQ1) || \
+	 (level > SP_TRAP_IACC && level < SP_TRAP_CPDIS) || \
+	 (level > SP_TRAP_BADFL && level < SP_TRAP_CPEXP) || \
+	 (level > SP_TRAP_DMM && level < SP_TRAP_IMM) || \
+	 (level > SP_TRAP_IMM && level < SP_TRAP_SUNOS) || \
+	 (level > SP_TRAP_LINUX && level < SP_TRAP_KBPT1))
+
+/* Is this a Hardware trap? */
+#define HW_TRAP_P(level) ((level > 0) && (level < SP_TRAP_SUNOS))
+
+/* Is this a Software trap? */
+#define SW_TRAP_P(level) ((level >= SP_TRAP_SUNOS) && (level <= SP_TRAP_KBPT2))
+
+/* Is this a system call for some OS we know about? */
+#define SCALL_TRAP_P(level) ((level == SP_TRAP_SUNOS) || \
+			     (level == SP_TRAP_SOLARIS) || \
+			     (level == SP_TRAP_NETBSD) || \
+			     (level == SP_TRAP_LINUX))
+
+#endif /* !(_SPARC_TRAPS_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/tsunami.h linux/include/asm-sparc/tsunami.h
--- v1.3.3/linux/include/asm-sparc/tsunami.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/tsunami.h	Tue Jun 20 03:51:36 1995
@@ -0,0 +1,45 @@
+/* tsunami.h:  Module specific definitions for Tsunami V8 Sparcs
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_TSUNAMI_H
+#define _SPARC_TSUNAMI_H
+
+/* The MMU control register on the Tsunami:
+ *
+ * -----------------------------------------------------------------------
+ * | implvers |SW|AV|DV|MV| RSV |PC|ITD|ALC| RSV |PE| RC |IE|DE|RSV|NF|ME|
+ * -----------------------------------------------------------------------
+ *  31      24 23 22 21 20 19-18 17  16 14  13-12 11 10-9  8  7 6-2  1  0
+ *
+ * SW: Enable Software Table Walks  0=off 1=on
+ * AV: Address View bit
+ * DV: Data View bit
+ * MV: Memory View bit
+ * PC: Parity Control
+ * ITD: ITBR disable
+ * ALC: Alternate Cacheable
+ * PE: Parity Enable   0=off 1=on
+ * RC: Refresh Control
+ * IE: Instruction cache Enable  0=off 1=on
+ * DE: Data cache Enable  0=off 1=on
+ * NF: No Fault, same as all other SRMMUs
+ * ME: MMU Enable, same as all other SRMMUs
+ */
+
+#define TSUNAMI_SW        0x00800000
+#define TSUNAMI_AV        0x00400000
+#define TSUNAMI_DV        0x00200000
+#define TSUNAMI_MV        0x00100000
+#define TSUNAMI_PC        0x00020000
+#define TSUNAMI_ITD       0x00010000
+#define TSUNAMI_ALC       0x00008000
+#define TSUNAMI_PE        0x00001000
+#define TSUNAMI_RCMASK    0x00000C00
+#define TSUNAMI_IENAB     0x00000200
+#define TSUNAMI_DENAB     0x00000100
+#define TSUNAMI_NF        0x00000002
+#define TSUNAMI_ME        0x00000001
+
+#endif /* !(_SPARC_TSUNAMI_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/ultra.h linux/include/asm-sparc/ultra.h
--- v1.3.3/linux/include/asm-sparc/ultra.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/ultra.h	Sat Jun 17 06:26:04 1995
@@ -0,0 +1,51 @@
+/* ultra.h: Definitions and defines for the TI V9 UltraSparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ULTRA_H
+#define _SPARC_ULTRA_H
+
+/* Spitfire MMU control register:
+ *
+ * ----------------------------------------------------------
+ * |        | IMPL  | VERS  |     |  MID  |                 |
+ * ----------------------------------------------------------
+ *  64        31-28   27-24  23-22  21-17   16             0
+ *
+ * IMPL: Implementation of this Spitfire.
+ * VERS: Version of this Spitfire.
+ * MID: Module ID of this processor.
+ */
+
+#define SPITFIRE_MIDMASK     0x00000000003e0000
+
+/* Spitfire Load Store Unit control register:
+ *
+ * ---------------------------------------------------------------------
+ * | RSV | PWR | PWW | VWR | VWW | RSV | PMASK | DME | IME | DCE | ICE |
+ * ---------------------------------------------------------------------
+ *  63-25  24    23     22    21    20   19-4      3     2     1     0
+ *
+ * PWR: Physical Watchpoint Read enable: 0=off 1=on
+ * PWW: Physical Watchpoint Write enable: 0=off 1=on
+ * VWR: Virtual Watchpoint Read enable: 0=off 1=on
+ * VWW: Virtual Watchpoint Write enable: 0=off 1=on
+ * PMASK: Parity MASK  ???
+ * DME: Data MMU Enable: 0=off 1=on
+ * IME: Instruction MMU Enable: 0=off 1=on
+ * DCE: Data Cache Enable: 0=off 1=on
+ * ICE: Instruction Cache Enable: 0=off 1=on
+ */
+
+#define SPITFIRE_LSU_PWR      0x01000000
+#define SPITFIRE_LSU_PWW      0x00800000
+#define SPITFIRE_LSU_VWR      0x00400000
+#define SPITFIRE_LSU_VWW      0x00200000
+#define SPITFIRE_LSU_PMASK    0x000ffff0
+#define SPITFIRE_LSU_DME      0x00000008
+#define SPITFIRE_LSU_IME      0x00000004
+#define SPITFIRE_LSU_DCE      0x00000002
+#define SPITFIRE_LSU_ICE      0x00000001
+
+#endif /* !(_SPARC_ULTRA_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v1.3.3/linux/include/asm-sparc/unistd.h	Wed Mar  1 09:12:33 1995
+++ linux/include/asm-sparc/unistd.h	Thu Jun  8 23:48:06 1995
@@ -8,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
@@ -17,7 +17,9 @@
 { \
 long __res; \
 __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
-		  "t 0xa\n\t" \
+		  "t 0x10\n\t" \
+		  "nop\n\t" \
+		  "or %%g0, %%o0, %0\n\t" \
 		  : "=r" (__res) \
 		  : "0" (__NR_##name) \
 		  : "o0"); \
@@ -33,7 +35,9 @@
 long __res; \
 __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
 		  "or %%g0, %1, %%o1\n\t" \
-		  "t 0xa\n\t" \
+		  "t 0x10\n\t" \
+		  "nop\n\t" \
+		  "or %%g0, %%o0, %0\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)) \
 		  : "o0", "o1"); \
@@ -50,7 +54,9 @@
 __asm__ volatile ("or %%g0, %0, %%o0\n\t" \
 		  "or %%g0, %1, %%o1\n\t" \
 		  "or %%g0, %2, %%o2\n\t" \
-		  "t 0xa\n\t" \
+		  "t 0x10\n\t" \
+		  "nop\n\t" \
+		  "or %%g0, %%o0, %0\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(args)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
 		  : "o0", "o1", "o2"); \
@@ -68,7 +74,9 @@
 		  "or %%g0, %1, %%o1\n\t" \
 		  "or %%g0, %2, %%o2\n\t" \
 		  "or %%g0, %3, %%o3\n\t" \
-		  "t 0xa\n\t" \
+		  "t 0x10\n\t" \
+		  "nop\n\t" \
+		  "or %%g0, %%o0, %0\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
 		    "=r" ((long)(arg3)) \
 		  : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
@@ -89,7 +97,9 @@
 		  "or %%g0, %2, %%o2\n\t" \
 		  "or %%g0, %3, %%o3\n\t" \
 		  "or %%g0, %4, %%o4\n\t" \
-		  "t 0xa\n\t" \
+		  "t 0x10\n\t" \
+		  "nop\n\t" \
+		  "or %%g0, %%o0, %0\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
 		    "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -112,7 +122,9 @@
 		  "or %%g0, %3, %%o3\n\t" \
 		  "or %%g0, %4, %%o4\n\t" \
 		  "or %%g0, %5, %%o5\n\t" \
-		  "t 0xa\n\t" \
+		  "t 0x10\n\t" \
+		  "nop\n\t" \
+		  "or %%g0, %%o0, %0\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
 		    "=r" ((long)(arg3)), "=r" ((long)(arg4)), "=r" ((long)(arg5)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -139,10 +151,10 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
+/* static inline _syscall0(int,idle) */
 static inline _syscall0(int,fork)
 static inline _syscall0(int,pause)
-static inline _syscall0(int,setup)
+/* static inline _syscall0(int,setup) */
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
 static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
@@ -153,9 +165,33 @@
 static inline _syscall1(int,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+extern void sys_idle(void);
+static inline void idle(void)
+{
+	printk("[%d]idle()\n",current->pid);
+	sys_idle();
+	for(;;);
+}
+
+extern int sys_setup(void);
+static inline int setup(void)
+{
+	int retval;
+
+	printk("[%d]setup()\n",current->pid);
+	retval = sys_setup();
+	printk("[%d]setup() returned %d\n",current->pid, retval);
+}
+
+extern int sys_waitpid(int, int *, int);
 static inline pid_t wait(int * wait_stat)
 {
-	return waitpid(-1,wait_stat,0);
+	long retval, i;
+	printk("[%d]wait(%p)\n", current->pid, wait_stat);
+	retval = waitpid(-1,wait_stat,0);
+	printk("[%d]wait(%p) returned %ld\n", current->pid, wait_stat, retval);
+	for (i = 0; i < 1000000000; i++);
+	return retval;
 }
 
 #endif
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/vac-ops.h linux/include/asm-sparc/vac-ops.h
--- v1.3.3/linux/include/asm-sparc/vac-ops.h	Wed Feb 22 08:47:40 1995
+++ linux/include/asm-sparc/vac-ops.h	Thu Jun  8 23:48:12 1995
@@ -8,7 +8,7 @@
 */
 
 extern unsigned long *trapbase;
-extern char end, etext, msgbuf;
+extern char end, etext, edata;
 
 extern void flush_vac_context(void);
 extern void flush_vac_segment(unsigned int foo_segment);
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h
--- v1.3.3/linux/include/asm-sparc/vaddrs.h	Thu Feb  2 08:42:35 1995
+++ linux/include/asm-sparc/vaddrs.h	Sat Jun 17 11:21:41 1995
@@ -1,6 +1,8 @@
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
+#include <asm/head.h>
+
 /* asm-sparc/vaddrs.h:  Here will be define the virtual addresses at
  *                      which important I/O addresses will be mapped.
  *                      For instance the timer register virtual address
@@ -9,8 +11,34 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#define  TIMER_VADDR    0x3000   /* Next page after where the interrupt enable
-				  * register gets mapped at boot.
-				  */
+/* I can see only one reason why we should have statically defined
+ * mappings for devices and is the speedup improvements of not loading
+ * a pointer and then the value in the assembly code
+ */
+
+#define  AUXIO_VADDR  (KERNBASE+0x6000)    /* Auxiliary IO register */
+#define  TIMER_VADDR  (AUXIO_VADDR+0x1000) /* One page after AUXIO, length is
+					    * 5 pages which is needed on sun4m.
+					    */
+#define  INTREG_VADDR (TIMER_VADDR+0x5000)
+
+#define  IOBASE_VADDR   0xfe000000  /* Base for mapping pages */
+#define  IOBASE_LEN     0x00400000  /* Length of the IO area */
+#define  IOBASE_SUN4C_SEGMAP 100
+#define  DVMA_VADDR     0xfff00000  /* Base area of the DVMA on the 4c */
+#define  DVMA_LEN       0x000c0000  /* Size of the DVMA address space */
+
+/* On sun4m machines we need per-cpu virtual areas */
+#define  PERCPU_VADDR   0xff000000  /* Base for per-cpu virtual mappings */
+#define  PERCPU_ENTSIZE 0x00100000
+#define  PERCPU_LEN     ((PERCPU_ENTSIZE*NCPUS))
+
+/* per-cpu offsets */
+#define  PERCPU_TBR_OFFSET      0x00000      /* %tbr, mainly used for identification. */
+#define  PERCPU_KSTACK_OFFSET   0x01000      /* Beginning of kernel stack for this cpu */
+#define  PERCPU_MBOX_OFFSET     0x02000      /* Prom SMP Mailbox */
+#define  PERCPU_CPUID_OFFSET    0x03000      /* Per-cpu ID number. */
+#define  PERCPU_ISALIVE_OFFSET  0x03004      /* Has CPU been initted yet? */
+#define  PERCPU_ISIDLING_OFFSET 0x03008      /* Is CPU in idle loop spinning? */
 
 #endif /* !(_SPARC_VADDRS_H) */
diff -u --recursive --new-file v1.3.3/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h
--- v1.3.3/linux/include/asm-sparc/viking.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/viking.h	Wed Jun 14 09:39:18 1995
@@ -0,0 +1,51 @@
+/* viking.h:  Defines specific to the TI Viking MBUS module.
+ *            This is SRMMU stuff.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_VIKING_H
+#define _SPARC_VIKING_H
+
+/* Bits in the SRMMU control register for TI Viking modules.
+ *
+ * -------------------------------------------------------------
+ * |implvers| RSV |DP|RSV|TC|AC|SP|BM|PC|MBM|SB|IC|DC|RSV|NF|ME|
+ * -------------------------------------------------------------
+ *  31    24 23-20 19  18 17 16 15 14 13  12 11 10  9 8-2  1  0
+ *
+ * DP: Data Prefetcher Enable -- 0 = DP is off, 1 = DP is on
+ * TC: Tablewalk Cacheable -- 0 = Twalks are not cacheable
+ *                            1 = Twalks are cacheable
+ * AC: Alternate Cacheable -- 0 = Direct physical accesses not cacheable
+ *                            1 = Direct physical accesses are cacheable
+ * SP: SnooP Enable -- 0 = bus snooping off, 1 = bus snooping on
+ * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode
+ * MBM: MBus Mode -- 0 = not in MBus mode, 1 = in MBus mode
+ * SB: StoreBuffer enable -- 0 = store buffer off, 1 = store buffer on
+ * IC: Instruction Cache -- 0 = off, 1 = on
+ * DC: Data Cache -- 0 = off, 1 = 0n
+ * NF: No Fault -- 0 = faults generate traps, 1 = faults don't trap
+ * ME: MMU enable -- 0 = mmu not translating, 1 = mmu translating
+ *
+ */
+
+#define VIKING_DCENABLE     0x00000100   /* Enable data cache */
+#define VIKING_ICENABLE     0x00000200   /* Enable instruction cache */
+#define VIKING_SBENABLE     0x00000400   /* Enable store buffer */
+#define VIKING_MMODE        0x00000800   /* MBUS mode */
+#define VIKING_PCENABLE     0x00001000   /* Enable parity checking */
+
+/* Boot mode, 0 at boot-time, 1 after prom initializes the MMU. */
+#define VIKING_BMODE        0x00002000   
+#define VIKING_SPENABLE     0x00004000   /* Enable bus cache snooping */
+
+/* The deal with this AC bit is that if you are going to modify the
+ * contents of physical ram using the MMU bypass, you had better set
+ * this bit or things will get unsynchronized.  This is only applicable
+ * if an E-cache (ie. a PAC) is around and the Viking is not in MBUS mode.
+ */
+#define VIKING_ACENABLE     0x00008000   /* Enable alternate caching */
+#define VIKING_TCENABLE     0x00010000   /* Enable table-walks to be cached */
+#define VIKING_DPENABLE     0x00040000   /* Enable the data prefetcher */
+
+#endif
diff -u --recursive --new-file v1.3.3/linux/include/linux/fd.h linux/include/linux/fd.h
--- v1.3.3/linux/include/linux/fd.h	Tue Dec  6 11:44:59 1994
+++ linux/include/linux/fd.h	Tue Jun 20 08:22:36 1995
@@ -54,6 +54,9 @@
 			     512 : 128 << FD_SIZECODE(floppy) )
 #define FD_PERP 0x40
 
+#define FD_STRETCH 1
+#define FD_SWAPSIDES 2
+
 #ifndef __ASSEMBLY__
 /* the following structure is used by FDSETPRM, FDDEFPRM and FDGETPRM */
 struct floppy_struct {
@@ -184,7 +187,8 @@
   int fd_device;
   int last_checked; /* when was the drive last checked for a disk change? */
 
-
+  char *dmabuf;
+  int bufblocks;
 };
 
 struct floppy_write_errors {
diff -u --recursive --new-file v1.3.3/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.3/linux/include/linux/fs.h	Tue Jun 13 15:40:17 1995
+++ linux/include/linux/fs.h	Thu Jun 22 14:36:23 1995
@@ -331,7 +331,7 @@
  * This allows the kernel to read directories into kernel space or
  * to have different dirent layouts depending on the binary type.
  */
-typedef int (*filldir_t)(void *, char *, int, off_t, ino_t);
+typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
 	
 struct file_operations {
 	int (*lseek) (struct inode *, struct file *, off_t, int);
@@ -429,7 +429,7 @@
 extern int nr_files;
 extern struct super_block super_blocks[NR_SUPER];
 
-extern int shrink_buffers(unsigned int priority);
+extern int shrink_buffers(unsigned int priority, unsigned long limit);
 extern void refile_buffer(struct buffer_head * buf);
 extern void set_writetime(struct buffer_head * buf, int flag);
 extern void refill_freelist(int size);
diff -u --recursive --new-file v1.3.3/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.3/linux/include/linux/mm.h	Tue Jun 13 15:40:17 1995
+++ linux/include/linux/mm.h	Tue Jun 20 09:01:23 1995
@@ -149,9 +149,10 @@
  * goes to clearing the page. If you want a page without the clearing
  * overhead, just use __get_free_page() directly..
  */
-#define __get_free_page(priority) __get_free_pages((priority),0)
-extern unsigned long __get_free_pages(int priority, unsigned long gfporder);
-extern unsigned long __get_dma_pages(int priority, unsigned long gfporder);
+#define __get_free_page(priority) __get_free_pages((priority),0,~0UL)
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),MAX_DMA_ADDRESS)
+extern unsigned long __get_free_pages(int priority, unsigned long gfporder, unsigned long max_addr);
+
 extern inline unsigned long get_free_page(int priority)
 {
 	unsigned long page;
diff -u --recursive --new-file v1.3.3/linux/include/linux/module.h linux/include/linux/module.h
--- v1.3.3/linux/include/linux/module.h	Mon Jan 23 10:38:30 1995
+++ linux/include/linux/module.h	Mon Jun 26 11:06:53 1995
@@ -85,7 +85,7 @@
 /*
  * The first word of the module contains the use count.
  */
-#define GET_USE_COUNT(module)	(* (int *) (module)->addr)
+#define GET_USE_COUNT(module)	(* (long *) (module)->addr)
 /*
  * define the count variable, and usage macros.
  */
diff -u --recursive --new-file v1.3.3/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v1.3.3/linux/include/linux/mtio.h	Fri Jan 13 09:08:37 1995
+++ linux/include/linux/mtio.h	Mon Jun 26 08:31:37 1995
@@ -97,23 +97,11 @@
 #define MT_ISSCSI1		0x71	/* Generic ANSI SCSI-1 tape unit */
 #define MT_ISSCSI2		0x72	/* Generic ANSI SCSI-2 tape unit */
 
-/* QIC-40/QIC-80 ftape supported drives.
- * 20bit vendor ID + 0x800000
+/* QIC-40/80/3010/3020 ftape supported drives.
+ * 20bit vendor ID + 0x800000 (see vendors.h in ftape distribution)
  */
-#define MT_ISFTAPE_UNKNOWN	0x800000
-#define MT_ISCMSDJ10_DJ20	0x800047
-#define MT_ISCMSDJ10_DJ20_NEW	0x8011c4
-#define MT_ISARCHIVE_5580I	0x800005
-#define MT_ISARCHIVE_XL9250I	0x80014a
-#define MT_ISARCHIVE_31250Q	0x800146
-#define MT_ISINSIGHT_80		0x810005
-#define MT_ISCONNER_C250MQT	0x80014c
-#define MT_ISWANGTEK_2040F	0x8001c1
-#define MT_ISWANGTEK_2080F	0x8001c8
-#define MT_ISIOMEGA_250		0x808880
-#define MT_ISSUMMIT_SE150	0x800180
-#define MT_ISSUMMIT_SE250	0x800181
-#define MT_ISESCOM_IDTBU120E	0x800140
+#define MT_ISFTAPE_UNKNOWN	0x800000 /* obsolete */
+#define MT_ISFTAPE_FLAG	0x800000
 
 struct mt_tape_info {
 	long t_type;		/* device type id (mt_type) */
@@ -137,20 +125,6 @@
 	{MT_ISEVEREX_FT40A,	"Everex FT40A, QIC-40"}, \
 	{MT_ISSCSI1,		"Generic SCSI-1 tape"}, \
 	{MT_ISSCSI2,		"Generic SCSI-2 tape"}, \
-	{MT_ISFTAPE_UNKNOWN,	"Unknown floppy interface tape drive"},\
-	{MT_ISCMSDJ10_DJ20,	"Colorado DJ-10/DJ-20"},\
-	{MT_ISCMSDJ10_DJ20_NEW,	"Colorado DJ-10/DJ-20 (new)"},\
-	{MT_ISARCHIVE_5580I,	"Archive 5580i"},\
-	{MT_ISARCHIVE_XL9250I,	"Archive XL9250i [Conner/Escom]"},\
-	{MT_ISARCHIVE_31250Q,	"Escom/Archive 31250Q"},\
-	{MT_ISINSIGHT_80,	"Insight 80 Mb"},\
-	{MT_ISCONNER_C250MQT,	"Conner C250MQT"},\
-	{MT_ISWANGTEK_2040F,	"Wangtek 3040F"},\
-	{MT_ISWANGTEK_2080F,	"Wangtek 3080F"},\
-	{MT_ISIOMEGA_250,	"Iomega 250"},\
-	{MT_ISSUMMIT_SE150,	"Summit SE 150"},\
-	{MT_ISSUMMIT_SE250,	"Summit SE 250/Mountain FS8000"},\
-	{MT_ISESCOM_IDTBU120E,	"Identity IDTBU120E, Escom?"},\
 	{0, NULL} \
 }
 
diff -u --recursive --new-file v1.3.3/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- v1.3.3/linux/include/linux/sbpcd.h	Fri Jun  2 08:16:17 1995
+++ linux/include/linux/sbpcd.h	Mon Jun 19 10:28:40 1995
@@ -121,7 +121,7 @@
 #define _LINUX_SBPCD_H
 /*==========================================================================*/
 /*==========================================================================*/
-#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
+#define LONG_TIMING 1 /* test against timeouts with "gold" CDs on CR-521 */
 #undef  FUTURE
 
 #define TEST_UPC 0
diff -u --recursive --new-file v1.3.3/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v1.3.3/linux/include/linux/umsdos_fs.p	Mon Jun 12 16:49:42 1995
+++ linux/include/linux/umsdos_fs.p	Mon Jun 26 09:51:18 1995
@@ -1,6 +1,6 @@
-/* check.c 30/01/95 22.05.32 */
+/* check.c 23/01/95 03.38.30 */
 void check_page_tables (void);
-/* dir.c 18/03/95 00.30.50 */
+/* dir.c 22/06/95 00.22.12 */
 int UMSDOS_dir_read (struct inode *inode,
 	 struct file *filp,
 	 char *buf,
@@ -19,11 +19,7 @@
 	 int len,
 	 struct inode **result);
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
-/* emd.c 30/01/95 22.05.32 */
-int umsdos_readdir_kmem (struct inode *inode,
-	 struct file *filp,
-	 struct dirent *dirent,
-	 int count);
+/* emd.c 22/06/95 00.22.04 */
 int umsdos_file_read_kmem (struct inode *inode,
 	 struct file *filp,
 	 char *buf,
@@ -57,11 +53,13 @@
 int umsdos_findentry (struct inode *dir,
 	 struct umsdos_info *info,
 	 int expect);
-/* file.c 30/01/95 22.05.56 */
-/* inode.c 25/02/95 09.21.46 */
+/* file.c 25/01/95 02.25.38 */
+/* inode.c 12/06/95 09.49.40 */
 void UMSDOS_put_inode (struct inode *inode);
 void UMSDOS_put_super (struct super_block *sb);
-void UMSDOS_statfs (struct super_block *sb, struct statfs *buf, int);
+void UMSDOS_statfs (struct super_block *sb,
+	 struct statfs *buf,
+	 int bufsiz);
 int umsdos_real_lookup (struct inode *dir,
 	 const char *name,
 	 int len,
@@ -81,16 +79,16 @@
 struct super_block *UMSDOS_read_super (struct super_block *s,
 	 void *data,
 	 int silent);
-/* ioctl.c 21/02/95 20.58.22 */
+/* ioctl.c 22/06/95 00.22.08 */
 int UMSDOS_ioctl_dir (struct inode *dir,
 	 struct file *filp,
 	 unsigned int cmd,
 	 unsigned long data);
-/* mangle.c 30/01/95 22.05.56 */
+/* mangle.c 25/01/95 02.25.38 */
 void umsdos_manglename (struct umsdos_info *info);
 int umsdos_evalrecsize (int len);
 int umsdos_parse (const char *fname, int len, struct umsdos_info *info);
-/* namei.c 30/01/95 22.05.56 */
+/* namei.c 25/01/95 02.25.38 */
 void umsdos_lockcreate (struct inode *dir);
 void umsdos_startlookup (struct inode *dir);
 void umsdos_unlockcreate (struct inode *dir);
@@ -125,7 +123,7 @@
 	 struct inode *new_dir,
 	 const char *new_name,
 	 int new_len);
-/* rdir.c 18/03/95 00.30.18 */
+/* rdir.c 22/03/95 03.31.42 */
 int umsdos_rlookup_x (struct inode *dir,
 	 const char *name,
 	 int len,
@@ -135,4 +133,4 @@
 	 const char *name,
 	 int len,
 	 struct inode **result);
-/* symlink.c 30/01/95 22.05.32 */
+/* symlink.c 23/01/95 03.38.30 */
diff -u --recursive --new-file v1.3.3/linux/include/net/sock.h linux/include/net/sock.h
--- v1.3.3/linux/include/net/sock.h	Tue Jun  6 11:22:18 1995
+++ linux/include/net/sock.h	Mon Jun 26 09:26:03 1995
@@ -65,15 +65,15 @@
   struct options		*opt;
   volatile unsigned long	wmem_alloc;
   volatile unsigned long	rmem_alloc;
-  unsigned long			write_seq;
-  unsigned long			sent_seq;
-  unsigned long			acked_seq;
-  unsigned long			copied_seq;
-  unsigned long			rcv_ack_seq;
-  unsigned long			window_seq;
-  unsigned long			fin_seq;
-  unsigned long			urg_seq;
-  unsigned long			urg_data;
+  __u32				write_seq;
+  __u32				sent_seq;
+  __u32				acked_seq;
+  __u32				copied_seq;
+  __u32				rcv_ack_seq;
+  __u32				window_seq;
+  __u32				fin_seq;
+  __u32				urg_seq;
+  __u32				urg_data;
 
   /*
    * Not all are volatile, but some are, so we
diff -u --recursive --new-file v1.3.3/linux/include/net/tcp.h linux/include/net/tcp.h
--- v1.3.3/linux/include/net/tcp.h	Tue Jun  6 11:22:18 1995
+++ linux/include/net/tcp.h	Mon Jun 26 09:24:30 1995
@@ -85,19 +85,19 @@
  * and worry about wraparound (automatic with unsigned arithmetic).
  */
 
-extern __inline int before(unsigned long seq1, unsigned long seq2)
+extern __inline int before(__u32 seq1, __u32 seq2)
 {
-        return (long)(seq1-seq2) < 0;
+        return (__s32)(seq1-seq2) < 0;
 }
 
-extern __inline int after(unsigned long seq1, unsigned long seq2)
+extern __inline int after(__u32 seq1, __u32 seq2)
 {
-	return (long)(seq1-seq2) > 0;
+	return (__s32)(seq1-seq2) > 0;
 }
 
 
 /* is s2<=s1<=s3 ? */
-extern __inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
+extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
 {
 	return (after(seq1+1, seq2) && before(seq1, seq3+1));
 }
diff -u --recursive --new-file v1.3.3/linux/init/main.c linux/init/main.c
--- v1.3.3/linux/init/main.c	Fri Jun 16 22:02:56 1995
+++ linux/init/main.c	Mon Jun 26 12:42:52 1995
@@ -64,7 +64,7 @@
 extern void generic_NCR5380_setup(char *str, int *intr);
 extern void aha152x_setup(char *str, int *ints);
 extern void aha1542_setup(char *str, int *ints);
-extern void aha274x_setup(char *str, int *ints);
+extern void aic7xxx_setup(char *str, int *ints);
 extern void buslogic_setup(char *str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
@@ -175,8 +175,8 @@
 #ifdef CONFIG_SCSI_AHA1542
 	{ "aha1542=", aha1542_setup},
 #endif
-#ifdef CONFIG_SCSI_AHA274X
-	{ "aha274x=", aha274x_setup},
+#ifdef CONFIG_SCSI_AIC7XXX
+	{ "aic7xxx=", aic7xxx_setup},
 #endif
 #ifdef CONFIG_SCSI_BUSLOGIC
 	{ "buslogic=", buslogic_setup},
diff -u --recursive --new-file v1.3.3/linux/ipc/msg.c linux/ipc/msg.c
--- v1.3.3/linux/ipc/msg.c	Fri Jun 16 22:02:56 1995
+++ linux/ipc/msg.c	Mon Jun 26 11:06:53 1995
@@ -51,7 +51,7 @@
 	err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
 	if (err) 
 		return err;
-	if ((mtype = get_fs_long (&msgp->mtype)) < 1)
+	if ((mtype = get_user (&msgp->mtype)) < 1)
 		return -EINVAL;
 	id = (unsigned int) msqid % MSGMNI;
 	msq = msgque [id];
@@ -192,7 +192,7 @@
 			msq->msg_cbytes -= nmsg->msg_ts;
 			if (msq->wwait)
 				wake_up (&msq->wwait);
-			put_fs_long (nmsg->msg_type, &msgp->mtype);
+			put_user (nmsg->msg_type, &msgp->mtype);
 			memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
 			kfree(nmsg);
 			return msgsz;
diff -u --recursive --new-file v1.3.3/linux/ipc/shm.c linux/ipc/shm.c
--- v1.3.3/linux/ipc/shm.c	Fri Jun 16 22:02:56 1995
+++ linux/ipc/shm.c	Tue Jun 20 18:56:40 1995
@@ -674,7 +674,7 @@
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
 
-int shm_swap (int prio)
+int shm_swap (int prio, unsigned long limit)
 {
 	pte_t page;
 	struct shmid_ds *shp;
@@ -711,6 +711,8 @@
 	pte_val(page) = shp->shm_pages[idx];
 	if (!pte_present(page))
 		goto check_table;
+	if (pte_page(page) >= limit)
+		goto check_table;
 	swap_attempts++;
 
 	if (--counter < 0) { /* failed */
@@ -728,7 +730,7 @@
 		pte_t *page_table, pte;
 		unsigned long tmp;
 
-		if (SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK != id) {
+		if ((SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK) != id) {
 			printk ("shm_swap: id=%ld does not match shmd->vm_pte.id=%ld\n",
 				id, SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK);
 			continue;
diff -u --recursive --new-file v1.3.3/linux/ipc/util.c linux/ipc/util.c
--- v1.3.3/linux/ipc/util.c	Fri Jun 16 22:02:56 1995
+++ linux/ipc/util.c	Tue Jun 20 18:53:10 1995
@@ -57,7 +57,7 @@
     return;
 }
 
-int shm_swap (int prio)
+int shm_swap (int prio, unsigned long limit)
 {
     return 0;
 }
diff -u --recursive --new-file v1.3.3/linux/kernel/exit.c linux/kernel/exit.c
--- v1.3.3/linux/kernel/exit.c	Sat Jun 10 19:13:13 1995
+++ linux/kernel/exit.c	Mon Jun 26 11:06:53 1995
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#define DEBUG_PROC_TREE
+#undef DEBUG_PROC_TREE
 
 #include <linux/wait.h>
 #include <linux/errno.h>
@@ -515,7 +515,7 @@
 				if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
 					continue;
 				if (stat_addr)
-					put_fs_long((p->exit_code << 8) | 0x7f,
+					put_user((p->exit_code << 8) | 0x7f,
 						stat_addr);
 				p->exit_code = 0;
 				if (ru != NULL)
@@ -531,7 +531,7 @@
 					getrusage(p, RUSAGE_BOTH, ru);
 				flag = p->pid;
 				if (stat_addr)
-					put_fs_long(p->exit_code, stat_addr);
+					put_user(p->exit_code, stat_addr);
 				if (p->p_opptr != p->p_pptr) {
 					REMOVE_LINKS(p);
 					p->p_pptr = p->p_opptr;
diff -u --recursive --new-file v1.3.3/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.3/linux/kernel/ksyms.c	Tue Jun 20 09:10:32 1995
+++ linux/kernel/ksyms.c	Tue Jun 20 09:17:45 1995
@@ -57,7 +57,7 @@
 #endif
 
 #include <asm/irq.h>
-extern char floppy_track_buffer[];
+extern char *get_options(char *str, int *ints);
 extern void set_device_ro(int dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
   
@@ -88,6 +88,7 @@
 	/* stackable module support */
 	X(rename_module_symbol),
 	X(register_symtab),
+	X(get_options),
 
 	/* system info variables */
 	/* These check that they aren't defines (0/1) */
@@ -298,7 +299,6 @@
 	/* The next labels are needed for ftape driver.  */
 	X(ftape_big_buffer),
 #endif
-	X(floppy_track_buffer),
 #ifdef CONFIG_INET
 	/* support for loadable net drivers */
 	X(register_netdev),
diff -u --recursive --new-file v1.3.3/linux/kernel/module.c linux/kernel/module.c
--- v1.3.3/linux/kernel/module.c	Fri May 26 08:23:33 1995
+++ linux/kernel/module.c	Mon Jun 26 11:06:53 1995
@@ -154,8 +154,8 @@
 	}
 	strcpy((char *)(mp + 1), name); /* why not? */
 
-	npages = (size + sizeof (int) + 4095) / 4096;
-	if ((addr = vmalloc(npages * 4096)) == 0) {
+	npages = (size + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE;
+	if ((addr = vmalloc(npages * PAGE_SIZE)) == 0) {
 		kfree_s(mp, sspace);
 		return -ENOMEM;
 	}
@@ -169,7 +169,7 @@
 	mp->state = MOD_UNINITIALIZED;
 	mp->cleanup = NULL;
 
-	* (int *) addr = 0;	/* set use count to zero */
+	* (long *) addr = 0;	/* set use count to zero */
 	module_list = mp;	/* link it in */
 
 	PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
@@ -194,11 +194,14 @@
 	if (!suser())
 		return -EPERM;
 
+#ifdef __i386__
 	/* A little bit of protection... we "know" where the user stack is... */
+
 	if (symtab && ((unsigned long)symtab > 0xb0000000)) {
 		printk("warning: you are using an old insmod, no symbols will be inserted!\n");
 		symtab = NULL;
 	}
+#endif
 
 	/*
 	 * First reclaim any memory from dead modules that where not
@@ -214,11 +217,11 @@
 	memcpy_fromfs(&rt, routines, sizeof rt);
 	if ((mp = find_module(name)) == NULL)
 		return -ENOENT;
-	if ((codesize + sizeof (int) + 4095) / 4096 > mp->size)
+	if ((codesize + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE > mp->size)
 		return -EINVAL;
-	memcpy_fromfs((char *)mp->addr + sizeof (int), code, codesize);
-	memset((char *)mp->addr + sizeof (int) + codesize, 0,
-		mp->size * 4096 - (codesize + sizeof (int)));
+	memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize);
+	memset((char *)mp->addr + sizeof (long) + codesize, 0,
+		mp->size * PAGE_SIZE - (codesize + sizeof (long)));
 	PRINTK(( "module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
 		(unsigned long) rt.init, (unsigned long) rt.cleanup));
 	mp->cleanup = rt.cleanup;
@@ -231,9 +234,9 @@
 		int i;
 		int legal_start;
 
-		if ((error = verify_area(VERIFY_READ, symtab, sizeof(int))))
+		if ((error = verify_area(VERIFY_READ, &symtab->size, sizeof(symtab->size))))
 			return error;
-		memcpy_fromfs((char *)(&(size)), symtab, sizeof(int));
+		size = get_user(&symtab->size);
 
 		if ((newtab = (struct symbol_table*) kmalloc(size, GFP_KERNEL)) == NULL) {
 			return -ENOMEM;
@@ -417,7 +420,7 @@
 	int i;
 
 	i = 0;
-	for (i = 0 ; (buf[i] = get_fs_byte(user_name + i)) != '\0' ; ) {
+	for (i = 0 ; (buf[i] = get_user(user_name + i)) != '\0' ; ) {
 		if (++i >= MOD_MAX_NAME)
 			return -E2BIG;
 	}
@@ -613,7 +616,7 @@
  * - For a loadable module, the function should only be called in the
  *   context of init_module
  *
- * Those are the only restrictions! (apart from not being reenterable...)
+ * Those are the only restrictions! (apart from not being reentrant...)
  *
  * If you want to remove a symbol table for a loadable module,
  * the call looks like: "register_symtab(0)".
diff -u --recursive --new-file v1.3.3/linux/kernel/printk.c linux/kernel/printk.c
--- v1.3.3/linux/kernel/printk.c	Mon Jan 23 23:04:10 1995
+++ linux/kernel/printk.c	Mon Jun 26 11:06:53 1995
@@ -89,7 +89,7 @@
 				log_size--;
 				log_start &= LOG_BUF_LEN-1;
 				sti();
-				put_fs_byte(c,buf);
+				put_user(c,buf);
 				buf++;
 				i++;
 				cli();
@@ -115,7 +115,7 @@
 			j = log_start + log_size - count;
 			for (i = 0; i < count; i++) {
 				c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
-				put_fs_byte(c, buf++);
+				put_user(c, buf++);
 			}
 			if (do_clear)
 				logged_chars = 0;
diff -u --recursive --new-file v1.3.3/linux/kernel/signal.c linux/kernel/signal.c
--- v1.3.3/linux/kernel/signal.c	Fri Jun 16 22:02:56 1995
+++ linux/kernel/signal.c	Mon Jun 26 11:06:53 1995
@@ -28,7 +28,7 @@
 		error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
 		if (error)
 			return error;
-		new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
+		new_set = get_user(set) & _BLOCKABLE;
 		switch (how) {
 		case SIG_BLOCK:
 			current->blocked |= new_set;
@@ -47,7 +47,7 @@
 		error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
 		if (error)
 			return error;
-		put_fs_long(old_set, (unsigned long *) oset);
+		put_user(old_set, oset);
 	}
 	return 0;
 }
@@ -71,7 +71,7 @@
 	/* fill in "set" with signals pending but blocked. */
 	error = verify_area(VERIFY_WRITE, set, 4);
 	if (!error)
-		put_fs_long(current->blocked & current->signal, (unsigned long *)set);
+		put_user(current->blocked & current->signal, set);
 	return error;
 }
 
diff -u --recursive --new-file v1.3.3/linux/kernel/sys.c linux/kernel/sys.c
--- v1.3.3/linux/kernel/sys.c	Fri Jun 16 22:02:56 1995
+++ linux/kernel/sys.c	Mon Jun 26 11:06:53 1995
@@ -368,10 +368,10 @@
 		int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
 		if (error)
 			return error;
-		put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
-		put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
-		put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
-		put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
+		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);
 	}
 	return jiffies;
 }
@@ -554,7 +554,7 @@
 	if (gidsetsize > NGROUPS)
 		return -EINVAL;
 	for (i = 0; i < gidsetsize; i++, grouplist++) {
-		current->groups[i] = get_fs_word((unsigned short *) grouplist);
+		current->groups[i] = get_user(grouplist);
 	}
 	if (i < NGROUPS)
 		current->groups[i] = NOGROUP;
@@ -619,15 +619,15 @@
 	if (error)
 		return error;
 	memcpy_tofs(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
-	put_fs_byte(0,name->sysname+__OLD_UTS_LEN);
+	put_user(0,name->sysname+__OLD_UTS_LEN);
 	memcpy_tofs(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-	put_fs_byte(0,name->nodename+__OLD_UTS_LEN);
+	put_user(0,name->nodename+__OLD_UTS_LEN);
 	memcpy_tofs(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-	put_fs_byte(0,name->release+__OLD_UTS_LEN);
+	put_user(0,name->release+__OLD_UTS_LEN);
 	memcpy_tofs(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-	put_fs_byte(0,name->version+__OLD_UTS_LEN);
+	put_user(0,name->version+__OLD_UTS_LEN);
 	memcpy_tofs(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-	put_fs_byte(0,name->machine+__OLD_UTS_LEN);
+	put_user(0,name->machine+__OLD_UTS_LEN);
 	return 0;
 }
 
@@ -676,7 +676,7 @@
 	if (len > __NEW_UTS_LEN)
 		return -EINVAL;
 	for (i=0; i < len; i++) {
-		if ((system_utsname.domainname[i] = get_fs_byte(name+i)) == 0)
+		if ((system_utsname.domainname[i] = get_user(name+i)) == 0)
 			return 0;
 	}
 	system_utsname.domainname[i] = 0;
diff -u --recursive --new-file v1.3.3/linux/kernel/time.c linux/kernel/time.c
--- v1.3.3/linux/kernel/time.c	Fri Jun 16 22:02:56 1995
+++ linux/kernel/time.c	Mon Jun 26 11:06:53 1995
@@ -122,31 +122,30 @@
  */
 struct timezone sys_tz = { 0, 0};
 
-asmlinkage int sys_time(long * tloc)
+asmlinkage int sys_time(int * tloc)
 {
 	int i, error;
 
 	i = CURRENT_TIME;
 	if (tloc) {
-		error = verify_area(VERIFY_WRITE, tloc, 4);
+		error = verify_area(VERIFY_WRITE, tloc, sizeof(*tloc));
 		if (error)
 			return error;
-		put_fs_long(i,(unsigned long *)tloc);
+		put_user(i,tloc);
 	}
 	return i;
 }
 
-asmlinkage int sys_stime(unsigned long * tptr)
+asmlinkage int sys_stime(int * tptr)
 {
-	int error;
-	unsigned long value;
+	int error, value;
 
 	if (!suser())
 		return -EPERM;
 	error = verify_area(VERIFY_READ, tptr, sizeof(*tptr));
 	if (error)
 		return error;
-	value = get_fs_long(tptr);
+	value = get_user(tptr);
 	cli();
 	xtime.tv_sec = value;
 	xtime.tv_usec = 0;
diff -u --recursive --new-file v1.3.3/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- v1.3.3/linux/mm/kmalloc.c	Sat Jun 10 19:13:14 1995
+++ linux/mm/kmalloc.c	Tue Jun 20 09:29:13 1995
@@ -13,8 +13,9 @@
  */
 
 #include <linux/mm.h>
-#include <asm/system.h>
 #include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/dma.h>
 
 #define GFP_LEVEL_MASK 0xf
 
@@ -251,10 +252,13 @@
     sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */
 
     /* This can be done with ints on: This is private to this invocation */
-    if (dma_flag)
-      page = (struct page_descriptor *) __get_dma_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
-    else
-      page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
+    {
+    	unsigned long max_addr = ~0UL;
+    	if (dma_flag)
+    		max_addr = MAX_DMA_ADDRESS;
+	page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK,
+		sizes[order].gfporder, max_addr);
+    }
 
     if (!page) {
         static unsigned long last = 0;
diff -u --recursive --new-file v1.3.3/linux/mm/mmap.c linux/mm/mmap.c
--- v1.3.3/linux/mm/mmap.c	Sat Jun 10 12:55:57 1995
+++ linux/mm/mmap.c	Mon Jun 26 11:10:35 1995
@@ -189,26 +189,6 @@
 	}
 }
 
-asmlinkage int sys_mmap(unsigned long *buffer)
-{
-	int error;
-	unsigned long flags;
-	struct file * file = NULL;
-
-	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
-	if (error)
-		return error;
-	flags = get_fs_long(buffer+3);
-	if (!(flags & MAP_ANONYMOUS)) {
-		unsigned long fd = get_fs_long(buffer+4);
-		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
-	}
-	return do_mmap(file, get_fs_long(buffer), get_fs_long(buffer+1),
-		get_fs_long(buffer+2), flags, get_fs_long(buffer+5));
-}
-
-
 /*
  * Searching a VMA in the linear list task->mm->mmap is horribly slow.
  * Use an AVL (Adelson-Velskii and Landis) tree to speed up this search
diff -u --recursive --new-file v1.3.3/linux/mm/swap.c linux/mm/swap.c
--- v1.3.3/linux/mm/swap.c	Fri Jun 16 22:02:56 1995
+++ linux/mm/swap.c	Tue Jun 20 18:52:47 1995
@@ -53,7 +53,7 @@
 	int next;			/* next entry on swap list */
 } swap_info[MAX_SWAPFILES];
 
-extern int shm_swap (int);
+extern int shm_swap (int, unsigned long);
 
 unsigned long *swap_cache;
 
@@ -345,7 +345,7 @@
  * using a process that no longer actually exists (it might
  * have died while we slept).
  */
-static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table)
+static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table, unsigned long limit)
 {
 	pte_t pte;
 	unsigned long entry;
@@ -357,6 +357,8 @@
 	page = pte_page(pte);
 	if (page >= high_memory)
 		return 0;
+	if (page >= limit)
+		return 0;
 	if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
 		return 0;
 	if ((pte_dirty(pte) && delete_from_swap_cache(page)) || pte_young(pte))  {
@@ -428,7 +430,7 @@
 #define SWAP_RATIO	128
 
 static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir,
-	unsigned long address, unsigned long end)
+	unsigned long address, unsigned long end, unsigned long limit)
 {
 	pte_t * pte;
 	unsigned long pmd_end;
@@ -450,7 +452,7 @@
 	do {
 		int result;
 		vma->vm_task->mm->swap_address = address + PAGE_SIZE;
-		result = try_to_swap_out(vma, address, pte);
+		result = try_to_swap_out(vma, address, pte, limit);
 		if (result)
 			return result;
 		address += PAGE_SIZE;
@@ -460,7 +462,7 @@
 }
 
 static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir,
-	unsigned long address, unsigned long end)
+	unsigned long address, unsigned long end, unsigned long limit)
 {
 	pmd_t * pmd;
 	unsigned long pgd_end;
@@ -480,7 +482,7 @@
 		end = pgd_end;
 	
 	do {
-		int result = swap_out_pmd(vma, pmd, address, end);
+		int result = swap_out_pmd(vma, pmd, address, end, limit);
 		if (result)
 			return result;
 		address = (address + PMD_SIZE) & PMD_MASK;
@@ -490,7 +492,7 @@
 }
 
 static int swap_out_vma(struct vm_area_struct * vma, pgd_t *pgdir,
-	unsigned long start)
+	unsigned long start, unsigned long limit)
 {
 	unsigned long end;
 
@@ -501,7 +503,7 @@
 
 	end = vma->vm_end;
 	while (start < end) {
-		int result = swap_out_pgd(vma, pgdir, start, end);
+		int result = swap_out_pgd(vma, pgdir, start, end, limit);
 		if (result)
 			return result;
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
@@ -510,7 +512,7 @@
 	return 0;
 }
 
-static int swap_out_process(struct task_struct * p)
+static int swap_out_process(struct task_struct * p, unsigned long limit)
 {
 	unsigned long address;
 	struct vm_area_struct* vma;
@@ -531,7 +533,7 @@
 		address = vma->vm_start;
 
 	for (;;) {
-		int result = swap_out_vma(vma, pgd_offset(p, address), address);
+		int result = swap_out_vma(vma, pgd_offset(p, address), address, limit);
 		if (result)
 			return result;
 		vma = vma->vm_next;
@@ -543,7 +545,7 @@
 	return 0;
 }
 
-static int swap_out(unsigned int priority)
+static int swap_out(unsigned int priority, unsigned long limit)
 {
 	static int swap_task;
 	int loop, counter;
@@ -589,7 +591,7 @@
 		}
 		if (!--p->mm->swap_cnt)
 			swap_task++;
-		switch (swap_out_process(p)) {
+		switch (swap_out_process(p, limit)) {
 			case 0:
 				if (p->mm->swap_cnt)
 					swap_task++;
@@ -612,7 +614,7 @@
  * free'd, so hopefully we'll get reasonable behaviour even under very
  * different circumstances.
  */
-static int try_to_free_page(int priority)
+static int try_to_free_page(int priority, unsigned long limit)
 {
 	static int state = 0;
 	int i=6;
@@ -620,15 +622,15 @@
 	switch (state) {
 		do {
 		case 0:
-			if (priority != GFP_NOBUFFER && shrink_buffers(i))
+			if (priority != GFP_NOBUFFER && shrink_buffers(i, limit))
 				return 1;
 			state = 1;
 		case 1:
-			if (shm_swap(i))
+			if (shm_swap(i, limit))
 				return 1;
 			state = 2;
 		default:
-			if (swap_out(i))
+			if (swap_out(i, limit))
 				return 1;
 			state = 0;
 		} while(i--);
@@ -730,18 +732,22 @@
 /*
  * Some ugly macros to speed up __get_free_pages()..
  */
-#define RMQUEUE(order) \
+#define RMQUEUE(order, limit) \
 do { struct mem_list * queue = free_area_list+order; \
      unsigned long new_order = order; \
-	do { struct mem_list *next = queue->next; \
-		if (queue != next) { \
-			(queue->next = next->next)->prev = queue; \
-			mark_used((unsigned long) next, new_order); \
-			nr_free_pages -= 1 << order; \
-			restore_flags(flags); \
-			EXPAND(next, order, new_order); \
-			return (unsigned long) next; \
-		} new_order++; queue++; \
+	do { struct mem_list *prev = queue, *ret; \
+		while (queue != (ret = prev->next)) { \
+			if ((unsigned long) ret < (limit)) { \
+				(prev->next = ret->next)->prev = prev; \
+				mark_used((unsigned long) ret, new_order); \
+				nr_free_pages -= 1 << order; \
+				restore_flags(flags); \
+				EXPAND(ret, order, new_order); \
+				return (unsigned long) ret; \
+			} \
+			prev = ret; \
+		} \
+		new_order++; queue++; \
 	} while (new_order < NR_MEM_LISTS); \
 } while (0)
 
@@ -761,7 +767,7 @@
 	} mem_map[MAP_NR((unsigned long) addr)] = 1; \
 } while (0)
 
-unsigned long __get_free_pages(int priority, unsigned long order)
+unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
 {
 	unsigned long flags;
 	int reserved_pages;
@@ -781,41 +787,14 @@
 repeat:
 	cli();
 	if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
-		RMQUEUE(order);
+		RMQUEUE(order, limit);
 		restore_flags(flags);
 		return 0;
 	}
 	restore_flags(flags);
-	if (priority != GFP_BUFFER && try_to_free_page(priority))
+	if (priority != GFP_BUFFER && try_to_free_page(priority, limit))
 		goto repeat;
 	return 0;
-}
-
-/*
- * Yes, I know this is ugly. Don't tell me.
- */
-unsigned long __get_dma_pages(int priority, unsigned long order)
-{
-	unsigned long list = 0;
-	unsigned long result;
-	unsigned long limit = MAX_DMA_ADDRESS;
-
-	/* if (EISA_bus) limit = ~0UL; */
-	if (priority != GFP_ATOMIC)
-		priority = GFP_BUFFER;
-	for (;;) {
-		result = __get_free_pages(priority, order);
-		if (result < limit) /* covers failure as well */
-			break;
-		*(unsigned long *) result = list;
-		list = result;
-	}
-	while (list) {
-		unsigned long tmp = list;
-		list = *(unsigned long *) list;
-		free_pages(tmp, order);
-	}
-	return result;
 }
 
 /*
diff -u --recursive --new-file v1.3.3/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v1.3.3/linux/mm/vmalloc.c	Tue May 30 12:17:18 1995
+++ linux/mm/vmalloc.c	Mon Jun 26 11:06:53 1995
@@ -228,7 +228,7 @@
 		while (addr < vaddr) {
 			if (count == 0)
 				goto finished;
-			put_fs_byte('\0', buf++), addr++, count--;
+			put_user('\0', buf++), addr++, count--;
 		}
 		n = tmp->size - PAGE_SIZE;
 		if (addr > vaddr)
@@ -236,7 +236,7 @@
 		while (--n >= 0) {
 			if (count == 0)
 				goto finished;
-			put_fs_byte(*addr++, buf++), count--;
+			put_user(*addr++, buf++), count--;
 		}
 	}
 finished:
diff -u --recursive --new-file v1.3.3/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.3/linux/net/appletalk/ddp.c	Tue Jun  6 12:16:42 1995
+++ linux/net/appletalk/ddp.c	Mon Jun 26 11:06:53 1995
@@ -998,9 +998,9 @@
 	err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
 	if(err)
 		return err;
-	put_fs_long(sizeof(int),(unsigned long *)optlen);
+	put_user(sizeof(int),optlen);
 	err=verify_area(VERIFY_WRITE,optval,sizeof(int));
-	put_fs_long(val,(unsigned long *)optval);
+	put_user(val,optval);
 	return(0);
 }
 
diff -u --recursive --new-file v1.3.3/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.3/linux/net/ax25/af_ax25.c	Tue Jun  6 12:16:42 1995
+++ linux/net/ax25/af_ax25.c	Mon Jun 26 11:06:53 1995
@@ -708,12 +708,12 @@
 	if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0)
 		return err;
 
-	put_fs_long(sizeof(int), (unsigned long *)optlen);
+	put_user(sizeof(int), optlen);
 
 	if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
 		return err;
 
-	put_fs_long(val, (unsigned long *)optval);
+	put_user(val, optval);
 
 	return 0;
 }
diff -u --recursive --new-file v1.3.3/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v1.3.3/linux/net/ipv4/raw.c	Fri Jun 16 22:02:56 1995
+++ linux/net/ipv4/raw.c	Thu Jun 22 10:28:12 1995
@@ -75,7 +75,7 @@
 		return;
 
 	/* This is meaningless in raw sockets. */
-	if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) 
+	if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
 	{
 		if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
 		return;
diff -u --recursive --new-file v1.3.3/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.3/linux/net/ipv4/tcp.c	Tue Jun  6 12:16:44 1995
+++ linux/net/ipv4/tcp.c	Mon Jun 26 12:14:44 1995
@@ -1252,7 +1252,7 @@
  *	This routine sends an ack and also updates the window. 
  */
  
-static void tcp_send_ack(unsigned long sequence, unsigned long ack,
+static void tcp_send_ack(u32 sequence, u32 ack,
 	     struct sock *sk,
 	     struct tcphdr *th, unsigned long daddr)
 {
@@ -1361,7 +1361,7 @@
   	t1->doff = sizeof(*t1)/4;
   	tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
   	if (sk->debug)
-  		 printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
+  		 printk("\rtcp_ack: seq %x ack %x\n", sequence, ack);
   	tcp_statistics.TcpOutSegs++;
   	sk->prot->queue_xmit(sk, dev, buff, 1);
 }
@@ -1976,8 +1976,8 @@
 {
 	struct wait_queue wait = { current, NULL };
 	int copied = 0;
-	unsigned long peek_seq;
-	volatile unsigned long *seq;	/* So gcc doesn't overoptimise */
+	u32 peek_seq;
+	volatile u32 *seq;	/* So gcc doesn't overoptimise */
 	unsigned long used;
 
 	/* 
@@ -2614,7 +2614,7 @@
  *	That's funny, Linux has one built in!  Use it!
  */
 
-extern inline unsigned long tcp_init_seq(void)
+extern inline u32 tcp_init_seq(void)
 {
 	struct timeval tv;
 	do_gettimeofday(&tv);
@@ -2631,7 +2631,7 @@
  
 static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
 		 unsigned long daddr, unsigned long saddr,
-		 struct options *opt, struct device *dev, unsigned long seq)
+		 struct options *opt, struct device *dev, u32 seq)
 {
 	struct sk_buff *buff;
 	struct tcphdr *t1;
@@ -3069,7 +3069,7 @@
 
 extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
 {
-	unsigned long ack;
+	u32 ack;
 	int flag = 0;
 
 	/* 
@@ -3116,7 +3116,7 @@
 	if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq)) 
 	{
 		if(sk->debug)
-			printk("Ack ignored %lu %lu\n",ack,sk->sent_seq);
+			printk("Ack ignored %u %u\n",ack,sk->sent_seq);
 			
 		/*
 		 *	Keepalive processing.
@@ -3541,7 +3541,7 @@
 		if (!sk->dead)
 			sk->state_change(sk);
 		if(sk->debug)
-			printk("rcv_ack_seq: %lX==%lX, acked_seq: %lX==%lX\n",
+			printk("rcv_ack_seq: %X==%X, acked_seq: %X==%X\n",
 				sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq);
 		if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/) 
 		{
@@ -3763,8 +3763,7 @@
 	struct sk_buff *skb1, *skb2;
 	struct tcphdr *th;
 	int dup_dumped=0;
-	unsigned long new_seq;
-	unsigned long shut_seq;
+	u32 new_seq, shut_seq;
 
 	th = skb->h.th;
 	skb->len = len -(th->doff*4);
@@ -3824,7 +3823,7 @@
 			if(after(new_seq,shut_seq))
 			{
 				if(sk->debug)
-					printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n",
+					printk("Data arrived on %p after close [Data right edge %X, Socket shut on %X] %d\n",
 						sk, new_seq, shut_seq, sk->blog);
 				if(sk->dead)
 				{
@@ -3868,9 +3867,9 @@
 			if(sk->debug)
 			{
 				printk("skb1=%p :", skb1);
-				printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
-				printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
-				printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
+				printk("skb1->h.th->seq = %d: ", skb1->h.th->seq);
+				printk("skb->h.th->seq = %d\n",skb->h.th->seq);
+				printk("copied_seq = %d acked_seq = %d\n", sk->copied_seq,
 						sk->acked_seq);
 			}
 			
@@ -4382,7 +4381,7 @@
 extern __inline__ int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
 	     struct options *opt, unsigned long saddr, struct device *dev)
 {
-	unsigned long next_seq;
+	u32 next_seq;
 
 	next_seq = len - 4*th->doff;
 	if (th->fin)
@@ -4751,7 +4750,7 @@
 		if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead && 
 			after(th->seq, sk->acked_seq) && !th->rst)
 		{
-			long seq=sk->write_seq;
+			u32 seq = sk->write_seq;
 			if(sk->debug)
 				printk("Doing a BSD time wait\n");
 			tcp_statistics.TcpEstabResets++;	   
diff -u --recursive --new-file v1.3.3/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v1.3.3/linux/net/ipv4/udp.c	Tue Jun  6 12:16:44 1995
+++ linux/net/ipv4/udp.c	Thu Jun 22 10:28:32 1995
@@ -142,7 +142,7 @@
 	if (sk == NULL) 
 	  	return;	/* No socket for error */
   	
-	if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) 
+	if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
 	{	/* Slow down! */
 		if (sk->cong_window > 1) 
 			sk->cong_window = sk->cong_window/2;
diff -u --recursive --new-file v1.3.3/linux/net/socket.c linux/net/socket.c
--- v1.3.3/linux/net/socket.c	Fri Jun 16 22:02:56 1995
+++ linux/net/socket.c	Mon Jun 26 11:06:54 1995
@@ -136,7 +136,7 @@
 		
 	if((err=verify_area(VERIFY_WRITE,ulen,sizeof(*ulen)))<0)
 		return err;
-	len=get_fs_long(ulen);
+	len=get_user(ulen);
 	if(len>klen)
 		len=klen;
 	if(len<0 || len> MAX_SOCK_ADDR)
@@ -147,7 +147,7 @@
 			return err;
 		memcpy_tofs(uaddr,kaddr,len);
 	}
- 	put_fs_long(len,ulen);
+ 	put_user(len,ulen);
  	return 0;
 }
 
@@ -625,7 +625,7 @@
  *	Create a pair of connected sockets.
  */
 
-asmlinkage int sys_socketpair(int family, int type, int protocol, unsigned long usockvec[2])
+asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2])
 {
 	int fd1, fd2, i;
 	struct socket *sock1, *sock2;
@@ -668,15 +668,15 @@
 	sock1->state = SS_CONNECTED;
 	sock2->state = SS_CONNECTED;
 
-	er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int));
+	er=verify_area(VERIFY_WRITE, usockvec, sizeof(usockvec));
 	if(er)
 	{
 		sys_close(fd1);
 		sys_close(fd2);
 	 	return er;
 	}
-	put_fs_long(fd1, &usockvec[0]);
-	put_fs_long(fd2, &usockvec[1]);
+	put_user(fd1, &usockvec[0]);
+	put_user(fd2, &usockvec[1]);
 
 	return(0);
 }
@@ -1132,72 +1132,72 @@
 	if(er)
 		return er;
 		
-	a0=get_fs_long(args);
-	a1=get_fs_long(args+1);
+	a0=get_user(args);
+	a1=get_user(args+1);
 	
 		
 	switch(call) 
 	{
 		case SYS_SOCKET:
-			return(sys_socket(a0,a1,get_fs_long(args+2)));
+			return(sys_socket(a0,a1,get_user(args+2)));
 		case SYS_BIND:
 			return(sys_bind(a0,(struct sockaddr *)a1,
-				get_fs_long(args+2)));
+					get_user(args+2)));
 		case SYS_CONNECT:
 			return(sys_connect(a0, (struct sockaddr *)a1,
-				get_fs_long(args+2)));
+					   get_user(args+2)));
 		case SYS_LISTEN:
 			return(sys_listen(a0,a1));
 		case SYS_ACCEPT:
 			return(sys_accept(a0,(struct sockaddr *)a1,
-				(int *)get_fs_long(args+2)));
+					  (int *)get_user(args+2)));
 		case SYS_GETSOCKNAME:
 			return(sys_getsockname(a0,(struct sockaddr *)a1,
-				(int *)get_fs_long(args+2)));
+					       (int *)get_user(args+2)));
 		case SYS_GETPEERNAME:
 			return(sys_getpeername(a0, (struct sockaddr *)a1,
-				(int *)get_fs_long(args+2)));
+					       (int *)get_user(args+2)));
 		case SYS_SOCKETPAIR:
 			return(sys_socketpair(a0,a1,
-				get_fs_long(args+2),
-				(unsigned long *)get_fs_long(args+3)));
+					      get_user(args+2),
+					      (int *)get_user(args+3)));
 		case SYS_SEND:
 			return(sys_send(a0,
 				(void *)a1,
-				get_fs_long(args+2),
-				get_fs_long(args+3)));
+				get_user(args+2),
+				get_user(args+3)));
 		case SYS_SENDTO:
 			return(sys_sendto(a0,(void *)a1,
-				get_fs_long(args+2),
-				get_fs_long(args+3),
-				(struct sockaddr *)get_fs_long(args+4),
-				get_fs_long(args+5)));
+				get_user(args+2),
+				get_user(args+3),
+				(struct sockaddr *)get_user(args+4),
+				get_user(args+5)));
 		case SYS_RECV:
 			return(sys_recv(a0,
 				(void *)a1,
-				get_fs_long(args+2),
-				get_fs_long(args+3)));
+				get_user(args+2),
+				get_user(args+3)));
 		case SYS_RECVFROM:
 			return(sys_recvfrom(a0,
 				(void *)a1,
-				get_fs_long(args+2),
-				get_fs_long(args+3),
-				(struct sockaddr *)get_fs_long(args+4),
-				(int *)get_fs_long(args+5)));
+				get_user(args+2),
+				get_user(args+3),
+				(struct sockaddr *)get_user(args+4),
+				(int *)get_user(args+5)));
 		case SYS_SHUTDOWN:
 			return(sys_shutdown(a0,a1));
 		case SYS_SETSOCKOPT:
 			return(sys_setsockopt(a0,
 				a1,
-				get_fs_long(args+2),
-				(char *)get_fs_long(args+3),
-				get_fs_long(args+4)));
+				get_user(args+2),
+				(char *)get_user(args+3),
+				get_user(args+4)));
 		case SYS_GETSOCKOPT:
 			return(sys_getsockopt(a0,
 				a1,
-				get_fs_long(args+2),
-				(char *)get_fs_long(args+3),
-				(int *)get_fs_long(args+4)));
+				get_user(args+2),
+				(char *)get_user(args+3),
+				(int *)get_user(args+4)));
 	}
 	return -EINVAL; /* to keep gcc happy */
 }
