diff -u --recursive --new-file v2.1.47/linux/CREDITS linux/CREDITS
--- v2.1.47/linux/CREDITS	Thu Jul 17 10:06:03 1997
+++ linux/CREDITS	Thu Jul 31 13:09:16 1997
@@ -335,6 +335,15 @@
 S: 4850 Moresnet
 S: Belgium
 
+N: Cort Dougan
+E: cort@cs.nmt.edu
+W: http://www.cs.nmt.edu/~cort/
+D: PowerPC PReP port
+S: Computer Science Department
+S: New Mexico Tech
+S: Socorro NM 87801
+S: USA
+
 N: Thomas Dunbar
 E: tdunbar@vtaix.cc.vt.edu
 D: TeX & METAFONT hacking/maintenance
@@ -911,6 +920,14 @@
 N: Peter MacDonald
 D: SLS distribution
 D: Initial implementation of VC's, pty's and select()
+
+N: Paul Mackerras
+E: paulus@cs.anu.edu.au
+D: Linux port for PCI Power Macintosh
+S: Dept. of Computer Science
+S: Australian National University
+S: Canberra  ACT  0200
+S: AUSTRALIA
 
 N: James B. MacLean
 E: macleajb@ednet.ns.ca
diff -u --recursive --new-file v2.1.47/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.47/linux/Documentation/Configure.help	Thu Jul 17 10:06:03 1997
+++ linux/Documentation/Configure.help	Sun Aug  3 19:39:57 1997
@@ -1672,20 +1672,62 @@
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
-Adaptec AHA274X/284X/294X support
+Adaptec AIC7xxx support (includes 274x/284x/294x)
 CONFIG_SCSI_AIC7XXX
   Information about this SCSI host adapter is contained in
   drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
-  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it
-  doesn't work out of the box, you may have to change some settings in
-  drivers/scsi/aic7xxx.h. It has been reported that the "wide
-  negotiation" on these cards is not quite working and should be
-  disabled. Note that the AHA2920 SCSI host adapter is *not* supported
-  by this driver; choose "Future Domain 16xx SCSI support" instead. If
-  you want to compile this driver a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called aic7xxx.o.
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that
+  the AHA2920 SCSI host adapter is *not* supported by this driver; choose
+  "Future Domain 16xx SCSI support" instead. If you want to compile this
+  driver as module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read Documentation/
+  modules.txt. The module will be called aic7xxx.o.
+
+Enable tagged command queueing
+CONFIG_AIC7XXX_TAGGED_QUEUEING
+  This option allows you to enable tagged command queueing for this
+  driver.  Some scsi devices do not properly support this
+  feature.  Tagged command queueing will improve performance.
+
+Maximum number of commands per LUN
+  CONFIG_AIC7XXX_CMDS_PER_LUN
+  This option allows you to set the maximum number of commands queued
+  per LUN.  If tagged queueing is enabled, then you may want to try
+  increasing AIC7XXX_CMDS_PER_LUN to more than 2.  By default, we limit
+  the SCBs per LUN to 2 with or without tagged queueing enabled.  If
+  tagged queueing is disabled, the sequencer will keep the 2nd SCB in
+  the input queue until the first one completes - so it is OK to to have
+  more than 1 SCB queued.  If tagged queueing is enabled, then the
+  sequencer will attempt to send the 2nd SCB to the device while the
+  first SCB is executing and the device is disconnected.  For adapters
+  limited to 4 SCBs, you may want to actually decrease the commands per
+  LUN to 1, if you often have more than 2 devices active at the same
+  time.  This will allocate 1 SCB for each device and ensure that there
+  will always be a free SCB for up to 4 devices active at the same time.
+  When SCB paging is enabled, set the commands per LUN to 8 or higher
+  (see SCB paging support below).  Note that if AIC7XXX_CMDS_PER_LUN is
+  not defined and tagged queueing is enabled, the driver will attempt to
+  set the commands per LUN using its own heuristic based on the number
+  of available SCBs.
+
+Enable SCB paging
+CONFIG_AIC7XXX_PAGE_ENABLE
+  This option enables SCB paging.  This will increase performance when
+  tagged queueing is enabled.  Note that you should increase the
+  AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices allow at
+  least this many.  Note that EISA and VLB controllers do not support
+  SCB paging due to chip limitations; enabling it on these controllers
+  has no effect.
+
+Collect statistics to report in /proc
+CONFIG_AIC7XXX_PROC_STATS
+  This option enables collection of SCSI transfer statistics for the
+  /proc filesystem.  This does affect performance since it has to
+  maintain statistics.
+
+Delay in seconds after SCSI bus reset
+CONFIG_AIC7XXX_RESET_DELAY
+  This option sets the delay in seconds after a SCSI bus reset.
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
@@ -4645,6 +4687,18 @@
   fashion. (They should also read Documentation/smp.) If you think you
   have a use for such a device (such as periodic data sampling), then
   say Y here, and go read the file Documentation/rtc.txt for details.
+
+/dev/nvram support
+CONFIG_NVRAM
+  If you say Y here and create a character special file /dev/nvram
+  with major number 10 and minor number 144 using mknod ("man mknod"),
+  you get access to the non-volatile memory in the real time clock
+  (RTC). This is conventionally called "CMOS RAM" on PCs and "NVRAM"
+  on Ataris. /dev/nvram may be used to view settings there, or to
+  change them (with some utility). It could also be used to frequently
+  save a few bits of very important data, that may not be lost over
+  power-off and for which writing to disk is too insecure. On Atari
+  machines, /dev/nvram is always configured and needs not be selected.
 
 ARC console time
 CONFIG_RTC_ARC
diff -u --recursive --new-file v2.1.47/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.1.47/linux/Documentation/ioctl-number.txt	Thu Jun 26 12:33:36 1997
+++ linux/Documentation/ioctl-number.txt	Fri Jul 25 11:11:17 1997
@@ -1,5 +1,5 @@
 Ioctl Numbers
-10 Apr 1997
+25 Jul 1997
 Michael Chastain
 <mec@shout.net>
 
@@ -119,3 +119,5 @@
 					<mailto:b.kohl@ipn-b.comlink.apc.org>
 0xA0	all	Small Device Project	in development:
 					<mailto:khollis@northwest.com>
+0xA3	90-9F	DoubleTalk driver	in development:
+					<mailto:jrv@vanzandt.mv.com>
diff -u --recursive --new-file v2.1.47/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.47/linux/MAINTAINERS	Thu Jul 17 10:06:03 1997
+++ linux/MAINTAINERS	Thu Jul 31 13:09:16 1997
@@ -452,6 +452,18 @@
 W:	http://www.cage.curtin.edu.au/~campbell/parbus/
 S:	Maintained
 
+LINUX FOR POWERPC (PREP)
+P:	Cort Dougan
+M:	cort@cs.nmt.edu
+W:	http://www.cs.nmt.edu/~linuxppc/
+S:	Maintained
+
+LINUX FOR POWER MACINTOSH
+P:	Paul Mackerras
+M:	paulus@cs.anu.edu.au
+L:	linux-pmac@samba.anu.edu.au
+S:	Maintained
+
 FPU EMULATOR
 P:	Bill Metzenthen
 M:	billm@suburbia.net
diff -u --recursive --new-file v2.1.47/linux/Makefile linux/Makefile
--- v2.1.47/linux/Makefile	Sun Jul 27 12:11:00 1997
+++ linux/Makefile	Sun Aug  3 19:39:57 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 47
+SUBLEVEL = 48
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
@@ -335,7 +335,6 @@
 mrproper: clean
 	rm -f include/linux/autoconf.h include/linux/version.h
 	rm -f drivers/sound/local.h drivers/sound/.defines
-	rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
 	rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash
 	rm -f drivers/net/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h
 	rm -f drivers/net/soundmodem/sm_tbl_{hapn4800,psk4800}.h
diff -u --recursive --new-file v2.1.47/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.1.47/linux/arch/alpha/kernel/ptrace.c	Sat May 24 09:10:22 1997
+++ linux/arch/alpha/kernel/ptrace.c	Mon Aug  4 14:37:19 1997
@@ -650,7 +650,7 @@
 		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
diff -u --recursive --new-file v2.1.47/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.1.47/linux/arch/alpha/kernel/signal.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/kernel/signal.c	Mon Aug  4 14:37:32 1997
@@ -315,7 +315,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			single_stepping |= ptrace_cancel_bpt(current);
 			if (!(signr = current->exit_code))
@@ -354,7 +354,7 @@
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 						SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				single_stepping |= ptrace_cancel_bpt(current);
 				continue;
diff -u --recursive --new-file v2.1.47/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.1.47/linux/arch/i386/boot/setup.S	Sun Jul 27 12:11:00 1997
+++ linux/arch/i386/boot/setup.S	Fri Jul 25 18:52:51 1997
@@ -272,8 +272,8 @@
 	! and fall into the old memory detection code to populate the
 	! compatability slot.
 
-	pop	ebx
 oldstylemem:
+	pop	ebx
 #endif
 	mov	ah,#0x88
 	int	0x15
diff -u --recursive --new-file v2.1.47/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.47/linux/arch/i386/defconfig	Sun Jul 27 12:11:00 1997
+++ linux/arch/i386/defconfig	Thu Jul 31 14:57:56 1997
@@ -139,6 +139,7 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
@@ -171,6 +172,7 @@
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
@@ -234,6 +236,7 @@
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
 
 #
diff -u --recursive --new-file v2.1.47/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.1.47/linux/arch/i386/kernel/ptrace.c	Thu May 15 16:48:01 1997
+++ linux/arch/i386/kernel/ptrace.c	Mon Aug  4 13:57:54 1997
@@ -577,7 +577,7 @@
 		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
diff -u --recursive --new-file v2.1.47/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.1.47/linux/arch/i386/kernel/signal.c	Thu May 15 16:48:01 1997
+++ linux/arch/i386/kernel/signal.c	Mon Aug  4 13:58:13 1997
@@ -346,7 +346,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -386,7 +386,7 @@
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 						SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
diff -u --recursive --new-file v2.1.47/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.47/linux/arch/i386/kernel/smp.c	Mon Jun 16 16:35:53 1997
+++ linux/arch/i386/kernel/smp.c	Thu Jul 31 13:09:16 1997
@@ -156,6 +156,9 @@
 volatile unsigned long  smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
 volatile int smp_process_available=0;
 
+const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
+
+
 /*#define SMP_DEBUG*/
 
 #ifdef SMP_DEBUG
diff -u --recursive --new-file v2.1.47/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.47/linux/arch/i386/mm/init.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/mm/init.c	Wed Jul 30 16:17:21 1997
@@ -209,7 +209,7 @@
 	pgd_val(pg_dir[0]) = 0;
 
 	/* Map whole memory from 0xC0000000 */
-
+	pg_dir += 768;
 	while (address < end_mem) {
 		/*
 		 * If we're running on a Pentium CPU, we can use the 4MB
@@ -224,13 +224,13 @@
 
 			set_in_cr4(X86_CR4_PSE);
 			wp_works_ok = 1;
-			__pe = _PAGE_TABLE + _PAGE_4M + __pa(address);
+			__pe = _KERNPG_TABLE + _PAGE_4M + __pa(address);
 			/* Make it "global" too if supported */
 			if (x86_capability & X86_FEATURE_PGE) {
 				set_in_cr4(X86_CR4_PGE);
 				__pe += _PAGE_GLOBAL;
 			}
-			pgd_val(pg_dir[768]) = _PAGE_TABLE + _PAGE_4M + __pa(address);
+			pgd_val(*pg_dir) = __pe;
 			pg_dir++;
 			address += 4*1024*1024;
 			continue;
@@ -239,13 +239,13 @@
 		 * We're on a [34]86, use normal page tables.
 		 * pg_table is physical at this point
 		 */
-		pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
+		pg_table = (pte_t *) (PAGE_MASK & pgd_val(*pg_dir));
 		if (!pg_table) {
 			pg_table = (pte_t *) __pa(start_mem);
 			start_mem += PAGE_SIZE;
 		}
 
-		pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table;
+		pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pg_table;
 		pg_dir++;
 		/* now change pg_table to kernel virtual addresses */
 		pg_table = (pte_t *) __va(pg_table);
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.1.47/linux/arch/m68k/Makefile	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/Makefile	Thu Jul 31 13:09:16 1997
@@ -79,8 +79,6 @@
 SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
 endif
 
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
 lilo:	vmlinux
 	if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
@@ -106,7 +104,5 @@
 
 archclean:
 	rm -f vmlinux.gz
-	@$(MAKEBOOT) clean
 
 archdep:
-	$(MAKEBOOT) dep
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c
--- v2.1.47/linux/arch/m68k/amiga/amikeyb.c	Mon Jun 16 16:35:53 1997
+++ linux/arch/m68k/amiga/amikeyb.c	Thu Jul 31 13:09:16 1997
@@ -195,7 +195,7 @@
 
 static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
-    unsigned char scancode, break_flag;
+    unsigned char scancode, break_flag, keycode;
     static int reset_warning = 0;
 
     /* save frame for register dump */
@@ -207,6 +207,7 @@
     /* switch SP pin to output for handshake */
     ciaa.cra |= 0x40;
 
+#if 0 // No longer used
     /*
      *  On receipt of the second RESET_WARNING, we must not pull KDAT high
      *  again to delay the hard reset as long as possible.
@@ -222,6 +223,7 @@
 	} else
 	    /* Probably a mistake, cancel the alert */
 	    reset_warning = 0;
+#endif
 
     /* wait until 85 us have expired */
     udelay(85);
@@ -237,27 +239,27 @@
      * Check make/break first
      */
     break_flag = scancode & BREAK_MASK;
-    scancode &= (unsigned char )~BREAK_MASK;
+    keycode = scancode & (unsigned char)~BREAK_MASK;
 
-    if (scancode == AMIKEY_CAPS) {
+    if (keycode == AMIKEY_CAPS) {
 	/* if the key is CAPS, fake a press/release. */
 	handle_scancode(AMIKEY_CAPS);
 	handle_scancode(BREAK_MASK | AMIKEY_CAPS);
-    } else if (scancode < 0x78) {
+    } else if (keycode < 0x78) {
 	/* handle repeat */
 	if (break_flag) {
 	    del_timer(&amikeyb_rep_timer);
 	    rep_scancode = 0;
 	} else {
 	    del_timer(&amikeyb_rep_timer);
-	    rep_scancode = scancode;
+	    rep_scancode = keycode;
 	    amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
 	    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
 	    add_timer(&amikeyb_rep_timer);
 	}
-	handle_scancode(break_flag | scancode);
+	handle_scancode(scancode);
     } else
-	switch (scancode) {
+	switch (keycode) {
 	    case 0x78:
 		reset_warning = 1;
 		break;
@@ -288,7 +290,7 @@
 #endif
 	    default:
 		printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
-		       break_flag | scancode);
+		       scancode);
 		break;
 	}
 }
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c
--- v2.1.47/linux/arch/m68k/amiga/zorro.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/amiga/zorro.c	Thu Jul 31 13:09:16 1997
@@ -730,7 +730,7 @@
 {
    int key;
    struct ConfigDev *cd;
-  
+
    if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
       return(0);
 
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/Makefile linux/arch/m68k/boot/Makefile
--- v2.1.47/linux/arch/m68k/boot/Makefile	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,65 +0,0 @@
-#
-# linux/arch/m68k/boot/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-
-ifdef CONFIG_AMIGA
-AMIGA_BOOTSTRAP = amiga_bootstrap
-AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o
-AMIGA_HOSTCC = m68k-cbm-amigados-gcc
-AMIGA_HOSTINC = -I$(TOPDIR)/include
-AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux
-endif
-
-ifdef CONFIG_ATARI
-ATARI_BOOTSTRAP = atari_bootstrap
-ATARI_BOOTOBJS := atari/bootstrap.o
-ATARI_HOSTCC = m68k-mint-gcc
-ATARI_HOSTINC = -I$(TOPDIR)/include
-ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall
-
-# BOOTP/TFTP support in bootstrap?
-# USE_BOOTP = y
-
-ifdef USE_BOOTP
-ATARI_BOOTOBJS += atari/bootp.o
-ATARI_HOSTFLAGS += -DUSE_BOOTP
-
-# low-level Ethernet drivers:
-
-# Lance (RieblCard, PAM-VME)
-ATARI_BOOTOBJS += atari/ethlance.o
-ATARI_HOSTFLAGS += -DETHLL_LANCE
-
-endif
-endif
-
-ifdef CONFIG_ATARI
-atari_bootstrap: $(ATARI_BOOTOBJS)
-	$(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
-	rm -f ../../../bootstrap
-	ln $@ ../../../bootstrap
-endif
-
-ifdef CONFIG_AMIGA
-amiga_bootstrap: $(AMIGA_BOOTOBJS)
-	$(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS)
-	rm -f ../../../bootstrap
-	ln $@ ../../../bootstrap
-endif
-
-$(AMIGA_BOOTOBJS): %.o: %.c
-	$(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -c $< -o $@
-
-$(ATARI_BOOTOBJS): %.o: %.c
-	$(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -c $< -o $@
-
-bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP)
-
-clean:
-	rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap \
-          ../../../bootstrap
-
-dep:
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/amiga/bootstrap.c linux/arch/m68k/boot/amiga/bootstrap.c
--- v2.1.47/linux/arch/m68k/boot/amiga/bootstrap.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/boot/amiga/bootstrap.c	Wed Dec 31 16:00:00 1969
@@ -1,335 +0,0 @@
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
-**					     kernel into an Amiga and launches
-**					     it.
-**
-** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
-**
-** Modified 11-May-94 by Geert Uytterhoeven
-**			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
-**     - A3640 MapROM check
-** Modified 31-May-94 by Geert Uytterhoeven
-**     - Memory thrash problem solved
-** Modified 07-March-95 by Geert Uytterhoeven
-**     - Memory block sizes are rounded to a multiple of 256K instead of 1M
-**	 This _requires_ >0.9pl5 to work!
-**	 (unless all block sizes are multiples of 1M :-)
-** Modified 11-July-95 by Andreas Schwab
-**     - Support for ELF kernel (untested!)
-** Modified 10-Jan-96 by Geert Uytterhoeven
-**     - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-**     - Rewritten option parsing
-**     - New parameter passing to linuxboot() (linuxboot_args)
-** Modified 6-Oct-96 by Geert Uytterhoeven
-**     - Updated for the new boot information structure
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/file.h>
-#include <unistd.h>
-
-/* required Linux/m68k include files */
-#define __KERNEL_STRICT_NAMES		/* This is ugly, I know */
-#define _LINUX_POSIX_TYPES_H
-#include <asm/posix_types.h>
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-/* Amiga bootstrap include files */
-#include "linuxboot.h"
-#include "bootstrap.h"
-
-
-/* Library Bases */
-long __oslibversion = 36;
-extern const struct ExecBase *SysBase;
-
-static const char *memfile_name = NULL;
-
-static int model = AMI_UNKNOWN;
-
-static const char *ProgramName;
-
-struct linuxboot_args args;
-
-
-    /*
-     *  Function Prototypes
-     */
-
-static void Usage(void) __attribute__ ((noreturn));
-int main(int argc, char *argv[]);
-static void Puts(const char *str);
-static long GetChar(void);
-static void PutChar(char c);
-static void Printf(const char *fmt, ...);
-static int Open(const char *path);
-static int Seek(int fd, int offset);
-static int Read(int fd, char *buf, int count);
-static void Close(int fd);
-static int FileSize(const char *path);
-static void Sleep(u_long micros);
-
-
-static void Usage(void)
-{
-    fprintf(stderr,
-	"Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
-	"Usage: %s [options] [kernel command line]\n\n"
-	"Basic options:\n"
-	"    -h, --help           Display this usage information\n"
-	"    -k, --kernel file    Use kernel image `file' (default is `vmlinux')\n"
-	"    -r, --ramdisk file   Use ramdisk image `file'\n"
-	"Advanced options:\n"
-	"    -d, --debug          Enable debug mode\n"
-	"    -b, --baud speed     Set the serial port speed (default is 9600)\n"
-	"    -m, --memfile file   Use memory file `file'\n"
-	"    -v, --keep-video     Don't reset the video mode\n"
-	"    -t, --model id       Set the Amiga model to `id'\n"
-	"    -p, --processor cfm  Set the processor type to `cfm\n\n",
-	ProgramName);
-    exit(EXIT_FAILURE);
-}
-
-
-int main(int argc, char *argv[])
-{
-    int i;
-    int processor = 0, debugflag = 0, keep_video = 0;
-    u_int baud = 0;
-    const char *kernel_name = NULL;
-    const char *ramdisk_name = NULL;
-    char commandline[CL_SIZE] = "";
-
-    ProgramName = argv[0];
-    while (--argc) {
-	argv++;
-	if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
-	    Usage();
-	else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
-	    if (--argc && !kernel_name) {
-		kernel_name = argv[1];
-		argv++;
-	    } else
-		Usage();
-	else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
-	    if (--argc && !ramdisk_name) {
-		ramdisk_name = argv[1];
-		argv++;
-	    } else
-		Usage();
-	else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
-	    debugflag = 1;
-	else if (!strcmp(argv[0], "-b") || !strcmp(argv[0], "--baud"))
-	    if (--argc && !baud) {
-		baud = atoi(argv[1]);
-		argv++;
-	    } else
-		Usage();
-	else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
-	    if (--argc && !memfile_name) {
-		memfile_name = argv[1];
-		argv++;
-	    } else
-		Usage();
-	else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
-	    keep_video = 1;
-	else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
-	    if (--argc && !model) {
-		model = atoi(argv[1]);
-		argv++;
-	    } else
-		Usage();
-	else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--processor"))
-	    if (--argc && !processor) {
-		processor = atoi(argv[1]);
-		argv++;
-	    } else
-		Usage();
-	else
-	    break;
-    }
-    if (!kernel_name)
-	kernel_name = "vmlinux";
-
-    SysBase = *(struct ExecBase **)4;
-
-    /*
-     *	Join command line options
-     */
-    i = 0;
-    while (argc--) {
-	if ((i+strlen(*argv)+1) < CL_SIZE) {
-	    i += strlen(*argv) + 1;
-	    if (commandline[0])
-		strcat(commandline, " ");
-	    strcat(commandline, *argv++);
-	}
-    }
-
-    memset(&args.bi, 0, sizeof(args.bi));
-    if (processor) {
-	int cpu = processor/100%10;
-	int fpu = processor/10%10;
-	int mmu = processor%10;
-	if (cpu)
-	    args.bi.cputype = 1<<(cpu-1);
-	if (fpu)
-	    args.bi.fputype = 1<<(fpu-1);
-	if (mmu)
-	    args.bi.mmutype = 1<<(mmu-1);
-    }
-    /*
-     *	If we have a memory file, read the memory information from it
-     */
-    if (memfile_name) {
-	FILE *fp;
-	int i;
-
-	if ((fp = fopen(memfile_name, "r")) == NULL) {
-	    perror("open memory file");
-	    fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
-	    return(FALSE);
-	}
-
-	if (fscanf(fp, "%lu", &args.bi.chip_size) != 1) {
-	    fprintf(stderr, "memory file does not contain chip memory size\n");
-	    fclose(fp);
-	    return(FALSE);
-	}
-
-	for (i = 0; i < NUM_MEMINFO; i++)
-	    if (fscanf(fp, "%lx %lu", &args.bi.memory[i].addr,
-		       &args.bi.memory[i].size) != 2)
-		break;
-
-	fclose(fp);
-	args.bi.num_memory = i;
-    }
-    strncpy(args.bi.command_line, commandline, CL_SIZE);
-    args.bi.command_line[CL_SIZE-1] = '\0';
-    if (model != AMI_UNKNOWN)
-	args.bi.model = model;
-
-    args.kernelname = kernel_name;
-    args.ramdiskname = ramdisk_name;
-    args.debugflag = debugflag;
-    args.keep_video = keep_video;
-    args.reset_boards = 1;
-    args.baud = baud;
-    args.puts = Puts;
-    args.getchar = GetChar;
-    args.putchar = PutChar;
-    args.printf = Printf;
-    args.open = Open;
-    args.seek = Seek;
-    args.read = Read;
-    args.close = Close;
-    args.filesize = FileSize;
-    args.sleep = Sleep;
-
-    /* Do The Right Stuff */
-    linuxboot(&args);
-
-    /* if we ever get here, something went wrong */
-    exit(EXIT_FAILURE);
-}
-
-
-    /*
-     *  Routines needed by linuxboot
-     */
-
-static void Puts(const char *str)
-{
-    fputs(str, stderr);
-    fflush(stderr);
-}
-
-static long GetChar(void)
-{
-    return(getchar());
-}
-
-static void PutChar(char c)
-{
-    fputc(c, stderr);
-    fflush(stderr);
-}
-
-static void Printf(const char *fmt, ...)
-{
-    va_list args;
-
-    va_start(args, fmt);
-    vfprintf(stderr, fmt, args);
-    va_end(args);
-    fflush(stderr);
-}
-
-static int Open(const char *path)
-{
-    return(open(path, O_RDONLY));
-}
-
-static int Seek(int fd, int offset)
-{
-    return(lseek(fd, offset, SEEK_SET));
-}
-
-
-static int Read(int fd, char *buf, int count)
-{
-    return(read(fd, buf, count));
-}
-
-static void Close(int fd)
-{
-    close(fd);
-}
-
-static int FileSize(const char *path)
-{
-    int fd, size = -1;
-
-    if ((fd = open(path, O_RDONLY)) != -1) {
-	size = lseek(fd, 0, SEEK_END);
-	close(fd);
-    }
-    return(size);
-}
-
-static void Sleep(u_long micros)
-{
-    struct MsgPort *TimerPort;
-    struct timerequest *TimerRequest;
-
-    if ((TimerPort = CreateMsgPort())) {
-	if ((TimerRequest = CreateIORequest(TimerPort,
-					    sizeof(struct timerequest)))) {
-	    if (!OpenDevice("timer.device", UNIT_VBLANK,
-			    (struct IORequest *)TimerRequest, 0)) {
-		TimerRequest->io_Command = TR_ADDREQUEST;
-		TimerRequest->io_Flags = IOF_QUICK;
-		TimerRequest->tv_secs = micros/1000000;
-		TimerRequest->tv_micro = micros%1000000;
-		DoIO((struct IORequest *)TimerRequest);
-		CloseDevice((struct IORequest *)TimerRequest);
-	    }
-	    DeleteIORequest(TimerRequest);
-	}
-	DeleteMsgPort(TimerPort);
-    }
-}
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/amiga/bootstrap.h linux/arch/m68k/boot/amiga/bootstrap.h
--- v2.1.47/linux/arch/m68k/boot/amiga/bootstrap.h	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/amiga/bootstrap.h	Wed Dec 31 16:00:00 1969
@@ -1,149 +0,0 @@
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.h -- This file is part of the Amiga
-**					     bootloader.
-**
-** Copyright 1993, 1994 by Hamish Macdonald
-**
-** Some minor additions by Michael Rausch 1-11-94
-** Modified 11-May-94 by Geert Uytterhoeven
-**			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
-**     - inline Supervisor() call
-** Modified 10-Jan-96 by Geert Uytterhoeven
-**     - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-**     - const library bases
-**     - fixed register naming for m68k-cbm-amigados-gcc
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-
-struct MsgPort {
-    u_char fill1[15];
-    u_char mp_SigBit;
-    u_char fill2[18];
-};
-
-struct IOStdReq {
-    u_char fill1[20];
-    struct Device *io_Device;
-    u_char fill2[4];
-    u_short io_Command;
-    u_char io_Flags;
-    char io_Error;
-    u_long io_Actual;
-    u_long io_Length;
-    void *io_Data;
-    u_char fill4[4];
-};
-
-#define IOF_QUICK	(1<<0)
-
-struct timerequest {
-    u_char fill1[28];
-    u_short io_Command;
-    u_char io_Flags;
-    u_char fill2[1];
-    u_long tv_secs;
-    u_long tv_micro;
-};
-
-#define UNIT_VBLANK	1
-#define TR_ADDREQUEST	9
-
-
-struct Library;
-struct IORequest;
-
-
-static __inline char OpenDevice(u_char *devName, u_long unit,
-				struct IORequest *ioRequest, u_long flags)
-{
-    register char _res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register u_char *a0 __asm("a0") = devName;
-    register u_long d0 __asm("d0") = unit;
-    register struct IORequest *a1 __asm("a1") = ioRequest;
-    register u_long d1 __asm("d1") = flags;
-
-    __asm __volatile ("jsr a6@(-0x1bc)"
-		      : "=r" (_res)
-		      : "r" (a6), "r" (a0), "r" (a1), "r" (d0), "r" (d1)
-		      : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void CloseDevice(struct IORequest *ioRequest)
-{
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct IORequest *a1 __asm("a1") = ioRequest;
-
-    __asm __volatile ("jsr a6@(-0x1c2)"
-		      : /* no output */
-		      : "r" (a6), "r" (a1)
-		      : "a0","a1","d0","d1", "memory");
-}
-
-static __inline char DoIO(struct IORequest *ioRequest)
-{
-    register char _res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct IORequest *a1 __asm("a1") = ioRequest;
-
-    __asm __volatile ("jsr a6@(-0x1c8)"
-		      : "=r" (_res)
-		      : "r" (a6), "r" (a1)
-		      : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void *CreateIORequest(struct MsgPort *port, u_long size)
-{
-    register struct Library *_res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct MsgPort *a0 __asm("a0") = port;
-    register u_long d0 __asm("d0") = size;
-
-    __asm __volatile ("jsr a6@(-0x28e)"
-		      : "=r" (_res)
-		      : "r" (a6), "r" (a0), "r" (d0)
-		      : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void DeleteIORequest(void *ioRequest)
-{
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register void *a0 __asm("a0") = ioRequest;
-
-    __asm __volatile ("jsr a6@(-0x294)"
-		      : /* no output */
-		      : "r" (a6), "r" (a0)
-		      : "a0","a1","d0","d1", "memory");
-}
-
-static __inline struct MsgPort *CreateMsgPort(void)
-{
-    register struct MsgPort *_res __asm("d0");
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x29a)"
-		      : "=r" (_res)
-		      : "r" (a6)
-		      : "a0","a1","d0","d1", "memory");
-    return(_res);
-}
-
-static __inline void DeleteMsgPort(struct MsgPort *port)
-{
-    register const struct ExecBase *a6 __asm("a6") = SysBase;
-    register struct MsgPort *a0 __asm("a0") = port;
-
-    __asm __volatile ("jsr a6@(-0x2a0)"
-		      : /* no output */
-		      : "r" (a6), "r" (a0)
-		      : "a0","a1","d0","d1", "memory");
-}
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/amiga/linuxboot.c linux/arch/m68k/boot/amiga/linuxboot.c
--- v2.1.47/linux/arch/m68k/boot/amiga/linuxboot.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/boot/amiga/linuxboot.c	Wed Dec 31 16:00:00 1969
@@ -1,1692 +0,0 @@
-/*
- *  linux/arch/m68k/boot/amiga/linuxboot.c -- Generic routine to boot Linux/m68k
- *					      on Amiga, used by both Amiboot and
- *					      Amiga-Lilo.
- *
- *	Created 1996 by Geert Uytterhoeven
- *
- *
- *  This file is based on the original bootstrap code (bootstrap.c):
- *
- *	Copyright (C) 1993, 1994 Hamish Macdonald
- *				 Greg Harp
- *
- *		    with work by Michael Rausch
- *				 Geert Uytterhoeven
- *				 Frank Neumann
- *				 Andreas Schwab
- *
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- *
- *  History:
- *	11 Jun 1997 Fix for unpadded gzipped ramdisks with bootinfo interface
- *		    version 1.0
- *	27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
- *		    interface version 1.0 (Geert)
- *	 3 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
- *		    code for ataboot)
- *	30 Dec 1996 Reverted the CPU detection to the old scheme
- *		    New boot parameter override scheme (Geert)
- *      27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
- *       9 Sep 1996 Rewritten option parsing
- *		    New parameter passing to linuxboot() (linuxboot_args)
- *		    (Geert)
- *	18 Aug 1996 Updated for the new boot information structure (Geert)
- *	10 Jan 1996 The real Linux/m68k boot code moved to linuxboot.[ch]
- *		    (Geert)
- *	11 Jul 1995 Support for ELF kernel (untested!) (Andreas)
- *	 7 Mar 1995 Memory block sizes are rounded to a multiple of 256K
- *		    instead of 1M (Geert)
- *	31 May 1994 Memory thrash problem solved (Geert)
- *	11 May 1994 A3640 MapROM check (Geert)
- */
-
-
-#ifndef __GNUC__
-#error GNU CC is required to compile this program
-#endif /* __GNUC__ */
-
-
-#define BOOTINFO_COMPAT_1_0	/* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <linux/linkage.h>
-#include <asm/bootinfo.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-#include "linuxboot.h"
-
-
-#undef custom
-#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
-
-/* a.out linkage conventions */
-#undef SYMBOL_NAME_STR
-#define SYMBOL_NAME_STR(X) "_"#X
-
-/* temporary stack size */
-#define TEMP_STACKSIZE	(256)
-
-#define DEFAULT_BAUD	(9600)
-
-extern char copyall, copyallend;
-
-static struct exec kexec;
-static Elf32_Ehdr kexec_elf;
-static const struct linuxboot_args *linuxboot_args;
-
-/* Bootinfo */
-struct amiga_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE	(4096)
-static u_long bi_size;
-static union {
-    struct bi_record record;
-    u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-#define kernelname	linuxboot_args->kernelname
-#define ramdiskname	linuxboot_args->ramdiskname
-#define debugflag	linuxboot_args->debugflag
-#define keep_video	linuxboot_args->keep_video
-#define reset_boards	linuxboot_args->reset_boards
-#define baud		linuxboot_args->baud
-
-#define Puts		linuxboot_args->puts
-#define GetChar		linuxboot_args->getchar
-#define PutChar		linuxboot_args->putchar
-#define Printf		linuxboot_args->printf
-#define Open		linuxboot_args->open
-#define Seek		linuxboot_args->seek
-#define Read		linuxboot_args->read
-#define Close		linuxboot_args->close
-#define FileSize	linuxboot_args->filesize
-#define Sleep		linuxboot_args->sleep
-
-    /*
-     *  Function Prototypes
-     */
-
-static u_long get_chipset(void);
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu);
-static u_long get_model(u_long chipset);
-static int probe_resident(const char *name);
-static int probe_resource(const char *name);
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-static int check_bootinfo_version(const char *memptr);
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
-			 u_long start_mem, u_long kernel_size, u_long rd_dest,
-			 u_long rd_size) __attribute__ ((noreturn));
-asmlinkage u_long maprommed(void);
-#ifdef ZKERNEL
-static int load_zkernel(int fd);
-static int KRead(int fd, void *buf, int cnt);
-static int KSeek(int fd, int offset);
-static int KClose(int fd);
-#else
-#define KRead		Read
-#define KSeek		Seek
-#define KClose		Close
-#endif
-
-
-    /*
-     *	Reset functions for nasty Zorro boards
-     */
-
-static void reset_rb3(const struct ConfigDev *cd);
-static void reset_piccolo(const struct ConfigDev *cd);
-static void reset_sd64(const struct ConfigDev *cd);
-static void reset_ariadne(const struct ConfigDev *cd);
-static void reset_hydra(const struct ConfigDev *cd);
-#if 0
-static void reset_a2060(const struct ConfigDev *cd);
-#endif
-
-struct boardreset {
-    u_short manuf;
-    u_short prod;
-    const char *name;
-    void (*reset)(const struct ConfigDev *cd);
-};
-
-static struct boardreset boardresetdb[] = {
-    { MANUF_HELFRICH1, PROD_RAINBOW3, "Rainbow 3", reset_rb3 },
-    { MANUF_HELFRICH2, PROD_PICCOLO_REG, "Piccolo", reset_piccolo },
-    { MANUF_HELFRICH2, PROD_SD64_REG, "SD64", reset_sd64 },
-    { MANUF_VILLAGE_TRONIC, PROD_ARIADNE, "Ariadne", reset_ariadne },
-    { MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, "Hydra", reset_hydra },
-#if 0
-    { MANUF_COMMODORE, PROD_A2060, "A2060", reset_a2060 },
-#endif
-};
-#define NUM_BOARDRESET	sizeof(boardresetdb)/sizeof(*boardresetdb)
-
-static void (*boardresetfuncs[ZORRO_NUM_AUTO])(const struct ConfigDev *cd);
-
-
-const char *amiga_models[] = {
-    "Amiga 500", "Amiga 500+", "Amiga 600", "Amiga 1000", "Amiga 1200",
-    "Amiga 2000", "Amiga 2500", "Amiga 3000", "Amiga 3000T", "Amiga 3000+",
-    "Amiga 4000", "Amiga 4000T", "CDTV", "CD32", "Draco"
-};
-const u_long first_amiga_model = AMI_500;
-const u_long last_amiga_model = AMI_DRACO;
-
-
-#define MASK(model)	(1<<AMI_##model)
-
-#define CLASS_A3000	(MASK(3000) | MASK(3000T))
-#define CLASS_A4000	(MASK(4000) | MASK(4000T))
-#define CLASS_ZKICK	(MASK(500) | MASK(1000) | MASK(2000) | MASK(2500))
-
-
-    /*
-     *	Boot the Linux/m68k Operating System
-     */
-
-u_long linuxboot(const struct linuxboot_args *args)
-{
-    int kfd = -1, rfd = -1, elf_kernel = 0, do_fast, do_chip;
-    int i, j;
-    const struct MemHeader *mnp;
-    struct ConfigDev *cdp = NULL;
-    char *memptr = NULL;
-    u_long *stack = NULL;
-    u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
-    u_long kernel_size;
-    u_int realbaud;
-    u_long memreq = 0, text_offset = 0;
-    Elf32_Phdr *kernel_phdrs = NULL;
-    void (*startfunc)(void);
-    u_short manuf;
-    u_char prod;
-    void *bi_ptr;
-
-    linuxboot_args = args;
-
-    /* print the greet message */
-    Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
-    Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
-
-    /* Note: Initial values in bi override detected values */
-    bi = args->bi;
-
-    /* machine is Amiga */
-    bi.machtype = MACH_AMIGA;
-
-    /* determine chipset */
-    if (!bi.chipset)
-	bi.chipset = get_chipset();
-
-    /* determine CPU, FPU and MMU type */
-    if (!bi.cputype)
-	get_processor(&bi.cputype, &bi.fputype, &bi.mmutype);
-
-    /* determine Amiga model */
-    if (!bi.model)
-	bi.model = get_model(bi.chipset);
-    model_mask = (bi.model != AMI_UNKNOWN) ? 1<<bi.model : 0;
-
-    /* Memory & AutoConfig based on 'unix_boot.c' by C= */
-
-    /* find all of the autoconfig boards in the system */
-    if (!bi.num_autocon)
-	for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++)
-	    if (bi.num_autocon < ZORRO_NUM_AUTO)
-		/* copy the contents of each structure into our boot info and
-		   count this device */
-		memcpy(&bi.autocon[bi.num_autocon++], cdp,
-		       sizeof(struct ConfigDev));
-	    else
-		Printf("Warning: too many AutoConfig devices. Ignoring device at "
-		       "0x%08lx\n", cdp->cd_BoardAddr);
-
-    do_fast = bi.num_memory ? 0 : 1;
-    do_chip = bi.chip_size ? 0 : 1;
-    /* find out the memory in the system */
-    for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
-	 mnp->mh_Node.ln_Succ;
-	 mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
-	struct MemHeader mh;
-
-	/* copy the information */
-	mh = *mnp;
-
-	/* skip virtual memory */
-	if (!(mh.mh_Attributes & MEMF_PUBLIC))
-	    continue;
-
-	/* if we suspect that Kickstart is shadowed in an A3000,
-	   modify the entry to show 512K more at the top of RAM
-	   Check first for a MapROMmed A3640 board: overwriting the
-	   Kickstart image causes an infinite lock-up on reboot! */
-	if ((mh.mh_Upper == (void *)0x07f80000) &&
-	    (model_mask & (CLASS_A3000 | CLASS_A4000)))
-	    if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
-		Puts("A3640 MapROM detected.\n");
-	    else if (model_mask & CLASS_A3000) {
-		mh.mh_Upper = (void *)0x08000000;
-		Puts("A3000 shadowed Kickstart detected.\n");
-	    }
-
-	/* if we suspect that Kickstart is zkicked,
-	   modify the entry to show 512K more at the botton of RAM */
-	if ((mh.mh_Lower == (void *)0x00280020) &&
-	    (model_mask & CLASS_ZKICK)) {
-	    mh.mh_Lower = (void *)0x00200000;
-	    Puts("ZKick detected.\n");
-	}
-
-	/* mask the memory limit values */
-	mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
-	mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
-
-	/* if fast memory */
-	if (do_fast && mh.mh_Attributes & MEMF_FAST) {
-	    /* set the size value to the size of this block and mask off to a
-	       256K increment */
-	    u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
-	    if (size > 0)
-		if (bi.num_memory < NUM_MEMINFO) {
-		    /* record the start and size */
-		    bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
-		    bi.memory[bi.num_memory].size = size;
-		    /* count this block */
-		    bi.num_memory++;
-		} else
-		    Printf("Warning: too many memory blocks. Ignoring block "
-		    	   "of %ldK at 0x%08x\n", size>>10,
-			   (u_long)mh.mh_Lower);
-	} else if (do_chip && mh.mh_Attributes & MEMF_CHIP)
-	    /* if CHIP memory, record the size */
-	    bi.chip_size = (u_long)mh.mh_Upper;
-    }
-
-    /* get info from ExecBase */
-    if (!bi.vblank)
-	bi.vblank = SysBase->VBlankFrequency;
-    if (!bi.psfreq)
-	bi.psfreq = SysBase->PowerSupplyFrequency;
-    if (!bi.eclock)
-	bi.eclock = SysBase->ex_EClockFrequency;
-
-    /* serial port */
-    if (!bi.serper) {
-	realbaud = baud ? baud : DEFAULT_BAUD;
-	bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1;
-    }
-
-    /* display Amiga model */
-    if (bi.model >= first_amiga_model && bi.model <= last_amiga_model)
-	Printf("%s ", amiga_models[bi.model-first_amiga_model]);
-    else
-	Puts("Amiga ");
-
-    /* display the CPU type */
-    Puts("CPU: ");
-    switch (bi.cputype) {
-	case CPU_68020:
-	    Puts("68020 (Do you have an MMU?)");
-	    break;
-	case CPU_68030:
-	    Puts("68030");
-	    break;
-	case CPU_68040:
-	    Puts("68040");
-	    break;
-	case CPU_68060:
-	    Puts("68060");
-	    break;
-	default:
-	    Puts("Insufficient for Linux.  Aborting...\n");
-	    Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
-	    goto Fail;
-    }
-    switch (bi.fputype) {
-	case FPU_68881:
-	    Puts(" with 68881 FPU");
-	    break;
-	case FPU_68882:
-	    Puts(" with 68882 FPU");
-	    break;
-	case FPU_68040:
-	case FPU_68060:
-	    Puts(" with internal FPU");
-	    break;
-	default:
-	    Puts(" without FPU");
-	    break;
-    }
-
-    /* display the chipset */
-    switch (bi.chipset) {
-	case CS_STONEAGE:
-	    Puts(", old or unknown chipset");
-	    break;
-	case CS_OCS:
-	    Puts(", OCS");
-	    break;
-	case CS_ECS:
-	    Puts(", ECS");
-	    break;
-	case CS_AGA:
-	    Puts(", AGA chipset");
-	    break;
-    }
-
-    Puts("\n\n");
-
-    /* display the command line */
-    Printf("Command line is '%s'\n", bi.command_line);
-
-    /* display the clock statistics */
-    Printf("Vertical Blank Frequency: %ldHz\n", bi.vblank);
-    Printf("Power Supply Frequency: %ldHz\n", bi.psfreq);
-    Printf("EClock Frequency: %ldHz\n\n", bi.eclock);
-
-    /* display autoconfig devices */
-    if (bi.num_autocon) {
-	Printf("Found %ld AutoConfig Device%s\n", bi.num_autocon,
-	       bi.num_autocon > 1 ? "s" : "");
-	for (i = 0; i < bi.num_autocon; i++) {
-	    Printf("Device %ld: addr = 0x%08lx", i,
-		   (u_long)bi.autocon[i].cd_BoardAddr);
-	    boardresetfuncs[i] = NULL;
-	    if (reset_boards) {
-		manuf = bi.autocon[i].cd_Rom.er_Manufacturer;
-		prod = bi.autocon[i].cd_Rom.er_Product;
-		for (j = 0; j < NUM_BOARDRESET; j++)
-		    if ((manuf == boardresetdb[j].manuf) &&
-			(prod == boardresetdb[j].prod)) {
-			Printf(" [%s - will be reset at kernel boot time]",
-			       boardresetdb[j].name);
-			boardresetfuncs[i] = boardresetdb[j].reset;
-			break;
-		    }
-	    }
-	    PutChar('\n');
-	}
-    } else
-	Puts("No AutoConfig Devices Found\n");
-
-    /* display memory */
-    if (bi.num_memory) {
-	Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
-	       bi.num_memory > 1 ? "s " : " ");
-	for (i = 0; i < bi.num_memory; i++)
-	    Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\n", i,
-		   bi.memory[i].addr, bi.memory[i].addr+bi.memory[i].size,
-		   bi.memory[i].size>>10);
-    } else {
-	Puts("No memory found?!  Aborting...\n");
-	goto Fail;
-    }
-
-    /* display chip memory size */
-    Printf("%ldK of CHIP memory\n", bi.chip_size>>10);
-
-    start_mem = bi.memory[0].addr;
-    mem_size = bi.memory[0].size;
-
-    /* tell us where the kernel will go */
-    Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
-    /* verify that there is enough Chip RAM */
-    if (bi.chip_size < 512*1024) {
-	Puts("Not enough Chip RAM in this system.  Aborting...\n");
-	goto Fail;
-    }
-
-    /* verify that there is enough Fast RAM */
-    for (fast_total = 0, i = 0; i < bi.num_memory; i++)
-	fast_total += bi.memory[i].size;
-    if (fast_total < 2*1024*1024) {
-	Puts("Not enough Fast RAM in this system.  Aborting...\n");
-	goto Fail;
-    }
-
-    /* support for ramdisk */
-    if (ramdiskname) {
-	int size;
-
-	if ((size = FileSize(ramdiskname)) == -1) {
-	    Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
-	    goto Fail;
-	}
-	/* record ramdisk size */
-	bi.ramdisk.size = size;
-    } else
-	bi.ramdisk.size = 0;
-    rd_size = bi.ramdisk.size;
-    bi.ramdisk.addr = (u_long)start_mem+mem_size-rd_size;
-
-    /* create the bootinfo structure */
-    if (!create_bootinfo())
-	goto Fail;
-
-    /* open kernel executable and read exec header */
-    if ((kfd = Open(kernelname)) == -1) {
-	Printf("Unable to open kernel file `%s'\n", kernelname);
-	goto Fail;
-    }
-    if (KRead(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
-	Puts("Unable to read exec header from kernel file\n");
-	goto Fail;
-    }
-
-#ifdef ZKERNEL
-    if (((unsigned char *)&kexec)[0] == 037 &&
-	(((unsigned char *)&kexec)[1] == 0213 ||
-	 ((unsigned char *)&kexec)[1] == 0236)) {
-	/* That's a compressed kernel */
-	Puts("Kernel is compressed\n");
-	if (load_zkernel(kfd)) {
-	    Puts("Decompression error -- aborting\n");
-	    goto Fail;
-	}
-    }
-#endif
-
-    switch (N_MAGIC(kexec)) {
-	case ZMAGIC:
-	    if (debugflag)
-		Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
-	    text_offset = N_TXTOFF(kexec);
-	    break;
-
-	case QMAGIC:
-	    if (debugflag)
-		Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
-	    text_offset = sizeof(kexec);
-	    /* the text size includes the exec header; remove this */
-	    kexec.a_text -= sizeof(kexec);
-	    break;
-
-	default:
-	    /* Try to parse it as an ELF header */
-	    KSeek(kfd, 0);
-	    if ((KRead(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
-		 sizeof(kexec_elf)) &&
-		 (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
-		elf_kernel = 1;
-		if (debugflag)
-		    Puts("\nLoading ELF Linux/m68k kernel...\n");
-		/* A few plausibility checks */
-		if ((kexec_elf.e_type != ET_EXEC) ||
-		    (kexec_elf.e_machine != EM_68K) ||
-		    (kexec_elf.e_version != EV_CURRENT)) {
-		    Puts("Invalid ELF header contents in kernel\n");
-		    goto Fail;
-		}
-		/* Load the program headers */
-		if (!(kernel_phdrs =
-		      (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
-					     MEMF_FAST | MEMF_PUBLIC |
-					     MEMF_CLEAR))) {
-		    Puts("Unable to allocate memory for program headers\n");
-		    goto Fail;
-		}
-		KSeek(kfd, kexec_elf.e_phoff);
-		if (KRead(kfd, (void *)kernel_phdrs,
-			 kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
-		    kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
-		    Puts("Unable to read program headers from kernel file\n");
-		    goto Fail;
-		}
-		break;
-	    }
-	    Printf("Wrong magic number 0x%08lx in kernel header\n",
-		   N_MAGIC(kexec));
-	    goto Fail;
-    }
-
-    /* Load the kernel at one page after start of mem */
-    start_mem += PAGE_SIZE;
-    mem_size -= PAGE_SIZE;
-    /* Align bss size to multiple of four */
-    if (!elf_kernel)
-	kexec.a_bss = (kexec.a_bss+3) & ~3;
-
-    /* calculate the total required amount of memory */
-    if (elf_kernel) {
-	u_long min_addr = 0xffffffff, max_addr = 0;
-	for (i = 0; i < kexec_elf.e_phnum; i++) {
-	    if (min_addr > kernel_phdrs[i].p_vaddr)
-		min_addr = kernel_phdrs[i].p_vaddr;
-	    if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
-		max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
-	}
-	/* This is needed for newer linkers that include the header in
-	   the first segment.  */
-	if (min_addr == 0) {
-	    min_addr = PAGE_SIZE;
-	    kernel_phdrs[0].p_vaddr += PAGE_SIZE;
-	    kernel_phdrs[0].p_offset += PAGE_SIZE;
-	    kernel_phdrs[0].p_filesz -= PAGE_SIZE;
-	    kernel_phdrs[0].p_memsz -= PAGE_SIZE;
-	}
-	kernel_size = max_addr-min_addr;
-    } else
-	kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
-    memreq = kernel_size+bi_size+rd_size;
-#ifdef BOOTINFO_COMPAT_1_0
-    if (sizeof(compat_bootinfo) > bi_size)
-	memreq = kernel_size+sizeof(compat_bootinfo)+rd_size;
-#endif /* BOOTINFO_COMPAT_1_0 */
-    if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
-					    MEMF_CLEAR))) {
-	Puts("Unable to allocate memory\n");
-	goto Fail;
-    }
-
-    /* read the text and data segments from the kernel image */
-    if (elf_kernel)
-	for (i = 0; i < kexec_elf.e_phnum; i++) {
-	    if (KSeek(kfd, kernel_phdrs[i].p_offset) == -1) {
-		Printf("Failed to seek to segment %ld\n", i);
-		goto Fail;
-	    }
-	    if (KRead(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
-		      kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
-		Printf("Failed to read segment %ld\n", i);
-		goto Fail;
-	    }
-	}
-    else {
-	if (KSeek(kfd, text_offset) == -1) {
-	    Puts("Failed to seek to text\n");
-	    goto Fail;
-	}
-	if (KRead(kfd, memptr, kexec.a_text) != kexec.a_text) {
-	    Puts("Failed to read text\n");
-	    goto Fail;
-	}
-	/* data follows immediately after text */
-	if (KRead(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
-	    Puts("Failed to read data\n");
-	    goto Fail;
-	}
-    }
-    KClose(kfd);
-    kfd = -1;
-
-    /* Check kernel's bootinfo version */
-    switch (check_bootinfo_version(memptr)) {
-	case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
-	    bi_ptr = &bi_union.record;
-	    break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-	case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
-	    if (!create_compat_bootinfo())
-		goto Fail;
-	    bi_ptr = &compat_bootinfo;
-	    bi_size = sizeof(compat_bootinfo);
-	    break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-	default:
-	    goto Fail;
-    }
-
-    /* copy the bootinfo to the end of the kernel image */
-    memcpy((void *)(memptr+kernel_size), bi_ptr, bi_size);
-
-    if (ramdiskname) {
-	if ((rfd = Open(ramdiskname)) == -1) {
-	    Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
-	    goto Fail;
-	}
-	if (Read(rfd, memptr+kernel_size+bi_size, rd_size) != rd_size) {
-	    Puts("Failed to read ramdisk file\n");
-	    goto Fail;
-	}
-	Close(rfd);
-	rfd = -1;
-    }
-
-    /* allocate temporary chip ram stack */
-    if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
-	Puts("Unable to allocate memory for stack\n");
-	goto Fail;
-    }
-
-    /* allocate chip ram for copy of startup code */
-    startcodesize = &copyallend-&copyall;
-    if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
-					       MEMF_CHIP | MEMF_CLEAR))) {
-	Puts("Unable to allocate memory for startcode\n");
-	goto Fail;
-    }
-
-    /* copy startup code to CHIP RAM */
-    memcpy(startfunc, &copyall, startcodesize);
-
-    if (debugflag) {
-	if (bi.ramdisk.size)
-	    Printf("RAM disk at 0x%08lx, size is %ldK\n",
-		   (u_long)memptr+kernel_size+bi_size, bi.ramdisk.size>>10);
-
-	if (elf_kernel) {
-	    PutChar('\n');
-	    for (i = 0; i < kexec_elf.e_phnum; i++)
-		Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
-		       start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
-		       kernel_phdrs[i].p_memsz);
-	    Printf("Boot info        at 0x%08lx\n", start_mem+kernel_size);
-	} else {
-	    Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
-		   kexec.a_text);
-	    Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
-		   start_mem+kexec.a_text, kexec.a_data);
-	    Printf("Kernel bss  at 0x%08lx, bss  size 0x%08lx\n",
-		   start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
-	    Printf("Boot info   at 0x%08lx\n", start_mem+kernel_size);
-	}
-	Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
-							   kexec.a_entry);
-
-	Printf("ramdisk dest is 0x%08lx\n", bi.ramdisk.addr);
-	Printf("ramdisk lower limit is 0x%08lx\n",
-	       (u_long)memptr+kernel_size+bi_size);
-	Printf("ramdisk src top is 0x%08lx\n",
-	       (u_long)memptr+kernel_size+bi_size+rd_size);
-
-	Puts("\nType a key to continue the Linux/m68k boot...");
-	GetChar();
-	PutChar('\n');
-    }
-
-    /* wait for things to settle down */
-    Sleep(1000000);
-
-    if (!keep_video)
-	/* set graphics mode to a nice normal one */
-	LoadView(NULL);
-
-    Disable();
-
-    /* reset nasty Zorro boards */
-    if (reset_boards)
-	for (i = 0; i < bi.num_autocon; i++)
-	    if (boardresetfuncs[i])
-		boardresetfuncs[i](&bi.autocon[i]);
-
-    /* Turn off all DMA */
-    custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-    /* turn off caches */
-    CacheControl(0, ~0);
-
-    /* Go into supervisor state */
-    SuperState();
-
-    /* turn off any mmu translation */
-    disable_mmu();
-
-    /* execute the copy-and-go code (from CHIP RAM) */
-    start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
-		 kernel_size, bi.ramdisk.addr, rd_size);
-
-    /* Clean up and exit in case of a failure */
-Fail:
-    if (kfd != -1)
-	KClose(kfd);
-    if (rfd != -1)
-	Close(rfd);
-    if (memptr)
-	FreeMem((void *)memptr, memreq);
-    if (stack)
-	FreeMem((void *)stack, TEMP_STACKSIZE);
-    if (kernel_phdrs)
-	FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
-    return(FALSE);
-}
-
-
-    /*
-     *	Determine the Chipset
-     */
-
-static u_long get_chipset(void)
-{
-    u_char cs;
-    u_long chipset;
-
-    if (GfxBase->Version >= 39)
-	cs = SetChipRev(SETCHIPREV_BEST);
-    else
-	cs = GfxBase->ChipRevBits0;
-    if ((cs & GFXG_AGA) == GFXG_AGA)
-	chipset = CS_AGA;
-    else if ((cs & GFXG_ECS) == GFXG_ECS)
-	chipset = CS_ECS;
-    else if ((cs & GFXG_OCS) == GFXG_OCS)
-	chipset = CS_OCS;
-    else
-	chipset = CS_STONEAGE;
-    return(chipset);
-}
-
-
-    /*
-     *	Determine the CPU Type
-     */
-
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
-{
-    *cpu = *fpu = 0;
-
-    if (SysBase->AttnFlags & AFF_68060)
-	*cpu = CPU_68060;
-    else if (SysBase->AttnFlags & AFF_68040)
-	*cpu = CPU_68040;
-    else if (SysBase->AttnFlags & AFF_68030)
-	*cpu = CPU_68030;
-    else if (SysBase->AttnFlags & AFF_68020)
-	*cpu = CPU_68020;
-
-    if (*cpu == CPU_68040 || *cpu == CPU_68060) {
-	if (SysBase->AttnFlags & AFF_FPU40)
-	    *fpu = *cpu;
-    } else if (SysBase->AttnFlags & AFF_68882)
-	*fpu = FPU_68882;
-    else if (SysBase->AttnFlags & AFF_68881)
-	*fpu = FPU_68881;
-
-    *mmu = *cpu;
-}
-
-    /*
-     *	Determine the Amiga Model
-     */
-
-static u_long get_model(u_long chipset)
-{
-    u_long model = AMI_UNKNOWN;
-
-    if (debugflag)
-	Puts("Amiga model identification:\n");
-    if (probe_resource("draco.resource"))
-	model = AMI_DRACO;
-    else {
-	if (debugflag)
-	    Puts("    Chipset: ");
-	switch (chipset) {
-	    case CS_STONEAGE:
-		if (debugflag)
-		    Puts("Old or unknown\n");
-		goto OCS;
-		break;
-
-	    case CS_OCS:
-		if (debugflag)
-		    Puts("OCS\n");
-OCS:		if (probe_resident("cd.device"))
-		    model = AMI_CDTV;
-		else
-		    /* let's call it an A2000 (may be A500, A1000, A2500) */
-		    model = AMI_2000;
-		break;
-
-	    case CS_ECS:
-		if (debugflag)
-		    Puts("ECS\n");
-		if (probe_resident("Magic 36.7") ||
-		    probe_resident("kickad 36.57") ||
-		    probe_resident("A3000 Bonus") ||
-		    probe_resident("A3000 bonus"))
-		    /* let's call it an A3000 (may be A3000T) */
-		    model = AMI_3000;
-		else if (probe_resource("card.resource"))
-		    model = AMI_600;
-		else
-		    /* let's call it an A2000 (may be A500[+], A1000, A2500) */
-		    model = AMI_2000;
-		break;
-
-	    case CS_AGA:
-		if (debugflag)
-		    Puts("AGA\n");
-		if (probe_resident("A1000 Bonus") ||
-		    probe_resident("A4000 bonus"))
-		    model = probe_resident("NCR scsi.device") ? AMI_4000T :
-								AMI_4000;
-		else if (probe_resource("card.resource"))
-		    model = AMI_1200;
-		else if (probe_resident("cd.device"))
-		    model = AMI_CD32;
-		else
-		    model = AMI_3000PLUS;
-		break;
-	}
-    }
-    if (debugflag) {
-	Puts("\nType a key to continue...");
-	GetChar();
-	Puts("\n\n");
-    }
-    return(model);
-}
-
-
-    /*
-     *	Probe for a Resident Modules
-     */
-
-static int probe_resident(const char *name)
-{
-    const struct Resident *res;
-
-    if (debugflag)
-	Printf("    Module `%s': ", name);
-    res = FindResident(name);
-    if (debugflag)
-	if (res)
-	    Printf("0x%08lx\n", res);
-	else
-	    Puts("not present\n");
-    return(res ? TRUE : FALSE);
-}
-
-
-    /*
-     *	Probe for an available Resource
-     */
-
-static int probe_resource(const char *name)
-{
-    const void *res;
-
-    if (debugflag)
-	Printf("    Resource `%s': ", name);
-    res = OpenResource(name);
-    if (debugflag)
-	if (res)
-	    Printf("0x%08lx\n", res);
-	else
-	    Puts("not present\n");
-    return(res ? TRUE : FALSE);
-}
-
-
-    /*
-     *  Create the Bootinfo structure
-     */
-
-static int create_bootinfo(void)
-{
-    int i;
-    struct bi_record *record;
-
-    /* Initialization */
-    bi_size = 0;
-
-    /* Generic tags */
-    if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
-	return(0);
-    if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
-	return(0);
-    if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
-	return(0);
-    if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
-	return(0);
-    for (i = 0; i < bi.num_memory; i++)
-	if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
-	    return(0);
-    if (bi.ramdisk.size)
-	if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
-	    return(0);
-    if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
-	return(0);
-
-    /* Amiga tags */
-    if (!add_bi_record(BI_AMIGA_MODEL, sizeof(bi.model), &bi.model))
-	return(0);
-    for (i = 0; i < bi.num_autocon; i++)
-	if (!add_bi_record(BI_AMIGA_AUTOCON, sizeof(bi.autocon[i]),
-			    &bi.autocon[i]))
-	    return(0);
-    if (!add_bi_record(BI_AMIGA_CHIP_SIZE, sizeof(bi.chip_size), &bi.chip_size))
-	return(0);
-    if (!add_bi_record(BI_AMIGA_VBLANK, sizeof(bi.vblank), &bi.vblank))
-	return(0);
-    if (!add_bi_record(BI_AMIGA_PSFREQ, sizeof(bi.psfreq), &bi.psfreq))
-	return(0);
-    if (!add_bi_record(BI_AMIGA_ECLOCK, sizeof(bi.eclock), &bi.eclock))
-	return(0);
-    if (!add_bi_record(BI_AMIGA_CHIPSET, sizeof(bi.chipset), &bi.chipset))
-	return(0);
-    if (!add_bi_record(BI_AMIGA_SERPER, sizeof(bi.serper), &bi.serper))
-	return(0);
-
-    /* Trailer */
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = BI_LAST;
-    bi_size += sizeof(bi_union.record.tag);
-
-    return(1);
-}
-
-
-    /*
-     *  Add a Record to the Bootinfo Structure
-     */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
-    struct bi_record *record;
-    u_int size2;
-
-    size2 = (sizeof(struct bi_record)+size+3)&-4;
-    if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
-	Puts("Can't add bootinfo record. Ask a wizard to enlarge me.\n");
-	return(0);
-    }
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = tag;
-    record->size = size2;
-    memcpy(record->data, data, size);
-    bi_size += size2;
-    return(1);
-}
-
-
-    /*
-     *  Add a String Record to the Bootinfo Structure
-     */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
-    return(add_bi_record(tag, strlen(s)+1, (void *)s));
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
-    /*
-     *  Create the Bootinfo structure for backwards compatibility mode
-     */
-
-static int create_compat_bootinfo(void)
-{
-    u_int i;
-
-    compat_bootinfo.machtype = bi.machtype;
-    if (bi.cputype & CPU_68020)
-	compat_bootinfo.cputype = COMPAT_CPU_68020;
-    else if (bi.cputype & CPU_68030)
-	compat_bootinfo.cputype = COMPAT_CPU_68030;
-    else if (bi.cputype & CPU_68040)
-	compat_bootinfo.cputype = COMPAT_CPU_68040;
-    else if (bi.cputype & CPU_68060)
-	compat_bootinfo.cputype = COMPAT_CPU_68060;
-    else {
-	Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
-	return(0);
-    }
-    if (bi.fputype & FPU_68881)
-	compat_bootinfo.cputype |= COMPAT_FPU_68881;
-    else if (bi.fputype & FPU_68882)
-	compat_bootinfo.cputype |= COMPAT_FPU_68882;
-    else if (bi.fputype & FPU_68040)
-	compat_bootinfo.cputype |= COMPAT_FPU_68040;
-    else if (bi.fputype & FPU_68060)
-	compat_bootinfo.cputype |= COMPAT_FPU_68060;
-    else if (bi.fputype) {
-	Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
-	return(0);
-    }
-    compat_bootinfo.num_memory = bi.num_memory;
-    if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
-	Printf("Warning: using only %ld blocks of memory\n",
-	       COMPAT_NUM_MEMINFO);
-	compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
-    }
-    for (i = 0; i < compat_bootinfo.num_memory; i++) {
-	compat_bootinfo.memory[i].addr = bi.memory[i].addr;
-	compat_bootinfo.memory[i].size = bi.memory[i].size;
-    }
-    if (bi.ramdisk.size) {
-	bi.ramdisk.addr &= 0xfffffc00;
-	compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
-	compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
-    } else {
-	compat_bootinfo.ramdisk_size = 0;
-	compat_bootinfo.ramdisk_addr = 0;
-    }
-    strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
-    compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
-    compat_bootinfo.bi_amiga.model = bi.model;
-    compat_bootinfo.bi_amiga.num_autocon = bi.num_autocon;
-    if (compat_bootinfo.bi_amiga.num_autocon > COMPAT_NUM_AUTO) {
-	Printf("Warning: using only %ld AutoConfig devices\n",
-	       COMPAT_NUM_AUTO);
-	compat_bootinfo.bi_amiga.num_autocon = COMPAT_NUM_AUTO;
-    }
-    for (i = 0; i < compat_bootinfo.bi_amiga.num_autocon; i++)
-	compat_bootinfo.bi_amiga.autocon[i] = bi.autocon[i];
-    compat_bootinfo.bi_amiga.chip_size = bi.chip_size;
-    compat_bootinfo.bi_amiga.vblank = bi.vblank;
-    compat_bootinfo.bi_amiga.psfreq = bi.psfreq;
-    compat_bootinfo.bi_amiga.eclock = bi.eclock;
-    compat_bootinfo.bi_amiga.chipset = bi.chipset;
-    compat_bootinfo.bi_amiga.hw_present = 0;
-    return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-    /*
-     *  Compare the Bootstrap and Kernel Versions
-     */
-
-static int check_bootinfo_version(const char *memptr)
-{
-    const struct bootversion *bv = (struct bootversion *)memptr;
-    unsigned long version = 0;
-    int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
-    if (bv->magic == BOOTINFOV_MAGIC)
-	for (i = 0; bv->machversions[i].machtype != 0; ++i)
-	    if (bv->machversions[i].machtype == MACH_AMIGA) {
-		version = bv->machversions[i].version;
-		break;
-	    }
-    if (!version)
-	Puts("Kernel has no bootinfo version info, assuming 0.0\n");
-
-    kernel_major = BI_VERSION_MAJOR(version);
-    kernel_minor = BI_VERSION_MINOR(version);
-    boots_major  = BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION);
-    boots_minor  = BI_VERSION_MINOR(AMIGA_BOOTI_VERSION);
-    Printf("Bootstrap's bootinfo version: %ld.%ld\n", boots_major,
-	   boots_minor);
-    Printf("Kernel's bootinfo version   : %ld.%ld\n", kernel_major,
-	   kernel_minor);
-
-    switch (kernel_major) {
-	case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
-	    if (kernel_minor > boots_minor) {
-		Puts("Warning: Bootinfo version of bootstrap and kernel "
-		       "differ!\n");
-		Puts("         Certain features may not work.\n");
-	    }
-	    break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-	case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
-	    Puts("(using backwards compatibility mode)\n");
-	    break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-	default:
-	    Printf("\nThis bootstrap is too %s for this kernel!\n",
-		   boots_major < kernel_major ? "old" : "new");
-	    return(0);
-    }
-    return(kernel_major);
-}
-
-
-    /*
-     *	Call the copy-and-go-code
-     */
-
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
-			 u_long start_mem, u_long kernel_size, u_long rd_dest,
-			 u_long rd_size)
-{
-    register void (*a0)() __asm("a0") = startfunc;
-    register char *a2 __asm("a2") = stackp;
-    register char *a3 __asm("a3") = memptr;
-    register u_long a4 __asm("a4") = start_mem;
-    register u_long d0 __asm("d0") = rd_dest;
-    register u_long d1 __asm("d1") = rd_size;
-    register u_long d2 __asm("d2") = kernel_size;
-    register u_long d3 __asm("d3") = bi_size;
-
-    __asm __volatile ("movel a2,sp;"
-		      "jmp a0@"
-		      : /* no outputs */
-		      : "r" (a0), "r" (a2), "r" (a3), "r" (a4), "r" (d0),
-			"r" (d1), "r" (d2), "r" (d3)
-		      /* no return */);
-    /* fake a noreturn */
-    for (;;);
-}
-
-
-    /*
-     *	This assembler code is copied to chip ram, and then executed.
-     *	It copies the kernel to it's final resting place.
-     *
-     *	It is called with:
-     *
-     *	    a3 = memptr
-     *	    a4 = start_mem
-     *	    d0 = rd_dest
-     *	    d1 = rd_size
-     *	    d2 = kernel_size
-     *	    d3 = bi_size
-     */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(copyall) ":
-				| /* copy kernel text and data */
-	movel	a3,a0		| src = (u_long *)memptr;
-	movel	a0,a2		| limit = (u_long *)(memptr+kernel_size);
-	addl	d2,a2
-	movel	a4,a1		| dest = (u_long *)start_mem;
-1:	cmpl	a0,a2
-	jeq	2f		| while (src < limit)
-	moveb	a0@+,a1@+	|  *dest++ = *src++;
-	jra	1b
-2:
-				| /* copy bootinfo to end of bss */
-	movel	a3,a0		| src = (u_long *)(memptr+kernel_size);
-	addl	d2,a0		| dest = end of bss (already in a1)
-	movel	d3,d7		| count = bi_size
-	subql	#1,d7
-1:	moveb	a0@+,a1@+	| while (--count > -1)
-	dbra	d7,1b		|     *dest++ = *src++
-
-				| /* copy the ramdisk to the top of memory */
-	movel	a3,a0		| src = (u_long *)(memptr+kernel_size+bi_size);
-	addl	d2,a0
-	addl	d3,a0
-	movel	d0,a1		| dest = (u_long *)rd_dest;
-	movel	a0,a2		| limit = (u_long *)(memptr+kernel_size+
-	addl	d1,a2		|		     bi_size+rd_size);
-1:	cmpl	a0,a2
-	jeq	2f		| while (src > limit)
-	moveb	a0@+,a1@+	|     *dest++ = *src++;
-	jra	1b
-2:
-				| /* jump to start of kernel */
-	movel	a4,a0		| jump_to (start_mem);
-	jmp	a0@
-"
-SYMBOL_NAME_STR(copyallend) ":
-");
-
-
-    /*
-     *	Test for a MapROMmed A3640 Board
-     */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(maprommed) ":
-	oriw	#0x0700,sr
-	moveml	#0x3f20,sp@-
-				| /* Save cache settings */
-	.long	0x4e7a1002	| movec cacr,d1 */
-				| /* Save MMU settings */
-	.long	0x4e7a2003	| movec tc,d2
-	.long	0x4e7a3004	| movec itt0,d3
-	.long	0x4e7a4005	| movec itt1,d4
-	.long	0x4e7a5006	| movec dtt0,d5
-	.long	0x4e7a6007	| movec dtt1,d6
-	moveq	#0,d0
-	movel	d0,a2
-				| /* Disable caches */
-	.long	0x4e7b0002	| movec d0,cacr
-				| /* Disable MMU */
-	.long	0x4e7b0003	| movec d0,tc
-	.long	0x4e7b0004	| movec d0,itt0
-	.long	0x4e7b0005	| movec d0,itt1
-	.long	0x4e7b0006	| movec d0,dtt0
-	.long	0x4e7b0007	| movec d0,dtt1
-	lea	0x07f80000,a0
-	lea	0x00f80000,a1
-	movel	a0@,d7
-	cmpl	a1@,d7
-	jne	1f
-	movel	d7,d0
-	notl	d0
-	movel	d0,a0@
-	nop			| /* Thanks to Jörg Mayer! */
-	cmpl	a1@,d0
-	jne	1f
-	moveq	#-1,d0		| /* MapROMmed A3640 present */
-	movel	d0,a2
-1:	movel	d7,a0@
-				| /* Restore MMU settings */
-	.long	0x4e7b2003	| movec d2,tc
-	.long	0x4e7b3004	| movec d3,itt0
-	.long	0x4e7b4005	| movec d4,itt1
-	.long	0x4e7b5006	| movec d5,dtt0
-	.long	0x4e7b6007	| movec d6,dtt1
-				| /* Restore cache settings */
-	.long	0x4e7b1002	| movec d1,cacr
-	movel	a2,d0
-	moveml	sp@+,#0x04fc
-	rte
-");
-
-
-    /*
-     *	Reset functions for nasty Zorro boards
-     */
-
-static void reset_rb3(const struct ConfigDev *cd)
-{
-    volatile u_char *rb3_reg = (u_char *)(cd->cd_BoardAddr+0x01002000);
-
-    /* FN: If a Rainbow III board is present, reset it to disable */
-    /* its (possibly activated) vertical blank interrupts as the */
-    /* kernel is not yet prepared to handle them (level 6). */
-
-    /* set RESET bit in special function register */
-    *rb3_reg = 0x01;
-    /* actually, only a few cycles delay are required... */
-    Sleep(1000000);
-    /* clear reset bit */
-    *rb3_reg = 0x00;
-}
-
-static void reset_piccolo(const struct ConfigDev *cd)
-{
-    volatile u_char *piccolo_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
-    /* FN: the same stuff as above, for the Piccolo board. */
-    /* this also has the side effect of resetting the board's */
-    /* output selection logic to use the Amiga's display in single */
-    /* monitor systems - which is currently what we want. */
-
-    /* set RESET bit in special function register */
-    *piccolo_reg = 0x01;
-    /* actually, only a few cycles delay are required... */
-    Sleep(1000000);
-    /* clear reset bit */
-    *piccolo_reg = 0x51;
-}
-
-static void reset_sd64(const struct ConfigDev *cd)
-{
-    volatile u_char *sd64_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
-    /* FN: the same stuff as above, for the SD64 board. */
-    /* just as on the Piccolo, this also resets the monitor switch */
-
-    /* set RESET bit in special function register */
-    *sd64_reg = 0x1f;
-    /* actually, only a few cycles delay are required... */
-    Sleep(1000000);
-    /* clear reset bit AND switch monitor bit (0x20) */
-    *sd64_reg = 0x4f;
-}
-
-static void reset_ariadne(const struct ConfigDev *cd)
-{
-    volatile u_short *lance_rdp = (u_short *)(cd->cd_BoardAddr+0x0370);
-    volatile u_short *lance_rap = (u_short *)(cd->cd_BoardAddr+0x0372);
-    volatile u_short *lance_reset = (u_short *)(cd->cd_BoardAddr+0x0374);
-
-    volatile u_char *pit_paddr = (u_char *)(cd->cd_BoardAddr+0x1004);
-    volatile u_char *pit_pbddr = (u_char *)(cd->cd_BoardAddr+0x1006);
-    volatile u_char *pit_pacr = (u_char *)(cd->cd_BoardAddr+0x100b);
-    volatile u_char *pit_pbcr = (u_char *)(cd->cd_BoardAddr+0x100e);
-    volatile u_char *pit_psr = (u_char *)(cd->cd_BoardAddr+0x101a);
-
-    u_short in;
-
-    Disable();
-
-    /*
-     *	Reset the Ethernet part (Am79C960 PCnet-ISA)
-     */
-
-    in = *lance_reset;   /* Reset Chip on Read Access */
-    *lance_rap = 0x0000; /* PCnet-ISA Controller Status (CSR0) */
-    *lance_rdp = 0x0400; /* STOP */
-
-    /*
-     *	Reset the Parallel part (MC68230 PI/T)
-     */
-
-    *pit_pacr &= 0xfd;   /* Port A Control Register */
-    *pit_pbcr &= 0xfd;   /* Port B Control Register */
-    *pit_psr = 0x05;     /* Port Status Register */
-    *pit_paddr = 0x00;   /* Port A Data Direction Register */
-    *pit_pbddr = 0x00;   /* Port B Data Direction Register */
-
-    Enable();
-}
-
-static void reset_hydra(const struct ConfigDev *cd)
-{
-    volatile u_char *nic_cr  = (u_char *)(cd->cd_BoardAddr+0xffe1);
-    volatile u_char *nic_isr = (u_char *)(cd->cd_BoardAddr+0xffe1 + 14);
-    int n = 5000;
-
-    Disable();
- 
-    *nic_cr = 0x21;	/* nic command register: software reset etc. */
-    while (((*nic_isr & 0x80) == 0) && --n)  /* wait for reset to complete */
-	;
- 
-    Enable();
-}
-
-#if 0
-static void reset_a2060(const struct ConfigDev *cd)
-{
-#error reset_a2060: not yet implemented
-}
-#endif
-
-
-#ifdef ZKERNEL
-
-#define	ZFILE_CHUNK_BITS	16  /* chunk is 64 KB */
-#define	ZFILE_CHUNK_SIZE	(1 << ZFILE_CHUNK_BITS)
-#define	ZFILE_CHUNK_MASK	(ZFILE_CHUNK_SIZE-1)
-#define	ZFILE_N_CHUNKS		(2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0;	     /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-
-#define memzero(s, n)     memset ((s), 0, (n))
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000    /* window size--must be a power of two, and */
-			/*  at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0;  /* valid bytes in inbuf */
-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;  /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-		
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int  fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#define malloc(x)	AllocVec(x, MEMF_FAST | MEMF_PUBLIC)
-#define free(x)		FreeVec(x)
-
-#ifdef LILO
-#include "inflate.c"
-#else
-#include "../../../../lib/inflate.c"
-#endif
-
-static void gzip_mark(void **ptr)
-{
-}
-
-static void gzip_release(void **ptr)
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
-    if (exit_code)
-	return -1;
-
-    insize = Read(Zinfd, inbuf, INBUFSIZ);
-    if (insize <= 0)
-	return -1;
-
-    inptr = 1;
-    return(inbuf[0]);
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, ch;
-    int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
-    if (exit_code)
-	return;
-
-    if (chunk >= ZFILE_N_CHUNKS) {
-	error("Compressed image too large! Aborting.\n");
-	return;
-    }
-    if (!ZFile[chunk]) {
-	if (!(ZFile[chunk] = (char *)AllocMem(ZFILE_CHUNK_SIZE,
-					      MEMF_FAST | MEMF_PUBLIC))) {
-	    error("Out of memory for decompresing kernel image\n");
-	    return;
-	}
-    }
-    memcpy(ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt);
-    Zwpos += outcnt;
-    
-#define	DISPLAY_BITS 10
-    if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0)
-	PutChar('.');
-    
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-	ch = *in++;
-	c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void error(char *x)
-{
-    Printf("\n%s", x);
-    exit_code = 1;
-}
-
-static inline int call_sub(int (*func)(void), void *stackp)
-{
-    register int _res __asm("d0");
-    register int (*a0)(void) __asm("a0") = func;
-    register int (*a1)(void) __asm("a1") = stackp;
-
-    __asm __volatile ("movel sp,a2;"
-    		      "movel a1,sp;"
-    		      "jsr a0@;"
-    		      "movel a2,sp"
-		      : "=r" (_res)
-		      : "r" (a0), "r" (a1)
-		      : "a0", "a1", "a2", "d0", "d1", "memory");
-    return(_res);
-}
-
-static int load_zkernel(int fd)
-{
-    int i, err = -1;
-#define ZSTACKSIZE	(16384)
-    u_long *zstack;
-    
-    for (i = 0; i < ZFILE_N_CHUNKS; ++i)
-	ZFile[i] = NULL;
-    Zinfd = fd;
-    Seek(fd, 0);
-    
-    if (!(inbuf = (uch *)AllocMem(INBUFSIZ, MEMF_FAST | MEMF_PUBLIC)))
-	Puts("Couldn't allocate gunzip buffer\n");
-    else {
-	if (!(window = (uch *)AllocMem(WSIZE, MEMF_FAST | MEMF_PUBLIC)))
-	    Puts("Couldn't allocate gunzip window\n");
-	else {
-	    if (!(zstack = (u_long *)AllocMem(ZSTACKSIZE,
-	    				      MEMF_FAST | MEMF_PUBLIC)))
-		Puts("Couldn't allocate gunzip stack\n");
-	    else {
-		Puts("Uncompressing kernel image ");
-		makecrc();
-		if (!(err = call_sub(gunzip, (char *)zstack+ZSTACKSIZE)))
-		    Puts("done\n");
-		ZFileSize = Zwpos;
-		FreeMem(zstack, ZSTACKSIZE);
-	    }
-	    FreeMem(window, WSIZE);
-	    window = NULL;
-	}
-	FreeMem(inbuf, INBUFSIZ);
-	inbuf = NULL;
-    }
-    Close(Zinfd);	/* input file not needed anymore */
-    return(err);
-}
-
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. (Roman)
- */
-
-static int KRead(int fd, void *buf, int cnt)
-{
-    unsigned done = 0;
-	
-    if (!ZFileSize)
-	return(Read(fd, buf, cnt));
-    
-    if (ZFpos + cnt > ZFileSize)
-	cnt = ZFileSize - ZFpos;
-    
-    while (cnt > 0) {
-	unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
-	unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
-	unsigned n = cnt;
-
-	if (ZFpos + n > endchunk)
-	    n = endchunk - ZFpos;
-	memcpy(buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n);
-	cnt -= n;
-	buf += n;
-	done += n;
-	ZFpos += n;
-
-	if (ZFpos == endchunk) {
-	    FreeMem(ZFile[chunk], ZFILE_CHUNK_SIZE);
-	    ZFile[chunk] = NULL;
-	}
-    }
-
-    return(done);
-}
-
-
-static int KSeek(int fd, int offset)
-{
-    unsigned oldpos, oldchunk, newchunk;
-
-    if (!ZFileSize)
-	return(Seek(fd, offset));
-
-    oldpos = ZFpos;
-    ZFpos = offset;
-    if (ZFpos < 0) {
-	ZFpos = 0;
-	return(-1);
-    } else if (ZFpos > ZFileSize) {
-	ZFpos = ZFileSize;
-	return(-1);
-    }
-
-    /* free memory of skipped-over data */
-    oldchunk = oldpos >> ZFILE_CHUNK_BITS;
-    newchunk = ZFpos  >> ZFILE_CHUNK_BITS;
-    while(oldchunk < newchunk) {
-	if (ZFile[oldchunk]) {
-	    FreeMem(ZFile[oldchunk], ZFILE_CHUNK_SIZE);
-	    ZFile[oldchunk] = NULL;
-	}
-	++oldchunk;
-    }
-    return(ZFpos);
-}
-
-
-static void free_zfile(void)
-{
-    int i;
-
-    for (i = 0; i < ZFILE_N_CHUNKS; ++i)
-	if (ZFile[i]) {
-	    FreeMem(ZFile[i], ZFILE_CHUNK_SIZE);
-	    ZFile[i] = NULL;
-	}
-}
-
-static int KClose(int fd)
-{
-    if (ZFileSize) {
-	free_zfile();
-	ZFileSize = 0;
-    } else
-	Close(fd);
-    return(0);
-}
-#endif /* ZKERNEL */
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/amiga/linuxboot.h linux/arch/m68k/boot/amiga/linuxboot.h
--- v2.1.47/linux/arch/m68k/boot/amiga/linuxboot.h	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/boot/amiga/linuxboot.h	Wed Dec 31 16:00:00 1969
@@ -1,455 +0,0 @@
-/*
- *  linux/arch/m68k/boot/amiga/linuxboot.h -- Generic routine to boot Linux/m68k
- *					      on Amiga, used by both Amiboot and
- *					      Amiga-Lilo.
- *
- *	Created 1996 by Geert Uytterhoeven
- *
- *
- *  This file is based on the original bootstrap code (bootstrap.c):
- *
- *	Copyright (C) 1993, 1994 Hamish Macdonald
- *				 Greg Harp
- *
- *		    with work by Michael Rausch
- *				 Geert Uytterhoeven
- *				 Frank Neumann
- *				 Andreas Schwab
- *
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- */
-
-
-#include <asm/setup.h>
-#include <linux/zorro.h>
-
-
-    /*
-     *  Amiboot Version
-     */
-
-#define AMIBOOT_VERSION		"5.5"
-
-
-    /*
-     *  Amiga Bootinfo Definitions
-     *
-     *  All limits herein are `soft' limits, i.e. they don't put constraints
-     *  on the actual parameters in the kernel.
-     */
-
-struct amiga_bootinfo {
-    u_long machtype;			/* machine type = MACH_AMIGA */
-    u_long cputype;			/* system CPU */
-    u_long fputype;			/* system FPU */
-    u_long mmutype;			/* system MMU */
-    int num_memory;			/* # of memory blocks found */
-    struct mem_info memory[NUM_MEMINFO];/* memory description */
-    struct mem_info ramdisk;		/* ramdisk description */
-    char command_line[CL_SIZE];		/* kernel command line parameters */
-    u_long model;			/* Amiga Model */
-    int num_autocon;			/* # of autoconfig devices found */
-    struct ConfigDev autocon[ZORRO_NUM_AUTO];	/* autoconfig devices */
-    u_long chip_size;			/* size of chip memory (bytes) */
-    u_char vblank;			/* VBLANK frequency */
-    u_char psfreq;			/* power supply frequency */
-    u_long eclock;			/* EClock frequency */
-    u_long chipset;			/* native chipset present */
-    u_short serper;			/* serial port period */
-};
-
-
-    /*
-     *  Parameters passed to linuxboot()
-     */
-
-struct linuxboot_args {
-    struct amiga_bootinfo bi;	/* Initial values override detected values */
-    const char *kernelname;
-    const char *ramdiskname;
-    int debugflag;
-    int keep_video;
-    int reset_boards;
-    u_int baud;
-    void (*puts)(const char *str);
-    long (*getchar)(void);
-    void (*putchar)(char c);
-    void (*printf)(const char *fmt, ...);
-    int (*open)(const char *path);
-    int (*seek)(int fd, int offset);
-    int (*read)(int fd, char *buf, int count);
-    void (*close)(int fd);
-    int (*filesize)(const char *path);
-    void (*sleep)(u_long micros);
-};
-
-
-    /*
-     *  Boot the Linux/m68k Operating System
-     */
-
-extern u_long linuxboot(const struct linuxboot_args *args);
-
-
-    /*
-     *  Amiga Models
-     */
-
-extern const char *amiga_models[];
-extern const u_long first_amiga_model;
-extern const u_long last_amiga_model;
-
-
-    /*
-     *	Exec Library Definitions
-     */
-
-#define TRUE	(1)
-#define FALSE	(0)
-
-
-struct List {
-    struct Node *lh_Head;
-    struct Node *lh_Tail;
-    struct Node *lh_TailPred;
-    u_char lh_Type;
-    u_char l_pad;
-};
-
-struct MemChunk {
-     struct MemChunk *mc_Next;	/* pointer to next chunk */
-     u_long mc_Bytes;		/* chunk byte size    */
-};
-
-#define MEMF_PUBLIC	(1<<0)
-#define MEMF_CHIP	(1<<1)
-#define MEMF_FAST	(1<<2)
-#define MEMF_LOCAL	(1<<8)
-#define MEMF_CLEAR	(1<<16)
-
-struct MemHeader {
-    struct Node mh_Node;
-    u_short mh_Attributes;	/* characteristics of this region */
-    struct MemChunk *mh_First;	/* first free region */
-    void *mh_Lower;		/* lower memory bound */
-    void *mh_Upper;		/* upper memory bound+1 */
-    u_long mh_Free;		/* total number of free bytes */
-};
-
-struct ExecBase {
-    u_char fill1[20];
-    u_short Version;
-    u_char fill2[274];
-    u_short AttnFlags;
-    u_char fill3[24];
-    struct List MemList;
-    u_char fill4[194];
-    u_char VBlankFrequency;
-    u_char PowerSupplyFrequency;
-    u_char fill5[36];
-    u_long ex_EClockFrequency;
-    u_char fill6[60];
-};
-
-#define AFB_68020	(1)
-#define AFF_68020	(1<<AFB_68020)
-#define AFB_68030	(2)
-#define AFF_68030	(1<<AFB_68030)
-#define AFB_68040	(3)
-#define AFF_68040	(1<<AFB_68040)
-#define AFB_68881	(4)
-#define AFF_68881	(1<<AFB_68881)
-#define AFB_68882	(5)
-#define AFF_68882	(1<<AFB_68882)
-#define AFB_FPU40	(6)		/* ONLY valid if AFB_68040 or AFB_68060 */
-#define AFF_FPU40	(1<<AFB_FPU40)	/* is set; also set for 68060 FPU */
-#define AFB_68060	(7)
-#define AFF_68060	(1<<AFB_68060)
-
-struct Resident;
-
-
-    /*
-     *	Graphics Library Definitions
-     */
-
-struct GfxBase {
-    u_char fill1[20];
-    u_short Version;
-    u_char fill2[194];
-    u_short NormalDisplayRows;
-    u_short NormalDisplayColumns;
-    u_char fill3[16];
-    u_char ChipRevBits0;
-    u_char fill4[307];
-};
-
-#define GFXB_HR_AGNUS	(0)
-#define GFXF_HR_AGNUS	(1<<GFXB_HR_AGNUS)
-#define GFXB_HR_DENISE	(1)
-#define GFXF_HR_DENISE	(1<<GFXB_HR_DENISE)
-#define GFXB_AA_ALICE	(2)
-#define GFXF_AA_ALICE	(1<<GFXB_AA_ALICE)
-#define GFXB_AA_LISA	(3)
-#define GFXF_AA_LISA	(1<<GFXB_AA_LISA)
-
-    /*
-     *	HiRes(=Big) Agnus present; i.e. 
-     *	1MB chipmem, big blits (none of interest so far) and programmable sync
-     */
-#define GFXG_OCS	(GFXF_HR_AGNUS)
-    /*
-     *	HiRes Agnus/Denise present; we are running on ECS
-     */
-#define GFXG_ECS	(GFXF_HR_AGNUS|GFXF_HR_DENISE)
-    /*
-     *	Alice and Lisa present; we are running on AGA
-     */
-#define GFXG_AGA	(GFXF_AA_ALICE|GFXF_AA_LISA)
-
-#define SETCHIPREV_BEST	(0xffffffff)
-#define HIRES		(0x8000)
-
-struct View;
-
-
-    /*
-     *	Amiga Shared Library/Device Functions
-     */
-
-extern const struct ExecBase *SysBase;
-
-#define LVOAllocMem		(-0xc6)
-#define LVOAllocVec		(-0x2ac)
-#define LVOCacheControl		(-0x288)
-#define LVODisable		(-0x78)
-#define LVOEnable		(-0x7e)
-#define LVOFindResident		(-0x60)
-#define LVOFreeMem		(-0xd2)
-#define LVOFreeVec		(-0x2b2)
-#define LVOOpenresource		(-0x1f2)
-#define LVOSuperState		(-0x96)
-#define LVOSupervisor		(-0x1e)
-
-static __inline void *AllocMem(u_long byteSize, u_long requirements)
-{
-    register void *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long d0 __asm("d0") = byteSize;
-    register u_long d1 __asm("d1") = requirements;
-
-    __asm __volatile ("jsr a6@(-0xc6)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (d0), "r" (d1)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline void *AllocVec(u_long byteSize, u_long requirements)
-{
-    register void *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long d0 __asm("d0") = byteSize;
-    register u_long d1 __asm("d1") = requirements;
-
-    __asm __volatile ("jsr a6@(-0x2ac)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (d0), "r" (d1)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline u_long CacheControl(u_long cacheBits, u_long cacheMask)
-{
-    register u_long _res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long d0 __asm("d0") = cacheBits;
-    register u_long d1 __asm("d1") = cacheMask;
-
-    __asm __volatile ("jsr a6@(-0x288)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (d0), "r" (d1)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline void Disable(void)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x78)"
-		      : /* no output */
-		      : "r" (_base)
-		      : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void Enable(void)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x7e)"
-		      : /* no output */
-		      : "r" (_base)
-		      : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline struct Resident *FindResident(const u_char *name)
-{
-    register struct Resident *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register const u_char *a1 __asm("a1") = name;
-
-    __asm __volatile ("jsr a6@(-0x60)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (a1)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return _res;
-}
-
-static __inline void FreeMem(void *memoryBlock, u_long byteSize)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register void *a1 __asm("a1") = memoryBlock;
-    register u_long d0 __asm("d0") = byteSize;
-
-    __asm __volatile ("jsr a6@(-0xd2)"
-		      : /* no output */
-		      : "r" (_base), "r" (a1), "r" (d0)
-		      : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void FreeVec(void *memoryBlock)
-{
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register void *a1 __asm("a1") = memoryBlock;
-
-    __asm __volatile ("jsr a6@(-0x2b2)"
-		      : /* no output */
-		      : "r" (_base), "r" (a1)
-		      : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void *OpenResource(const u_char *resName)
-{
-    register void *_res  __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register const u_char *a1 __asm("a1") = resName;
-
-    __asm __volatile ("jsr a6@(-0x1f2)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (a1)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return _res;
-}
-
-static __inline void *SuperState(void)
-{
-    register void *_res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-
-    __asm __volatile ("jsr a6@(-0x96)"
-		      : "=r" (_res)
-		      : "r" (_base)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-static __inline u_long Supervisor(u_long (*userfunc)(void))
-{
-    register u_long _res __asm("d0");
-    register const struct ExecBase *_base __asm("a6") = SysBase;
-    register u_long (*d7)() __asm("d7") = userfunc;
-
-    __asm __volatile ("exg d7,a5;"
-		      "jsr a6@(-0x1e);"
-		      "exg d7,a5"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (d7)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-
-extern const struct ExpansionBase *ExpansionBase;
-
-#define LVOFindConfigDev	(-0x48)
-
-static __inline struct ConfigDev *FindConfigDev(struct ConfigDev *oldConfigDev,
-						long manufacturer, long product)
-{
-    register struct ConfigDev *_res __asm("d0");
-    register const struct ExpansionBase *_base __asm("a6") = ExpansionBase;
-    register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
-    register long d0 __asm("d0") = manufacturer;
-    register long d1 __asm("d1") = product;
-
-    __asm __volatile ("jsr a6@(-0x48)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (a0), "r" (d0), "r" (d1)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-
-extern const struct GfxBase *GfxBase;
-
-#define LVOLoadView		(-0xde)
-#define LVOSetChipRev		(-0x378)
-
-static __inline void LoadView(struct View *view)
-{
-    register const struct GfxBase *_base __asm("a6") = GfxBase;
-    register struct View *a1 __asm("a1") = view;
-
-    __asm __volatile ("jsr a6@(-0xde)"
-		      : /* no output */
-		      : "r" (_base), "r" (a1)
-		      : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline u_long SetChipRev(u_long want)
-{
-    register u_long _res __asm("d0");
-    register const struct GfxBase *_base __asm("a6") = GfxBase;
-    register u_long d0 __asm("d0") = want;
-
-    __asm __volatile ("jsr a6@(-0x378)"
-		      : "=r" (_res)
-		      : "r" (_base), "r" (d0)
-		      : "a0", "a1", "d0", "d1", "memory");
-    return(_res);
-}
-
-
-    /*
-     *	Bootstrap Support Functions
-     */
-
-static __inline void disable_mmu(void)
-{
-    if (SysBase->AttnFlags & AFF_68040)
-	__asm __volatile ("moveq #0,d0;"
-			  ".long 0x4e7b0003;"	/* movec d0,tc */
-			  ".long 0x4e7b0004;"	/* movec d0,itt0 */
-			  ".long 0x4e7b0005;"	/* movec d0,itt1 */
-			  ".long 0x4e7b0006;"	/* movec d0,dtt0 */
-			  ".long 0x4e7b0007"	/* movec d0,dtt1 */
-			  : /* no outputs */
-			  : /* no inputs */
-			  : "d0");
-    else {
-	__asm __volatile ("subl #4,sp;"
-			  "pmove tc,sp@;"
-			  "bclr #7,sp@;"
-			  "pmove sp@,tc;"
-			  "addl #4,sp");
-	if (SysBase->AttnFlags & AFF_68030)
-	    __asm __volatile ("clrl sp@-;"
-			      ".long 0xf0170800;"	/* pmove sp@,tt0 */
-			      ".long 0xf0170c00;"	/* pmove sp@,tt1 */
-			      "addql #4,sp");
-    }
-}
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/bootp.c linux/arch/m68k/boot/atari/bootp.c
--- v2.1.47/linux/arch/m68k/boot/atari/bootp.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/atari/bootp.c	Wed Dec 31 16:00:00 1969
@@ -1,814 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bootp.h"
-
-
-/* --------------------------------------------------------------------- */
-/*						  Protocol Header Structures					 */
-
-struct etherhdr {
-	HWADDR			dst_addr;
-	HWADDR			src_addr;
-	unsigned short	type;
-};
-
-struct arphdr {
-	unsigned short	hrd;		/* format of hardware address	*/
-	unsigned short	pro;		/* format of protocol address	*/
-	unsigned char	hln;		/* length of hardware address	*/
-	unsigned char	pln;		/* length of protocol address	*/
-	unsigned short	op;			/* ARP opcode (command)			*/
-	unsigned char	addr[0];	/* addresses (var len)			*/
-};
-	
-struct iphdr {
-	unsigned char	version : 4;
-	unsigned char	ihl : 4;
-	unsigned char	tos;
-	unsigned short	tot_len;
-	unsigned short	id;
-	unsigned short	frag_off;
-	unsigned char	ttl;
-	unsigned char	protocol;
-	unsigned short	chksum;
-	IPADDR			src_addr;
-	IPADDR			dst_addr;
-};
-
-struct udphdr {
-	unsigned short	src_port;
-	unsigned short	dst_port;
-	unsigned short	len;
-	unsigned short	chksum;
-};
-
-struct bootp {
-	unsigned char	op;			/* packet opcode type */
-	unsigned char	htype;		/* hardware addr type */
-	unsigned char	hlen;		/* hardware addr length */
-	unsigned char	hops;		/* gateway hops */
-	unsigned long	xid;		/* transaction ID */
-	unsigned short	secs;		/* seconds since boot began */
-	unsigned short	unused;
-	IPADDR			ciaddr;		/* client IP address */
-	IPADDR			yiaddr;		/* 'your' IP address */
-	IPADDR			siaddr;		/* server IP address */
-	IPADDR			giaddr; 	/* gateway IP address */
-	unsigned char	chaddr[16];	/* client hardware address */
-	unsigned char	sname[64];	/* server host name */
-	unsigned char	file[128];	/* boot file name */
-	unsigned char	vend[64];	/* vendor-specific area */
-};
-
-struct tftp_req {
-	unsigned short	opcode;
-	char			name[512];
-};
-
-struct tftp_data {
-	unsigned short	opcode;
-	unsigned short	nr;
-	unsigned char	data[512];
-};
-
-struct tftp_ack {
-	unsigned short	opcode;
-	unsigned short	nr;
-};
-
-struct tftp_error {
-	unsigned short	opcode;
-	unsigned short	errcode;
-	char			str[512];
-};
-
-
-typedef struct {
-	struct etherhdr		ether;
-	struct arphdr		arp;
-} ARP;
-
-typedef struct {
-	struct etherhdr		ether;
-	struct iphdr		ip;
-	struct udphdr		udp;
-} UDP;
-
-#define	UDP_BOOTPS	67
-#define	UDP_BOOTPC	68
-#define	UDP_TFTP	69
-
-typedef struct {
-	struct etherhdr		ether;
-	struct iphdr		ip;
-	struct udphdr		udp;
-	struct bootp		bootp;
-} BOOTP;
-
-#define	BOOTREQUEST		1
-#define	BOOTREPLY		2
-#define	BOOTP_RETRYS	5
-
-typedef struct {
-	struct etherhdr		ether;
-	struct iphdr		ip;
-	struct udphdr		udp;
-	union tftp {
-		unsigned short		opcode;
-		struct tftp_req		req;
-		struct tftp_data	data;
-		struct tftp_ack		ack;
-		struct tftp_error	error;
-	} tftp;
-} TFTP;
-	
-#define	TFTP_RRQ	1
-#define	TFTP_WRQ	2
-#define	TFTP_DATA	3
-#define	TFTP_ACK	4
-#define	TFTP_ERROR	5
-
-
-/* --------------------------------------------------------------------- */
-/*								  Addresses								 */
-
-static HWADDR	MyHwaddr;
-static HWADDR	ServerHwaddr;
-static IPADDR	MyIPaddr;
-static IPADDR	ServerIPaddr;
-
-static IPADDR	IP_Unknown_Addr =   0x00000000;
-static IPADDR	IP_Broadcast_Addr = 0xffffffff;
-static HWADDR 	Eth_Broadcast_Addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-
-#define	HZ	200
-#define	_hz_200	(*(volatile unsigned long *)0x4ba)
-
-
-/* --------------------------------------------------------------------- */
-/*								Error Strings							 */
-
-static char *ErrStr[] = {
-	"timeout",
-	"general Ethernet transmit error",
-	"general Ethernet receive error",
-	"Ethernet framing error",
-	"Ethernet overflow error",
-	"Ethernet CRC error"
-};
-
-
-/* --------------------------------------------------------------------- */
-/*						 Kfile Emulation Definitions					 */
-
-#define	KFILE_CHUNK_BITS	16  /* chunk is 64 KB */
-#define	KFILE_CHUNK_SIZE	(1 << KFILE_CHUNK_BITS)
-#define	KFILE_CHUNK_MASK	(KFILE_CHUNK_SIZE-1)
-#define	KFILE_N_CHUNKS		(2*1024*1024/KFILE_CHUNK_SIZE)
-
-char *KFile[KFILE_N_CHUNKS];
-int  KFileSize = 0;
-int	 KFpos = 0;
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static void free_kfile( void );
-static int bootp( char *image_name );
-static int tftp( char *image_name );
-static int udp_send( UDP *pkt, int len, int fromport, int toport );
-static unsigned short ip_checksum( struct iphdr *buf );
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport );
-static void print_ip( IPADDR addr );
-static void print_hw( HWADDR addr );
-static int check_ethif( void );
-static int eth_send( Packet *pkt, int len );
-static int eth_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-
-/* --------------------------------------------------------------------- */
-/*						   Interface to bootstrap.c						 */
-
-/* get_remote_kernel():
- * Perform all necessary steps to get the kernel image
- * from the boot server. If successfull (retval == 0), subsequent calls to
- * kread() can access the data. Fatal errors (i.e., retrying is useless)
- * return -2, others -1.
- */
-
-int get_remote_kernel( const char *kname /* optional */ )
-
-{	char	image_name[256];
-	int		rv;
-
-	/* Check if a Ethernet interface is present and determine the Ethernet
-	 * address */
-	if (check_ethif() < 0) {
-		printf( "No Ethernet interface found -- no remote boot possible.\n" );
-		return( -2 );
-	}
-	
-	/* Do a BOOTP request to find out our IP address and the kernel image's
-	 * name; we also learn the IP and Ethernet address of our server */
-	if (kname)
-		strcpy( image_name, kname );
-	else
-		*image_name = 0;
-	if ((rv = bootp( image_name )) < 0)
-		return( rv );
-	
-	/* Now start a TFTP connection to receive the kernel image */
-	if ((rv = tftp( image_name )) < 0)
-		return( rv );
-
-	return( 0 );
-}
-
-
-/* ll_read(), ll_lseek(), ll_close():
- * Functions for accessing the received kernel image like with read(),
- * lseek(), close().
- */
-
-int ll_read( int fd, void *buf, unsigned cnt )
-
-{	unsigned done = 0;
-	
-	if (!KFileSize)
-		return( read( fd, buf, cnt ) );
-
-	if (KFpos + cnt > KFileSize)
-		cnt = KFileSize - KFpos;
-	
-	while( cnt > 0 ) {
-		unsigned chunk = KFpos >> KFILE_CHUNK_BITS;
-		unsigned endchunk = (chunk+1) << KFILE_CHUNK_BITS;
-		unsigned n = cnt;
-
-		if (KFpos + n > endchunk)
-			n = endchunk - KFpos;
-		memcpy( buf, KFile[chunk] + (KFpos & KFILE_CHUNK_MASK), n );
-		cnt -= n;
-		buf += n;
-		done += n;
-		KFpos += n;
-
-		if (KFpos == endchunk) {
-			free( KFile[chunk] );
-			KFile[chunk] = NULL;
-		}
-	}
-
-	return( done );
-}
-
-
-int ll_lseek( int fd, int where, int whence )
-
-{
-    unsigned oldpos, oldchunk, newchunk;
-
-	if (!KFileSize)
-		return( lseek( fd, where, whence ) );
-
-    oldpos = KFpos;
-	switch( whence ) {
-	  case SEEK_SET:
-		KFpos = where;
-		break;
-	  case SEEK_CUR:
-		KFpos += where;
-		break;
-	  case SEEK_END:
-		KFpos = KFileSize + where;
-		break;
-	  default:
-		return( -1 );
-	}
-	if (KFpos < 0) {
-		KFpos = 0;
-		return( -1 );
-	}
-	else if (KFpos > KFileSize) {
-		KFpos = KFileSize;
-		return( -1 );
-	}
-
-    /* free memory of skipped-over data */
-    oldchunk = oldpos >> KFILE_CHUNK_BITS;
-    newchunk = KFpos  >> KFILE_CHUNK_BITS;
-    while( oldchunk < newchunk ) {
-		if (KFile[oldchunk]) {
-			free( KFile[oldchunk] );
-			KFile[oldchunk] = NULL;
-		}
-		++oldchunk;
-    }
-    
-	return( KFpos );
-}
-
-
-int ll_close( int fd )
-
-{
-	if (!KFileSize)
-		return( close( fd ) );
-
-	free_kfile();
-	return( 0 );
-}
-
-
-static void free_kfile( void )
-
-{	int		i;
-
-	for( i = 0; i < KFILE_N_CHUNKS; ++i )
-		if (KFile[i]) free( KFile[i] );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/*							   BOOTP Procedure							 */
-
-
-static int bootp( char *image_name )
-
-{	BOOTP	req;
-	Packet	_reply;
-	BOOTP	*reply = (BOOTP *)_reply;
-	static unsigned char mincookie[] = { 99, 130, 83, 99, 255 };
-	unsigned long 	starttime, rancopy;
-	int				err, len, retry;
-	
-	memset( (char *)&req, 0, sizeof(req) );
-	/* Now fill in the packet... */
-	req.bootp.op = BOOTREQUEST;
-	req.bootp.htype = 1; /* 10Mb/s Ethernet */
-	req.bootp.hlen = 6;
-	memcpy( req.bootp.chaddr, &MyHwaddr, ETHADDRLEN );
-
-	/* Put in the minimal RFC1497 Magic cookie */
-	memcpy( req.bootp.vend, mincookie, sizeof(mincookie) );
-	/* Put the user precified bootfile name in place */
-	memcpy( req.bootp.file, image_name, strlen(image_name)+1);
-
-	starttime = _hz_200;
-	for( retry = 0; retry < BOOTP_RETRYS; ++retry ) {
-
-		/* Initialize server addresses and own IP to defaults */
-		ServerIPaddr = IP_Broadcast_Addr;  /* 255.255.255.255 */
-		MyIPaddr     = IP_Unknown_Addr;    /* 0.0.0.0 */
-		memcpy( ServerHwaddr, Eth_Broadcast_Addr, ETHADDRLEN );
-
-		if (retry)
-			sleep( 3 );
-		
-		req.bootp.xid = rancopy = _hz_200;
-		req.bootp.secs = (_hz_200 - starttime) / HZ;
-
-		if ((err = udp_send( (UDP *)&req, sizeof(req.bootp),
-							 UDP_BOOTPC, UDP_BOOTPS )) < 0) {
-			printf( "bootp send: %s\n", ErrStr[-err-1] );
-			continue;
-		}
-		
-		if ((err = udp_rcv( (UDP *)reply, &len,
-							UDP_BOOTPS, UDP_BOOTPC )) < 0) {
-			printf( "bootp rcv: %s\n", ErrStr[-err-1] );
-			continue;
-		}
-		if (len < sizeof(struct bootp)) {
-			printf( "received short BOOTP packet (%d bytes)\n", len );
-			continue;
-		}
-
-		if (reply->bootp.xid == rancopy)
-			/* Ok, got the answer */
-			break;
-		printf( "bootp: xid mismatch\n" );
-	}
-	if (retry >= BOOTP_RETRYS) {
-		printf( "No response from a bootp server\n" );
-		return( -2 );
-	}
-	
-	ServerIPaddr = reply->bootp.siaddr;
-	memcpy( ServerHwaddr, reply->ether.src_addr, ETHADDRLEN );
-	printf( "\nBoot server is " );
-	if (strlen(reply->bootp.sname) > 0)
-		printf( "%s, IP ", reply->bootp.sname );
-	print_ip( ServerIPaddr );
-	printf( ", HW address " );
-	print_hw( ServerHwaddr );
-	printf( "\n" );
-
-	MyIPaddr = reply->bootp.yiaddr;
-	printf( "My IP address is " );
-	print_ip( MyIPaddr );
-	printf( "\n" );
-
-	strcpy( image_name, reply->bootp.file );
-	return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/*								TFTP Procedure							 */
-
-
-static int tftp( char *image_name )
-
-{	TFTP	spkt;
-	Packet	_rpkt;
-	TFTP	*rpkt = (TFTP *)&_rpkt;
-	unsigned short	mytid, rtid = 0;
-	int				blk, retries, i, wpos, err, len, datalen;
-	static char		rotchar[4] = { '|', '/', '-', '\\' };
-	
-	retries = 5;
-	/* Construct and send a read request */
-  repeat_req:
-	spkt.tftp.req.opcode = TFTP_RRQ;
-	strcpy( spkt.tftp.req.name, image_name );
-	strcpy( spkt.tftp.req.name + strlen(spkt.tftp.req.name) + 1, "octet" );
-	mytid = _hz_200 & 0xffff;
-	
-	if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.req.opcode) +
-									   strlen(image_name) + 1 +
-									   strlen( "octect" ) +1,
-						 mytid, UDP_TFTP )) < 0) {
-		printf( "TFTP RREQ: %s\n", ErrStr[-err-1] );
-		if (--retries > 0)
-			goto repeat_req;
-		return( err == ETIMEO ? -2 : -1 );
-	}
-
-	retries = 5;
-	for( i = 0; i < KFILE_N_CHUNKS; ++i )
-		KFile[i] = NULL;
-	wpos = 0;
-	printf( "Receiving kernel image %s:\n", image_name );
-
-	for( blk = 1; ; ++blk ) {
-
-	  repeat_data:
-		if ((err = udp_rcv( (UDP *)rpkt, &len, rtid, mytid )) < 0) {
-			printf( "TFTP rcv: %s\n", ErrStr[-err-1] );
-			if (--retries > 0)
-				goto repeat_data;
-			goto err;
-		}
-		if (rtid == 0)
-			/* Store the remote port at the first packet received */
-			rtid = rpkt->udp.src_port;
-
-		if (rpkt->tftp.opcode == TFTP_ERROR) {
-			if (strlen(rpkt->tftp.error.str) > 0)
-				printf( "TFTP error: %s\n", rpkt->tftp.error.str );
-			else
-				printf( "TFTP error #%d (no description)\n",
-						rpkt->tftp.error.errcode );
-			goto err;
-		}
-		else if (rpkt->tftp.opcode != TFTP_DATA) {
-			printf( "Bad TFTP packet type: %d\n", rpkt->tftp.opcode );
-			if (--retries > 0)
-				goto repeat_data;
-			goto err;
-		}
-
-		if (rpkt->tftp.data.nr != blk) {
-			/* doubled data packet; ignore it */
-			goto repeat_data;
-		}
-		datalen = len - sizeof(rpkt->tftp.data.opcode) -
-			            sizeof(rpkt->tftp.data.nr);
-		
-		/* store data */
-		if (datalen > 0) {
-			int chunk = wpos >> KFILE_CHUNK_BITS;
-			if (chunk >= KFILE_N_CHUNKS) {
-				printf( "TFTP: file too large! Aborting.\n" );
-			  out_of_mem:
-				spkt.tftp.error.opcode = TFTP_ERROR;
-				spkt.tftp.error.errcode = 3;
-				strcpy( spkt.tftp.error.str, "Out of memory" );
-				udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack), mytid, rtid );
-				goto err;
-			}
-			if (!KFile[chunk]) {
-				if (!(KFile[chunk] = malloc( KFILE_CHUNK_SIZE ))) {
-					printf( "TFTP: Out of memory for kernel image\n" );
-					goto out_of_mem;
-				}
-			}
-			memcpy( KFile[chunk] + (wpos & KFILE_CHUNK_MASK),
-					rpkt->tftp.data.data, datalen );
-			wpos += datalen;
-
-#define	DISPLAY_BITS 13
-			if ((wpos & ((1 << DISPLAY_BITS)-1)) == 0) {
-				printf( "\r %c %7d Bytes ",
-						rotchar[(wpos>>DISPLAY_BITS)&3], wpos );
-				fflush( stdout );
-			}
-		}
-
-		/* Send ACK packet */
-	  repeat_ack:
-		spkt.tftp.ack.opcode = TFTP_ACK;
-		spkt.tftp.ack.nr = blk;
-		if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack),
-							 mytid, rtid )) < 0) {
-			printf( "TFTP ACK: %s\n", ErrStr[-err-1] );
-			if (--retries > 0)
-				goto repeat_ack;
-			goto err;
-		}
-
-		if (datalen < 512) {
-			/* This was the last packet */
-			printf( "\r   %7d Bytes done\n\n", wpos );
-			break;
-		}
-
-		retries = 5;
-	}
-
-	KFileSize = wpos;
-	return( 0 );
-
-  err:
-	free_kfile();
-	return( -1 );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/*				  UDP/IP Protocol Quick Hack Implementation				 */
-
-
-static int udp_send( UDP *pkt, int len, int fromport, int toport )
-
-{
-	/* UDP layer */
-	pkt->udp.src_port = fromport;
-	pkt->udp.dst_port = toport;
-	pkt->udp.len      = (len += sizeof(struct udphdr));
-	pkt->udp.chksum   = 0; /* Too lazy to calculate :-) */
-
-	/* IP layer */
-	pkt->ip.version  = 4;
-	pkt->ip.ihl      = 5;
-	pkt->ip.tos      = 0;
-	pkt->ip.tot_len  = (len += sizeof(struct iphdr));
-	pkt->ip.id       = 0;
-	pkt->ip.frag_off = 0;
-	pkt->ip.ttl      = 255;
-	pkt->ip.protocol = 17; /* UDP */
-	pkt->ip.src_addr = MyIPaddr;
-	pkt->ip.dst_addr = ServerIPaddr;
-	pkt->ip.chksum   = 0;
-	pkt->ip.chksum   = ip_checksum( &pkt->ip );
-
-	/* Ethernet layer */
-	memcpy( &pkt->ether.dst_addr, ServerHwaddr, ETHADDRLEN );
-	memcpy( &pkt->ether.src_addr, MyHwaddr, ETHADDRLEN );
-	pkt->ether.type     = 0x0800;
-	len += sizeof(struct etherhdr);
-
-	return( eth_send( (Packet *)pkt, len ) );
-}
-
-
-static unsigned short ip_checksum( struct iphdr *buf )
-
-{	unsigned long sum = 0, wlen = 5;
-
-	__asm__ ("subqw #1,%2\n"
-			 "1:\t"
-			 "movel %1@+,%/d0\n\t"
-			 "addxl %/d0,%0\n\t"
-			 "dbra %2,1b\n\t"
-			 "movel %0,%/d0\n\t"
-			 "swap %/d0\n\t"
-			 "addxw %/d0,%0\n\t"
-			 "clrw %/d0\n\t"
-			 "addxw %/d0,%0"
-			 : "=d" (sum), "=a" (buf), "=d" (wlen)
-			 : "0" (sum), "1" (buf), "2" (wlen)
-			 : "d0");
-	return( (~sum) & 0xffff );
-}
-
-
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport )
-
-{	int				err;
-
-  repeat:
-	if ((err = eth_rcv( (Packet *)pkt, len )))
-		return( err );
-	
-	/* Ethernet layer */
-	if (pkt->ether.type == 0x0806) {
-		/* ARP */
-		ARP *pk = (ARP *)pkt;
-		unsigned char *shw, *sip, *thw, *tip;
-
-		if (pk->arp.hrd != 1 || pk->arp.pro != 0x0800 ||
-			pk->arp.op != 1 || MyIPaddr == IP_Unknown_Addr)
-			/* Wrong hardware type or protocol; or reply -> ignore */
-			goto repeat;
-		shw = pk->arp.addr;
-		sip = shw + pk->arp.hln;
-		thw = sip + pk->arp.pln;
-		tip = thw + pk->arp.hln;
-		
-		if (memcmp( tip, &MyIPaddr, pk->arp.pln ) == 0) {
-			memcpy( thw, shw, pk->arp.hln );
-			memcpy( tip, sip, pk->arp.pln );
-			memcpy( shw, &MyHwaddr, pk->arp.hln );
-			memcpy( sip, &MyIPaddr, pk->arp.pln );
-
-			memcpy( &pk->ether.dst_addr, thw, ETHADDRLEN );
-			memcpy( &pk->ether.src_addr, &MyHwaddr, ETHADDRLEN );
-			eth_send( (Packet *)pk, *len );
-		}
-		goto repeat;
-	}
-	else if (pkt->ether.type != 0x0800) {
-		printf( "Unknown Ethernet packet type %04x received\n",
-				pkt->ether.type );
-		goto repeat;
-	}
-
-	/* IP layer */
-	if (MyIPaddr != IP_Unknown_Addr && pkt->ip.dst_addr != MyIPaddr) {
-		printf( "Received packet for wrong IP address\n" );
-		goto repeat;
-	}
-	if (ServerIPaddr != IP_Unknown_Addr &&
-		ServerIPaddr != IP_Broadcast_Addr &&
-		pkt->ip.src_addr != ServerIPaddr) {
-		printf( "Received packet from wrong server\n" );
-		goto repeat;
-	}
-	/* If IP header is longer than 5 longs, delete the options */
-	if (pkt->ip.ihl > 5) {
-		char *udpstart = (char *)((long *)&pkt->ip + pkt->ip.ihl);
-		memmove( &pkt->udp, udpstart, *len - (udpstart-(char *)pkt) );
-	}
-	
-	/* UDP layer */
-	if (fromport != 0 && pkt->udp.src_port != fromport) {
-		printf( "Received packet from wrong port %d\n", pkt->udp.src_port );
-		goto repeat;
-	}
-	if (pkt->udp.dst_port != atport) {
-		printf( "Received packet at wrong port %d\n", pkt->udp.dst_port );
-		goto repeat;
-	}
-
-	*len = pkt->udp.len - sizeof(struct udphdr);
-	return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/*							   Address Printing							 */
-
-
-static void print_ip( IPADDR addr )
-
-{
-	printf( "%ld.%ld.%ld.%ld",
-			(addr >> 24) & 0xff,
-			(addr >> 16) & 0xff,
-			(addr >>  8) & 0xff,
-			addr & 0xff );
-}
-
-
-static void print_hw( HWADDR addr )
-
-{
-	printf( "%02x:%02x:%02x:%02x:%02x:%02x",
-			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] );
-}
-
-
-/* --------------------------------------------------------------------- */
-/*					 Ethernet Interface Abstraction Layer				 */
-
-
-#ifdef ETHLL_LANCE
-#include "ethlance.h"
-#endif
-
-static ETHIF_SWITCH *PossibleInterfaces[] = {
-#ifdef ETHLL_LANCE
-	&LanceSwitch,
-#endif
-};
-
-#define	N_PossibleInterfaces (sizeof(PossibleInterfaces)/sizeof(*PossibleInterfaces))
-
-/* Detected interface */
-static ETHIF_SWITCH *Ethif = NULL;
-
-
-static int check_ethif( void )
-
-{	int i;
-
-	/* Check for configured interfaces */
-	Ethif = NULL;
-	for( i = 0; i < N_PossibleInterfaces; ++i ) {
-		if (PossibleInterfaces[i]->probe() >= 0) {
-			Ethif = PossibleInterfaces[i];
-			break;
-		}
-	}
-	if (!Ethif)
-		return( -1 );
-
-	if (Ethif->init() < 0) {
-		printf( "Ethernet interface initialization failed\n" );
-		return( -1 );
-	}
-	Ethif->get_hwaddr( &MyHwaddr );
-	return( 0 );
-}
-
-
-static int eth_send( Packet *pkt, int len )
-
-{
-	return( Ethif->snd( pkt, len ));
-}
-
-
-static int eth_rcv( Packet *pkt, int *len )
-
-{
-	return( Ethif->rcv( pkt, len ));
-}
-
-
-#if 0
-static void dump_packet( UDP *pkt )
-
-{	int		i, l;
-	unsigned char *p;
-	
-	printf( "Packet dump:\n" );
-
-	printf( "Ethernet header:\n" );
-	printf( "  dst addr: " ); print_hw( pkt->ether.dst_addr ); printf( "\n" );
-	printf( "  src addr: " ); print_hw( pkt->ether.src_addr ); printf( "\n" );
-	printf( "  type: %04x\n", pkt->ether.type );
-
-	printf( "IP header:\n" );
-	printf( "  version: %d\n", pkt->ip.version );
-	printf( "  hdr len: %d\n", pkt->ip.ihl );
-	printf( "  tos: %d\n", pkt->ip.tos );
-	printf( "  tot_len: %d\n", pkt->ip.tot_len );
-	printf( "  id: %d\n", pkt->ip.id );
-	printf( "  frag_off: %d\n", pkt->ip.frag_off );
-	printf( "  ttl: %d\n", pkt->ip.ttl );
-	printf( "  prot: %d\n", pkt->ip.protocol );
-	printf( "  src addr: " ); print_ip( pkt->ip.src_addr ); printf( "\n" );
-	printf( "  dst addr: " ); print_ip( pkt->ip.dst_addr ); printf( "\n" );
-
-	printf( "UDP header:\n" );
-	printf( "  src port: %d\n", pkt->udp.src_port );
-	printf( "  dst port: %d\n", pkt->udp.dst_port );
-	printf( "  len: %d\n", pkt->udp.len );
-
-	printf( "Data:" );
-	l = pkt->udp.len - sizeof(pkt->udp);
-	p = (unsigned char *)&pkt->udp + sizeof(pkt->udp);
-	for( i = 0; i < l; ++i ) {
-		if ((i % 32) == 0)
-			printf( "\n  %04x ", i );
-		printf( "%02x ", *p );
-	}
-	printf( "\n" );
-}
-#endif
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/bootp.h linux/arch/m68k/boot/atari/bootp.h
--- v2.1.47/linux/arch/m68k/boot/atari/bootp.h	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/atari/bootp.h	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-#ifndef _bootp_h
-#define _bootp_h
-
-/* --------------------------------------------------------------------- */
-/*							 Ethernet Definitions						 */
-
-#define	PKTLEN			1544
-typedef unsigned char	Packet[PKTLEN];
-
-#define	ETHADDRLEN		6
-typedef unsigned char	HWADDR[ETHADDRLEN];
-
-typedef struct {
-	int		(*probe)( void );
-	int		(*init)( void );
-	void	(*get_hwaddr)( HWADDR *addr );
-	int		(*snd)( Packet *pkt, int len );
-	int		(*rcv)( Packet *pkt, int *len );
-} ETHIF_SWITCH;
-
-
-/* error codes */
-#define	ETIMEO	-1		/* Timeout */
-#define	ESEND	-2		/* General send error (carrier, abort, ...) */
-#define	ERCV	-3		/* General receive error */
-#define	EFRAM	-4		/* Framing error */
-#define	EOVERFL	-5		/* Overflow (too long packet) */
-#define	ECRC	-6		/* CRC error */
-
-
-typedef unsigned long IPADDR;
-
-
-/***************************** Prototypes *****************************/
-
-int get_remote_kernel( const char *kname );
-int ll_read( int fd, void *buf, unsigned cnt );
-int ll_lseek( int fd, int where, int whence );
-int ll_close( int fd );
-
-/************************* End of Prototypes **************************/
-
-#endif  /* _bootp_h */
-
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/bootstrap.c linux/arch/m68k/boot/atari/bootstrap.c
--- v2.1.47/linux/arch/m68k/boot/atari/bootstrap.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/boot/atari/bootstrap.c	Wed Dec 31 16:00:00 1969
@@ -1,1602 +0,0 @@
-/*
-** bootstrap.c -- Load and launch the Atari Linux kernel
-**
-** Copyright 1993 by Arjan Knor
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-** History:
-**	01 Feb 1997 Implemented kernel decompression (Roman)
-**	28 Nov 1996 Fixed and tested previous change (James)
-**	27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
-**	12 Nov 1996 Fixed and tested previous change (Andreas)
-**	18 Aug 1996 Updated for the new boot information structure (untested!)
-**		    (Geert)
-**	10 Dec 1995 BOOTP/TFTP support (Roman)
-**	03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
-**	11 Jul 1995 Add support for ELF format kernel (Andreas)
-**	16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
-**		    (Andreas)
-**      14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
-**		    start address is KSTART_ADDR + PAGE_SIZE, this
-**		    does not need the ugly kludge with
-**		    -fwritable-strings (++andreas)
-**      09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
-**                  mentions all ST-Ram and the mover is located somewhere
-**                  in the middle of memory (roman)
-**                  Added the default arguments file known from the other
-**                  bootstrap version
-**      19 Feb 1994 Changed everything so that it works? (rdv)
-**      14 Mar 1994 New mini-copy routine used (rdv)
-*/
-
-
-#define BOOTINFO_COMPAT_1_0	/* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-#include "sysvars.h"
-#include <osbind.h>
-#include <sys/types.h>
-#include <sys/file.h>
-
-/* linux specific include files */
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/page.h>
-
-#define _LINUX_TYPES_H		/* Hack to prevent including <linux/types.h> */
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-
-/* Atari bootstrap include file */
-#include "bootstrap.h"
-
-#define MIN_RAMSIZE     (3)	/* 3 MB */
-#define TEMP_STACKSIZE 256
-
-extern char *optarg;
-extern int optind;
-static void get_default_args( int *argc, char ***argv );
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-/* This is missing in <unistd.h> */
-extern int sync (void);
-
-/* Bootinfo */
-static struct atari_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE     (4096)
-static u_long bi_size;
-static union {
-struct bi_record record;
-    u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-u_long *cookiejar;
-u_long userstk;
-
-/* getcookie -- function to get the value of the given cookie. */
-static int getcookie(char *cookie, u_long *value)
-{
-    int i = 0;
-
-    while(cookiejar[i] != 0L) {
-	if(cookiejar[i] == *(u_long *)cookie) {
-	    *value = cookiejar[i + 1];
-	    return 1;
-	}
-	i += 2;
-    }
-    return -1;
-}
-
-static void usage(void)
-{
-    fprintf(stderr, "Usage:\n"
-	    "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
-	    " [option...]\n");
-    exit(EXIT_FAILURE);
-}
-
-/*
- * Copy the kernel and the ramdisk to their final resting places.
- *
- * I assume that the kernel data and the ramdisk reside somewhere
- * in the middle of the memory.
- *
- * This program itself should be somewhere in the first 4096 bytes of memory
- * where the kernel never will be. In this way it can never be overwritten
- * by itself.
- *
- * At this point the registers have:
- * a0: the start of the final kernel
- * a1: the start of the current kernel
- * a2: the end of the final ramdisk
- * a3: the end of the current ramdisk
- * d0: the kernel size
- * d1: the ramdisk size 
- */
-asm ("
-.text
-.globl _copyall, _copyallend
-_copyall:
-
-	movel	a0,a4	    	/* save the start of the kernel for booting */
-
-1:	movel	a1@+,a0@+   	/* copy the kernel starting at the beginning */
-	subql	#4,d0
-	jcc	1b
-
-	tstl	d1
-	beq		3f
-
-2:	movel	a3@-,a2@-   	/* copy the ramdisk starting at the end */
-	subql	#4,d1
-	jcc	2b
-
-3:	jmp	a4@ 	    	/* jump to the start of the kernel */
-_copyallend:
-");
-
-extern char copyall, copyallend;
-
-
-/* Test for a Medusa: This is the only machine on which address 0 is
- * writeable!
- * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
- * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
- * in the range where the Medusa always asserts DTACK.
- * On the Hades address 0 is writeable as well and it asserts DTACK on
- * address 0x00ff82fe. To test if the machine is a Hades, address 0xb0000000
- * is tested. On the Medusa this gives a bus error.
- */
-
-int test_medusa( void )
-
-{	int		rv = 0;
-
-	__asm__ __volatile__
-		( "movel	0x8,a0\n\t"
-		  "movel	sp,a1\n\t"
-		  "moveb	0x0,d1\n\t"
-		  "movel	#Lberr,0x8\n\t"
-		  "moveq	#0,%0\n\t"
-		  "clrb		0x0\n\t"
-		  "nop		\n\t"
-		  "moveb	d1,0x0\n\t"
-		  "nop		\n\t"
-		  "tstb		0x00ff82fe\n\t"
-		  "nop		\n\t"
-		  "moveq	#1,%0\n\t"
-		  "tstb		0xb0000000\n\t"
-		  "nop		\n\t"
-		  "moveq	#0,%0\n"
-		"Lberr:\t"
-		  "movel	a1,sp\n\t"
-		  "movel	a0,0x8"
-		  : "=d" (rv)
-		  : /* no inputs */
-		  : "d1", "a0", "a1", "memory" );
-
-	return( rv );
-}
-
-
-/* Test if FPU instructions are executed in hardware, or if they're
-   emulated in software.  For this, the F-line vector is temporarily
-   replaced. */
-
-int test_software_fpu(void)
-{
-	int rv = 0;
-
-	__asm__ __volatile__
-		( "movel	0x2c,a0\n\t"
-		  "movel	sp,a1\n\t"
-		  "movel	#Lfline,0x2c\n\t"
-		  "moveq	#1,%0\n\t"
-		  "fnop 	\n\t"
-		  "nop		\n\t"
-		  "moveq	#0,%0\n"
-		"Lfline:\t"
-		  "movel	a1,sp\n\t"
-		  "movel	a0,0x2c"
-		  : "=d" (rv)
-		  : /* no inputs */
-		  : "a0", "a1" );
-
-	return rv;
-}
-
-
-void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
-
-{	static u_long	save_addr;
-	u_long			test_base, saved_contents[16];
-#define	TESTADDR(i)	(*((u_long *)((char *)test_base + i*8*MB)))
-#define	TESTPAT		0x12345678
-	unsigned short	oldflags;
-	int				i;
-
-	/* This ensures at least that none of the test addresses conflicts
-	 * with the test code itself */
-	test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000;
-	*bank1 = *bank2 = 0;
-	
-	/* Interrupts must be disabled because arbitrary addresses may be
-	 * temporarily overwritten, even code of an interrupt handler */
-	__asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : );
-	disable_cache();
-	
-	/* save contents of the test addresses */
-	for( i = 0; i < 16; ++i )
-		saved_contents[i] = TESTADDR(i);
-	
-	/* write 0s into all test addresses */
-	for( i = 0; i < 16; ++i )
-		TESTADDR(i) = 0;
-
-	/* test for bank 1 */
-#if 0
-	/* This is Freddi's original test, but it didn't work. */
-	TESTADDR(0) = TESTADDR(1) = TESTPAT;
-	if (TESTADDR(1) == TESTPAT) {
-		if (TESTADDR(2) == TESTPAT)
-			*bank1 = 8*MB;
-		else if (TESTADDR(3) == TESTPAT)
-			*bank1 = 16*MB;
-		else
-			*bank1 = 32*MB;
-	}
-	else {
-		if (TESTADDR(2) == TESTPAT)
-			*bank1 = 0;
-		else
-			*bank1 = 16*MB;
-	}
-#else
-	TESTADDR(0) = TESTPAT;
-	if (TESTADDR(1) == TESTPAT)
-		*bank1 = 8*MB;
-	else if (TESTADDR(2) == TESTPAT)
-		*bank1 = 16*MB;
-	else if (TESTADDR(4) == TESTPAT)
-		*bank1 = 32*MB;
-	else
-		*bank1 = 64*MB;
-#endif
-
-	/* test for bank2 */
-	if (TESTADDR(8) != 0)
-		*bank2 = 0;
-	else {
-		TESTADDR(8) = TESTPAT;
-		if (TESTADDR(9) != 0) {
-			if (TESTADDR(10) == TESTPAT)
-				*bank2 = 8*MB;
-			else
-				*bank2 = 32*MB;
-		}
-		else {
-			TESTADDR(9) = TESTPAT;
-			if (TESTADDR(10) == TESTPAT)
-				*bank2 = 16*MB;
-			else
-				*bank2 = 64*MB;
-		}
-	}
-	
-	/* restore contents of the test addresses and restore interrupt mask */
-	for( i = 0; i < 16; ++i )
-		TESTADDR(i) = saved_contents[i];
-	__asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) );
-}
-
-#undef TESTADDR
-#undef TESTPAT
-
-
-static int check_bootinfo_version(char *memptr)
-{
-    struct bootversion *bv = (struct bootversion *)memptr;
-    unsigned long version = 0;
-    int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
-    printf( "\n" );
-    if (bv->magic == BOOTINFOV_MAGIC) {
-	for( i = 0; bv->machversions[i].machtype != 0; ++i ) {
-	    if (bv->machversions[i].machtype == MACH_ATARI) {
-		version = bv->machversions[i].version;
-		break;
-	    }
-	}
-    }
-    if (!version)
-	printf("Kernel has no bootinfo version info, assuming 0.0\n");
-
-    kernel_major = BI_VERSION_MAJOR(version);
-    kernel_minor = BI_VERSION_MINOR(version);
-    boots_major  = BI_VERSION_MAJOR(ATARI_BOOTI_VERSION);
-    boots_minor  = BI_VERSION_MINOR(ATARI_BOOTI_VERSION);
-    printf("Bootstrap's bootinfo version: %d.%d\n",
-	   boots_major, boots_minor);
-    printf("Kernel's bootinfo version   : %d.%d\n",
-	   kernel_major, kernel_minor);
-    
-    switch (kernel_major) {
-	case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
-	    if (kernel_minor > boots_minor) {
-		printf("Warning: Bootinfo version of bootstrap and kernel "
-		       "differ!\n");
-		printf("         Certain features may not work.\n");
-	    }
-	    break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-	case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
-	    printf("(using backwards compatibility mode)\n");
-	    break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-	default:
-	    printf("\nThis bootstrap is too %s for this kernel!\n",
-		   boots_major < kernel_major ? "old" : "new");
-	    return 0;
-    }
-    return kernel_major;
-}
-
-
-#ifdef USE_BOOTP
-# include "bootp.h"
-#else
-# define ll_read	read
-# define ll_lseek	lseek
-# define ll_close	close
-#endif
-
-#ifdef ZKERNEL
-static int load_zkernel( int fd );
-static int kread( int fd, void *buf, unsigned cnt );
-static int klseek( int fd, int where, int whence );
-static int kclose( int fd );
-#else
-# define kread		read
-# define klseek		lseek
-# define kclose		close
-#endif
-
-/* ++andreas: this must be inline due to Super */
-static inline void boot_exit (int) __attribute__ ((noreturn));
-static inline void boot_exit(int status)
-{
-    /* first go back to user mode */
-    (void)Super(userstk);
-	getchar();
-    exit(status);
-}
-
-int main(int argc, char *argv[])
-{
-    int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
-    int load_to_stram = 0;
-    char *ramdisk_name, *kernel_name, *memptr;
-    u_long ST_ramsize, TT_ramsize, memreq;
-    u_long cpu_type, fpu_type, mch_type, mint;
-    struct exec kexec;
-    int elf_kernel = 0;
-    Elf32_Ehdr kexec_elf;
-    Elf32_Phdr *kernel_phdrs = NULL;
-    u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
-    int prefer_bootp = 1, kname_set = 0, n_knames;
-#ifdef USE_BOOTP
-    int err;
-#endif
-    char kname_list[5][64];
-    void *bi_ptr;
-
-    ramdisk_name = NULL;
-    kernel_name = "vmlinux";
-
-    /* print the startup message */
-    puts("\fLinux/68k Atari Bootstrap version 2.2"
-#ifdef USE_BOOTP
-	 " (with BOOTP)"
-#endif
-	 );
-    puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
-
-	/* ++roman: If no arguments on the command line, read them from
-	 * file */
-	if (argc == 1)
-		get_default_args( &argc, &argv );
-
-    /* machine is Atari */
-    bi.machtype = MACH_ATARI;
-
-    /* check arguments */
-    while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
-	switch (ch) {
-	  case 'd':
-	    debugflag = 1;
-	    break;
-	  case 't':
-	    ignore_ttram = 1;
-	    break;
-	  case 's':
-	    load_to_stram = 1;
-	    break;
-	  case 'k':
-	    kernel_name = optarg;
-	    kname_set = 1;
-	    break;
-	  case 'r':
-	    ramdisk_name = optarg;
-	    break;
-	  case 'b':
-	    prefer_bootp = 0;
-	    break;
-	  case '?':
-	  default:
-	    usage();
-	}
-
-    argc -= optind;
-    argv += optind;
-  
-    /* We have to access some system variables to get
-     * the information we need, so we must switch to
-     * supervisor mode first.
-     */
-    userstk = Super(0L);
-
-    /* get the info we need from the cookie-jar */
-    cookiejar = *_p_cookies;
-    if(cookiejar == 0L) {
-	/* if we find no cookies, it's probably an ST */
-	fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
-	boot_exit(EXIT_FAILURE);
-    }
-
-    /* Exit if MiNT/MultiTOS is running.  */
-    if(getcookie("MiNT", &mint) != -1)
-    {
-	puts("Warning: MiNT is running\n");
-#if 0
-	puts("Linux cannot be started when MiNT is running. Aborting...\n");
-	boot_exit(EXIT_FAILURE);
-#endif
-    }
-
-    /* get _CPU, _FPU and _MCH */
-    getcookie("_CPU", &cpu_type);
-    getcookie("_FPU", &fpu_type);
-    getcookie("_MCH", &mch_type);
-
-    /* check if we are on a 68030/40 with FPU */
-    if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
-    {
-	puts("Machine type currently not supported. Aborting...");
-	boot_exit(EXIT_FAILURE);
-    }
-
-    switch(cpu_type) {
-      case  0:
-      case 10: break;
-      case 20: bi.cputype = CPU_68020; bi.mmutype = MMU_68851; break;
-      case 30: bi.cputype = CPU_68030; bi.mmutype = MMU_68030; break;
-      case 40: bi.cputype = CPU_68040; bi.mmutype = MMU_68040; break;
-      case 60: bi.cputype = CPU_68060; bi.mmutype = MMU_68060; break;
-      default:
-	fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
-	boot_exit(EXIT_FAILURE);
-	break;
-    }
-
-    printf("CPU: %ld; ", cpu_type + 68000);
-    printf("FPU: ");
-
-    /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
-     * some software may set it to wrong values (68882 or the like) */
-	if (cpu_type == 40) {
-		bi.fputype = FPU_68040;
-		puts( "68040\n" );
-	}
-	else if (cpu_type == 60) {
-		bi.fputype = FPU_68060;
-		puts( "68060\n" );
-	}
-	else {
-		switch ((fpu_type >> 16) & 7) {
-		  case 0:
-			puts("not present\n");
-			break;
-		  case 1:
-			puts("SFP004 not supported. Assuming no FPU.");
-			break;
-		  case 2:
-			/* try to determine real type */
-			if (fpu_idle_frame_size () != 0x18)
-				goto m68882;
-			/* fall through */
-		  case 4:
-			bi.fputype = FPU_68881;
-			puts("68881\n");
-			break;
-		  case 6:
-		  m68882:
-			bi.fputype = FPU_68882;
-			puts("68882\n");
-			break;
-		  default:
-			puts("Unknown FPU type. Assuming no FPU.");
-			break;
-		}
-	}
-	/* ++roman: If an FPU was announced in the cookie, test
-	   whether it is a real hardware FPU or a software emulator!  */
-	if (bi.fputype) {
-		if (test_software_fpu()) {
-			bi.fputype = 0;
-			puts("FPU: software emulated. Assuming no FPU.");
-		}
-	}
-
-    /* Get the amounts of ST- and TT-RAM. */
-    /* The size must be a multiple of 1MB. */
-    i = 0;
-	
-    if (!test_medusa()) {
-	struct {
-		unsigned short version;   /* version - currently 1 */
-		unsigned long fr_start; /* start addr FastRAM */
-		unsigned long fr_len;   /* length FastRAM */
-	} *magn_cookie;
-	struct {
-		unsigned long version;
-		unsigned long fr_start; /* start addr */
-		unsigned long fr_len;   /* length */
-	} *fx_cookie;
-
-        TT_ramsize = 0;
-        if (!ignore_ttram) {
-	    /* "Original" or properly emulated TT-Ram */
-	    if (*ramtop) {
-		/* the 'ramtop' variable at 0x05a4 is not
-		 * officially documented. We use it anyway
-		 * because it is the only way to get the TTram size.
-		 * (It is zero if there is no TTram.)
-		 */
-		bi.memory[i].addr = TT_RAM_BASE;
-		bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
-		TT_ramsize = bi.memory[i].size / MB;
-		i++;
-		printf("TT-RAM: %ld Mb; ", TT_ramsize);
-	    }
-
-	    /* test for MAGNUM alternate RAM
-	     * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
-	     */
-	    if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
-		bi.memory[i].addr = magn_cookie->fr_start;
-		bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
-		TT_ramsize += bi.memory[i].size / MB;
-		printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
-		i++;
-	    }
-
-	    /* BlowUps FX */
-	    if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
-		/* if fx is set (cookie call above),
-		 * we assume that BlowUps FX-card
-		 * is installed. (Nat!)
-		 */
-		bi.memory[i].addr = fx_cookie->fr_start;
-		bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
-		printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
-		i++;
-	    }
-	}
-
-        bi.memory[i].addr = 0;
-        bi.memory[i].size = *phystop & ~(MB - 1);
-        ST_ramsize = bi.memory[i].size / MB;
-        i++;
-        printf("ST-RAM: %ld Mb\n", ST_ramsize );
-
-        bi.num_memory = i;
-
-	if (load_to_stram && i > 1) {
-	    /* Put ST-RAM first in the list of mem blocks */
-	    struct mem_info temp = bi.memory[i - 1];
-	    bi.memory[i - 1] = bi.memory[0];
-	    bi.memory[0] = temp;
-	}
-    }
-    else {
-        u_long	bank1, bank2, medusa_st_ram;
-
-        get_medusa_bank_sizes( &bank1, &bank2 );
-	medusa_st_ram = *phystop & ~(MB - 1);
-        bank1 -= medusa_st_ram;
-        TT_ramsize = 0;
-
-        bi.memory[i].addr = 0;
-        bi.memory[i].size = medusa_st_ram;
-        ST_ramsize = bi.memory[i].size / MB;
-        i++;
-        printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );
-
-        if (!ignore_ttram && bank1 > 0) {
-            bi.memory[i].addr = 0x20000000 + medusa_st_ram;
-            bi.memory[i].size = bank1;
-            TT_ramsize += bank1;
-            i++;
-            printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
-        }
-			
-        if (!ignore_ttram && bank2 > 0) {
-            bi.memory[i].addr = 0x24000000;
-            bi.memory[i].size = bank2;
-            TT_ramsize += bank2;
-            i++;
-            printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
-        }
-			
-        bi.num_memory = i;
-        printf("\n");
-    }
-
-    /* verify that there is enough RAM; ST- and TT-RAM combined */
-    if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
-	puts("Not enough RAM. Aborting...");
-	boot_exit(10);
-    }
-
-#if 0	
-    /* Get language/keyboard info */
-    /* TODO: do we need this ? */
-    /* Could be used to auto-select keyboard map later on. (rdv) */
-    if (getcookie("_AKP",&language) == -1)
-    {
-	/* Get the language info from the OS-header */
-	os_header = *_sysbase;
-	os_header = os_header->os_beg;
-	lang = (os_header->os_conf) >> 1;
-	printf("Language: ");
-	switch(lang) {
-	  case HOL: puts("Dutch"); break; /* Own country first :-) */
-	  case USA: puts("American"); break;
-	  case SWG: puts("Switzerland (German)"); break;
-	  case FRG: puts("German"); break;
-	  case FRA: puts("French"); break;
-	  case SWF: puts("Switzerland (French)"); break;
-	  case UK:  puts("English"); break;
-	  case SPA: puts("Spanish"); break;
-	  case ITA: puts("Italian"); break;
-	  case SWE: puts("Swedish"); break;
-	  case TUR: puts("Turkey"); break;
-	  case FIN: puts("Finnish"); break;
-	  case NOR: puts("Norwegian"); break;
-	  case DEN: puts("Danish"); break;
-	  case SAU: puts("Saudi-Arabian"); break;
-	  default:  puts("Unknown"); break;
-	}
-    }
-    else
-    {
-	printf("Language: ");
-	switch(language & 0x0F)
-	{
-	  case 1: printf("German "); break;
-	  case 2: printf("French "); break;
-	  case 4: printf("Spanish "); break;
-	  case 5: printf("Italian "); break;
-	  case 7: printf("Swiss French "); break;
-	  case 8: printf("Swiss German "); break;
-	  default: printf("English ");
-	}
-	printf("Keyboard type :");
-	switch(language >> 8)
-	{
-	  case 1: printf("German "); break;
-	  case 2: printf("French "); break;
-	  case 4: printf("Spanish "); break;
-	  case 5: printf("Italian "); break;
-	  case 7: printf("Swiss French "); break;
-	  case 8: printf("Swiss German "); break;
-	  default: printf("English ");
-	}
-	printf("\n");
-    }
-#endif
-	
-    /* Pass contents of the _MCH cookie to the kernel */
-    bi.mch_cookie = mch_type;
-    
-    /*
-     * Copy command line options into the kernel command line.
-     */
-    i = 0;
-    while (argc--) {
-	if ((i+strlen(*argv)+1) < CL_SIZE) {
-	    i += strlen(*argv) + 1;
-	    if (bi.command_line[0])
-		strcat (bi.command_line, " ");
-	    strcat (bi.command_line, *argv++);
-	}
-    }
-    printf ("Command line is '%s'\n", bi.command_line);
-
-    start_mem = bi.memory[0].addr;
-    mem_size = bi.memory[0].size;
-
-    /* tell us where the kernel will go */
-    printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
-#ifdef TEST
-    /*
-    ** Temporary exit point for testing
-    */
-    boot_exit(-1);
-#endif /* TEST */
-
-    i = 0;
-#ifdef USE_BOOTP
-    if (!kname_set)
-	kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */
-#endif
-#ifdef ZKERNEL
-    strcpy( kname_list[i], kernel_name );
-    strcat( kname_list[i], ".gz" );
-    ++i;
-#endif
-    strcpy( kname_list[i++], kernel_name );
-#ifdef ZKERNEL
-    if (!kname_set)
-	strcpy( kname_list[i++], "vmlinuz" );
-#endif
-    n_knames = i;
-
-    kfd = -1;
-#ifdef USE_BOOTP
-    if (prefer_bootp) {
-	for( i = 0; i < n_knames; ++i ) {
-	    if ((err = get_remote_kernel( kname_list[i] )) >= 0)
-		goto kernel_open;
-	    if (err < -1) /* fatal error; retries don't help... */
-		break;
-	}
-	printf( "\nremote boot failed; trying local kernel\n" );
-    }
-#endif
-    for( i = 0; i < n_knames; ++i ) {
-	if ((kfd = open( kname_list[i], O_RDONLY )) != -1)
-	    goto kernel_open;
-    }
-#ifdef USE_BOOTP
-    if (!prefer_bootp) {
-	printf( "\nlocal kernel failed; trying remote boot\n" );
-	for( i = 0; i < n_knames; ++i ) {
-	    if ((err = get_remote_kernel( kname_list[i] )) >= 0)
-		goto kernel_open;
-	    if (err < -1) /* fatal error; retries don't help... */
-		break;
-	}
-    }
-#endif
-    fprintf( stderr, "Unable to open any kernel file\n(Tried " );
-    for( i = 0; i < n_knames; ++i ) {
-	fprintf( stderr, "%s%s", kname_list[i],
-		 i <  n_knames-2 ? ", " :
-		 i == n_knames-2 ? ", and " :
-		 ")\n" );
-    }
-    boot_exit( EXIT_FAILURE );
-    
-  kernel_open:
-
-    if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
-    {
-	fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
-	boot_exit (EXIT_FAILURE);
-    }
-
-#ifdef ZKERNEL
-    if (((unsigned char *)&kexec)[0] == 037 &&
-	(((unsigned char *)&kexec)[1] == 0213 ||
-	 ((unsigned char *)&kexec)[1] == 0236)) {
-	/* That's a compressed kernel */
-	printf( "Kernel is compressed\n" );
-	if (load_zkernel( kfd )) {
-	    printf( "Decompression error -- aborting\n" );
-	    boot_exit( EXIT_FAILURE );
-	}
-    }
-#endif
-    
-    switch (N_MAGIC(kexec)) {
-    case ZMAGIC:
-	text_offset = N_TXTOFF(kexec);
-	break;
-    case QMAGIC:
-	text_offset = sizeof(kexec);
-	/* the text size includes the exec header; remove this */
-	kexec.a_text -= sizeof(kexec);
-	break;
-    default:
-	/* Try to parse it as an ELF header */
-	klseek (kfd, 0, SEEK_SET);
-	if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
-	    && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
-	  {
-	    elf_kernel = 1;
-	    /* A few plausibility checks */
-	    if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
-		|| kexec_elf.e_version != EV_CURRENT)
-	      {
-		fprintf (stderr, "Invalid ELF header contents in kernel\n");
-		boot_exit (EXIT_FAILURE);
-	      }
-	    /* Load the program headers */
-	    kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
-	    if (kernel_phdrs == NULL)
-	      {
-		fprintf (stderr, "Unable to allocate memory for program headers\n");
-		boot_exit (EXIT_FAILURE);
-	      }
-	    klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
-	    if (kread (kfd, (void *) kernel_phdrs,
-		      kexec_elf.e_phnum * sizeof (*kernel_phdrs))
-		!= kexec_elf.e_phnum * sizeof (*kernel_phdrs))
-	      {
-		fprintf (stderr, "Unable to read program headers from %s\n",
-			 kernel_name);
-		boot_exit (EXIT_FAILURE);
-	      }
-	    break;
-	  }
-	fprintf (stderr, "Wrong magic number %lo in kernel header\n",
-		 N_MAGIC(kexec));
-	boot_exit (EXIT_FAILURE);
-    }
-
-    /* Load the kernel one page after start of mem */
-    start_mem += PAGE_SIZE;
-    mem_size -= PAGE_SIZE;
-    /* Align bss size to multiple of four */
-    if (!elf_kernel)
-      kexec.a_bss = (kexec.a_bss + 3) & ~3;
-
-    /* init ramdisk */
-    if(ramdisk_name) {
-	if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
-	    fprintf(stderr, "Unable to open ramdisk file %s\n",
-		    ramdisk_name);
-	    boot_exit(EXIT_FAILURE);
-	}
-	bi.ramdisk.size = lseek(rfd, 0, SEEK_END);
-    }
-    else
-	bi.ramdisk.size = 0;
- 
-    /* calculate the total required amount of memory */
-    if (elf_kernel)
-      {
-	u_long min_addr = 0xffffffff, max_addr = 0;
-	for (i = 0; i < kexec_elf.e_phnum; i++)
-	  {
-	    if (min_addr > kernel_phdrs[i].p_vaddr)
-	      min_addr = kernel_phdrs[i].p_vaddr;
-	    if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
-	      max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
-	  }
-	/* This is needed for newer linkers that include the header in
-	   the first segment.  */
-	if (min_addr == 0)
-	  {
-	    min_addr = PAGE_SIZE;
-	    kernel_phdrs[0].p_vaddr += PAGE_SIZE;
-	    kernel_phdrs[0].p_offset += PAGE_SIZE;
-	    kernel_phdrs[0].p_filesz -= PAGE_SIZE;
-	    kernel_phdrs[0].p_memsz -= PAGE_SIZE;
-	  }
-	kernel_size = max_addr - min_addr;
-      }
-    else
-      kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
-
-    rd_size = bi.ramdisk.size;
-    if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1)
-      /* If running low on ST ram load ramdisk into alternate ram.  */
-      bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
-    else
-      /* Else hopefully there is enough ST ram. */
-      bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;
-
-    /* create the bootinfo structure */
-    if (!create_bootinfo())
-	boot_exit (EXIT_FAILURE);
-
-    memreq = kernel_size + bi_size;
-#ifdef BOOTINFO_COMPAT_1_0
-    if (sizeof(compat_bootinfo) > bi_size)
-	memreq = kernel_size+sizeof(compat_bootinfo);
-#endif /* BOOTINFO_COMPAT_1_0 */
-    /* align load address of ramdisk image, read() is sloooow on odd addr. */
-    memreq = ((memreq + 3) & ~3) + rd_size;
-	
-    /* allocate RAM for the kernel */
-    if (!(memptr = (char *)Malloc (memreq)))
-    {
-	fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
-	boot_exit (EXIT_FAILURE);
-    }
-    else
-	fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);
-
-    (void)memset(memptr, 0, memreq);
-
-    /* read the text and data segments from the kernel image */
-    if (elf_kernel)
-      {
-	for (i = 0; i < kexec_elf.e_phnum; i++)
-	  {
-	    if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
-	      {
-		fprintf (stderr, "Failed to seek to segment %d\n", i);
-		boot_exit (EXIT_FAILURE);
-	      }
-	    if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
-		      kernel_phdrs[i].p_filesz)
-		!= kernel_phdrs[i].p_filesz)
-	      {
-		fprintf (stderr, "Failed to read segment %d\n", i);
-		boot_exit (EXIT_FAILURE);
-	      }
-	  }
-      }
-    else
-      {
-	if (klseek (kfd, text_offset, SEEK_SET) == -1)
-	{
-	    fprintf (stderr, "Failed to seek to text\n");
-	    Mfree ((void *)memptr);
-	    boot_exit (EXIT_FAILURE);
-	}
-
-	if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
-	{
-	    fprintf (stderr, "Failed to read text\n");
-	    Mfree ((void *)memptr);
-	    boot_exit (EXIT_FAILURE);
-	}
-
-	/* data follows immediately after text */
-	if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
-	{
-	    fprintf (stderr, "Failed to read data\n");
-	    Mfree ((void *)memptr);
-	    boot_exit (EXIT_FAILURE);
-	}
-      }
-    kclose (kfd);
-
-    /* Check kernel's bootinfo version */
-    switch (check_bootinfo_version(memptr)) {
-	case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
-	    bi_ptr = &bi_union.record;
-	    break;
-
-#ifdef BOOTINFO_COMPAT_1_0
-	case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
-	    if (!create_compat_bootinfo()) {
-		Mfree ((void *)memptr);
-		boot_exit (EXIT_FAILURE);
-	    }
-	    bi_ptr = &compat_bootinfo;
-	    bi_size = sizeof(compat_bootinfo);
-	    break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-	default:
-	    Mfree ((void *)memptr);
-	    boot_exit (EXIT_FAILURE);
-    }
-
-    /* copy the boot_info struct to the end of the kernel image */
-    memcpy ((void *)(memptr + kernel_size), bi_ptr, bi_size);
-
-    /* read the ramdisk image */
-    if (rfd != -1)
-    {
-	if (lseek (rfd, 0, SEEK_SET) == -1)
-	{
-	    fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
-	    Mfree ((void *)memptr);
-	    boot_exit (EXIT_FAILURE);
-	}
-	if (read (rfd, memptr + memreq - rd_size,
-		  rd_size) != rd_size)
-	{
-	    fprintf (stderr, "Failed to read ramdisk file\n");
-	    Mfree ((void *)memptr);
-	    boot_exit (EXIT_FAILURE);
-	}
-	close (rfd);
-    }
-
-    /* for those who want to debug */
-    if (debugflag)
-    {
-	if (bi.ramdisk.size)
-	    printf ("RAM disk at %#lx, size is %ld\n",
-		    (u_long)(memptr + memreq - rd_size),
-		    bi.ramdisk.size);
-
-	if (elf_kernel)
-	  {
-	    for (i = 0; i < kexec_elf.e_phnum; i++)
-	      {
-		printf ("Kernel segment %d at %#lx, size %ld\n", i,
-			start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
-			kernel_phdrs[i].p_memsz);
-	      }
-	  }
-	else
-	  {
-	    printf ("\nKernel text at %#lx, code size %d\n",
-		    start_mem, kexec.a_text);
-	    printf ("Kernel data at %#lx, data size %d\n",
-		    start_mem + kexec.a_text, kexec.a_data );
-	    printf ("Kernel bss  at %#lx, bss  size %d\n",
-		    start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
-	  }
-	printf ("\nboot_info is at %#lx\n",
-		start_mem + kernel_size);
-	printf ("\nKernel entry is %#lx\n",
-		elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
-	printf ("ramdisk dest top is %#lx\n", bi.ramdisk.addr + rd_size);
-	printf ("ramdisk lower limit is %#lx\n",
-		(u_long)(memptr + memreq - rd_size));
-	printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));
-
-	printf ("Type a key to continue the Linux boot...");
-	fflush (stdout);
-	getchar();
-    }
-
-    printf("Booting Linux...\n");
-
-    sync ();
-
-    /* turn off interrupts... */
-    disable_interrupts();
-
-    /* turn off caches... */
-    disable_cache();
-
-    /* ..and any MMU translation */
-    disable_mmu();
-
-    /* ++guenther: allow reset if launched with MiNT */
-    *(long*)0x426 = 0;
-
-    /* copy mover code to a safe place if needed */
-    memcpy ((void *) 0x400, &copyall, &copyallend - &copyall);
-
-    /* setup stack */
-    change_stack ((void *) PAGE_SIZE);
-
-    /*
-     * On the Atari you can have two situations:
-     * 1. One piece of contiguous RAM (Falcon)
-     * 2. Two pieces of contiguous RAM (TT)
-     * In case 2 you can load your program into ST-ram and load your data in
-     * any old RAM you have left.
-     * In case 1 you could overwrite your own program when copying the
-     * kernel and ramdisk to their final positions.
-     * To solve this the mover code is copied to a safe place first.
-     * Then this program jumps to the mover code. After the mover code
-     * has finished it jumps to the start of the kernel in its new position.
-     * I thought the memory just after the interrupt vector table was a safe
-     * place because it is used by TOS to store some system variables.
-     * This range goes from 0x400 to approx. 0x5B0.
-     * This is more than enough for the miniscule mover routine (16 bytes).
-     */
-
-    jump_to_mover((char *) start_mem, memptr,
-		  (char *) bi.ramdisk.addr + rd_size, memptr + memreq,
-		  kernel_size + bi_size, rd_size,
-		  (void *) 0x400);
-
-    for (;;);
-    /* NOTREACHED */
-}
-
-
-
-#define	MAXARGS		30
-
-static void get_default_args( int *argc, char ***argv )
-
-{	FILE		*f;
-	static char	*nargv[MAXARGS];
-	char		arg[256], *p;
-	int			c, quote, state;
-
-	if (!(f = fopen( "bootargs", "r" )))
-		return;
-	
-	*argc = 1;
-	if (***argv)
-	  nargv[0] = **argv;
-	else
-	  nargv[0] = "bootstrap";
-	*argv = nargv;
-
-	quote = state = 0;
-	p = arg;
-	while( (c = fgetc(f)) != EOF ) {		
-
-		if (state == 0) {
-			/* outside args, skip whitespace */
-			if (!isspace(c)) {
-				state = 1;
-				p = arg;
-			}
-		}
-		
-		if (state) {
-			/* inside an arg: copy it into 'arg', obeying quoting */
-			if (!quote && (c == '\'' || c == '"'))
-				quote = c;
-			else if (quote && c == quote)
-				quote = 0;
-			else if (!quote && isspace(c)) {
-				/* end of this arg */
-				*p = 0;
-				nargv[(*argc)++] = strdup(arg);
-				state = 0;
-			}
-			else
-				*p++ = c;
-		}
-	}
-	if (state) {
-		/* last arg finished by EOF! */
-		*p = 0;
-		nargv[(*argc)++] = strdup(arg);
-	}
-	fclose( f );
-	
-	nargv[*argc] = 0;
-}    
-
-
-    /*
-     *  Create the Bootinfo Structure
-     */
-
-static int create_bootinfo(void)
-{
-    int i;
-    struct bi_record *record;
-
-    /* Initialization */
-    bi_size = 0;
-
-    /* Generic tags */
-    if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
-	return(0);
-    if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
-	return(0);
-    if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
-	return(0);
-    if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
-	return(0);
-    for (i = 0; i < bi.num_memory; i++)
-	if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
-	    return(0);
-    if (bi.ramdisk.size)
-	if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
-	    return(0);
-    if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
-	return(0);
-
-    /* Atari tags */
-    if (!add_bi_record(BI_ATARI_MCH_COOKIE, sizeof(bi.mch_cookie),
-		       &bi.mch_cookie))
-	return(0);
-
-    /* Trailer */
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = BI_LAST;
-    bi_size += sizeof(bi_union.record.tag);
-
-    return(1);
-}
-
-
-    /*
-     *  Add a Record to the Bootinfo Structure
-     */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
-    struct bi_record *record;
-    u_short size2;
-
-    size2 = (sizeof(struct bi_record)+size+3)&-4;
-    if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
-	fprintf (stderr, "Can't add bootinfo record. Ask a wizard to enlarge me.\n");
-	return(0);
-    }
-    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
-    record->tag = tag;
-    record->size = size2;
-    memcpy(record->data, data, size);
-    bi_size += size2;
-    return(1);
-}
-
-
-    /*
-     *  Add a String Record to the Bootinfo Structure
-     */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
-    return add_bi_record(tag, strlen(s)+1, (void *)s);
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
-    /*
-     *  Create the Bootinfo structure for backwards compatibility mode
-     */
-
-static int create_compat_bootinfo(void)
-{
-    u_int i;
-
-    compat_bootinfo.machtype = bi.machtype;
-    if (bi.cputype & CPU_68020)
-	compat_bootinfo.cputype = COMPAT_CPU_68020;
-    else if (bi.cputype & CPU_68030)
-	compat_bootinfo.cputype = COMPAT_CPU_68030;
-    else if (bi.cputype & CPU_68040)
-	compat_bootinfo.cputype = COMPAT_CPU_68040;
-    else if (bi.cputype & CPU_68060)
-	compat_bootinfo.cputype = COMPAT_CPU_68060;
-    else {
-	printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
-	return(0);
-    }
-    if (bi.fputype & FPU_68881)
-	compat_bootinfo.cputype |= COMPAT_FPU_68881;
-    else if (bi.fputype & FPU_68882)
-	compat_bootinfo.cputype |= COMPAT_FPU_68882;
-    else if (bi.fputype & FPU_68040)
-	compat_bootinfo.cputype |= COMPAT_FPU_68040;
-    else if (bi.fputype & FPU_68060)
-	compat_bootinfo.cputype |= COMPAT_FPU_68060;
-    else {
-	printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
-	return(0);
-    }
-    compat_bootinfo.num_memory = bi.num_memory;
-    if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
-	printf("Warning: using only %d blocks of memory\n",
-	       COMPAT_NUM_MEMINFO);
-	compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
-    }
-    for (i = 0; i < compat_bootinfo.num_memory; i++) {
-	compat_bootinfo.memory[i].addr = bi.memory[i].addr;
-	compat_bootinfo.memory[i].size = bi.memory[i].size;
-    }
-    if (bi.ramdisk.size) {
-	compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
-	compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
-    } else {
-	compat_bootinfo.ramdisk_size = 0;
-	compat_bootinfo.ramdisk_addr = 0;
-    }
-    strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
-    compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
-    compat_bootinfo.bi_atari.hw_present = 0;
-    compat_bootinfo.bi_atari.mch_cookie = bi.mch_cookie;
-    return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-#ifdef ZKERNEL
-
-#define	ZFILE_CHUNK_BITS	16  /* chunk is 64 KB */
-#define	ZFILE_CHUNK_SIZE	(1 << ZFILE_CHUNK_BITS)
-#define	ZFILE_CHUNK_MASK	(ZFILE_CHUNK_SIZE-1)
-#define	ZFILE_N_CHUNKS		(2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0;	     /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-
-#define memzero(s, n)     memset ((s), 0, (n))
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000    /* window size--must be a power of two, and */
-			/*  at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0;  /* valid bytes in inbuf */
-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;  /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-		
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int  fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#include "../../../../lib/inflate.c"
-
-static void gzip_mark( void **ptr )
-{
-}
-
-static void gzip_release( void **ptr )
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf( void )
-{
-    if (exit_code)
-	return -1;
-
-    insize = ll_read( Zinfd, inbuf, INBUFSIZ );
-    if (insize <= 0)
-	return -1;
-
-    inptr = 1;
-    return( inbuf[0] );
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window( void )
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, ch;
-    int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
-    if (chunk >= ZFILE_N_CHUNKS) {
-	fprintf( stderr, "compressed image too large! Aborting.\n" );
-	boot_exit( EXIT_FAILURE );
-    }
-    if (!ZFile[chunk]) {
-	if (!(ZFile[chunk] = (char *)Malloc( ZFILE_CHUNK_SIZE ))) {
-	    fprintf( stderr, "Out of memory for decompresing kernel image\n" );
-	    boot_exit( EXIT_FAILURE );
-	}
-    }
-    memcpy( ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt );
-    Zwpos += outcnt;
-    
-#define	DISPLAY_BITS 13
-    if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) {
-	printf( "." );
-	fflush( stdout );
-    }
-    
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-	    ch = *in++;
-	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void error( char *x )
-{
-    fprintf( stderr, "\n%s", x);
-    exit_code = 1;
-}
-
-static int load_zkernel( int fd )
-{
-    int i, err;
-    
-    for( i = 0; i < ZFILE_N_CHUNKS; ++i )
-	ZFile[i] = NULL;
-    Zinfd = fd;
-    ll_lseek( fd, 0, SEEK_SET );
-    
-    if (!(inbuf = (uch *)Malloc( INBUFSIZ ))) {
-	fprintf( stderr, "Couldn't allocate gunzip buffer\n" );
-	boot_exit( EXIT_FAILURE );
-    }
-    if (!(window = (uch *)Malloc( WSIZE ))) {
-	fprintf( stderr, "Couldn't allocate gunzip window\n" );
-	boot_exit( EXIT_FAILURE );
-    }
-
-    printf( "Uncompressing kernel image " );
-    fflush( stdout );
-    makecrc();
-    if (!(err = gunzip()))
-	printf( "done\n" );
-    ZFileSize = Zwpos;
-    ll_close( Zinfd ); /* input file not needed anymore */
-    
-    Mfree( inbuf );
-    Mfree( window );
-    return( err );
-}
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. Same considerations apply to the TFTP file buffers. (Roman)
- */
-
-static int kread( int fd, void *buf, unsigned cnt )
-{
-    unsigned done = 0;
-	
-    if (!ZFileSize)
-	return( ll_read( fd, buf, cnt ) );
-    
-    if (ZFpos + cnt > ZFileSize)
-	cnt = ZFileSize - ZFpos;
-    
-    while( cnt > 0 ) {
-	unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
-	unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
-	unsigned n = cnt;
-
-	if (ZFpos + n > endchunk)
-	    n = endchunk - ZFpos;
-	memcpy( buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n );
-	cnt -= n;
-	buf += n;
-	done += n;
-	ZFpos += n;
-
-	if (ZFpos == endchunk) {
-	    Mfree( ZFile[chunk] );
-	    ZFile[chunk] = NULL;
-	}
-    }
-
-    return( done );
-}
-
-
-static int klseek( int fd, int where, int whence )
-{
-    unsigned oldpos, oldchunk, newchunk;
-
-    if (!ZFileSize)
-	return( ll_lseek( fd, where, whence ) );
-
-    oldpos = ZFpos;
-    switch( whence ) {
-      case SEEK_SET:
-	ZFpos = where;
-	break;
-      case SEEK_CUR:
-	ZFpos += where;
-	break;
-      case SEEK_END:
-	ZFpos = ZFileSize + where;
-	break;
-      default:
-	return( -1 );
-    }
-    if (ZFpos < 0) {
-	ZFpos = 0;
-	return( -1 );
-    }
-    else if (ZFpos > ZFileSize) {
-	ZFpos = ZFileSize;
-	return( -1 );
-    }
-
-    /* free memory of skipped-over data */
-    oldchunk = oldpos >> ZFILE_CHUNK_BITS;
-    newchunk = ZFpos  >> ZFILE_CHUNK_BITS;
-    while( oldchunk < newchunk ) {
-	if (ZFile[oldchunk]) {
-	    Mfree( ZFile[oldchunk] );
-	    ZFile[oldchunk] = NULL;
-	}
-	++oldchunk;
-    }
-    
-    return( ZFpos );
-}
-
-
-static void free_zfile( void )
-{
-    int i;
-
-    for( i = 0; i < ZFILE_N_CHUNKS; ++i )
-	if (ZFile[i]) Mfree( ZFile[i] );
-}
-
-static int kclose( int fd )
-{
-    if (ZFileSize) {
-	free_zfile();
-	return( 0 );
-    }
-    else
-	return( ll_close( fd ) );
-}
-
-
-
-#endif /* ZKERNEL */
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/bootstrap.h linux/arch/m68k/boot/atari/bootstrap.h
--- v2.1.47/linux/arch/m68k/boot/atari/bootstrap.h	Fri Dec 20 01:19:58 1996
+++ linux/arch/m68k/boot/atari/bootstrap.h	Wed Dec 31 16:00:00 1969
@@ -1,171 +0,0 @@
-/*
-** bootstrap.h -- This file is a part of the Atari bootloader.
-**
-** Copyright 1993 by Arjan Knor
-**
-** Modified by Andreas Schwab
-**     - clear transparent translation registers
-** Modified 18-Aug-96 by Geert Uytterhoeven
-**     - Updated for the new boot information structure (untested!)
-** Modified 1996-11-12 by Andreas Schwab
-**     - Fixed and tested previous change
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#ifndef BOOTSTRAP_H
-#define BOOTSTRAP_H
-
-     /*
-     *  Atari Bootinfo Definitions
-     *
-     *  All limits herein are `soft' limits, i.e. they don't put constraints
-     *  on the actual parameters in the kernel.
-     */
-
-struct atari_bootinfo {
-    unsigned long machtype;		    /* machine type */
-    unsigned long cputype;		    /* system CPU */
-    unsigned long fputype;		    /* system FPU */
-    unsigned long mmutype;		    /* system MMU */
-    int num_memory;			    /* # of memory blocks found */
-    struct mem_info memory[NUM_MEMINFO];    /* memory description */
-    struct mem_info ramdisk;		    /* ramdisk description */
-    char command_line[CL_SIZE];		    /* kernel command line parameters */
-    unsigned long mch_cookie;		    /* _MCH cookie from TOS */
-};
-
-
-/* _MCH cookie values */
-#define MACH_ST  0
-#define MACH_STE 1
-#define MACH_TT  2
-#define MACH_FALCON 3
-
-/* some constants for memory handling */
-#define ST_RAM 0
-#define TT_RAM 1
-#define TT_RAM_BASE  (u_long)(0x01000000)
-#define MB           (1024 * 1024)
-#define START_MEM    (bi.memory[0].addr)
-#define MEM_SIZE     (bi.memory[0].size)
-
-/* the various CPU- and FPU-types */
-#define AFF_68000 (1)
-#define AFF_68020 (2)
-#define AFF_68030 (4)
-#define AFF_68040 (8)
-#define AFF_68881 (16)
-#define AFF_68882 (32)
-
-/* the possible OS-languages */
-#define USA 0
-#define FRG 1
-#define FRA 2
-#define UK  3
-#define SPA 4
-#define ITA 5
-#define SWE 6
-#define SWF 7
-#define SWG 8
-#define TUR 9
-#define FIN 10
-#define NOR 11
-#define DEN 12
-#define SAU 13
-#define HOL 14
-
-/* some inline functions */
-
-static __inline int fpu_idle_frame_size (void)
-{
-  char fpu_frame[216];
-  __asm__ __volatile__ ("fnop"::);
-  __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame));
-  return fpu_frame[1];
-}
-
-static __inline void change_stack (u_long *stackp)
-{
-    __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
-}
-
-static __inline void disable_interrupts (void)
-{
-  __asm__ volatile ("orw #0x700,sr":);
-}
-
-extern struct atari_bootinfo bi;
-static __inline void disable_cache (void)
-{
-    __asm__ volatile ("movec %0,cacr" :: "d" (0));
-    if (bi.cputype & CPU_68060) {
-	/* '060: clear branch cache after disabling it;
-	 * disable superscalar operation (and enable FPU) */
-	__asm__ volatile ("movec %0,cacr" :: "d" (0x00400000));
-	__asm__ volatile ("moveq #0,d0;"
-			  ".long 0x4e7b0808"	/* movec d0,pcr */
-			  : /* no outputs */
-			  : /* no inputs */
-			  : "d0");
-    }
-}
-
-static __inline void disable_mmu (void)
-{
-	if (bi.cputype & (CPU_68040|CPU_68060)) {
-	    __asm__ volatile ("moveq #0,d0;"
-						  ".long 0x4e7b0003;"	/* movec d0,tc */
-						  ".long 0x4e7b0004;"	/* movec d0,itt0 */
-						  ".long 0x4e7b0005;"	/* movec d0,itt1 */
-						  ".long 0x4e7b0006;"	/* movec d0,dtt0 */
-						  ".long 0x4e7b0007"	/* movec d0,dtt1 */
-						  : /* no outputs */
-						  : /* no inputs */
-						  : "d0");
-	}
-	else {
-		__asm__ volatile ("subl  #4,sp\n\t"
-						  "pmove tc,sp@\n\t"
-						  "bclr  #7,sp@\n\t"
-						  "pmove sp@,tc\n\t"
-						  "addl  #4,sp");
-		if (bi.cputype & CPU_68030) {
-			__asm__ volatile ("clrl sp@-\n\t"
-							  ".long 0xf0170800\n\t" /* pmove sp@,tt0 */
-							  ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */
-							  "addl  #4,sp\n");
-		}
-	}
-}
-
-static __inline void jump_to_mover (void *, void *, void *, void *, int, int,
-				    void *) __attribute__ ((noreturn));
-static __inline void jump_to_mover (void *kernel_start, void *mem_start,
-				    void *ramdisk_end, void *mem_end,
-				    int kernel_size, int ramdisk_size,
-				    void *mover_addr)
-{
-    asm volatile ("movel %0,a0\n\t"
-		  "movel %1,a1\n\t"
-		  "movel %2,a2\n\t"
-		  "movel %3,a3\n\t"
-		  "movel %4,d0\n\t"
-		  "movel %5,d1\n\t"
-		  "jmp   %6@\n"
-		  : /* no outputs */
-		  : "g" (kernel_start), "g" (mem_start),
-		    "g" (ramdisk_end), "g" (mem_end),
-		    "g" (kernel_size), "g" (ramdisk_size),
-		    "a" (mover_addr)
-		  : "a0", "a1", "a2", "a3", "d0", "d1");
-
-	/* Avoid warning that function may return */
-	for (;;) ;
-}
-
-#endif /* BOOTSTRAP_H */
-
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/ethlance.c linux/arch/m68k/boot/atari/ethlance.c
--- v2.1.47/linux/arch/m68k/boot/atari/ethlance.c	Wed Sep 25 00:47:39 1996
+++ linux/arch/m68k/boot/atari/ethlance.c	Wed Dec 31 16:00:00 1969
@@ -1,435 +0,0 @@
-
-#include <stdio.h>
-#include <string.h>
-
-#include "bootp.h"
-#include "ethlance.h"
-
-
-struct {
-	volatile unsigned short	*memaddr;
-	volatile unsigned short	*ioaddr;
-} lance_addr_list[] = {
-	{ (void *)0xfe010000, (void *)0xfe00fff0 },	/* RieblCard VME in TT */
-	{ (void *)0xfec10000, (void *)0xfec0fff0 },	/* RieblCard VME in MegaSTE
-												   (highest byte stripped) */
-	{ (void *)0xfee00000, (void *)0xfeff7000 },	/* RieblCard in ST
-												   (highest byte stripped) */
-	{ (void *)0xfecf0000, (void *)0xfecffff0 },	/* PAMCard VME in TT and MSTE
-												   (highest byte stripped) */
-};
-
-#define	N_LANCE_ADDR	(sizeof(lance_addr_list)/sizeof(*lance_addr_list))
-
-#define TX_RING_SIZE			1
-#define TX_RING_LEN_BITS		0
-
-#define RX_RING_SIZE			16
-#define RX_RING_LEN_BITS		(4 << 5)
-
-#define	offsetof(type,elt)	((unsigned long)(&(((type *)0)->elt)))
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance_rx_head {
-	unsigned short			base;		/* Low word of base addr */
-	volatile unsigned char	flag;
-	unsigned char			base_hi;	/* High word of base addr (unused) */
-	short					buf_length;	/* This length is 2s complement! */
-	short					msg_length;	/* This length is "normal". */
-};
-
-struct lance_tx_head {
-	unsigned short			base;		/* Low word of base addr */
-	volatile unsigned char	flag;
-	unsigned char			base_hi;	/* High word of base addr (unused) */
-	short					length;		/* Length is 2s complement! */
-	volatile short			misc;
-};
-
-struct ringdesc {
-	unsigned short	adr_lo;		/* Low 16 bits of address */
-	unsigned char	len;		/* Length bits */
-	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
-};
-
-struct lance_packet {
-	volatile unsigned char	data[PKTLEN];
-};
-
-/* The LANCE initialization block, described in databook. */
-struct lance_init_block {
-	unsigned short	mode;		/* Pre-set mode */
-	unsigned char	hwaddr[6];	/* Physical ethernet address */
-	unsigned		filter[2];	/* Multicast filter (unused). */
-	/* Receive and transmit ring base, along with length bits. */
-	struct ringdesc	rx_ring;
-	struct ringdesc	tx_ring;
-};
-
-/* The whole layout of the Lance shared memory */
-struct lance_memory {
-	struct lance_init_block	init;
-	struct lance_tx_head	tx_head[TX_RING_SIZE];
-	struct lance_rx_head	rx_head[RX_RING_SIZE];
-	struct lance_packet		tx_packet[TX_RING_SIZE];
-	struct lance_packet		rx_packet[TX_RING_SIZE];
-};
-
-#define RIEBL_MAGIC			0x09051990
-#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
-#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
-#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
-
-struct lance_ioreg {
-/* base+0x0 */	volatile unsigned short	data;
-/* base+0x2 */	volatile unsigned short	addr;
-				unsigned char			_dummy1[3];
-/* base+0x7 */	volatile unsigned char	ivec;
-				unsigned char			_dummy2[5];
-/* base+0xd */	volatile unsigned char	eeprom;
-				unsigned char			_dummy3;
-/* base+0xf */	volatile unsigned char	mem;
-};
-
-enum lance_type {
-	OLD_RIEBL,		/* old Riebl card without battery */
-	NEW_RIEBL,		/* new Riebl card with battery */
-	PAM_CARD		/* PAM card with EEPROM */
-} CardType;
-
-HWADDR	dev_addr;
-
-/* This is a default address for the old RieblCards without a battery
- * that have no ethernet address at boot time. 00:00:36:04 is the
- * prefix for Riebl cards, the 00:00 at the end is arbitrary.
- */
-
-HWADDR OldRieblDefHwaddr = {
-	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
-};
-
-struct lance_ioreg	*IO;
-struct lance_memory	*MEM;
-
-#define	DREG	IO->data
-#define	AREG	IO->addr
-#define	REGA(a)	( AREG = (a), DREG )
-
-int CurRx;
-
-
-/* Definitions for the Lance */
-
-/* tx_head flags */
-#define	TMD1_ENP		0x01
-#define TMD1_STP		0x02
-#define	TMD1_DEF		0x04
-#define TMD1_ONE		0x08
-#define	TMD1_MORE		0x10
-#define	TMD1_ERR		0x40
-#define TMD1_OWN 		0x80
-
-#define TMD1_OWN_CHIP	TMD1_OWN
-#define TMD1_OWN_HOST	0
-
-/* tx_head misc field */
-#define TMD3_TDR		0x03FF
-#define TMD3_RTRY		0x0400
-#define TMD3_LCAR		0x0800
-#define TMD3_LCOL		0x1000
-#define TMD3_UFLO		0x4000
-#define TMD3_BUFF3		0x8000
-
-/* rx_head flags */
-#define	RMD1_ENP		0x01
-#define RMD1_STP		0x02
-#define RMD1_BUFF		0x04
-#define RMD1_CRC		0x08
-#define RMD1_OFLO		0x10
-#define RMD1_FRAM		0x20
-#define	RMD1_ERR		0x40
-#define RMD1_OWN 		0x80
-
-#define RMD1_OWN_CHIP	RMD1_OWN
-#define RMD1_OWN_HOST	0
-
-/* register names */
-#define CSR0	0
-#define CSR1	1
-#define CSR2	2
-#define CSR3	3
-
-/* CSR0 */
-#define CSR0_INIT	0x0001		/* initialize */
-#define CSR0_STRT	0x0002		/* start */
-#define CSR0_STOP	0x0004		/* stop */
-#define CSR0_TDMD	0x0008		/* transmit demand */
-#define CSR0_TXON	0x0010		/* transmitter on */
-#define CSR0_RXON	0x0020		/* receiver on */
-#define CSR0_INEA	0x0040		/* interrupt enable */
-#define CSR0_INTR	0x0080		/* interrupt active */
-#define CSR0_IDON	0x0100		/* initialization done */
-#define CSR0_TINT	0x0200		/* transmitter interrupt */
-#define CSR0_RINT	0x0400		/* receiver interrupt */
-#define CSR0_MERR	0x0800		/* memory error */
-#define CSR0_MISS	0x1000		/* missed frame */
-#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) */
-#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits */
-#define CSR0_ERR	0x8000		/* error */
-
-/* CSR3 */
-#define CSR3_BCON	0x0001
-#define CSR3_ACON	0x0002
-#define CSR3_BSWP	0x0004
-
-
-#define	HZ	200
-#define	_hz_200	(*(volatile unsigned long *)0x4ba)
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static int lance_probe( void );
-static int addr_readable( volatile void *regp, int wordflag );
-static int lance_init( void );
-static void lance_get_hwaddr( HWADDR *addr );
-static int lance_snd( Packet *pkt, int len );
-static int lance_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-ETHIF_SWITCH LanceSwitch = {
-	lance_probe, lance_init, lance_get_hwaddr, 
-	lance_snd, lance_rcv
-};
-
-
-static int lance_probe( void )
-
-{	int		i;
-	
-	for( i = 0; i < N_LANCE_ADDR; ++i ) {
-		if (addr_readable( lance_addr_list[i].memaddr, 1 ) &&
-			(lance_addr_list[i].memaddr[0] = 1,
-			 lance_addr_list[i].memaddr[0] == 1) &&
-			(lance_addr_list[i].memaddr[0] = 0,
-			 lance_addr_list[i].memaddr[0] == 0) &&
-			addr_readable( lance_addr_list[i].ioaddr, 1 )) {
-			break;
-		}
-	}
-	if (i == N_LANCE_ADDR) return( -1 );
-
-	IO = (struct lance_ioreg *)lance_addr_list[i].ioaddr;
-	MEM = (struct lance_memory *)lance_addr_list[i].memaddr;
-	REGA( CSR0 ) = CSR0_STOP;
-
-	return( 0 );
-}
-
-
-static int addr_readable( volatile void *regp, int wordflag )
-
-{	int		ret;
-	long	*vbr, save_berr;
-
-	__asm__ __volatile__ ( "movec	%/vbr,%0" : "=r" (vbr) : );
-	save_berr = vbr[2];
-	
-	__asm__ __volatile__
-	(	"movel	%/sp,%/d1\n\t"
-		"movel	#Lberr,%2@\n\t"
-		"moveq	#0,%0\n\t"
-		"tstl   %3\n\t"
-		"bne	1f\n\t"
-		"tstb	%1@\n\t"
-		"bra	2f\n"
-"1:		 tstw	%1@\n"
-"2:		 moveq	#1,%0\n"
-"Lberr:	 movel	%/d1,%/sp"
-		: "=&d" (ret)
-		: "a" (regp), "a" (&vbr[2]), "rm" (wordflag)
-		: "d1", "memory"
-	);
-
-	vbr[2] = save_berr;
-	
-	return( ret );
-}
-
-
-static int lance_init( void )
-
-{	int		i;
-	
-	/* Now test for type: If the eeprom I/O port is readable, it is a
-	 * PAM card */
-	if (addr_readable( &(IO->eeprom), 0 )) {
-		/* Switch back to Ram */
-		i = IO->mem;
-		CardType = PAM_CARD;
-	}
-	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
-		CardType = NEW_RIEBL;
-	}
-	else
-		CardType = OLD_RIEBL;
-		
-	/* Get the ethernet address */
-	switch( CardType ) {
-	  case OLD_RIEBL:
-		/* No ethernet address! (Set some default address) */
-		memcpy( dev_addr, OldRieblDefHwaddr, ETHADDRLEN );
-		break;
-	  case NEW_RIEBL:
-		memcpy( dev_addr, RIEBL_HWADDR_ADDR, ETHADDRLEN );
-		break;
-	  case PAM_CARD:
-		i = IO->eeprom;
-		for( i = 0; i < ETHADDRLEN; ++i )
-			dev_addr[i] = 
-				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
-				((((unsigned short *)MEM)[i*2+1] & 0x0f));
-		i = IO->mem;
-		break;
-	}
-
-	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
-	for( i = 0; i < ETHADDRLEN; i++ )
-		MEM->init.hwaddr[i] = dev_addr[i^1]; /* <- 16 bit swap! */
-	MEM->init.filter[0] = 0x00000000;
-	MEM->init.filter[1] = 0x00000000;
-	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
-	MEM->init.rx_ring.adr_hi = 0;
-	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
-	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
-	MEM->init.tx_ring.adr_hi = 0;
-	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
-	
-	REGA( CSR3 ) = CSR3_BSWP | (CardType == PAM_CARD ? CSR3_ACON : 0); 
-	REGA( CSR2 ) = 0;
-	REGA( CSR1 ) = 0;
-	REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
-
-	i = 1000000;
-	while( i-- > 0 )
-		if (DREG & CSR0_IDON)
-			break;
-	if (i < 0 || (DREG & CSR0_ERR)) {
-		DREG = CSR0_STOP;
-		return( -1 );
-	}
-	DREG = CSR0_IDON;
-
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		MEM->tx_head[i].base = offsetof( struct lance_memory, tx_packet[i] );
-		MEM->tx_head[i].flag = TMD1_OWN_HOST;
- 		MEM->tx_head[i].base_hi = 0;
-		MEM->tx_head[i].length = 0;
-		MEM->tx_head[i].misc = 0;
-	}
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		MEM->rx_head[i].base = offsetof( struct lance_memory, rx_packet[i] );
-		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
-		MEM->rx_head[i].base_hi = 0;
-		MEM->rx_head[i].buf_length = -PKTLEN;
-		MEM->rx_head[i].msg_length = 0;
-	}
-	CurRx = 0;
-	
-	return( 0 );
-}
-
-
-static void lance_get_hwaddr( HWADDR *addr )
-
-{
-	memcpy( addr, dev_addr, ETHADDRLEN );
-}
-
-
-static int lance_snd( Packet *pkt, int len )
-
-{	unsigned long timeout;
-	
-	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
-	len = (len < 60) ? 60 : len;
-	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
-	if (CardType == PAM_CARD && (len & 1))
-		++len;
-
-	MEM->tx_head[0].length = -len;
-	MEM->tx_head[0].misc = 0;
-	memcpy( (void *)&MEM->tx_packet[0].data, pkt, len );
-	MEM->tx_head[0].base = offsetof(struct lance_memory, tx_packet[0]);
-	MEM->tx_head[0].base_hi = 0;
-	MEM->tx_head[0].flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
-
-	/* Trigger an immediate send poll. */
-	REGA( CSR0 ) = CSR0_TDMD;
-
-	/* Wait for packet being sent */
-	timeout = _hz_200 + 3*HZ;
-	while( (MEM->tx_head[0].flag & TMD1_OWN_CHIP) &&
-		   !MEM->tx_head[0].misc &&
-		   _hz_200 < timeout )
-		;
-
-	if ((MEM->tx_head[0].flag & TMD1_OWN) == TMD1_OWN_HOST &&
-		!(MEM->tx_head[0].misc & TMD1_ERR))
-		/* sent ok */
-		return( 0 );
-
-	/* failure */
-	if (_hz_200 >= timeout)
-		return( ETIMEO );
-	if (MEM->tx_head[0].misc & TMD3_UFLO) {
-		/* On FIFO errors, must re-turn on TX! */
-		DREG = CSR0_STRT;
-	}
-
-	return( ESEND );
-}
-
-
-static int lance_rcv( Packet *pkt, int *len )
-
-{	unsigned long	timeout;
-	int				stat;
-	
-	/* Wait for a packet */
-	timeout = _hz_200 + 4*HZ;
-	while( (MEM->rx_head[CurRx].flag & TMD1_OWN_CHIP) &&
-		   _hz_200 < timeout )
-		;
-	/* Not ours -> was a timeout */
-	if (((stat = MEM->rx_head[CurRx].flag) & TMD1_OWN) == TMD1_OWN_CHIP)
-		return( ETIMEO );
-
-	/* Check for errors */
-	if (stat != (RMD1_ENP|RMD1_STP)) {
-		MEM->rx_head[CurRx].flag &= (RMD1_ENP|RMD1_STP);
-		if (stat & RMD1_FRAM) return( EFRAM );
-		if (stat & RMD1_OFLO) return( EOVERFL );
-		if (stat & RMD1_CRC)  return( ECRC );
-		return( ERCV );
-	}
-
-	/* Get the packet */
-	*len = MEM->rx_head[CurRx].msg_length & 0xfff;
-	memcpy( pkt, (void *)&MEM->rx_packet[CurRx].data, *len );
-
-	/* Give the buffer back to the chip */
-	MEM->rx_head[CurRx].buf_length = -PKTLEN;
-	MEM->rx_head[CurRx].flag |= RMD1_OWN_CHIP;
-	CurRx = (CurRx + 1) % RX_RING_SIZE;
-
-	return( 0 );
-}
-
-
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/ethlance.h linux/arch/m68k/boot/atari/ethlance.h
--- v2.1.47/linux/arch/m68k/boot/atari/ethlance.h	Wed Sep 25 00:47:39 1996
+++ linux/arch/m68k/boot/atari/ethlance.h	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-
-#ifndef _ethlance_h
-#define _ethlance_h
-
-extern ETHIF_SWITCH LanceSwitch;
-
-#endif /* _ethlance_h */
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/boot/atari/sysvars.h linux/arch/m68k/boot/atari/sysvars.h
--- v2.1.47/linux/arch/m68k/boot/atari/sysvars.h	Wed Dec 27 12:44:47 1995
+++ linux/arch/m68k/boot/atari/sysvars.h	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-typedef struct _osheader
-{
-  unsigned short os_entry;
-  unsigned short os_version;
-  void *reseth;
-  struct _osheader *os_beg;
-  void *os_end;
-  long os_rsv1;
-  void *os_magic;
-  long os_date;
-  unsigned short os_conf;
-  unsigned short os_dosdate;
-  char **p_root;
-  unsigned char **pkbshift;
-  void **p_run;
-  char *p_rsv2;
-} OSHEADER;
-
-#define phystop    ((unsigned long *)0x42e)
-#define _sysbase   ((OSHEADER **)0x4f2)
-#define _p_cookies ((unsigned long **)0x5a0)
-#define ramtop     ((unsigned long *)0x5a4)
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.1.47/linux/arch/m68k/config.in	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/config.in	Thu Jul 31 13:09:16 1997
@@ -218,6 +218,10 @@
 define_bool CONFIG_VT_CONSOLE y
 define_bool CONFIG_FB_CONSOLE y
 
+if [ "$CONFIG_ATARI" = "y" ]; then
+  define_bool CONFIG_NVRAM y
+fi
+
 tristate 'Parallel printer support' CONFIG_PRINTER
 if [ "$CONFIG_AMIGA" = "y" ]; then
   dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
@@ -243,6 +247,7 @@
   dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
 fi
 if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
      "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v2.1.47/linux/arch/m68k/defconfig	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/defconfig	Thu Jul 31 13:09:16 1997
@@ -152,9 +152,6 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=y
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=y
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- v2.1.47/linux/arch/m68k/ifpsp060/iskeleton.S	Thu Jun 26 12:33:36 1997
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Thu Jul 31 13:09:16 1997
@@ -37,6 +37,7 @@
 #include <linux/linkage.h>
 #include <asm/entry.h>
 
+
 |################################
 | (1) EXAMPLE CALL-OUTS 	#
 |				#
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c
--- v2.1.47/linux/arch/m68k/kernel/console.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/kernel/console.c	Thu Jul 31 13:09:16 1997
@@ -420,7 +420,10 @@
 	set_scrmem(fg_console, 0);
 	set_origin(fg_console);
 #endif /* XXX */
-	update_screen(fg_console);
+	/* don't update in graphics mode */
+	if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+	    update_screen(fg_console);
+
 	set_cursor(fg_console);
 
 	return 0;
@@ -512,8 +515,9 @@
 	    console_table[currcons]->winsize = ws;
 	}
 
-   if (currcons == fg_console)
-      update_screen(fg_console);
+	/* don't update in graphics mode */
+	if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+	    update_screen(fg_console);
 }
 
 void vc_disallocate(unsigned int currcons)
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.1.47/linux/arch/m68k/kernel/entry.S	Mon Jun 16 16:35:53 1997
+++ linux/arch/m68k/kernel/entry.S	Thu Jul 31 13:09:16 1997
@@ -190,7 +190,7 @@
 	andw	#ALLOWINT,%sr
 
 	/* check if we need to do software interrupts */
-	
+
 	movel	SYMBOL_NAME(bh_active),%d0
 	andl	SYMBOL_NAME(bh_mask),%d0
 	jeq	SYMBOL_NAME(ret_from_exception)
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.1.47/linux/arch/m68k/kernel/head.S	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/kernel/head.S	Thu Jul 31 13:09:16 1997
@@ -273,6 +273,9 @@
 	movel	%d2,%a0@
 	lea	%pc@(SYMBOL_NAME(is_medusa)),%a0
 	movel	%d3,%a0@
+	lea     %pc@(Liobase),%a0
+	movel   %d2,%a0@		/* On a Hades the iobase must be set
+					   before opening the serial port. */
 Lnotypetest:
 #endif
 
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.47/linux/arch/m68k/kernel/process.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/kernel/process.c	Thu Jul 31 13:09:16 1997
@@ -283,8 +283,9 @@
 	struct pt_regs *regs = (struct pt_regs *) &name;
 
 	lock_kernel();
-	error = getname(name, &filename);
-	if (error)
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
 		goto out;
 	error = do_execve(filename, argv, envp, regs);
 	putname(filename);
diff -u --recursive --new-file v2.1.47/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.1.47/linux/arch/m68k/kernel/sys_m68k.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/kernel/sys_m68k.c	Thu Jul 31 13:09:16 1997
@@ -205,11 +205,10 @@
   return -ENOSYS;
 }
 
-/* Convert virtual address VADDR to physical address PADDR, recording
-   in VALID whether the virtual address is actually mapped.  */
-#define virt_to_phys_040(vaddr, paddr, valid)				\
-{									\
-  unsigned long _mmusr;							\
+/* Convert virtual address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr)						\
+({									\
+  unsigned long _mmusr, _paddr;						\
 									\
   __asm__ __volatile__ (".chip 68040\n\t"				\
 			"ptestr (%1)\n\t"				\
@@ -217,20 +216,14 @@
 			".chip 68k"					\
 			: "=r" (_mmusr)					\
 			: "a" (vaddr));					\
-  if (!(_mmusr & MMU_R_040))						\
-    (valid) = 0;							\
-  else									\
-    {									\
-      (valid) = 1;							\
-      (paddr) = _mmusr & PAGE_MASK;					\
-    }									\
-}
+  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;		\
+  _paddr;								\
+})
 
 static inline int
 cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
 {
-  unsigned long paddr;
-  int valid;
+  unsigned long paddr, i;
 
   switch (scope)
     {
@@ -261,19 +254,31 @@
       break;
 
     case FLUSH_SCOPE_LINE:
-      len >>= 4;
       /* Find the physical address of the first mapped page in the
 	 address range.  */
-      for (;;)
-	{
-	  virt_to_phys_040 (addr, paddr, valid);
-	  if (valid)
-	    break;
-	  if (len <= PAGE_SIZE / 16)
-	    return 0;
-	  len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-	  addr = (addr + PAGE_SIZE) & PAGE_MASK;
-	}
+      if ((paddr = virt_to_phys_040(addr))) {
+        paddr += addr & ~(PAGE_MASK | 15);
+        len = (len + (addr & 15) + 15) >> 4;
+      } else {
+	unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+	if (len <= tmp)
+	  return 0;
+	addr += tmp;
+	len -= tmp;
+	tmp = PAGE_SIZE;
+	for (;;)
+	  {
+	    if ((paddr = virt_to_phys_040(addr)))
+	      break;
+	    if (len <= tmp)
+	      return 0;
+	    addr += tmp;
+	    len -= tmp;
+	  }
+	len = (len + 15) >> 4;
+      }
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
       while (len--)
 	{
 	  switch (cache)
@@ -301,36 +306,33 @@
 				    : : "a" (paddr));
 	      break;
 	    }
-	  addr += 16;
-	  if (len)
+	  if (!--i && len)
 	    {
-	      if ((addr & (PAGE_SIZE-1)) < 16)
+	      addr += PAGE_SIZE;
+	      i = PAGE_SIZE / 16;
+	      /* Recompute physical address when crossing a page
+	         boundary. */
+	      for (;;)
 		{
-		  /* Recompute physical address when crossing a page
-		     boundary. */
-		  for (;;)
-		    {
-		      virt_to_phys_040 (addr, paddr, valid);
-		      if (valid)
-			break;
-		      if (len <= PAGE_SIZE / 16)
-			return 0;
-		      len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-		      addr = (addr + PAGE_SIZE) & PAGE_MASK;
-		    }
+		  if ((paddr = virt_to_phys_040(addr)))
+		    break;
+		  if (len <= i)
+		    return 0;
+		  len -= i;
+		  addr += PAGE_SIZE;
 		}
-	      else
-		paddr += 16;
 	    }
+	  else
+	    paddr += 16;
 	}
       break;
 
     default:
     case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
 	{
-	  virt_to_phys_040 (addr, paddr, valid);
-	  if (!valid)
+	  if (!(paddr = virt_to_phys_040(addr)))
 	    continue;
 	  switch (cache)
 	    {
@@ -363,21 +365,21 @@
   return 0;
 }
 
-#define virt_to_phys_060(vaddr, paddr, valid)		\
-{							\
+#define virt_to_phys_060(vaddr)				\
+({							\
+  unsigned long paddr;					\
   __asm__ __volatile__ (".chip 68060\n\t"		\
 			"plpar (%0)\n\t"		\
 			".chip 68k"			\
 			: "=a" (paddr)			\
 			: "0" (vaddr));			\
-  (valid) = 1; /* XXX */				\
-}
+  (paddr); /* XXX */					\
+})
 
 static inline int
 cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
 {
-  unsigned long paddr;
-  int valid;
+  unsigned long paddr, i;
 
   switch (scope)
     {
@@ -407,19 +409,30 @@
       break;
 
     case FLUSH_SCOPE_LINE:
-      len >>= 4;
       /* Find the physical address of the first mapped page in the
 	 address range.  */
-      for (;;)
-	{
-	  virt_to_phys_060 (addr, paddr, valid);
-	  if (valid)
-	    break;
-	  if (len <= PAGE_SIZE / 16)
-	    return 0;
-	  len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-	  addr = (addr + PAGE_SIZE) & PAGE_MASK;
-	}
+      len += addr & 15;
+      addr &= -16;
+      if (!(paddr = virt_to_phys_060(addr))) {
+	unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+	if (len <= tmp)
+	  return 0;
+	addr += tmp;
+	len -= tmp;
+	tmp = PAGE_SIZE;
+	for (;;)
+	  {
+	    if ((paddr = virt_to_phys_060(addr)))
+	      break;
+	    if (len <= tmp)
+	      return 0;
+	    addr += tmp;
+	    len -= tmp;
+	  }
+      }
+      len = (len + 15) >> 4;
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
       while (len--)
 	{
 	  switch (cache)
@@ -447,36 +460,35 @@
 				    : : "a" (paddr));
 	      break;
 	    }
-	  addr += 16;
-	  if (len)
+	  if (!--i && len)
 	    {
-	      if ((addr & (PAGE_SIZE-1)) < 16)
-		{
-		  /* Recompute the physical address when crossing a
-		     page boundary.  */
-		  for (;;)
-		    {
-		      virt_to_phys_060 (addr, paddr, valid);
-		      if (valid)
-			break;
-		      if (len <= PAGE_SIZE / 16)
-			return 0;
-		      len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
-		      addr = (addr + PAGE_SIZE) & PAGE_MASK;
-		    }
-		}
-	      else
-		paddr += 16;
+	      addr += PAGE_SIZE;
+	      i = PAGE_SIZE / 16;
+	      /* Recompute physical address when crossing a page
+	         boundary. */
+	      for (;;)
+	        {
+	          if ((paddr = virt_to_phys_060(addr)))
+	            break;
+	          if (len <= i)
+	            return 0;
+	          len -= i;
+	          addr += PAGE_SIZE;
+	        }
 	    }
+	  else
+	    paddr += 16;
 	}
       break;
 
     default:
     case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      addr &= PAGE_MASK;	/* Workaround for bug in some
+				   revisions of the 68060 */
       for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
 	{
-	  virt_to_phys_060 (addr, paddr, valid);
-	  if (!valid)
+	  if (!(paddr = virt_to_phys_060(addr)))
 	    continue;
 	  switch (cache)
 	    {
diff -u --recursive --new-file v2.1.47/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.1.47/linux/arch/mips/config.in	Sun Jul 27 12:11:00 1997
+++ linux/arch/mips/config.in	Thu Jul 31 13:09:16 1997
@@ -80,7 +80,7 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" ]; then
-  tristate 'Parallel port support' CONFIG_PARPORT
+  tristate 'Parallel port support' CONFIG_PNP_PARPORT
 fi
 
 endmenu
diff -u --recursive --new-file v2.1.47/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.1.47/linux/arch/mips/defconfig	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/defconfig	Thu Jul 31 13:09:16 1997
@@ -86,6 +86,7 @@
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 
 #
 # (it is safe to leave these untouched)
diff -u --recursive --new-file v2.1.47/linux/arch/mips/jazz/int-handler.S linux/arch/mips/jazz/int-handler.S
--- v2.1.47/linux/arch/mips/jazz/int-handler.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/jazz/int-handler.S	Thu Jul 31 13:09:16 1997
@@ -278,7 +278,10 @@
 		b	loc_call
 		li	t3,PTRSIZE*JAZZ_ETHERNET_IRQ 	# delay slot
 
-loc_scsi:	PANIC("Unimplemented loc_scsi handler")
+loc_scsi:	li	s1,~JAZZ_IE_SCSI
+		li	a0,12         # JAZZ_SCSI_IRQ */
+		b	loc_call
+		li	t3,PTRSIZE*12 # JAZZ_ETHERNET_IRQ 	# delay slot
 
 /*
  * Keyboard interrupt handler
diff -u --recursive --new-file v2.1.47/linux/arch/mips/jazz/jazzdma.c linux/arch/mips/jazz/jazzdma.c
--- v2.1.47/linux/arch/mips/jazz/jazzdma.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/jazz/jazzdma.c	Thu Jul 31 13:09:16 1997
@@ -375,6 +375,7 @@
      * Clear all interrupt flags
      */
     r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+		      r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
                       R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR);
 
     /*
diff -u --recursive --new-file v2.1.47/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c
--- v2.1.47/linux/arch/mips/jazz/setup.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/jazz/setup.c	Thu Jul 31 13:09:16 1997
@@ -11,6 +11,7 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <asm/bootinfo.h>
 #include <asm/irq.h>
 #include <asm/jazz.h>
 #include <asm/ptrace.h>
@@ -36,11 +37,21 @@
 extern void jazz_machine_halt(void);
 extern void jazz_machine_power_off(void);
 
+void (*board_time_init)(struct irqaction *irq);
+
+__initfunc(static void jazz_time_init(struct irqaction *irq))
+{
+        /* set the clock to 100 Hz */
+        r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
+        setup_x86_irq(0, irq);
+}
+
 __initfunc(static void jazz_irq_setup(void))
 {
         set_except_vector(0, jazz_handle_int);
 	r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
 			  JAZZ_IE_ETHERNET |
+			  JAZZ_IE_SCSI     |
 			  JAZZ_IE_SERIAL1  |
 			  JAZZ_IE_SERIAL2  |
  			  JAZZ_IE_PARALLEL |
@@ -57,14 +68,42 @@
 
 __initfunc(void jazz_setup(void))
 {
+    tag *atag;
+
+    /*
+     * we just check if a tag_screen_info can be gathered
+     * in setup_arch(), if yes we don't proceed futher...
+     */
+    atag = bi_TagFind(tag_screen_info);
+    if (!atag) {
+	/*
+	 * If no, we try to find the tag_arc_displayinfo which is
+	 * always created by Milo for an ARC box (for now Milo only
+	 * works on ARC boxes :) -Stoned.
+	 */
+	atag = bi_TagFind(tag_arcdisplayinfo);
+	if (atag) {
+	    screen_info.orig_x = 
+		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x;
+	    screen_info.orig_y = 
+		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y;
+	    screen_info.orig_video_cols  = 
+		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns;
+	    screen_info.orig_video_lines  = 
+		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines;
+	}
+    }
+
 	irq_setup = jazz_irq_setup;
 	fd_cacheflush = jazz_fd_cacheflush;
 	feature = &jazz_feature;			// Will go away
+	port_base = JAZZ_PORT_BASE;
 	isa_slot_offset = 0xe3000000;
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
 	request_region(0x80,0x10,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
+        board_time_init = jazz_time_init;
 	/* The RTC is outside the port address space */
 
 	_machine_restart = jazz_machine_restart;
diff -u --recursive --new-file v2.1.47/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.1.47/linux/arch/mips/kernel/irixelf.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/irixelf.c	Thu Jul 31 13:09:17 1997
@@ -228,7 +228,7 @@
  * an ELF header.
  */
 static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
-				     struct inode * interpreter_inode,
+				     struct dentry * interpreter_dentry,
 				     unsigned int *interp_load_addr)
 {
 	struct file * file;
@@ -256,8 +256,8 @@
 	if((interp_elf_ex->e_type != ET_EXEC &&
 	    interp_elf_ex->e_type != ET_DYN) ||
 	    !elf_check_arch(interp_elf_ex->e_machine) ||
-	   (!interpreter_inode->i_op ||
-	    !interpreter_inode->i_op->default_file_ops->mmap)){
+	   (!interpreter_dentry->d_inode->i_op ||
+	    !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)) {
 		printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type);
 		return 0xffffffff;
 	}
@@ -288,7 +288,7 @@
 		return 0xffffffff;
 	}
 
-	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+	retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
 			   (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
 
@@ -296,7 +296,7 @@
 	dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
 #endif
 
-	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+	elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
 	if (elf_exec_fileno < 0) {
 		printk("Could not open IRIX interp inode.\n");
 		kfree(elf_phdata);
@@ -408,8 +408,9 @@
 	/* First of all, some simple consistency checks */
 	if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || 
 	    !elf_check_arch(ehp->e_machine) ||
-	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-	    !bprm->inode->i_op->default_file_ops->mmap)) {
+	   (!bprm->dentry->d_inode->i_op ||
+	    !bprm->dentry->d_inode->i_op->default_file_ops ||
+	    !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) {
 		return -ENOEXEC;
 	}
 
@@ -435,13 +436,14 @@
 
 /* Look for an IRIX ELF interpreter. */
 static inline int look_for_irix_interpreter(char **name,
-					    struct inode **interpreter_inode,
+					    struct dentry **interpreter_dentry,
 					    struct elfhdr *interp_elf_ex,
 					    struct elf_phdr *epp,
 					    struct linux_binprm *bprm, int pnum)
 {
 	int i, old_fs;
 	int retval = -EINVAL;
+	struct dentry *dentry = NULL;
 
 	*name = NULL;
 	for(i = 0; i < pnum; i++, epp++) {
@@ -450,7 +452,7 @@
 
 		/* It is illegal to have two interpreters for one executable. */
 		if(*name != NULL)
-			goto losing;
+			goto out;
 
 		*name = (char *) kmalloc((epp->p_filesz +
 					  strlen(IRIX_INTERP_PREFIX)),
@@ -459,26 +461,31 @@
 			return -ENOMEM;
 
 		strcpy(*name, IRIX_INTERP_PREFIX);
-		retval = read_exec(bprm->inode, epp->p_offset, (*name + 16),
+		retval = read_exec(bprm->dentry, epp->p_offset, (*name + 16),
 				   epp->p_filesz, 1);
 		if(retval < 0)
-			goto losing;
+			goto out;
 
 		old_fs = get_fs(); set_fs(get_ds());
-		retval = namei(NAM_FOLLOW_LINK, *name, interpreter_inode);
+		dentry = namei(*name);
 		set_fs(old_fs);
-		if(retval < 0)
-			goto losing;
+		if(IS_ERR(dentry)) {
+			retval = PTR_ERR(dentry);
+			goto out;
+		}
 
-		retval = read_exec(*interpreter_inode, 0, bprm->buf, 128, 1);
-		if(retval < 0)
-			goto losing;
+		retval = read_exec(dentry, 0, bprm->buf, 128, 1);
+		if(retval)
+			goto dput_and_out;
 
 		*interp_elf_ex = *((struct elfhdr *) bprm->buf);
 	}
+	*interpreter_dentry = dentry;
 	return 0;
 
-losing:
+dput_and_out:
+	dput(dentry);
+out:
 	kfree(*name);
 	return retval;
 }
@@ -538,7 +545,7 @@
 }
 
 static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
-				  struct inode *iino, unsigned int *iladdr,
+				  struct dentry *identry, unsigned int *iladdr,
 				  int pnum, int old_fs,
 				  unsigned int *eentry)
 {
@@ -554,11 +561,11 @@
 			return -1;
 
 		set_fs(old_fs);
-		*eentry = load_irix_interp(ihp, iino, iladdr);
+		*eentry = load_irix_interp(ihp, identry, iladdr);
 		old_fs = get_fs();
 		set_fs(get_ds());
 
-		iput(iino);
+		dput(identry);
 
 		if(*eentry == 0xffffffff)
 			return -1;
@@ -573,7 +580,7 @@
 				      struct pt_regs * regs)
 {
 	struct elfhdr elf_ex, interp_elf_ex;
-	struct inode *interpreter_inode;
+	struct dentry *interpreter_dentry;
 	struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr;
 	unsigned int load_addr, elf_bss, elf_brk;
 	unsigned int elf_entry, interp_load_addr = 0;
@@ -599,7 +606,7 @@
 	if (elf_phdata == NULL)
 		return -ENOMEM;
 	
-	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+	retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
 			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
 	if (retval < 0) {
 		kfree (elf_phdata);
@@ -629,7 +636,7 @@
 
 	elf_bss = 0;
 	elf_brk = 0;
-	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+	elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
 
 	if (elf_exec_fileno < 0) {
 		kfree (elf_phdata);
@@ -642,7 +649,8 @@
 	end_code = 0;
 	end_data = 0;
 	
-	retval = look_for_irix_interpreter(&elf_interpreter, &interpreter_inode,
+	retval = look_for_irix_interpreter(&elf_interpreter,
+	                                   &interpreter_dentry,
 					   &interp_elf_ex, elf_phdata, bprm,
 					   elf_ex.e_phnum);
 	if(retval) {
@@ -703,7 +711,7 @@
 
 	if(elf_interpreter) {
 		retval = map_interpreter(elf_phdata, &interp_elf_ex,
-					 interpreter_inode, &interp_load_addr,
+					 interpreter_dentry, &interp_load_addr,
 					 elf_ex.e_phnum, old_fs, &elf_entry);
 		kfree(elf_interpreter);
 		if(retval) {
@@ -795,7 +803,8 @@
 	struct file * file;
 	struct elfhdr elf_ex;
 	struct elf_phdr *elf_phdata  =  NULL;
-	struct  inode * inode;
+	struct dentry *dentry;
+	struct inode *inode;
 	unsigned int len;
 	int elf_bss;
 	int retval;
@@ -805,7 +814,8 @@
 
 	len = 0;
 	file = current->files->fd[fd];
-	inode = file->f_inode;
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
 	elf_bss = 0;
 	
 	if (!file || !file->f_op)
@@ -831,7 +841,8 @@
 	/* First of all, some simple consistency checks. */
 	if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
 	   !elf_check_arch(elf_ex.e_machine) ||
-	   (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+	   (!dentry->d_inode->i_op ||
+	    !dentry->d_inode->i_op->default_file_ops->mmap))
 		return -ENOEXEC;
 	
 	/* Now read in all of the header information. */
@@ -843,7 +854,7 @@
 	if (elf_phdata == NULL)
 		return -ENOMEM;
 	
-	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+	retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
 	
 	j = 0;
@@ -973,14 +984,13 @@
  */
 static int dump_write(struct file *file, const void *addr, int nr)
 {
-	file->f_inode->i_status |= ST_MODIFIED;
-	return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+	return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
 }
 
 static int dump_seek(struct file *file, off_t off)
 {
 	if (file->f_op->llseek) {
-		if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+		if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off)
 			return 0;
 	} else
 		file->f_pos = off;
@@ -1071,6 +1081,7 @@
 {
 	int has_dumped = 0;
 	struct file file;
+	struct dentry *dentry;
 	struct inode *inode;
 	unsigned short fs;
 	char corefile[6+sizeof(current->comm)];
@@ -1138,30 +1149,24 @@
 	
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	memcpy(corefile,"core.",5);
+	memcpy(corefile,"core.", 5);
 #if 0
 	memcpy(corefile+5,current->comm,sizeof(current->comm));
 #else
 	corefile[4] = '\0';
 #endif
-	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+	dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600);
+	if (IS_ERR(dentry)) {
 		inode = NULL;
 		goto end_coredump;
 	}
+	inode = dentry->d_inode;
 	if (!S_ISREG(inode->i_mode))
 		goto end_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto end_coredump;
-	file.f_mode = 3;
-	file.f_flags = 0;
-	file.f_count = 1;
-	file.f_inode = inode;
-	file.f_pos = 0;
-	file.f_reada = 0;
-	file.f_op = inode->i_op->default_file_ops;
-	if (file.f_op->open)
-		if (file.f_op->open(inode,&file))
-			goto end_coredump;
+	if (init_private_file(&file, dentry, 3))
+		goto end_coredump;
 	if (!file.f_op->write)
 		goto close_coredump;
 	has_dumped = 1;
@@ -1330,11 +1335,11 @@
 
  close_coredump:
 	if (file.f_op->release)
-		file.f_op->release(inode,&file);
+		file.f_op->release(inode, &file);
 
  end_coredump:
 	set_fs(fs);
-	iput(inode);
+	dput(dentry);
 #ifndef CONFIG_BINFMT_ELF
 	MOD_DEC_USE_COUNT;
 #endif
diff -u --recursive --new-file v2.1.47/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
--- v2.1.47/linux/arch/mips/kernel/syscall.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/syscall.c	Thu Jul 31 13:09:17 1997
@@ -131,20 +131,21 @@
  */
 asmlinkage int sys_execve(struct pt_regs *regs)
 {
-	int res;
+	int error;
 	char * filename;
 
 	lock_kernel();
-	res = getname((char *) (long)regs->regs[4], &filename);
-	if (res)
+	filename = getname((char *) (long)regs->regs[4]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
 		goto out;
-	res = do_execve(filename, (char **) (long)regs->regs[5],
-	                (char **) (long)regs->regs[6], regs);
+	error = do_execve(filename, (char **) (long)regs->regs[5],
+	                  (char **) (long)regs->regs[6], regs);
 	putname(filename);
 
 out:
 	unlock_kernel();
-	return res;
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.1.47/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h
--- v2.1.47/linux/arch/mips/kernel/syscalls.h	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/syscalls.h	Thu Jul 31 13:09:17 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996 by Ralf Baechle
  *
- * $Id: syscalls.h,v 1.5 1997/06/25 17:08:35 ralf Exp $
+ * $Id: syscalls.h,v 1.6 1997/07/20 15:32:25 ralf Exp $
  */
 
 /*
@@ -208,3 +208,5 @@
 SYS(sys_query_module, 5)
 SYS(sys_poll, 3)
 SYS(sys_nfsservctl, 3)
+SYS(sys_setresgid, 3)				/* 4190 */
+SYS(sys_getresgid, 3)
diff -u --recursive --new-file v2.1.47/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.1.47/linux/arch/mips/kernel/sysirix.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/kernel/sysirix.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.2 1997/06/17 15:24:26 ralf Exp $
+/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
  * sysirix.c: IRIX system call emulation.
  *
  * Copyright (C) 1996 David S. Miller
@@ -652,6 +652,7 @@
 asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
 			   int len, int fs_type)
 {
+	struct dentry *dentry;
 	struct inode *inode;
 	struct statfs kbuf;
 	int error, old_fs, i;
@@ -664,20 +665,19 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
 	if (error)
 		goto out;
-	error = namei(NAM_FOLLOW_LINK, path, &inode);
-	if (error)
-		goto out;
-	if (!inode->i_sb->s_op->statfs) {
-		iput(inode);
-		error = -ENOSYS;
+	dentry = namei(path);
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
-	}
 
+	inode = dentry->d_inode;
 	old_fs = get_fs(); set_fs(get_ds());
-	inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+	                                  sizeof(struct statfs));
 	set_fs(old_fs);
+	if (error)
+		goto dput_and_out;
 
-	iput(inode);
 	__put_user(kbuf.f_type, &buf->f_type);
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -691,6 +691,8 @@
 	}
 	error = 0;
 
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -698,7 +700,8 @@
 
 asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
 {
-	struct inode * inode;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct statfs kbuf;
 	struct file *file;
 	int error, old_fs, i;
@@ -711,18 +714,29 @@
 		error = -EBADF;
 		goto out;
 	}
-	if (!(inode = file->f_inode)) {
+	if (!(dentry = file->f_dentry)) {
+		error = -ENOENT;
+		goto out;
+	}
+	if (!(inode = dentry->d_inode)) {
 		error = -ENOENT;
 		goto out;
 	}
+	if (!inode->i_sb) {
+		error = -ENODEV;
+		goto out;
+	}
 	if (!inode->i_sb->s_op->statfs) {
 		error = -ENOSYS;
 		goto out;
 	}
 
 	old_fs = get_fs(); set_fs(get_ds());
-	inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+	                                  sizeof(struct statfs));
 	set_fs(old_fs);
+	if (error)
+		goto out;
 
 	__put_user(kbuf.f_type, &buf->f_type);
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
@@ -789,13 +803,14 @@
 asmlinkage int irix_exec(struct pt_regs *regs)
 {
 	int error, base = 0;
-	char * filename;
+	char *filename;
 
 	lock_kernel();
 	if(regs->regs[2] == 1000)
 		base = 1;
-	error = getname((char *) (long)regs->regs[base + 4], &filename);
-	if (error)
+	filename = getname((char *) (long)regs->regs[base + 4]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
 		goto out;
 	error = do_execve(filename, (char **) (long)regs->regs[base + 5],
 	                  (char **) 0, regs);
@@ -809,13 +824,14 @@
 asmlinkage int irix_exece(struct pt_regs *regs)
 {
 	int error, base = 0;
-	char * filename;
+	char *filename;
 
 	lock_kernel();
 	if(regs->regs[2] == 1000)
 		base = 1;
-	error = getname((char *) (long)regs->regs[base + 4], &filename);
-	if (error)
+	filename = getname((char *) (long)regs->regs[base + 4]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
 		goto out;
 	error = do_execve(filename, (char **) (long)regs->regs[base + 5],
 	                  (char **) (long)regs->regs[base + 6], regs);
@@ -1380,6 +1396,7 @@
 
 asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
 {
+	struct dentry *dentry;
 	struct inode *inode;
 	struct statfs kbuf;
 	int error, old_fs, i;
@@ -1390,20 +1407,23 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
 	if(error)
 		goto out;
-	error = namei(NAM_FOLLOW_LINK, fname, &inode);
-	if(error)
-		goto out;
-	if(!inode->i_sb->s_op->statfs) {
-		iput(inode);
-		error = -ENOSYS;
-		goto out;
-	}
+	dentry = namei(fname);
+	error = PTR_ERR(dentry);
+	if(!IS_ERR(dentry))
+		goto out;
+	inode = dentry->d_inode;
+
+	error = -ENOSYS;
+	if(!inode->i_sb->s_op->statfs)
+		goto dput_and_out;
 
 	old_fs = get_fs(); set_fs(get_ds());
-	inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+	                                  sizeof(struct statfs));
 	set_fs(old_fs);
+	if (error)
+		goto dput_and_out;
 
-	iput(inode);
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
 	__put_user(kbuf.f_blocks, &buf->f_blocks);
@@ -1426,6 +1446,8 @@
 
 	error = 0;
 
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -1433,7 +1455,8 @@
 
 asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
 {
-	struct inode * inode;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct statfs kbuf;
 	struct file *file;
 	int error, old_fs, i;
@@ -1449,7 +1472,11 @@
 		error = -EBADF;
 		goto out;
 	}
-	if (!(inode = file->f_inode)) {
+	if (!(dentry = file->f_dentry)) {
+		error = -ENOENT;
+		goto out;
+	}
+	if (!(inode = dentry->d_inode)) {
 		error = -ENOENT;
 		goto out;
 	}
@@ -1459,8 +1486,11 @@
 	}
 
 	old_fs = get_fs(); set_fs(get_ds());
-	inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+	                                  sizeof(struct statfs));
 	set_fs(old_fs);
+	if (error)
+		goto out;
 
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1489,26 +1519,28 @@
 	return error;
 }
 
-#define NOFOLLOW_LINKS  NAM_FOLLOW_TRAILSLASH
-#define FOLLOW_LINKS    NAM_FOLLOW_LINK
+#define NOFOLLOW_LINKS  0
+#define FOLLOW_LINKS    1
 
-static inline int chown_common(char *filename, uid_t user, gid_t group, int follow)
+static inline int chown_common(uid_t user, gid_t group, struct dentry *dentry)
 {
 	struct inode * inode;
 	int error;
 	struct iattr newattrs;
 
-	error = namei(follow, filename,&inode);
-	if (error)
-		return error;
-	if (IS_RDONLY(inode)) {
-		iput(inode);
-		return -EROFS;
-	}
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
-		iput(inode);
-		return -EPERM;
-	}
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto out;
+	inode = dentry->d_inode;
+
+	error = -EROFS;
+	if (IS_RDONLY(inode))
+		goto dput_and_out;
+
+	error = -EPERM;
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+		goto dput_and_out;
+
 	if (user == (uid_t) -1)
 		user = inode->i_uid;
 	if (group == (gid_t) -1)
@@ -1534,38 +1566,45 @@
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
-	inode->i_dirt = 1;
 	if (inode->i_sb->dq_op) {
 		inode->i_sb->dq_op->initialize(inode, -1);
+		error = -EDQUOT;
 		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-			return -EDQUOT;
+			goto dput_and_out;
 		error = notify_change(inode, &newattrs);
 		if (error)
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
-	iput(inode);
-	return(error);
+
+dput_and_out:
+	dput(dentry);
+out:
+	return error;
 }
 
-asmlinkage int irix_chown(char *fname, int uid, int gid)
+asmlinkage int irix_chown(const char *filename, int uid, int gid)
 {
 	int retval;
+	struct dentry *dentry;
 
 	lock_kernel();
 	/* Do follow any and all links... */
-	retval = chown_common(fname, uid, gid, FOLLOW_LINKS);
+	dentry = namei(filename);
+	retval = chown_common(uid, gid, dentry);
 	unlock_kernel();
 	return retval;
 }
 
-asmlinkage int irix_lchown(char *fname, int uid, int gid)
+asmlinkage int irix_lchown(const char *filename, int uid, int gid)
 {
 	int retval;
+	struct dentry *dentry;
 
 	lock_kernel();
 	/* Do _not_ follow any links... */
-	retval = chown_common(fname, uid, gid, NOFOLLOW_LINKS);
+	dentry = lnamei(filename);
+	retval = chown_common(uid, gid, dentry);
 	unlock_kernel();
 	return retval;
 }
@@ -1722,6 +1761,7 @@
 
 asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
 {
+	struct dentry *dentry;
 	struct inode *inode;
 	struct statfs kbuf;
 	int error, old_fs, i;
@@ -1731,20 +1771,22 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
 	if(error)
 		goto out;
-	error = namei(NAM_FOLLOW_LINK, fname, &inode);
-	if(error)
-		goto out;
-	if(!inode->i_sb->s_op->statfs) {
-		iput(inode);
-		error = -ENOSYS;
-		goto out;
-	}
+	dentry = namei(fname);
+	error = PTR_ERR(dentry);
+	if(IS_ERR(dentry))
+		goto out;
+	error = -ENOSYS;
+	inode = dentry->d_inode;
+	if(!inode->i_sb->s_op->statfs)
+		goto dput_and_out;
 
 	old_fs = get_fs(); set_fs(get_ds());
-	inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+	                                  sizeof(struct statfs));
 	set_fs(old_fs);
+	if (error)
+		goto dput_and_out;
 
-	iput(inode);
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
 	__put_user(kbuf.f_blocks, &buf->f_blocks);
@@ -1767,6 +1809,8 @@
 
 	error = 0;
 
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -1774,7 +1818,8 @@
 
 asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
 {
-	struct inode * inode;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct statfs kbuf;
 	struct file *file;
 	int error, old_fs, i;
@@ -1790,7 +1835,11 @@
 		error = -EBADF;
 		goto out;
 	}
-	if (!(inode = file->f_inode)) {
+	if (!(dentry = file->f_dentry)) {
+		error = -ENOENT;
+		goto out;
+	}
+	if (!(inode = dentry->d_inode)) {
 		error = -ENOENT;
 		goto out;
 	}
@@ -1800,8 +1849,11 @@
 	}
 
 	old_fs = get_fs(); set_fs(get_ds());
-	inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+	error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+	                                  sizeof(struct statfs));
 	set_fs(old_fs);
+	if (error)
+		goto out;
 
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1927,6 +1979,8 @@
 asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
 {
 	struct file *file;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct irix_dirent32 *lastdirent;
 	struct irix_dirent32_callback buf;
 	int error;
@@ -1936,25 +1990,34 @@
 	printk("[%s:%d] ngetdents(%d, %p, %d, %p) ", current->comm,
 	       current->pid, fd, dirent, count, eob);
 #endif
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
-		error = -EBADF;
+	error = -EBADF;
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		goto out;
-	}
-	if (!file->f_op || !file->f_op->readdir) {
-		error = -ENOTDIR;
+
+	dentry = file->f_dentry;
+	if (!dentry)
 		goto out;
-	}
-	if(verify_area(VERIFY_WRITE, dirent, count) ||
-	   verify_area(VERIFY_WRITE, eob, sizeof(*eob))) {
-		error = -EFAULT;
+
+	inode = dentry->d_inode;
+	if (!inode)
 		goto out;
-	}
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = -EFAULT;
+	if(!access_ok(VERIFY_WRITE, dirent, count) ||
+	   !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+		goto out;
+
 	__put_user(0, eob);
 	buf.current_dir = (struct irix_dirent32 *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32);
+
+	error = file->f_op->readdir(inode, file, &buf, irix_filldir32);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
@@ -2027,6 +2090,8 @@
 asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
 {
 	struct file *file;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct irix_dirent64 *lastdirent;
 	struct irix_dirent64_callback buf;
 	int error;
@@ -2036,28 +2101,35 @@
 	printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm,
 	       current->pid, fd, dirent, cnt);
 #endif
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
-		error = -EBADF;
+	error = -EBADF;
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		goto out;
-	}
-	if (!file->f_op || !file->f_op->readdir) {
-		error = -ENOTDIR;
+
+	dentry = file->f_dentry;
+	if (!dentry)
 		goto out;
-	}
-	if(verify_area(VERIFY_WRITE, dirent, cnt)) {
-		error = -EFAULT;
+
+	inode = dentry->d_inode;
+	if (!inode)
 		goto out;
-	}
-	if(cnt < (sizeof(struct irix_dirent64) + 255)) {
-		error = -EINVAL;
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = -EFAULT;
+	if(!access_ok(VERIFY_WRITE, dirent, cnt))
+		goto out;
+
+	error = -EINVAL;
+	if(cnt < (sizeof(struct irix_dirent64) + 255))
 		goto out;
-	}
 
 	buf.curr = (struct irix_dirent64 *) dirent;
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64);
+	error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
@@ -2079,6 +2151,8 @@
 asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
 {
 	struct file *file;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct irix_dirent64 *lastdirent;
 	struct irix_dirent64_callback buf;
 	int error;
@@ -2088,30 +2162,37 @@
 	printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm,
 	       current->pid, fd, dirent, cnt);
 #endif
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
-		error = -EBADF;
+	error = -EBADF;
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		goto out;
-	}
-	if (!file->f_op || !file->f_op->readdir) {
-		error = -ENOTDIR;
+
+	dentry = file->f_dentry;
+	if (!dentry)
 		goto out;
-	}
-	if(verify_area(VERIFY_WRITE, dirent, cnt) ||
-	   verify_area(VERIFY_WRITE, eob, sizeof(*eob))) {
-		error = -EFAULT;
+
+	inode = dentry->d_inode;
+	if (!inode)
 		goto out;
-	}
-	if(cnt < (sizeof(struct irix_dirent64) + 255)) {
-		error = -EINVAL;
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = -EFAULT;
+	if(!access_ok(VERIFY_WRITE, dirent, cnt) ||
+	   !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+		goto out;
+
+	error = -EINVAL;
+	if(cnt < (sizeof(struct irix_dirent64) + 255))
 		goto out;
-	}
 
 	*eob = 0;
 	buf.curr = (struct irix_dirent64 *) dirent;
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64);
+	error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
diff -u --recursive --new-file v2.1.47/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c
--- v2.1.47/linux/arch/mips/kernel/sysmips.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/kernel/sysmips.c	Thu Jul 31 13:09:17 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: sysmips.c,v 1.4 1997/06/30 15:52:37 ralf Exp $
+ * $Id: sysmips.c,v 1.5 1997/07/20 15:32:27 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -57,18 +57,21 @@
 	switch(cmd)
 	{
 	case SETNAME:
-		if (!suser()) {
-			retval = -EPERM;
+		retval = -EPERM;
+		if (!suser())
 			goto out;
-		}
+
 		name = (char *) arg1;
 		len = strlen_user(name);
+
+		retval = len;
 		if (len < 0)
-			retval = len;
 			goto out;
+
+		retval = -EINVAL;
 		if (len == 0 || len > __NEW_UTS_LEN)
-			retval = -EINVAL;
 			goto out;
+
 		copy_from_user(system_utsname.nodename, name, len);
 		system_utsname.nodename[len] = '\0';
 		retval = 0;
diff -u --recursive --new-file v2.1.47/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.1.47/linux/arch/mips/mm/fault.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/mm/fault.c	Thu Jul 31 13:09:17 1997
@@ -81,17 +81,6 @@
  */
 bad_area:
 	up(&mm->mmap_sem);
-	/* Did we have an exception handler installed? */
-
-	fixup = search_exception_table(regs->cp0_epc);
-	if (fixup) {
-		long new_epc;
-		new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
-		printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n",
-		       regs->cp0_epc, new_epc);
-		regs->cp0_epc = new_epc;
-		goto out;
-	}
 
 	if (user_mode(regs)) {
 		tsk->tss.cp0_badvaddr = address;
@@ -111,6 +100,18 @@
 		force_sig(SIGSEGV, tsk);
 		goto out;
 	}
+
+	/* Did we have an exception handler installed? */
+	fixup = search_exception_table(regs->cp0_epc);
+	if (fixup) {
+		long new_epc;
+		new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
+		printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+		       tsk->comm, regs->cp0_epc, new_epc);
+		regs->cp0_epc = new_epc;
+		goto out;
+	}
+
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to
 	 * terminate things with extreme prejudice.
diff -u --recursive --new-file v2.1.47/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.1.47/linux/arch/mips/mm/init.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/mm/init.c	Thu Jul 31 13:09:17 1997
@@ -156,7 +156,6 @@
 zeropage(unsigned long page)
 {
 	flush_page_to_ram(page);
-	sync_mem();
 	__zeropage(page);
 }
 
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.1.47/linux/arch/ppc/Makefile	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/Makefile	Thu Jul 31 13:09:17 1997
@@ -25,61 +25,62 @@
 CC		= gcc$(SUFFIX)
 CFLAGSINC	= -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
 CFLAGS		= $(CFLAGSINC) \
-		-Wstrict-prototypes \
-		-fomit-frame-pointer \
+		-Wstrict-prototypes -fomit-frame-pointer \
 		-fno-builtin \
-		-finhibit-size-directive -fno-strength-reduce\
-		-O2 -fsigned-char -pipe -mstring -mmultiple
+		-finhibit-size-directive \
+		-O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
+# -fverbose-asm 
 CPP		= $(CC) -E $(CFLAGS)
 AR		= ar$(SUFFIX)
 RANLIB		= ranlib$(SUFFIX)
 STRIP		= strip$(SUFFIX)
 NM		= nm$(SUFFIX)
 
-ifdef CONFIG_603
-CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
+ifdef CONFIG_601
+CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
 endif
 
-ifdef CONFIG_603e
-CFLAGS := $(CFLAGS) -mcpu=603e -DCPU=603e
+ifdef CONFIG_603
+CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
 endif
 
 ifdef CONFIG_604
 CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
 endif
 
-#
-# NFS_ROOT_NAME specifies the default name of the directory to mount
-# as root via NFS, if the kernel does not get the "root=" option from
-# the boot loader. The "%s" will be replaced by the IP-number of the
-# local system.
-#
-NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root\""
-
 HEAD := arch/ppc/kernel/head.o
 
 ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
 SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
 ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
-
+CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-netboot: vmlinux
+checks:
+	@$(MAKE) -C arch/$(ARCH)/kernel checks
+
+netboot: checks vmlinux
 	@$(MAKEBOOT) netboot
 
-znetboot: vmlinux
+znetboot: checks vmlinux
 	@$(MAKEBOOT) znetboot
 
-zImage: vmlinux
+#rcpboot: checks vmlinux
+#	@$(MAKEBOOT) rcpboot
+
+zImage: checks vmlinux
 	@$(MAKEBOOT) zImage
 
-floppy: vmlinux
+floppy: checks vmlinux
 	@$(MAKEBOOT) floppy
 
-install: vmlinux
+install: checks vmlinux
 	@$(MAKEBOOT) install
 
+vmlinux.coff : checks vmlinux
+	$(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
+
 arch/ppc/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
 
@@ -89,12 +90,24 @@
 arch/ppc/lib: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
 
+diffs:
+	arch/ppc/mkdiff
+
+tar:
+	arch/ppc/mktar
 
 archclean:
-	rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h TAGS
+	rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
+	rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+	rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
 	@$(MAKEBOOT) clean
 
 archdep:
+	$(MAKE) -C arch/ppc/boot fastdep
+	$(MAKE) -C arch/ppc/kernel fastdep
+	$(MAKE) -C arch/ppc/mm fastdep
+	$(MAKE) -C arch/ppc/lib fastdep
+
+tags :
+	etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c 
 
-corttags :
-	etags arch/ppc/*/*.c include/asm/* */*.c drivers/*/*.c net/*.c
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.1.47/linux/arch/ppc/boot/Makefile	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/Makefile	Thu Jul 31 13:09:17 1997
@@ -7,6 +7,7 @@
 #
 # Copyright (C) 1994 by Linus Torvalds
 # Adapted for PowerPC by Gary Thomas
+# modified by Cort (cort@cs.nmt.edu)
 #
 
 .c.s:
@@ -22,7 +23,7 @@
 
 
 ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
-GZIP_FLAGS = -9
+GZIP_FLAGS = -v9
 
 SYSTEM = $(TOPDIR)/vmlinux
 
@@ -32,49 +33,51 @@
 
 all:	$(TOPDIR)/zImage
 
-mkboot : cortstrip.c
-	$(HOSTCC) $(CFLAGSINC) -Wl,-static -o mkboot cortstrip.c
+mkprep : mkprep.c
+	$(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c
+
+find_name : find_name.c
+	$(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
 
 mk_type41: mk_type41.c
-	$(HOSTCC) $(CFLAGSINC) -Wl,-static -o mk_type41 mk_type41.c
+	$(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
+
+piggyback: piggyback.c
+	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
 
-floppy: zImage $(TOPDIR)/vmlinux
+floppy: $(TOPDIR)/vmlinux zImage 
 	dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
 
-netboot : $(TOPDIR)/vmlinux mkboot
-	mkboot $(TOPDIR)/vmlinux $(TOPDIR)/netboot
-#	rcp $(TOPDIR)/netboot charon:/usr/tftpboot/vmlinux
+netboot : $(TOPDIR)/vmlinux mkprep
+	mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+
+znetboot : zvmlinux mkprep
+	mkprep zvmlinux $(TOPDIR)/znetboot
+	cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
 
-znetboot : mkboot zvmlinux
-	mkboot zvmlinux $(TOPDIR)/znetboot
+rcpboot : znetboot
 	rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
 
-zImage: mk_type41 zvmlinux
-# make znetboot ourselves since using the normal dep
-# will rcp it -- Cort
-	mkboot zvmlinux $(TOPDIR)/znetboot
-	mk_type41 $(TOPDIR)/znetboot $(TOPDIR)/zImage
+zImage: zvmlinux mkprep
+	mkprep -pbp zvmlinux $(TOPDIR)/zImage
 
 install: zImage
 	dd if=$(TOPDIR)/zImage of=/dev/sda4
 	ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
 	cp $(TOPDIR)/System.map $(INSTALL_PATH)/	
 
-zvmlinux: $(OBJECTS) $(SYSTEM) piggyback netboot $(TOPDIR)/vmlinux
-	gzip ${GZIP_FLAGS} <$(TOPDIR)/netboot | ./piggyback | $(AS) -o piggy.o
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep  find_name
+	mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
 	$(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
-	rm -f piggy.o xx_boot
-
-head.o:	head.s
-
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
-	$(CPP) -traditional head.S -o head.s
-
-piggyback: piggyback.c
-	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+	rm -f piggy.o
 
 clean:
-	rm -f piggyback zvmlinux mk_type41 mkprep mkboot
+	rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
 	rm -f $(TOPDIR)/{zImage,znetboot,netboot}
 
+fastdep:
+	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
 dep:
+	$(CPP) -M *.S *.c > .depend
+
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/cortstrip.c linux/arch/ppc/boot/cortstrip.c
--- v2.1.47/linux/arch/ppc/boot/cortstrip.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/cortstrip.c	Wed Dec 31 16:00:00 1969
@@ -1,73 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* amount to skip */
-#define PLACE 65536
-
-/* size of read buffer */
-#define SIZE 0x100000
-
-/* crude program to strip the elf header to make a bootable
-   image via tftp
- */
-
-
-int main(int argc, char **argv )
-{
-  int fd, fdo;
-  unsigned char data[SIZE];
-  int i, n, skip;
-
-#if 0
-  if ( argc != 3 )
-  {
-    fprintf(stderr,"%s infile outfile\n", argv[0]);
-    exit(-1);
-  }
-#endif
-
-
-  fd = open(argv[1], O_RDONLY);
-  if ( fd == -1 )
-  {
-    fprintf(stderr,"Couldn't open %s\n", argv[1]);
-    perror("open()");
-    exit(-1);
-  }
-  
-  fdo = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,0755);
-  if ( fdo == -1 )
-  {
-    fprintf(stderr,"Couldn't open %s\n", argv[2]);
-    perror("open()");
-    exit(-1);
-  }
-
-#if 0
-  skip = atoi(argv[3]);
-#else
-  skip = PLACE;
-#endif
-  i = lseek(fd, skip, SEEK_SET);
- /*printf("lseek'd %d bytes\n", i);*/
-  if ( i == -1 )
-  {
-      perror("lseek()");
-  }
-
-  while ( (n = read(fd, data, SIZE)) > 0 )
-  {
-    /*printf("Read %d bytes\n", n);*/
-    i = write(fdo, data, n);
-    /*printf("Wrote %d bytes\n", i);    */
-  }
-
-
-  close(fdo);
-  close(fd);
-  return(0);
-}
-
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/find_name.c linux/arch/ppc/boot/find_name.c
--- v2.1.47/linux/arch/ppc/boot/find_name.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/boot/find_name.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <asm/page.h>
+#include <sys/mman.h>
+/*
+ * Finds a given address in the System.map and prints it out
+ * with its neighbors.  -- Cort
+ */
+
+void main(int argc, char **argv)
+{
+	unsigned long addr, cmp, i;
+	FILE *f;
+	char *ptr;
+	char s[256], last[256];
+	
+	if ( argc < 2 )
+	{
+		fprintf(stderr, "Usage: %s <address>\n", argv[0]);
+		exit(-1);
+	}
+
+	for ( i = 1 ; argv[i] ; i++ )
+	{
+		sscanf( argv[i], "%0x", &addr );
+		/* adjust if addr is relative to kernelbase */
+		if ( addr < PAGE_OFFSET )
+			addr += PAGE_OFFSET;
+		
+		if ( (f = fopen( "System.map", "r" )) == NULL )
+		{
+			perror("fopen()\n");
+			exit(-1);
+		}
+		
+		while ( !feof(f) )
+		{
+			fgets(s, 255 , f);
+			sscanf( s, "%0x", &cmp );
+			if ( addr < cmp )
+				break;
+			strcpy( last, s);
+		}
+		
+		printf( "%s", last);
+	}		
+	fclose(f);
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/gzip.h linux/arch/ppc/boot/gzip.h
--- v2.1.47/linux/arch/ppc/boot/gzip.h	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/gzip.h	Thu Jul 31 13:09:17 1997
@@ -271,7 +271,7 @@
 extern void flush_outbuf  OF((void));
 extern void flush_window  OF((void));
 extern char *strlwr       OF((char *s));
-extern char *basename     OF((char *fname));
+/*extern char *basename     OF((char *fname));*/
 extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
 extern void error         OF((char *m));
 extern void warn          OF((char *a, char *b));
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S
--- v2.1.47/linux/arch/ppc/boot/head.S	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/head.S	Thu Jul 31 13:09:17 1997
@@ -1,5 +1,6 @@
 #include "../kernel/ppc_defs.h"
 #include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
 
 	.text
 
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/inflate.c linux/arch/ppc/boot/inflate.c
--- v2.1.47/linux/arch/ppc/boot/inflate.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/inflate.c	Thu Jul 31 13:09:17 1997
@@ -9,7 +9,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
+static char rcsid[] = "$Id: inflate.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
 #endif
 
 #include "gzip.h"
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- v2.1.47/linux/arch/ppc/boot/misc.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/misc.c	Thu Jul 31 13:09:17 1997
@@ -327,7 +327,7 @@
   _put_MSR(_get_MSR() & ~0x0030);
 
   vga_init(0xC0000000);
-  clear_screen();
+  /*clear_screen();*/
 
   output_ptr = 0;
 
@@ -373,93 +373,6 @@
 #endif
 }
 
-#if 0
-verify_ram()
-{
-  unsigned long loc;
-  puts("Clearing memory:");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0x0;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0x0)
-      {
-	puts(" - failed at ");
-	puthex(loc);
-	puts(": ");
-	puthex(*(unsigned long *)loc);
-	while (1);
-      }
-  }
-  puts("0");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0xFFFFFFFF;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0xFFFFFFFF)
-      {
-	puts(" - failed at ");
-	puthex(loc);
-	puts(": ");
-	puthex(*(unsigned long *)loc);
-	while (1);
-      }
-  }
-  puts("1");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = loc;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != loc)
-      {
-	puts(" - failed at ");
-	puthex(loc);
-	puts(": ");
-	puthex(*(unsigned long *)loc);
-	while (1);
-      }
-  }
-  puts("?");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0xDEADB00B;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0xDEADB00B)
-      {
-	puts(" - failed at ");
-	puthex(loc);
-	puts(": ");
-	puthex(*(unsigned long *)loc);
-	while (1);
-      }
-  }
-  puts(">");
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    *(unsigned long *)loc = 0x0;
-  }
-  for (loc = 0;  loc <= 0x400000;  loc += 4);
-  {
-    if (*(unsigned long *)loc != 0x0)
-      {
-	puts(" - failed at ");
-	puthex(loc);
-	puts(": ");
-	puthex(*(unsigned long *)loc);
-	while (1);
-      }
-  }
-  puts("\n");
-}
-
 do_cksum(unsigned long loc)
 {
   unsigned int ptr, cksum;
@@ -582,7 +495,6 @@
   }
   return (errors == 0);
 }
-#endif
 
 void puthex(unsigned long val)
 {
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/mk_type41.c linux/arch/ppc/boot/mk_type41.c
--- v2.1.47/linux/arch/ppc/boot/mk_type41.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/mk_type41.c	Wed Dec 31 16:00:00 1969
@@ -1,208 +0,0 @@
-/*
- * This program will make a type 0x41 load image from an
- * executable file.  Note:  assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
- */
-
-#include <stdio.h>
-#include <errno.h>
-#ifdef linux
-#include <asm/stat.h>
-#else
-#include <sys/stat.h>
-#endif
-
-_LE(long val, unsigned char *le)
-{
-	le[0] = val;
-	le[1] = val >> 8;
-	le[2] = val >> 16;
-	le[3] = val >> 24;
-}
-
-main(int argc, char *argv[])
-{
-	int in_fd, out_fd, len, size;
-	struct stat info;
-	char buf[8192];
-	struct hdr
-	{
-		unsigned long entry_point;
-		unsigned long image_length;
-	} hdr;
-	if (argc != 3)
-	{
-		fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
-		exit(1);
-	}
-	if ((in_fd = open(argv[1], 0)) < 0)
-	{
-		fprintf(stderr, "Can't open input file: '%s': %s\n", argv[1], strerror(errno));
-		exit(2);
-	}
-	if ((out_fd = creat(argv[2], 0666)) < 0)
-	{
-		fprintf(stderr, "Can't create output file: '%s': %s\n", argv[2], strerror(errno));
-		exit(2);
-	}
-	if (fstat(in_fd, &info) < 0)
-	{
-		fprintf(stderr, "Can't get info on input file: %s\n", strerror(errno));
-		exit(4);
-	}
-	write_prep_boot_partition(out_fd);
-	_LE(0x400, &hdr.entry_point);
-	_LE(info.st_size+0x400, &hdr.image_length);
-	lseek(out_fd, 0x200, 0);
-	if (write(out_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
-	{
-		fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
-		exit(5);
-	}
-	lseek(out_fd, 0x400, 0);
-	while ((len = read(in_fd, buf, sizeof(buf))) > 0)
-	{
-		if (write(out_fd, buf, len) != len)
-		{
-			fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
-			exit(5);
-		}
-	}
-	if (len < 0)
-	{
-		fprintf(stderr, "Can't read input file: %s\n", strerror(errno));
-		exit(6);
-	}
-	close(in_fd);
-	close(out_fd);
-}
-
-/* Adapted from IBM Naked Application Package (NAP) */
-
-#define Align(value,boundary)						\
-	(((value) + (boundary) - 1) & ~((boundary) - 1))
-
-#define HiByte(word)		((word_t)(word) >> 8)
-#define LoByte(word)		((word_t)(word) & 0xFF)
-
-#define HiWord(dword)		((dword_t)(dword) >> 16)
-#define LoWord(dword)		((dword_t)(dword) & 0xFFFF)
-
-/*
- * Little-endian stuff
- */
-#define LeWord(word)							\
-	(((word_t)(word) >> 8) | ((word_t)(word) << 8))
-
-#define LeDword(dword)							\
-	(LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-#define PcDword(dword)							\
-	(LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-
-typedef unsigned long dword_t;
-typedef unsigned short word_t;
-typedef unsigned char byte_t;
-typedef byte_t block_t[512];
-typedef byte_t page_t[4096];
-
-/*
- * Partition table entry
- *  - from the PReP spec
- */
-typedef struct partition_entry {
-    byte_t	boot_indicator;
-    byte_t	starting_head;
-    byte_t	starting_sector;
-    byte_t	starting_cylinder;
-
-    byte_t	system_indicator;
-    byte_t	ending_head;
-    byte_t	ending_sector;
-    byte_t	ending_cylinder;
-
-    dword_t	beginning_sector;
-    dword_t	number_of_sectors;
-} partition_entry_t;
-
-#define BootActive	0x80
-#define SystemPrep	0x41
-
-
-/*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block.  It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition.  The "PReP" partition contains the "load image" starting
- * at offset zero within the partition.  The first block of the load image is
- * a dummy PC boot block.  The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image.  The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-void
-write_prep_boot_partition(int out_fd)
-{
-    block_t block;
-    partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
-    dword_t *entry  = (dword_t *)&block[0];
-    dword_t *length = (dword_t *)&block[4];
-
-    bzero( &block, sizeof block );
-
-    /*
-     * Magic marker
-     */
-    block[510] = 0x55;
-    block[511] = 0xAA;
-
-    /*
-     * Build a "PReP" partition table entry in the boot record
-     *  - "PReP" may only look at the system_indicator
-     */
-    pe->boot_indicator   = BootActive;
-    pe->system_indicator = SystemPrep;
-
-    /*
-     * The first block of the diskette is used by this "boot record" which
-     * actually contains the partition table. (The first block of the
-     * partition contains the boot image, but I digress...)  We'll set up
-     * one partition on the diskette and it shall contain the rest of the
-     * diskette.
-     */
-    pe->starting_head     = 0;		/* zero-based			     */
-    pe->starting_sector   = 2;		/* one-based			     */
-    pe->starting_cylinder = 0;		/* zero-based			     */
-
-    pe->ending_head       = 1;		/* assumes two heads		     */
-    pe->ending_sector     = 18;		/* assumes 18 sectors/track	     */
-    pe->ending_cylinder   = 79;		/* assumes 80 cylinders/diskette     */
-
-    /*
-     * The "PReP" software ignores the above fields and just looks at
-     * the next two.
-     *   - size of the diskette is (assumed to be)
-     *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
-     *   - unlike the above sector numbers, the beginning sector is zero-based!
-     */
-#if 0
-    pe->beginning_sector  = LeDword(1);
-#else
-    /* This has to be 0 on the PowerStack? */   
-    pe->beginning_sector  = LeDword(0);
-#endif    
-    pe->number_of_sectors = LeDword(2*18*80-1);
-
-    /*
-     * Write the partition table
-     */
-    lseek( out_fd, 0, 0 );
-    write( out_fd, block, sizeof block );
-}
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c
--- v2.1.47/linux/arch/ppc/boot/mkprep.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/mkprep.c	Thu Jul 31 13:09:17 1997
@@ -1,19 +1,54 @@
 /*
- * This program will make a type 0x41 load image from an
- * executable file.  Note:  assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
+ * Makes a prep bootable image which can be dd'd onto
+ * a disk device to make a bootdisk.  Will take
+ * as input a elf executable, strip off the header
+ * and write out a boot image as:
+ * 1) default - strips elf header
+ *      suitable as a network boot image
+ * 2) -pbp - strips elf header and writes out prep boot partition image
+ *      cat or dd onto disk for booting
+ * 3) -asm - strips elf header and writes out as asm data
+ *      useful for generating data for a compressed image
+ *                  -- Cort
  */
 
-#include <stdio.h>
-#include <errno.h>
 #ifdef linux
+#include <linux/types.h>
 #include <asm/stat.h>
+/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
 #else
+#include <unistd.h>
 #include <sys/stat.h>
 #endif
-#include <asm/byteorder.h> /* use same as kernel -- Cort */
+
+#include <stdio.h>
+#include <errno.h>
+
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+     	return (((x & 0x000000ffU) << 24) |
+		((x & 0x0000ff00U) <<  8) |
+		((x & 0x00ff0000U) >>  8) |
+		((x & 0xff000000U) >> 24));
+}
+
+
+#define cpu_to_le16(x) le16_to_cpu((x))
+unsigned short le16_to_cpu(unsigned short x)
+{
+	return (((x & 0x00ff) << 8) |
+		((x & 0xff00) >> 8));
+}
+
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be16_to_cpu(x) (x)
+
+/* size of read buffer */
+#define SIZE 0x1000
+
 
 typedef unsigned long dword_t;
 typedef unsigned short word_t;
@@ -21,119 +56,239 @@
 typedef byte_t block_t[512];
 typedef byte_t page_t[4096];
 
-_LE(long val, unsigned char *le)
-{
-	le[0] = val;
-	le[1] = val >> 8;
-	le[2] = val >> 16;
-	le[3] = val >> 24;
-}
 
 /*
  * Partition table entry
  *  - from the PReP spec
  */
 typedef struct partition_entry {
-    byte_t	boot_indicator;
-    byte_t	starting_head;
-    byte_t	starting_sector;
-    byte_t	starting_cylinder;
-
-    byte_t	system_indicator;
-    byte_t	ending_head;
-    byte_t	ending_sector;
-    byte_t	ending_cylinder;
+  byte_t	boot_indicator;
+  byte_t	starting_head;
+  byte_t	starting_sector;
+  byte_t	starting_cylinder;
+
+  byte_t	system_indicator;
+  byte_t	ending_head;
+  byte_t	ending_sector;
+  byte_t	ending_cylinder;
 
-    dword_t	beginning_sector;
-    dword_t	number_of_sectors;
+  dword_t	beginning_sector;
+  dword_t	number_of_sectors;
 } partition_entry_t;
 
 #define BootActive	0x80
 #define SystemPrep	0x41
 
+void copy_image(int , int);
+void write_prep_partition(int , int );
+void write_asm_data( int in, int out );
+
+unsigned int elfhdr_size = 65536;
 
 int main(int argc, char *argv[])
 {
-  struct stat info;
-  char buf[8192];
-  int in_fd, out_fd,len;
+  int in_fd, out_fd;
+  int argptr = 1;
+  unsigned int prep = 0;
+  unsigned int asmoutput = 0;
+
+  if ( (argc < 3) || (argc > 4) )
+  {
+    fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
+    exit(-1);
+  }
+
+  /* needs to handle args more elegantly -- but this is a small/simple program */
+  
+  /* check for -pbp */
+  if ( !strcmp( argv[argptr], "-pbp" ) )
+  {
+    prep = 1;
+    argptr++;
+  }
+  
+  /* check for -asm */
+  if ( !strcmp( argv[argptr], "-asm" ) )
+  {
+    asmoutput = 1;
+    argptr++;
+  }
+
+  /* input file */
+  if ( !strcmp( argv[argptr], "-" ) )
+    in_fd = 0;			/* stdin */
+  else
+    if ((in_fd = open( argv[argptr] , 0)) < 0)
+      exit(-1);
+  argptr++;
+
+  /* output file */
+  if ( !strcmp( argv[argptr], "-" ) )
+    out_fd = 1;			/* stdout */
+  else
+    if ((out_fd = creat( argv[argptr] , 0755)) < 0)
+      exit(-1);
+  argptr++;
+
+  /* skip elf header in input file */
+  lseek(in_fd, elfhdr_size, SEEK_SET);
+  
+  /* write prep partition if necessary */
+  if ( prep )
+    write_prep_partition( in_fd, out_fd );
+
+  /* write input image to bootimage */
+  if ( asmoutput )
+    write_asm_data( in_fd, out_fd );
+  else
+    copy_image(in_fd, out_fd);
+  
+  return 0;
+}
+
+void write_prep_partition(int in, int out)
+{
   unsigned char block[512];
   partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
-  dword_t *entry  = (dword_t *)&block[0x50];
-  dword_t *length = (dword_t *)&block[0x51];
+  dword_t *entry  = (dword_t *)&block[0];
+  dword_t *length = (dword_t *)&block[sizeof(long)];
+  struct stat info;
   
-  if (argc != 3)
-    {
-      fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
-      exit(1);
-    }
-  if ((in_fd = open(argv[1], 0)) < 0)
-    {
-      exit(2);
-    }
-  if ((out_fd = creat(argv[2], 0755)) < 0)
-    {
-      exit(2);
-    }
+  if (fstat(in, &info) < 0)
+  {
+    fprintf(stderr,"info failed\n");
+    exit(-1);
+  }
+  
+  bzero( block, sizeof block );
 
-  bzero( &block, sizeof block );
-    
+ 
+  /* set entry point and boot image size */
+  *entry = cpu_to_le32(0x400);
+  /* need use size - elfheader? */
+  *length = cpu_to_le32(info.st_size+0x400);
 
   /*
-   * Magic marker
+   * Writes the "boot record", which contains the partition table, to the
+   * diskette, followed by the dummy PC boot block and load image descriptor
+   * block.  It returns the number of bytes it has written to the load
+   * image.
+   *
+   * The boot record is the first block of the diskette and identifies the
+   * "PReP" partition.  The "PReP" partition contains the "load image" starting
+   * at offset zero within the partition.  The first block of the load image is
+   * a dummy PC boot block.  The second block is the "load image descriptor"
+   * which contains the size of the load image and the entry point into the
+   * image.  The actual boot image starts at offset 1024 bytes (third sector)
+   * in the partition.
    */
+  
+  /* sets magic number for msdos partition (used by linux) */
   block[510] = 0x55;
   block[511] = 0xAA;
   
+  /*
+   * Build a "PReP" partition table entry in the boot record
+   *  - "PReP" may only look at the system_indicator
+   */
   pe->boot_indicator   = BootActive;
   pe->system_indicator = SystemPrep;
-    pe->starting_head     = 0;		/* zero-based			     */
-    pe->starting_sector   = 2;		/* one-based			     */
-    pe->starting_cylinder = 0;		/* zero-based			     */
-
-    pe->ending_head       = 1;		/* assumes two heads		     */
-    pe->ending_sector     = 18;		/* assumes 18 sectors/track	     */
-    pe->ending_cylinder   = 79;		/* assumes 80 cylinders/diskette     */
+  /*
+   * The first block of the diskette is used by this "boot record" which
+   * actually contains the partition table. (The first block of the
+   * partition contains the boot image, but I digress...)  We'll set up
+   * one partition on the diskette and it shall contain the rest of the
+   * diskette.
+   */
+  pe->starting_head     = 0;	/* zero-based			     */
+  pe->starting_sector   = 2;	/* one-based			     */
+  pe->starting_cylinder = 0;	/* zero-based			     */
+  pe->ending_head       = 1;	/* assumes two heads		     */
+  pe->ending_sector     = 18;	/* assumes 18 sectors/track	     */
+  pe->ending_cylinder   = 79;	/* assumes 80 cylinders/diskette     */
 
+  /*
+   * The "PReP" software ignores the above fields and just looks at
+   * the next two.
+   *   - size of the diskette is (assumed to be)
+   *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+   *   - unlike the above sector numbers, the beginning sector is zero-based!
+   */
 #if 0
-#if 0    
-  pe->beginning_sector  = LeDword(1);
+  pe->beginning_sector  = cpu_to_le32(1);
 #else
-  /* This has to be 0 on the PowerStack? */
-  pe->beginning_sector  = LeDword(0);
-#endif
-  pe->number_of_sectors = LeDword(2*18*80-1);
-#endif
+  /* This has to be 0 on the PowerStack? */   
+  pe->beginning_sector  = cpu_to_le32(0);
+#endif    
+/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+
+  write( out, block, sizeof(block) );
+  write( out, entry, sizeof(*entry) );
+  write( out, length, sizeof(*length) );  
+  /* set file position to 2nd sector where image will be written */
+  lseek( out, 0x400, SEEK_SET );
+}
+
+
+
+void
+copy_image(int in, int out)
+{
+  char buf[SIZE];
+  int n;
+
+  while ( (n = read(in, buf, SIZE)) > 0 )
+    write(out, buf, n);
+}
+
+
+void
+write_asm_data( int in, int out )
+{
+  int i, cnt, pos, len;
+  unsigned int cksum, val;
+  unsigned char *lp;
+  unsigned char buf[SIZE];
+  unsigned char str[256];
   
-  if (fstat(in_fd, &info) < 0)
+  write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
+	 strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
+  pos = 0;
+  cksum = 0;
+  while ((len = read(in, buf, sizeof(buf))) > 0)
+  {
+    cnt = 0;
+    lp = (unsigned char *)buf;
+    len = (len + 3) & ~3;  /* Round up to longwords */
+    for (i = 0;  i < len;  i += 4)
     {
-      exit(4);
+      if (cnt == 0)
+      {
+	write( out, "\t.long\t", strlen( "\t.long\t" ) );
+      }
+      sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+      write( out, str, strlen(str) );
+      val = *(unsigned long *)lp;
+      cksum ^= val;
+      lp += 4;
+      if (++cnt == 4)
+      {
+	cnt = 0;
+	sprintf( str, " # %x \n", pos+i-12);
+	write( out, str, strlen(str) );
+      } else
+      {
+	write( out, ",", 1 );
+      }
     }
-  /* begin execution at 0x400 */
-  _LE(0x400,(unsigned char *)entry);
-  _LE(info.st_size+0x400,length);
-  
-  lseek( out_fd, 0, 0 );
-  /* write out 1st block */
-  write( out_fd, block, sizeof block );
-  
-  /* copy image */
-#if 1 
-	lseek(out_fd, 0x400, 0);
-	while ((len = read(in_fd, buf, sizeof(buf))) > 0)
-	{
-		if (write(out_fd, buf, len) != len)
-		{
-			exit(5);
-		}
-	}
-	if (len < 0)
-	{
-		exit(6);
-	}
-	close(in_fd);
-	close(out_fd);
-#endif	
-  return 0;
-}
+    if (cnt)
+    {
+      write( out, "0\n", 2 );
+    }
+    pos += len;
+  }
+  sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+  write( out, str, strlen(str) );
 
+  fprintf(stderr, "cksum = %x\n", cksum);
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/piggyback.c linux/arch/ppc/boot/piggyback.c
--- v2.1.47/linux/arch/ppc/boot/piggyback.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/piggyback.c	Wed Dec 31 16:00:00 1969
@@ -1,64 +0,0 @@
-#include <stdio.h>
-
-extern long ce_exec_config[];
-
-main(int argc, char *argv[])
-{
-	int i, cnt, pos, len;
-	unsigned int cksum, val;
-	unsigned char *lp;
-	unsigned char buf[8192];
-	if (argc != 1)
-	{
-		fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
-		exit(1);
-	}
-	fprintf(stdout, "#\n");
-	fprintf(stdout, "# Miscellaneous data structures:\n");
-	fprintf(stdout, "# WARNING - this file is automatically generated!\n");
-	fprintf(stdout, "#\n");
-	fprintf(stdout, "\n");
-	fprintf(stdout, "\t.data\n");
-	fprintf(stdout, "\t.globl input_data\n");
-	fprintf(stdout, "input_data:\n");
-	pos = 0;
-	cksum = 0;
-	while ((len = read(0, buf, sizeof(buf))) > 0)
-	{
-		cnt = 0;
-		lp = (unsigned char *)buf;
-		len = (len + 3) & ~3;  /* Round up to longwords */
-		for (i = 0;  i < len;  i += 4)
-		{
-			if (cnt == 0)
-			{
-				fprintf(stdout, "\t.long\t");
-			}
-			fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
-			val = *(unsigned long *)lp;
-			cksum ^= val;
-			lp += 4;
-			if (++cnt == 4)
-			{
-				cnt = 0;
-				fprintf(stdout, " # %x \n", pos+i-12);
-				fflush(stdout);
-			} else
-			{
-				fprintf(stdout, ",");
-			}
-		}
-		if (cnt)
-		{
-			fprintf(stdout, "0\n");
-		}
-		pos += len;
-	}
-	fprintf(stdout, "\t.globl input_len\n");
-	fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
-	fflush(stdout);
-	fclose(stdout);
-	fprintf(stderr, "cksum = %x\n", cksum);
-	exit(0);
-}
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/unzip.c linux/arch/ppc/boot/unzip.c
--- v2.1.47/linux/arch/ppc/boot/unzip.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/unzip.c	Thu Jul 31 13:09:17 1997
@@ -17,7 +17,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
+static char rcsid[] = "$Id: unzip.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
 #endif
 
 #include "gzip.h"
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/boot/vreset.c linux/arch/ppc/boot/vreset.c
--- v2.1.47/linux/arch/ppc/boot/vreset.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/boot/vreset.c	Thu Jul 31 13:09:17 1997
@@ -7,6 +7,864 @@
  *                                      Steve Sellgren
  *                                      San Francisco Indigo Company
  *                                      sfindigo!sellgren@uunet.uu.net
+ *
+ * Original concept by:
+ *                                      Gary Thomas <gdt@linuxppc.org>
+ * Adapted for Moto boxes by:
+ *                                      Pat Kane & Mark Scott, 1996
+ * Adapted for IBM portables by:
+ *                                      Takeshi Ishimoto
+ * Multi-console support:
+ *                                      Terje Malmedal <terje.malmedal@usit.uio.no>
+ */
+
+#include "iso_font.h"
+#include <linux/delay.h>
+
+extern char *vidmem;
+extern int lines, cols;
+/* estimate for delay */
+unsigned long loops_per_sec = 50000000;;
+/*
+ * VGA Register  
+ */
+struct VgaRegs
+{
+	unsigned short io_port;
+	unsigned char  io_index;
+	unsigned char  io_value;
+};
+
+/*
+ * Default console text mode registers  used to reset
+ * graphics adapter.
+ */
+#define NREGS 54
+#define ENDMK  0xFFFF  /* End marker */
+
+#define S3Vendor        0x5333
+#define CirrusVendor    0x1013
+#define DiamondVendor   0x100E
+#define MatroxVendor    0x102B
+#define ParadiseVendor  0x101C
+
+struct VgaRegs GenVgaTextRegs[NREGS+1] = {
+/*      port    index   value  */
+  /* SR Regs */
+        0x3c4,  0x1,    0x0,
+        0x3c4,  0x2,    0x3,
+        0x3c4,  0x3,    0x0,
+        0x3c4,  0x4,    0x2,
+   /* CR Regs */
+        0x3d4,  0x0,    0x5f,
+        0x3d4,  0x1,    0x4f,
+        0x3d4,  0x2,    0x50,
+        0x3d4,  0x3,    0x82,
+        0x3d4,  0x4,    0x55,
+        0x3d4,  0x5,    0x81,
+        0x3d4,  0x6,    0xbf,
+        0x3d4,  0x7,    0x1f,
+        0x3d4,  0x8,    0x00,
+        0x3d4,  0x9,    0x4f,
+        0x3d4,  0xa,    0x0d,
+        0x3d4,  0xb,    0x0e,
+        0x3d4,  0xc,    0x00,
+        0x3d4,  0xd,    0x00,
+        0x3d4,  0xe,    0x00,
+        0x3d4,  0xf,    0x00,
+        0x3d4,  0x10,   0x9c,
+        0x3d4,  0x11,   0x8e,
+        0x3d4,  0x12,   0x8f,
+        0x3d4,  0x13,   0x28,
+        0x3d4,  0x14,   0x1f,
+        0x3d4,  0x15,   0x96,
+        0x3d4,  0x16,   0xb9,
+        0x3d4,  0x17,   0xa3,
+   /* GR Regs */
+        0x3ce,  0x0,    0x0,
+        0x3ce,  0x1,    0x0,
+        0x3ce,  0x2,    0x0,
+        0x3ce,  0x3,    0x0,
+        0x3ce,  0x4,    0x0,
+        0x3ce,  0x5,    0x10,
+        0x3ce,  0x6,    0xe,
+        0x3ce,  0x7,    0x0,
+        0x3ce,  0x8,    0xff,
+        ENDMK
+};
+
+struct VgaRegs S3TextRegs[NREGS+1] = {
+/*	port	index	value  */
+  /* SR Regs */
+	0x3c4,	0x1,	0x0,
+	0x3c4,	0x2,	0x3,
+	0x3c4,	0x3,	0x0,
+	0x3c4,	0x4,	0x2,
+   /* CR Regs */
+	0x3d4,	0x0,	0x5f,
+	0x3d4,	0x1,	0x4f,
+	0x3d4,	0x2,	0x50,
+	0x3d4,	0x3,	0x82,
+	0x3d4,	0x4,	0x55,
+	0x3d4,	0x5,	0x81,
+	0x3d4,	0x6,	0xbf,
+	0x3d4,	0x7,	0x1f,
+	0x3d4,	0x8,	0x00,
+	0x3d4,	0x9,	0x4f,
+	0x3d4,	0xa,	0x0d,
+	0x3d4,	0xb,	0x0e,
+	0x3d4,	0xc,	0x00,
+	0x3d4,	0xd,	0x00,
+	0x3d4,	0xe,	0x00,
+	0x3d4,	0xf,	0x00,
+	0x3d4,	0x10,	0x9c,
+	0x3d4,	0x11,	0x8e,
+	0x3d4,	0x12,	0x8f,
+	0x3d4,	0x13,	0x28,
+	0x3d4,	0x14,	0x1f,
+	0x3d4,	0x15,	0x96,
+	0x3d4,	0x16,	0xb9,
+	0x3d4,	0x17,	0xa3,
+   /* GR Regs */
+	0x3ce,	0x0,	0x0,
+	0x3ce,	0x1,	0x0,
+	0x3ce,	0x2,	0x0,
+	0x3ce,	0x3,	0x0,
+	0x3ce,	0x4,	0x0,
+	0x3ce,	0x5,	0x10,
+	0x3ce,	0x6,	0xe,
+	0x3ce,	0x7,	0x0,
+	0x3ce,	0x8,	0xff,
+        ENDMK
+};
+
+struct RGBColors
+{
+  unsigned char r, g, b;
+};
+
+/*
+ * Default console text mode color table.
+ * These values were obtained by booting Linux with
+ * text mode firmware & then dumping the registers.  
+ */
+struct RGBColors TextCLUT[256] = 
+{
+  /*	red	green	blue  */
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x2a,
+	0x0,	0x2a,	0x0,
+	0x0,	0x2a,	0x2a,
+	0x2a,	0x0,	0x0,
+	0x2a,	0x0,	0x2a,
+	0x2a,	0x2a,	0x0,
+	0x2a,	0x2a,	0x2a,
+	0x0,	0x0,	0x15,
+	0x0,	0x0,	0x3f,
+	0x0,	0x2a,	0x15,
+	0x0,	0x2a,	0x3f,
+	0x2a,	0x0,	0x15,
+	0x2a,	0x0,	0x3f,
+	0x2a,	0x2a,	0x15,
+	0x2a,	0x2a,	0x3f,
+	0x0,	0x15,	0x0,
+	0x0,	0x15,	0x2a,
+	0x0,	0x3f,	0x0,
+	0x0,	0x3f,	0x2a,
+	0x2a,	0x15,	0x0,
+	0x2a,	0x15,	0x2a,
+	0x2a,	0x3f,	0x0,
+	0x2a,	0x3f,	0x2a,
+	0x0,	0x15,	0x15,
+	0x0,	0x15,	0x3f,
+	0x0,	0x3f,	0x15,
+	0x0,	0x3f,	0x3f,
+	0x2a,	0x15,	0x15,
+	0x2a,	0x15,	0x3f,
+	0x2a,	0x3f,	0x15,
+	0x2a,	0x3f,	0x3f,
+	0x15,	0x0,	0x0,
+	0x15,	0x0,	0x2a,
+	0x15,	0x2a,	0x0,
+	0x15,	0x2a,	0x2a,
+	0x3f,	0x0,	0x0,
+	0x3f,	0x0,	0x2a,
+	0x3f,	0x2a,	0x0,
+	0x3f,	0x2a,	0x2a,
+	0x15,	0x0,	0x15,
+	0x15,	0x0,	0x3f,
+	0x15,	0x2a,	0x15,
+	0x15,	0x2a,	0x3f,
+	0x3f,	0x0,	0x15,
+	0x3f,	0x0,	0x3f,
+	0x3f,	0x2a,	0x15,
+	0x3f,	0x2a,	0x3f,
+	0x15,	0x15,	0x0,
+	0x15,	0x15,	0x2a,
+	0x15,	0x3f,	0x0,
+	0x15,	0x3f,	0x2a,
+	0x3f,	0x15,	0x0,
+	0x3f,	0x15,	0x2a,
+	0x3f,	0x3f,	0x0,
+	0x3f,	0x3f,	0x2a,
+	0x15,	0x15,	0x15,
+	0x15,	0x15,	0x3f,
+	0x15,	0x3f,	0x15,
+	0x15,	0x3f,	0x3f,
+	0x3f,	0x15,	0x15,
+	0x3f,	0x15,	0x3f,
+	0x3f,	0x3f,	0x15,
+	0x3f,	0x3f,	0x3f,
+	0x39,	0xc,	0x5,
+	0x15,	0x2c,	0xf,
+	0x26,	0x10,	0x3d,
+	0x29,	0x29,	0x38,
+	0x4,	0x1a,	0xe,
+	0x2,	0x1e,	0x3a,
+	0x3c,	0x25,	0x33,
+	0x3c,	0xc,	0x2c,
+	0x3f,	0x3,	0x2b,
+	0x1c,	0x9,	0x13,
+	0x25,	0x2a,	0x35,
+	0x1e,	0xa,	0x38,
+	0x24,	0x8,	0x3,
+	0x3,	0xe,	0x36,
+	0xc,	0x6,	0x2a,
+	0x26,	0x3,	0x32,
+	0x5,	0x2f,	0x33,
+	0x3c,	0x35,	0x2f,
+	0x2d,	0x26,	0x3e,
+	0xd,	0xa,	0x10,
+	0x25,	0x3c,	0x11,
+	0xd,	0x4,	0x2e,
+	0x5,	0x19,	0x3e,
+	0xc,	0x13,	0x34,
+	0x2b,	0x6,	0x24,
+	0x4,	0x3,	0xd,
+	0x2f,	0x3c,	0xc,
+	0x2a,	0x37,	0x1f,
+	0xf,	0x12,	0x38,
+	0x38,	0xe,	0x2a,
+	0x12,	0x2f,	0x19,
+	0x29,	0x2e,	0x31,
+	0x25,	0x13,	0x3e,
+	0x33,	0x3e,	0x33,
+	0x1d,	0x2c,	0x25,
+	0x15,	0x15,	0x5,
+	0x32,	0x25,	0x39,
+	0x1a,	0x7,	0x1f,
+	0x13,	0xe,	0x1d,
+	0x36,	0x17,	0x34,
+	0xf,	0x15,	0x23,
+	0x2,	0x35,	0xd,
+	0x15,	0x3f,	0xc,
+	0x14,	0x2f,	0xf,
+	0x19,	0x21,	0x3e,
+	0x27,	0x11,	0x2f,
+	0x38,	0x3f,	0x3c,
+	0x36,	0x2d,	0x15,
+	0x16,	0x17,	0x2,
+	0x1,	0xa,	0x3d,
+	0x1b,	0x11,	0x3f,
+	0x21,	0x3c,	0xd,
+	0x1a,	0x39,	0x3d,
+	0x8,	0xe,	0xe,
+	0x22,	0x21,	0x23,
+	0x1e,	0x30,	0x5,
+	0x1f,	0x22,	0x3d,
+	0x1e,	0x2f,	0xa,
+	0x0,	0x1c,	0xe,
+	0x0,	0x1c,	0x15,
+	0x0,	0x1c,	0x1c,
+	0x0,	0x15,	0x1c,
+	0x0,	0xe,	0x1c,
+	0x0,	0x7,	0x1c,
+	0xe,	0xe,	0x1c,
+	0x11,	0xe,	0x1c,
+	0x15,	0xe,	0x1c,
+	0x18,	0xe,	0x1c,
+	0x1c,	0xe,	0x1c,
+	0x1c,	0xe,	0x18,
+	0x1c,	0xe,	0x15,
+	0x1c,	0xe,	0x11,
+	0x1c,	0xe,	0xe,
+	0x1c,	0x11,	0xe,
+	0x1c,	0x15,	0xe,
+	0x1c,	0x18,	0xe,
+	0x1c,	0x1c,	0xe,
+	0x18,	0x1c,	0xe,
+	0x15,	0x1c,	0xe,
+	0x11,	0x1c,	0xe,
+	0xe,	0x1c,	0xe,
+	0xe,	0x1c,	0x11,
+	0xe,	0x1c,	0x15,
+	0xe,	0x1c,	0x18,
+	0xe,	0x1c,	0x1c,
+	0xe,	0x18,	0x1c,
+	0xe,	0x15,	0x1c,
+	0xe,	0x11,	0x1c,
+	0x14,	0x14,	0x1c,
+	0x16,	0x14,	0x1c,
+	0x18,	0x14,	0x1c,
+	0x1a,	0x14,	0x1c,
+	0x1c,	0x14,	0x1c,
+	0x1c,	0x14,	0x1a,
+	0x1c,	0x14,	0x18,
+	0x1c,	0x14,	0x16,
+	0x1c,	0x14,	0x14,
+	0x1c,	0x16,	0x14,
+	0x1c,	0x18,	0x14,
+	0x1c,	0x1a,	0x14,
+	0x1c,	0x1c,	0x14,
+	0x1a,	0x1c,	0x14,
+	0x18,	0x1c,	0x14,
+	0x16,	0x1c,	0x14,
+	0x14,	0x1c,	0x14,
+	0x14,	0x1c,	0x16,
+	0x14,	0x1c,	0x18,
+	0x14,	0x1c,	0x1a,
+	0x14,	0x1c,	0x1c,
+	0x14,	0x1a,	0x1c,
+	0x14,	0x18,	0x1c,
+	0x14,	0x16,	0x1c,
+	0x0,	0x0,	0x10,
+	0x4,	0x0,	0x10,
+	0x8,	0x0,	0x10,
+	0xc,	0x0,	0x10,
+	0x10,	0x0,	0x10,
+	0x10,	0x0,	0xc,
+	0x10,	0x0,	0x8,
+	0x10,	0x0,	0x4,
+	0x10,	0x0,	0x0,
+	0x10,	0x4,	0x0,
+	0x10,	0x8,	0x0,
+	0x10,	0xc,	0x0,
+	0x10,	0x10,	0x0,
+	0xc,	0x10,	0x0,
+	0x8,	0x10,	0x0,
+	0x4,	0x10,	0x0,
+	0x0,	0x10,	0x0,
+	0x0,	0x10,	0x4,
+	0x0,	0x10,	0x8,
+	0x0,	0x10,	0xc,
+	0x0,	0x10,	0x10,
+	0x0,	0xc,	0x10,
+	0x0,	0x8,	0x10,
+	0x0,	0x4,	0x10,
+	0x8,	0x8,	0x10,
+	0xa,	0x8,	0x10,
+	0xc,	0x8,	0x10,
+	0xe,	0x8,	0x10,
+	0x10,	0x8,	0x10,
+	0x10,	0x8,	0xe,
+	0x10,	0x8,	0xc,
+	0x10,	0x8,	0xa,
+	0x10,	0x8,	0x8,
+	0x10,	0xa,	0x8,
+	0x10,	0xc,	0x8,
+	0x10,	0xe,	0x8,
+	0x10,	0x10,	0x8,
+	0xe,	0x10,	0x8,
+	0xc,	0x10,	0x8,
+	0xa,	0x10,	0x8,
+	0x8,	0x10,	0x8,
+	0x8,	0x10,	0xa,
+	0x8,	0x10,	0xc,
+	0x8,	0x10,	0xe,
+	0x8,	0x10,	0x10,
+	0x8,	0xe,	0x10,
+	0x8,	0xc,	0x10,
+	0x8,	0xa,	0x10,
+	0xb,	0xb,	0x10,
+	0xc,	0xb,	0x10,
+	0xd,	0xb,	0x10,
+	0xf,	0xb,	0x10,
+	0x10,	0xb,	0x10,
+	0x10,	0xb,	0xf,
+	0x10,	0xb,	0xd,
+	0x10,	0xb,	0xc,
+	0x10,	0xb,	0xb,
+	0x10,	0xc,	0xb,
+	0x10,	0xd,	0xb,
+	0x10,	0xf,	0xb,
+	0x10,	0x10,	0xb,
+	0xf,	0x10,	0xb,
+	0xd,	0x10,	0xb,
+	0xc,	0x10,	0xb,
+	0xb,	0x10,	0xb,
+	0xb,	0x10,	0xc,
+	0xb,	0x10,	0xd,
+	0xb,	0x10,	0xf,
+	0xb,	0x10,	0x10,
+	0xb,	0xf,	0x10,
+	0xb,	0xd,	0x10,
+	0xb,	0xc,	0x10,
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x0,
+	0x0,	0x0,	0x0
+};
+
+unsigned char AC[21] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 
+    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+    0x0C, 0x00, 0x0F, 0x08, 0x00};
+
+static int scanPCI(int start_slt);
+static int PCIVendor(int);
+static void printslots(void);
+int delayLoop(int);
+extern void puthex(unsigned long);
+extern void puts(const char *);
+static void unlockS3(void);
+
+static inline
+outw(int port, unsigned short val)
+{
+	outb(port, val >> 8);
+	outb(port+1, val);
+}
+ 
+#define PPC_601 1
+
+vga_init(unsigned char *ISA_mem)
+{
+	int slot;
+	struct VgaRegs *VgaTextRegs;
+
+	if ((_get_PVR()>>16) == PPC_601) {
+		return(old_vga_init(ISA_mem));
+	}
+
+#if 1
+	/* See if VGA already in TEXT mode - exit if so! */
+	outb(0x3CE, 0x06);
+	if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;}
+#endif
+
+	/* If no VGA responding in text mode, then we have some work to do...
+	 */
+	slot = -1;
+	while((slot = scanPCI(slot)) > -1) { /* find video card in use  */
+		unlockVideo(slot);           /* enable I/O to card      */
+		VgaTextRegs = GenVgaTextRegs;
+	
+		switch (PCIVendor(slot)) {
+		default:
+			break;
+		case(S3Vendor):
+			unlockS3();
+			VgaTextRegs = S3TextRegs;
+			break;
+	
+		case(CirrusVendor):
+			outw(0x3C4, 0x0612);       /* unlock ext regs */
+			outw(0x3C4, 0x0700);       /* reset ext sequence mode */
+			break;
+	
+		case(ParadiseVendor):                 /* IBM Portable 850 */
+			outw(0x3ce, 0x0f05);      /* unlock pardise registers */
+			outw(0x3c4, 0x0648);
+			outw(0x3d4, 0x2985);
+			outw(0x3d4, 0x34a6);
+			outb(0x3ce, 0x0b);       /* disable linear addressing */
+			outb(0x3cf, inb(0x3cf) & ~0x30);
+			outw(0x3c4, 0x1400);
+			outb(0x3ce, 0x0e);       /* disable 256 color mode */
+			outb(0x3cf, inb(0x3cf) & ~0x01);
+			outb(0xd00, 0xff);       /* enable auto-centering */
+			if (!(inb(0xd01) & 0x03)) {
+				outb(0x3d4, 0x33);
+				outb(0x3d5, inb(0x3d5) & ~0x90);
+				outb(0x3d4, 0x32);
+				outb(0x3d5, inb(0x3d5) | 0x04);
+				outw(0x3d4, 0x0250);
+				outw(0x3d4, 0x07ba);
+				outw(0x3d4, 0x0900);
+				outw(0x3d4, 0x15e7);
+				outw(0x3d4, 0x2a95);
+			}
+			outw(0x3d4, 0x34a0);
+			break;
+	
+	#if 0 /* Untested - probably doesn't work */
+		case(MatroxVendor):
+		case(DiamondVendor):
+			puts("VGA Chip Vendor ID: ");
+			puthex(PCIVendor(slot));
+			puts("\n");
+			delayLoop(1);
+	#endif
+		};
+	
+		outw(0x3C4, 0x0120);           /* disable video              */
+		setTextRegs(VgaTextRegs);      /* initial register setup     */
+		setTextCLUT(0);                /* load color lookup table    */
+		loadFont(ISA_mem);             /* load font                  */
+		setTextRegs(VgaTextRegs);      /* reload registers           */
+		outw(0x3C4, 0x0100);           /* re-enable video            */
+		clearVideoMemory();
+	
+		if (PCIVendor(slot) == S3Vendor) {
+			outb(0x3c2, 0x63);                  /* MISC */
+		} /* endif */
+	
+	#ifdef DEBUG
+		printslots();
+		delayLoop(5);	
+	#endif
+	
+		delayLoop(1);	/* give time for the video monitor to come up */
+        }
+	return (1);  /* 'CRT' I/O supported */
+}
+
+static int
+NOP(int x)
+{
+}
+
+/*
+ * Write to VGA Attribute registers.  
+ */
+writeAttr(index, data, videoOn)
+     unsigned char index;
+     unsigned char data;
+     unsigned char videoOn;   /* video on flag */
+{
+	unsigned char v;
+	v = inb(0x3da);   /* reset attr. address toggle */
+	if (videoOn)
+		outb(0x3c0, (index & 0x1F) | 0x20);
+	else
+		outb(0x3c0, (index & 0x1F));
+	outb(0x3c0, data);
+}
+
+setTextRegs(struct VgaRegs *svp)
+{
+	int i;
+
+	/*
+	 *  saved settings
+	 */ 
+	while( svp->io_port != ENDMK ) {
+		outb(svp->io_port,   svp->io_index);
+		outb(svp->io_port+1, svp->io_value);
+		svp++; 
+	}
+
+	outb(0x3c2, 0x67);  /* MISC */
+	outb(0x3c6, 0xff);  /* MASK */
+
+	for ( i = 0; i < 0x10; i++)
+		writeAttr(i, AC[i], 0);  /* pallete */ 
+	writeAttr(0x10, 0x0c, 0);    /* text mode */
+	writeAttr(0x11, 0x00, 0);    /* overscan color (border) */
+	writeAttr(0x12, 0x0f, 0);    /* plane enable */
+	writeAttr(0x13, 0x08, 0);    /* pixel panning */
+	writeAttr(0x14, 0x00, 1);    /* color select; video on  */
+}
+
+setTextCLUT(int shift)
+{
+	int i;
+
+	outb(0x3C6, 0xFF); 
+	i = inb(0x3C7);
+	outb(0x3C8, 0); 
+	i = inb(0x3C7);
+
+	for ( i = 0; i < 256; i++) {
+		outb(0x3C9, TextCLUT[i].r << shift);
+		outb(0x3C9, TextCLUT[i].g << shift);
+		outb(0x3C9, TextCLUT[i].b << shift);
+	}
+}
+
+
+loadFont(unsigned char *ISA_mem)
+{
+	int i, j;
+	unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+    
+	outb(0x3C2, 0x67);
+	/* 
+	 * Load font 
+	 */
+	i = inb(0x3DA);  /* Reset Attr toggle */
+
+	outb(0x3C0,0x30); 
+	outb(0x3C0, 0x01);      /* graphics mode */
+
+	outw(0x3C4, 0x0001);    /* reset sequencer */
+	outw(0x3C4, 0x0204);    /* write to plane 2 */
+	outw(0x3C4, 0x0406);    /* enable plane graphics */
+	outw(0x3C4, 0x0003);    /* reset sequencer */
+	outw(0x3CE, 0x0402);    /* read plane 2 */
+	outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
+	outw(0x3CE, 0x0605);    /* set graphics mode */
+
+	for (i = 0;  i < sizeof(font);  i += 16) {
+		for (j = 0;  j < 16;  j++) {
+			__asm__ volatile("eieio");
+			font_page[(2*i)+j] = font[i+j];
+		}
+	}
+}
+
+static void
+unlockS3(void)
+{
+        int s3_device_id;
+	outw(0x3d4, 0x3848);
+	outw(0x3d4, 0x39a5);
+	outb(0x3d4, 0x2d);
+	s3_device_id = inb(0x3d5) << 8;
+	outb(0x3d4, 0x2e);
+	s3_device_id |= inb(0x3d5);
+
+	if (s3_device_id != 0x8812) {
+		/* From the S3 manual */
+		outb(0x46E8, 0x10);  /* Put into setup mode */
+		outb(0x3C3, 0x10);
+		outb(0x102, 0x01);   /* Enable registers */
+		outb(0x46E8, 0x08);  /* Enable video */
+		outb(0x3C3, 0x08);
+		outb(0x4AE8, 0x00);
+
+#if 0
+		outb(0x42E8, 0x80);  /* Reset graphics engine? */
+#endif
+
+		outb(0x3D4, 0x38);  /* Unlock all registers */
+		outb(0x3D5, 0x48);
+		outb(0x3D4, 0x39);
+		outb(0x3D5, 0xA5);
+		outb(0x3D4, 0x40);
+		outb(0x3D5, inb(0x3D5)|0x01);
+		outb(0x3D4, 0x33);
+		outb(0x3D5, inb(0x3D5)&~0x52);
+		outb(0x3D4, 0x35);
+		outb(0x3D5, inb(0x3D5)&~0x30);
+		outb(0x3D4, 0x3A);
+		outb(0x3D5, 0x00);
+		outb(0x3D4, 0x53);
+		outb(0x3D5, 0x00);
+		outb(0x3D4, 0x31);
+		outb(0x3D5, inb(0x3D5)&~0x4B);
+		outb(0x3D4, 0x58);
+
+		outb(0x3D5, 0);
+
+		outb(0x3D4, 0x54);
+		outb(0x3D5, 0x38);
+		outb(0x3D4, 0x60);
+		outb(0x3D5, 0x07);
+		outb(0x3D4, 0x61);
+		outb(0x3D5, 0x80);
+		outb(0x3D4, 0x62);
+		outb(0x3D5, 0xA1);
+		outb(0x3D4, 0x69);  /* High order bits for cursor address */
+		outb(0x3D5, 0);
+
+		outb(0x3D4, 0x32);
+		outb(0x3D5, inb(0x3D5)&~0x10);
+	} else {
+                outw(0x3c4, 0x0806);            /* IBM Portable 860 */
+                outw(0x3c4, 0x1041);
+                outw(0x3c4, 0x1128);
+                outw(0x3d4, 0x4000);
+                outw(0x3d4, 0x3100);
+                outw(0x3d4, 0x3a05);
+                outw(0x3d4, 0x6688);
+                outw(0x3d4, 0x5800);            /* disable linear addressing */
+                outw(0x3d4, 0x4500);            /* disable H/W cursor */
+                outw(0x3c4, 0x5410);            /* enable auto-centering */
+                outw(0x3c4, 0x561f);
+                outw(0x3c4, 0x1b80);            /* lock DCLK selection */
+                outw(0x3d4, 0x3900);            /* lock S3 registers */
+                outw(0x3d4, 0x3800);
+	} /* endif */
+}
+
+/*
+ * cursor() sets an offset (0-1999) into the 80x25 text area   
+ */
+void
+cursor(int x, int y)
+{
+	int pos = (y*cols)+x;
+	outb(0x3D4, 14);
+	outb(0x3D5, pos >> 8);
+	outb(0x3D4, 15);
+	outb(0x3D5, pos);
+}
+
+clearVideoMemory()
+{
+	int i, j;
+	for (i = 0;  i < lines;  i++) {
+		for (j = 0;  j < cols;  j++) {
+			vidmem[((i*cols)+j)*2] = 0x20;	/* fill with space character */
+			vidmem[((i*cols)+j)*2+1] = 0x07;  /* set bg & fg attributes */
+		}
+	}
+}
+
+/* ============ */
+
+
+#define NSLOTS 8
+#define NPCIREGS  5
+
+
+/* 
+ should use devfunc number/indirect method to be totally safe on 
+ all machines, this works for now on 3 slot Moto boxes 
+*/
+
+struct PCI_ConfigInfo {
+  unsigned long * config_addr;
+  unsigned long regs[NPCIREGS];  
+} PCI_slots [NSLOTS] = {
+
+    { (unsigned long *)0x80808000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80800800, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80801000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80802000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80804000, 0xDEADBEEF },   /* onboard */
+    { (unsigned long *)0x80810000, 0xDEADBEEF },   /* slot A/1 */
+    { (unsigned long *)0x80820000, 0xDEADBEEF },   /* slot B/2 */
+    { (unsigned long *)0x80840000, 0xDEADBEEF }    /* slot C/3 */
+};
+
+
+
+/*
+ * The following code modifies the PCI Command register
+ * to enable memory and I/O accesses.    
+ */ 
+unlockVideo(slot)        
+{
+       volatile unsigned char * ppci;
+
+        ppci =  (unsigned char * )PCI_slots[slot].config_addr;
+	ppci[4] = 0x0003;         /* enable memory and I/O accesses */
+	ppci[0x10] = 0x00000;     /* turn off memory mapping */
+	ppci[0x11] = 0x00000;     /* mem_base = 0 */
+	ppci[0x12] = 0x00000;
+	ppci[0x13] = 0x00000;
+	__asm__ volatile("eieio");
+
+	outb(0x3d4, 0x11);
+	outb(0x3d5, 0x0e);   /* unlock CR0-CR7 */
+}
+
+long
+SwapBytes(long lv)   /* turn little endian into big indian long */
+{
+    long t;
+    t  = (lv&0x000000FF) << 24;
+    t |= (lv&0x0000FF00) << 8;
+    t |= (lv&0x00FF0000) >> 8;
+    t |= (lv&0xFF000000) >> 24;
+    return(t);
+}
+
+
+#define DEVID   0
+#define CMD     1
+#define CLASS   2
+#define MEMBASE 4
+
+int
+scanPCI(int start_slt)
+{
+	int slt, r;
+	struct PCI_ConfigInfo *pslot;
+	int theSlot = -1;
+	int highVgaSlot = 0;
+
+	for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
+		pslot = &PCI_slots[slt];
+		for ( r = 0; r < NPCIREGS; r++) {
+			pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
+		}
+		/* card in slot ? */
+		if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {     
+			/* VGA ? */
+			if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) || 
+			     ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
+				highVgaSlot = slt;
+				/* did firmware enable it ? */
+				if ( (pslot->regs[CMD] & 0x03) ) { 
+					theSlot = slt;
+					break;
+				}
+			}
+		}
+	}
+
+	return ( theSlot );
+}
+
+/* Delay for a certain number of seconds */
+/* Note: They loop is used since 'udelay' can't handle really long counts! */
+
+int
+delayLoop(int k)
+{
+	int i;
+	while (k-- > 0) {
+		for (i = 0;  i < 1000;  i++) {
+			udelay(1000);
+		}
+	}
+}
+
+
+/* return Vendor ID of card in the slot */
+static
+int PCIVendor(int slotnum) {
+ struct PCI_ConfigInfo *pslot;
+
+ pslot = &PCI_slots[slotnum];
+
+return (pslot->regs[DEVID] & 0xFFFF);
+}
+
+static
+void printslots(void) 
+{
+	int i;
+	struct PCI_ConfigInfo *pslot;
+	for(i=0; i < NSLOTS; i++) {
+#if 0
+		pslot = &PCI_slots[i];
+		printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
+		       i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
+#else
+		puts("PCI Slot number: "); puthex(i);
+		puts(" Vendor ID: "); 
+		puthex(PCIVendor(i)); puts("\n");
+#endif
+
+	}
+}
+
+/*
+ * OLD vreset.c
+ *
+ * Initialize the VGA control registers to 80x25 text mode.
+ *
+ * Adapted from a program by:
+ *                                      Steve Sellgren
+ *                                      San Francisco Indigo Company
+ *                                      sfindigo!sellgren@uunet.uu.net
  */
  
 unsigned char CRTC[24] = {
@@ -15,13 +873,8 @@
     0x9C, 0xAE, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3};
 unsigned char SEQ[5] = {0x3, 0x0, 0x3, 0x0, 0x2};
 unsigned char GC[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0xE, 0x0, 0xFF};
-unsigned char AC[21] = {
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 
-    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
-    0x0C, 0x00, 0x0F, 0x08, 0x00};
-
-#include "iso_font.h"
 
+#if 0
 static const unsigned char color_LUT[] =
    {
 	0x00, 0x00, 0x00, /* 0 - black */
@@ -41,124 +894,124 @@
 	0x2A, 0x2A, 0x15, /* 14 - yellow */
 	0x2A, 0x2A, 0x3F, /* 15 - bright white */
    };
-
-static inline
-outw(int port, unsigned short val)
-{
-	outb(port, val >> 8);
-	outb(port+1, val);
-}
+#endif
  
-vga_init(unsigned char *ISA_mem)
+old_vga_init(unsigned char *ISA_mem)
 {
-  int i, j;
-  int value;
-  unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
-
-  /* See if VGA already in TEXT mode - exit if so! */
-  outb(0x3CE, 0x06);
-  if ((inb(0x3CF) & 0x01) == 0) return;
+	int i, j;
+	int value;
+	unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+
+	/* See if VGA already in TEXT mode - exit if so! */
+	outb(0x3CE, 0x06);
+	if ((inb(0x3CF) & 0x01) == 0) return;
     
-  /* From the S3 manual */
-  outb(0x46E8, 0x10);  /* Put into setup mode */
-  outb(0x3C3, 0x10);
-  outb(0x102, 0x01);   /* Enable registers */
-  outb(0x46E8, 0x08);  /* Enable video */
-  outb(0x3C3, 0x08);
-  outb(0x4AE8, 0x00);
-
-  outb(0x42E8, 0x80);  /* Reset graphics engine? */
-
-  outb(0x3D4, 0x38);  /* Unlock all registers */
-  outb(0x3D5, 0x48);
-  outb(0x3D4, 0x39);
-  outb(0x3D5, 0xA5);
-  outb(0x3D4, 0x40);
-  outb(0x3D5, inb(0x3D5)|0x01);
-  outb(0x3D4, 0x33);
-  outb(0x3D5, inb(0x3D5)&~0x52);
-  outb(0x3D4, 0x35);
-  outb(0x3D5, inb(0x3D5)&~0x30);
-  outb(0x3D4, 0x3A);
-  outb(0x3D5, 0x00);
-  outb(0x3D4, 0x53);
-  outb(0x3D5, 0x00);
-  outb(0x3D4, 0x31);
-  outb(0x3D5, inb(0x3D5)&~0x4B);
-  outb(0x3D4, 0x58);
-  outb(0x3D5, 0);
-
-  outb(0x3D4, 0x54);
-  outb(0x3D5, 0x38);
-  outb(0x3D4, 0x60);
-  outb(0x3D5, 0x07);
-  outb(0x3D4, 0x61);
-  outb(0x3D5, 0x80);
-  outb(0x3D4, 0x62);
-  outb(0x3D5, 0xA1);
-  outb(0x3D4, 0x69);  /* High order bits for cursor address */
-  outb(0x3D5, 0);
+	/* From the S3 manual */
+	outb(0x46E8, 0x10);  /* Put into setup mode */
+	outb(0x3C3, 0x10);
+	outb(0x102, 0x01);   /* Enable registers */
+	outb(0x46E8, 0x08);  /* Enable video */
+	outb(0x3C3, 0x08);
+	outb(0x4AE8, 0x00);
+
+#if 0
+	outb(0x42E8, 0x80);  /* Reset graphics engine? */
+#endif
+
+	outb(0x3D4, 0x38);  /* Unlock all registers */
+	outb(0x3D5, 0x48);
+	outb(0x3D4, 0x39);
+	outb(0x3D5, 0xA5);
+	outb(0x3D4, 0x40);
+	outb(0x3D5, inb(0x3D5)|0x01);
+	outb(0x3D4, 0x33);
+	outb(0x3D5, inb(0x3D5)&~0x52);
+	outb(0x3D4, 0x35);
+	outb(0x3D5, inb(0x3D5)&~0x30);
+	outb(0x3D4, 0x3A);
+	outb(0x3D5, 0x00);
+	outb(0x3D4, 0x53);
+	outb(0x3D5, 0x00);
+	outb(0x3D4, 0x31);
+	outb(0x3D5, inb(0x3D5)&~0x4B);
+	outb(0x3D4, 0x58);
+	outb(0x3D5, 0);
+
+	outb(0x3D4, 0x54);
+	outb(0x3D5, 0x38);
+	outb(0x3D4, 0x60);
+	outb(0x3D5, 0x07);
+	outb(0x3D4, 0x61);
+	outb(0x3D5, 0x80);
+	outb(0x3D4, 0x62);
+	outb(0x3D5, 0xA1);
+	outb(0x3D4, 0x69);  /* High order bits for cursor address */
+	outb(0x3D5, 0);
   
-  outb(0x3D4, 0x32);
-  outb(0x3D5, inb(0x3D5)&~0x10);
+	outb(0x3D4, 0x32);
+	outb(0x3D5, inb(0x3D5)&~0x10);
 
-  outb(0x3C2, 0x67);
-
-  /* Initialize DAC */
-  outb(0x3C6,0xFF);
-  inb(0x3C7);
-  outb(0x3C8,0x00);
-  inb(0x3C7);
-  for (i=0; i<sizeof(color_LUT); i++) {
-    outb(0x3C9, color_LUT[i]);
-  }
-  for (i; i<768; i += 3) {
-    outb(0x3C9, 0x3F); /* White? */
-    outb(0x3C9, 0x3F); /* White? */
-    outb(0x3C9, 0x3F); /* White? */
-  }
-
-  /* Load font */
-  NOP(inb(0x3DA));  /* Reset Address/Data FlipFlop for Attribute ctlr */
-  outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
-  outw(0x3C4, 0x0001);    /* reset sequencer */
-  outw(0x3C4, 0x0204);    /* write to plane 2 */
-  outw(0x3C4, 0x0407);    /* enable plane graphics */
-  outw(0x3C4, 0x0003);    /* reset sequencer */
-  outw(0x3CE, 0x0402);    /* read plane 2 */
-  outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
-  outw(0x3CE, 0x0600);    /* set graphics */
-  for (i = 0;  i < sizeof(font);  i += 16) {
-    for (j = 0;  j < 16;  j++) {
-      font_page[(2*i)+j] = font[i+j];
-    }
-  }
-
-  for (i = 0; i < 24; i++) {
-    outb(0x3D4, i);
-    outb(0x3D5, CRTC[i]);
-  }
-  for (i = 0; i < 5; i++) {
-    outb(0x3C4, i);
-    outb(0x3C5, SEQ[i]);
-  }
-  for (i = 0; i < 9; i++) {
-    outb(0x3CE, i);
-    outb(0x3CF, GC[i]);
-  }
-  value = inb(0x3DA);         /* reset flip-flop */
-  for (i = 0; i < 16; i++) {
-    outb(0x3C0, i);
-    outb(0x3C0, AC[i]);
-  }
-  for (i = 16; i < 21; i++) {
-    outb(0x3C0, i | 0x20);
-    outb(0x3C0, AC[i]);
-  }
-  outb(0x3C2, 0x23);
-}
+	outb(0x3C2, 0x67);
 
-static int
-NOP(int x)
-{
+#if 0
+	/* Initialize DAC */
+	outb(0x3C6,0xFF);
+	inb(0x3C7);
+	outb(0x3C8,0x00);
+	inb(0x3C7);
+	for (i=0; i<sizeof(color_LUT); i++) {
+		outb(0x3C9, color_LUT[i]);
+	}
+	for (i; i<768; i += 3) {
+		outb(0x3C9, 0x3F); /* White? */
+		outb(0x3C9, 0x3F); /* White? */
+		outb(0x3C9, 0x3F); /* White? */
+	}
+
+	/* Load font */
+	NOP(inb(0x3DA));  /* Reset Address/Data FlipFlop for Attribute ctlr */
+	outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
+	outw(0x3C4, 0x0001);    /* reset sequencer */
+	outw(0x3C4, 0x0204);    /* write to plane 2 */
+	outw(0x3C4, 0x0407);    /* enable plane graphics */
+	outw(0x3C4, 0x0003);    /* reset sequencer */
+	outw(0x3CE, 0x0402);    /* read plane 2 */
+	outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
+	outw(0x3CE, 0x0600);    /* set graphics */
+	for (i = 0;  i < sizeof(font);  i += 16) {
+		for (j = 0;  j < 16;  j++) {
+			font_page[(2*i)+j] = font[i+j];
+		}
+	}
+#else
+	outw(0x3C4, 0x0120);                /* disable video              */
+	setTextCLUT(2);                     /* load color lookup table    */
+	loadFont(ISA_mem);                  /* load font                  */
+#endif
+
+	for (i = 0; i < 24; i++) {
+		outb(0x3D4, i);
+		outb(0x3D5, CRTC[i]);
+	}
+	for (i = 0; i < 5; i++) {
+		outb(0x3C4, i);
+		outb(0x3C5, SEQ[i]);
+	}
+	for (i = 0; i < 9; i++) {
+		outb(0x3CE, i);
+		outb(0x3CF, GC[i]);
+	}
+	value = inb(0x3DA);         /* reset flip-flop */
+	for (i = 0; i < 16; i++) {
+		outb(0x3C0, i);
+		outb(0x3C0, AC[i]);
+	}
+	for (i = 16; i < 21; i++) {
+		outb(0x3C0, i | 0x20);
+		outb(0x3C0, AC[i]);
+	}
+	clearVideoMemory();
+	outw(0x3C4, 0x0100);                /* re-enable video            */
+	outb(0x3C2, 0x23);
+	return (1); /* Keyboard should work */
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.1.47/linux/arch/ppc/config.in	Mon Apr  7 11:35:29 1997
+++ linux/arch/ppc/config.in	Thu Jul 31 13:09:17 1997
@@ -2,62 +2,62 @@
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
-mainmenu_name "Linux Kernel Configuration"
+mainmenu_name "Linux/PowerPC Kernel Configuration"
 
-mainmenu_option next_comment
-comment 'Code maturity level options'
+if [ "`uname`" != "Linux" ]; then
+  define_bool CONFIG_CROSSCOMPILE y
+else
+  define_bool CONFIG_NATIVE y
+fi
+
+bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
+bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
 bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
+bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+choice 'Processor type' \
+	"Common		CONFIG_MCOMMON \
+	 601		CONFIG_M601	\
+	 603		CONFIG_M603	\
+	 604		CONFIG_M604" Common
 
-mainmenu_option next_comment
-comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
   bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
-endmenu
 
-mainmenu_option next_comment
-comment 'General setup'
 
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION
+mainmenu_option next_comment
+define_bool CONFIG_PCI y
+bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 bool 'Networking support' CONFIG_NET
-bool 'PCI bios support' CONFIG_PCI
-if [ "$CONFIG_PCI" = "y" ]; then
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
-  fi
-fi
-bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+bool 'System V IPC' CONFIG_SYSVIPC
+
+# only elf supported, a.out is not -- Cort
+define_bool CONFIG_BINFMT_ELF y
+define_bool CONFIG_KERNEL_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
-  bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
 
-source drivers/block/Config.in
 
-if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
-fi
+source drivers/pnp/Config.in
+source drivers/block/Config.in
 
 mainmenu_option next_comment
 comment 'SCSI support'
-
 tristate 'SCSI support' CONFIG_SCSI
-
 if [ "$CONFIG_SCSI" != "n" ]; then
   source drivers/scsi/Config.in
 fi
 endmenu
 
+
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
   comment 'Network device support'
-
+  source net/Config.in
   bool 'Network device support' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     source drivers/net/Config.in
@@ -65,9 +65,9 @@
   endmenu
 fi
 
+
 mainmenu_option next_comment
 comment 'ISDN subsystem'
-
 tristate 'ISDN support' CONFIG_ISDN
 if [ "$CONFIG_ISDN" != "n" ]; then
   source drivers/isdn/Config.in
@@ -76,7 +76,6 @@
 
 mainmenu_option next_comment
 comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
 bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
   source drivers/cdrom/Config.in
@@ -84,12 +83,10 @@
 endmenu
 
 source fs/Config.in
-
 source drivers/char/Config.in
 
 mainmenu_option next_comment
 comment 'Sound'
-
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
   source drivers/sound/Config.in
@@ -97,11 +94,11 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'Kernel hacking'
-
+#comment 'Kernel hacking'
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Kernel profiling support' CONFIG_PROFILE
-if [ "$CONFIG_PROFILE" = "y" ]; then
-  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
-fi
+#bool 'Kernel profiling support' CONFIG_PROFILE
+#if [ "$CONFIG_PROFILE" = "y" ]; then
+#  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+#fi
 endmenu
+
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.1.47/linux/arch/ppc/defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/defconfig	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,239 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+# CONFIG_HEARTBEAT is not set
+# CONFIG_POWERSAVING is not set
+CONFIG_MCOMMON=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_NCR53C7xx=y
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI_QLOGIC_PMAC is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_BEXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RNFS_BOOTP is not set
+# CONFIG_RNFS_RARP is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_HFS_FS=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.1.47/linux/arch/ppc/kernel/Makefile	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/Makefile	Thu Jul 31 13:09:17 1997
@@ -22,32 +22,49 @@
 
 HOST_CC = gcc
 
-OBJS  = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \
-	signal.o ksyms.o time.o syscalls.o usercpy.o\
-	support.o ptrace.o 
+OBJS  = misc.o port_io.o pci.o traps.o process.o \
+	signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
 
 all: head.o kernel.o
+head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
 
-head.o: head.s
-head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
-
-ppc_defs.h: mk_defs
-	mk_defs $@
-
-mk_defs: mk_defs.c
-	$(HOSTCC) $(CFLAGSINC) -Wl,-static ${CFLAGS} -o mk_defs mk_defs.c
-
+ifeq ($(CONFIG_PREP),y)
+OBJS += prep_setup.o prep_time.o
+endif
+
+ifeq ($(CONFIG_PMAC),y)
+OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+endif
+
+ifeq ($(CONFIG_MODULES),y)
+OBJS = ksyms.o
+endif
+
+
+ppc_defs.h: mk_defs.c ppc_defs.head \
+		$(TOPDIR)/include/asm/mmu.h \
+		$(TOPDIR)/include/asm/processor.h \
+		$(TOPDIR)/include/asm/pgtable.h \
+		$(TOPDIR)/include/asm/ptrace.h
+	$(CC) ${CFLAGS} -S mk_defs.c
+	cp ppc_defs.head ppc_defs.h
+	grep '^#define' mk_defs.s >>ppc_defs.h
+	rm mk_defs.s
+
+checks: checks.c
+	$(HOSTCC) ${CFLAGS} -o checks checks.c
+	checks
 
 kernel.o: $(OBJS)
 	$(LD) -r -o kernel.o $(OBJS)
-	sync
-
-dep:
-	$(CPP) -M *.c > .depend
 
 fastdep:
+	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+	$(CPP) -M *.S *.c > .depend
 
-modules:
+modules: 
 
 dummy:
 
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/align.c linux/arch/ppc/kernel/align.c
--- v2.1.47/linux/arch/ppc/kernel/align.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/align.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,290 @@
+/*
+ * align.c - handle alignment exceptions for the Power PC.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras	(paulus@cs.anu.edu.au).
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+struct aligninfo {
+	unsigned char len;
+	unsigned char flags;
+};
+
+#define INVALID	{ 0, 0 }
+
+#define LD	1	/* load */
+#define ST	2	/* store */
+#define	SE	4	/* sign-extend value */
+#define F	8	/* to/from fp regs */
+#define U	0x10	/* update index register */
+#define M	0x20	/* multiple load/store */
+#define S	0x40	/* single-precision fp, or byte-swap value */
+#define HARD	0x80	/* string, stwcx. */
+
+/*
+ * The PowerPC stores certain bits of the instruction that caused the
+ * alignment exception in the DSISR register.  This array maps those
+ * bits to information about the operand length and what the
+ * instruction would do.
+ */
+static struct aligninfo aligninfo[128] = {
+	{ 4, LD },		/* 00 0 0000: lwz / lwarx */
+	INVALID,		/* 00 0 0001 */
+	{ 4, ST },		/* 00 0 0010: stw */
+	INVALID,		/* 00 0 0011 */
+	{ 2, LD },		/* 00 0 0100: lhz */
+	{ 2, LD+SE },		/* 00 0 0101: lha */
+	{ 2, ST },		/* 00 0 0110: sth */
+	{ 4, LD+M },		/* 00 0 0111: lmw */
+	{ 4, LD+F+S },		/* 00 0 1000: lfs */
+	{ 8, LD+F },		/* 00 0 1001: lfd */
+	{ 4, ST+F+S },		/* 00 0 1010: stfs */
+	{ 8, ST+F },		/* 00 0 1011: stfd */
+	INVALID,		/* 00 0 1100 */
+	INVALID,		/* 00 0 1101 */
+	INVALID,		/* 00 0 1110 */
+	INVALID,		/* 00 0 1111 */
+	{ 4, LD+U },		/* 00 1 0000: lwzu */
+	INVALID,		/* 00 1 0001 */
+	{ 4, ST+U },		/* 00 1 0010: stwu */
+	INVALID,		/* 00 1 0011 */
+	{ 2, LD+U },		/* 00 1 0100: lhzu */
+	{ 2, LD+SE+U },		/* 00 1 0101: lhau */
+	{ 2, ST+U },		/* 00 1 0110: sthu */
+	{ 4, ST+M },		/* 00 1 0111: stmw */
+	{ 4, LD+F+S+U },	/* 00 1 1000: lfsu */
+	{ 8, LD+F+U },		/* 00 1 1001: lfdu */
+	{ 4, ST+F+S+U },	/* 00 1 1010: stfsu */
+	{ 8, ST+F+U },		/* 00 1 1011: stfdu */
+	INVALID,		/* 00 1 1100 */
+	INVALID,		/* 00 1 1101 */
+	INVALID,		/* 00 1 1110 */
+	INVALID,		/* 00 1 1111 */
+	INVALID,		/* 01 0 0000 */
+	INVALID,		/* 01 0 0001 */
+	INVALID,		/* 01 0 0010 */
+	INVALID,		/* 01 0 0011 */
+	INVALID,		/* 01 0 0100 */
+	INVALID,		/* 01 0 0101: lwax?? */
+	INVALID,		/* 01 0 0110 */
+	INVALID,		/* 01 0 0111 */
+	{ 0, LD+HARD },		/* 01 0 1000: lswx */
+	{ 0, LD+HARD },		/* 01 0 1001: lswi */
+	{ 0, ST+HARD },		/* 01 0 1010: stswx */
+	{ 0, ST+HARD },		/* 01 0 1011: stswi */
+	INVALID,		/* 01 0 1100 */
+	INVALID,		/* 01 0 1101 */
+	INVALID,		/* 01 0 1110 */
+	INVALID,		/* 01 0 1111 */
+	INVALID,		/* 01 1 0000 */
+	INVALID,		/* 01 1 0001 */
+	INVALID,		/* 01 1 0010 */
+	INVALID,		/* 01 1 0011 */
+	INVALID,		/* 01 1 0100 */
+	INVALID,		/* 01 1 0101: lwaux?? */
+	INVALID,		/* 01 1 0110 */
+	INVALID,		/* 01 1 0111 */
+	INVALID,		/* 01 1 1000 */
+	INVALID,		/* 01 1 1001 */
+	INVALID,		/* 01 1 1010 */
+	INVALID,		/* 01 1 1011 */
+	INVALID,		/* 01 1 1100 */
+	INVALID,		/* 01 1 1101 */
+	INVALID,		/* 01 1 1110 */
+	INVALID,		/* 01 1 1111 */
+	INVALID,		/* 10 0 0000 */
+	INVALID,		/* 10 0 0001 */
+	{ 0, ST+HARD },		/* 10 0 0010: stwcx. */
+	INVALID,		/* 10 0 0011 */
+	INVALID,		/* 10 0 0100 */
+	INVALID,		/* 10 0 0101 */
+	INVALID,		/* 10 0 0110 */
+	INVALID,		/* 10 0 0111 */
+	{ 4, LD+S },		/* 10 0 1000: lwbrx */
+	INVALID,		/* 10 0 1001 */
+	{ 4, ST+S },		/* 10 0 1010: stwbrx */
+	INVALID,		/* 10 0 1011 */
+	{ 2, LD+S },		/* 10 0 1100: lhbrx */
+	INVALID,		/* 10 0 1101 */
+	{ 2, ST+S },		/* 10 0 1110: sthbrx */
+	INVALID,		/* 10 0 1111 */
+	INVALID,		/* 10 1 0000 */
+	INVALID,		/* 10 1 0001 */
+	INVALID,		/* 10 1 0010 */
+	INVALID,		/* 10 1 0011 */
+	INVALID,		/* 10 1 0100 */
+	INVALID,		/* 10 1 0101 */
+	INVALID,		/* 10 1 0110 */
+	INVALID,		/* 10 1 0111 */
+	INVALID,		/* 10 1 1000 */
+	INVALID,		/* 10 1 1001 */
+	INVALID,		/* 10 1 1010 */
+	INVALID,		/* 10 1 1011 */
+	INVALID,		/* 10 1 1100 */
+	INVALID,		/* 10 1 1101 */
+	INVALID,		/* 10 1 1110 */
+	{ 0, ST+HARD },		/* 10 1 1111: dcbz */
+	{ 4, LD },		/* 11 0 0000: lwzx */
+	INVALID,		/* 11 0 0001 */
+	{ 4, ST },		/* 11 0 0010: stwx */
+	INVALID,		/* 11 0 0011 */
+	{ 2, LD },		/* 11 0 0100: lhzx */
+	{ 2, LD+SE },		/* 11 0 0101: lhax */
+	{ 2, ST },		/* 11 0 0110: sthx */
+	INVALID,		/* 11 0 0111 */
+	{ 4, LD+F+S },		/* 11 0 1000: lfsx */
+	{ 8, LD+F },		/* 11 0 1001: lfdx */
+	{ 4, ST+F+S },		/* 11 0 1010: stfsx */
+	{ 8, ST+F },		/* 11 0 1011: stfdx */
+	INVALID,		/* 11 0 1100 */
+	INVALID,		/* 11 0 1101 */
+	INVALID,		/* 11 0 1110 */
+	INVALID,		/* 11 0 1111 */
+	{ 4, LD+U },		/* 11 1 0000: lwzux */
+	INVALID,		/* 11 1 0001 */
+	{ 4, ST+U },		/* 11 1 0010: stwux */
+	INVALID,		/* 11 1 0011 */
+	{ 2, LD+U },		/* 11 1 0100: lhzux */
+	{ 2, LD+SE+U },		/* 11 1 0101: lhaux */
+	{ 2, ST+U },		/* 11 1 0110: sthux */
+	INVALID,		/* 11 1 0111 */
+	{ 4, LD+F+S+U },	/* 11 1 1000: lfsux */
+	{ 8, LD+F+U },		/* 11 1 1001: lfdux */
+	{ 4, ST+F+S+U },	/* 11 1 1010: stfsux */
+	{ 8, ST+F+U },		/* 11 1 1011: stfdux */
+	INVALID,		/* 11 1 1100 */
+	INVALID,		/* 11 1 1101 */
+	INVALID,		/* 11 1 1110 */
+	INVALID,		/* 11 1 1111 */
+};
+
+#define SWAP(a, b)	(t = (a), (a) = (b), (b) = t)
+
+int
+fix_alignment(struct pt_regs *regs)
+{
+	int instr, nb, flags;
+	int i, t;
+	int reg, areg;
+	unsigned char *addr;
+	union {
+		long l;
+		float f;
+		double d;
+		unsigned char v[8];
+	} data;
+
+	instr = (regs->dsisr >> 10) & 0x7f;
+	nb = aligninfo[instr].len;
+	if (nb == 0)
+		return 0;	/* too hard or invalid instruction bits */
+	flags = aligninfo[instr].flags;
+	addr = (unsigned char *) regs->dar;
+	reg = (regs->dsisr >> 5) & 0x1f;	/* source/dest register */
+
+	/* Verify the address of the operand */
+	if (user_mode(regs)) {
+		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+			return -EFAULT;	/* bad address */
+	}
+
+	if ((flags & F) && last_task_used_math == current)
+		giveup_fpu();
+
+	if (flags & M)
+		return 0;		/* too hard for now */
+
+	/* If we read the operand, copy it in */
+	if (flags & LD) {
+		if (nb == 2) {
+			data.v[0] = data.v[1] = 0;
+			if (__get_user(data.v[2], addr)
+			    || __get_user(data.v[3], addr+1))
+				return -EFAULT;
+		} else {
+			for (i = 0; i < nb; ++i)
+				if (__get_user(data.v[i], addr+i))
+					return -EFAULT;
+		}
+	}
+
+	switch (flags & ~U) {
+	case LD+SE:
+		if (data.v[2] >= 0x80)
+			data.v[0] = data.v[1] = -1;
+		/* fall through */
+	case LD:
+		regs->gpr[reg] = data.l;
+		break;
+	case LD+S:
+		if (nb == 2) {
+			SWAP(data.v[2], data.v[3]);
+		} else {
+			SWAP(data.v[0], data.v[3]);
+			SWAP(data.v[1], data.v[2]);
+		}
+		regs->gpr[reg] = data.l;
+		break;
+	case ST:
+		data.l = regs->gpr[reg];
+		break;
+	case ST+S:
+		data.l = regs->gpr[reg];
+		if (nb == 2) {
+			SWAP(data.v[2], data.v[3]);
+		} else {
+			SWAP(data.v[0], data.v[3]);
+			SWAP(data.v[1], data.v[2]);
+		}
+		break;
+	case LD+F:
+		current->tss.fpr[reg] = data.d;
+		break;
+	case ST+F:
+		data.d = current->tss.fpr[reg];
+		break;
+	/* these require some floating point conversions... */
+	/* note that giveup_fpu enables the FPU for the kernel */
+	/* we'd like to use the assignment, but we have to compile
+	 * the kernel with -msoft-float so it doesn't use the
+	 * fp regs for copying 8-byte objects. */
+	case LD+F+S:
+		giveup_fpu();
+		cvt_fd(&data.f, &current->tss.fpr[reg]);
+		/* current->tss.fpr[reg] = data.f; */
+		break;
+	case ST+F+S:
+		giveup_fpu();
+		cvt_df(&current->tss.fpr[reg], &data.f);
+		/* data.f = current->tss.fpr[reg]; */
+		break;
+	default:
+		printk("align: can't handle flags=%x\n", flags);
+		return 0;
+	}
+
+	if (flags & ST) {
+		if (nb == 2) {
+			if (__put_user(data.v[2], addr)
+			    || __put_user(data.v[3], addr+1))
+				return -EFAULT;
+		} else {
+			for (i = 0; i < nb; ++i)
+				if (__put_user(data.v[i], addr+i))
+					return -EFAULT;
+		}
+	}
+
+	if (flags & U) {
+		areg = regs->dsisr & 0x1f;	/* register to update */
+		regs->gpr[areg] = regs->dar;
+	}
+
+	return 1;
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/bitops.c linux/arch/ppc/kernel/bitops.c
--- v2.1.47/linux/arch/ppc/kernel/bitops.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/bitops.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+
+/*
+ * I left these here since the problems with "cc" make it difficult to keep
+ * them in bitops.h -- Cort
+ */
+void set_bit(int nr, volatile void *addr)
+{
+	unsigned int t;
+	unsigned int mask = 1 << (nr & 0x1f);
+	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk(KERN_ERR "set_bit(%x, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2
+	or	%0,%0,%1
+	stwcx.	%0,0,%2
+	bne	1b"
+	: "=&r" (t)		/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+	: "cc");
+}
+
+void clear_bit(int nr, volatile void *addr)
+{
+	unsigned int t;
+	unsigned int mask = 1 << (nr & 0x1f);
+	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk(KERN_ERR "clear_bit(%x, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2
+	andc	%0,%0,%1
+	stwcx.	%0,0,%2
+	bne	1b"
+	: "=&r" (t)		/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+	: "cc");
+}
+
+void change_bit(int nr, volatile void *addr)
+{
+	unsigned int t;
+	unsigned int mask = 1 << (nr & 0x1f);
+	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk(KERN_ERR "change_bit(%x, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2
+	xor	%0,%0,%1
+	stwcx.	%0,0,%2
+	bne	1b"
+	: "=&r" (t)		/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+	: "cc");
+}
+
+int test_and_set_bit(int nr, volatile void *addr)
+{
+	unsigned int old, t;
+	unsigned int mask = 1 << (nr & 0x1f);
+	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk(KERN_ERR "test_and_set_bit(%x, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3
+	or	%1,%0,%2
+	stwcx.	%1,0,%3
+	bne	1b"
+	: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+	: "cc");
+
+	return (old & mask) != 0;
+}
+
+int test_and_clear_bit(int nr, volatile void *addr)
+{
+	unsigned int old, t;
+	unsigned int mask = 1 << (nr & 0x1f);
+	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk(KERN_ERR "test_and_clear_bit(%x, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3
+	andc	%1,%0,%2
+	stwcx.	%1,0,%3
+	bne	1b"
+	: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+	: "cc");
+
+	return (old & mask) != 0;
+}
+
+int test_and_change_bit(int nr, volatile void *addr)
+{
+	unsigned int old, t;
+	unsigned int mask = 1 << (nr & 0x1f);
+	volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk(KERN_ERR "test_and_change_bit(%x, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3
+	xor	%1,%0,%2
+	stwcx.	%1,0,%3
+	bne	1b"
+	: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+	: "cc");
+
+	return (old & mask) != 0;
+}
+
+/* I put it in bitops.h -- Cort */
+#if 0
+int ffz(unsigned int x)
+{
+	int n;
+
+	x = ~x & (x+1);		/* set LS zero to 1, other bits to 0 */
+	__asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+	return 31 - n;
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+int find_first_zero_bit(void * addr, int size)
+{
+	unsigned int * p = ((unsigned int *) addr);
+	unsigned int result = 0;
+	unsigned int tmp;
+
+	if (size == 0)
+		return 0;
+	while (size & ~31UL) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+	tmp |= ~0UL << size;
+found_middle:
+	return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+int find_next_zero_bit(void * addr, int size, int offset)
+{
+	unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+	unsigned int result = offset & ~31UL;
+	unsigned int 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 & ~31UL) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+found_first:
+	tmp |= ~0UL << size;
+found_middle:
+	return result + ffz(tmp);
+}
+#endif
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/checks.c linux/arch/ppc/kernel/checks.c
--- v2.1.47/linux/arch/ppc/kernel/checks.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/checks.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,56 @@
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+
+/*
+ * Do various before compile checks of data structures
+ * -- Cort
+ */
+int main(void)
+{
+	int ret = 0;
+	
+	if ( sizeof(struct thread_struct) % 16 )
+	{
+		printf("Thread struct is not modulo 16 bytes: "
+			"%d bytes total, %d bytes off\n",
+			sizeof(struct thread_struct),
+			sizeof(struct thread_struct)%16);
+		ret = -1;
+	}
+
+	if ( sizeof(struct pt_regs) % 16 )
+	{
+		printf("pt_regs struct is not modulo 16 bytes: "
+			"%d bytes total, %d bytes off\n",
+			sizeof(struct pt_regs),
+			sizeof(struct pt_regs)%16);
+		ret = -1;
+		
+	}
+
+	printf("Task size        : %d bytes\n"
+	       "Tss size         : %d bytes\n"
+	       "pt_regs size     : %d bytes\n"
+	       "Kernel stack size: %d bytes\n",
+	       sizeof(struct task_struct), sizeof(struct thread_struct),
+	       sizeof(struct pt_regs),
+	       sizeof(union task_union) - sizeof(struct task_struct));
+	return ret;
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.1.47/linux/arch/ppc/kernel/head.S	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/head.S	Thu Jul 31 13:09:17 1997
@@ -1,1040 +1,1144 @@
+/*
+ *  arch/ppc/kernel/head.S
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *
+ *  This file contains the low-level support and setup for the
+ *  PowerPC platform, including trap and interrupt dispatch.
+ *  Also included here is low-level thread/task switch support.
+ *
+ *  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.
+ *	
+ */
+
 #include "ppc_asm.tmpl"
 #include "ppc_defs.h"
-#include <linux/errno.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
 #include <linux/sys.h>
-#include <asm/ppc_machine.h>
-	
-#define NEWMM 1
-#define SYNC() \
-	isync; \
-	sync
-
-#define STATS
-/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
- */
-#define BUMP(ctr) \
-	lis	r2,ctr@h; \
-	ori	r2,r2,ctr@l; \
-	lwz	r3,4(r2); \
-	addic	r3,r3,1; \
-	stw	r3,4(r2); \
-	lwz	r3,0(r2); \
-	addze	r3,r3; \
-	stw	r3,0(r2)
-
-/* The same as 'BUMP' but running unmapped (TLB code) */	
-#define BUMP_UNMAPPED(ctr) \
-	mfspr	r0,XER; \
-	lis	r2,ctr@h; \
-	ori	r2,r2,ctr@l; \
-	lis	r3,0xF000; \
-	andc	r2,r2,r3; \
-	lwz	r3,4(r2); \
-	addic	r3,r3,1; \
-	stw	r3,4(r2); \
-	lwz	r3,0(r2); \
-	addze	r3,r3; \
-	mtspr	XER,r0; \
-	stw	r3,0(r2)
-
-#define DO_RFI_TRACE_UNMAPPED(mark)
-#define DO_RFI_TRACE_MAPPED(mark)
-
-#define DEFAULT_TRAP(offset) \
-	li	r13,0; \
-	ori	r13,r13,HID0_ICE; \
-	mtspr	HID0,r13; \
-	lis	r13,0xFFF00000>>16; \
-	ori	r13,r13,offset; \
-	mtlr	r13; \
-	blr
-#define TRACE_TRAP(offset)	
+#include <linux/errno.h>
+#include <linux/config.h>
 
-#define DATA_CACHE_OFF() \
-	mfspr	r2,HID0; \
-	li	r3,0; \
-	ori	r3,r3,HID0_DCE; \
-	andc	r2,r2,r3; \
-	mtspr	HID0,r2;
-
-#define DATA_CACHE_ON() \
-	mfspr	r2,HID0; \
-	ori	r2,r2,HID0_DCE; \
-	mtspr	HID0,r2;
+#define SYNC() \
+	sync; \
+	isync
 
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 603 or 601 */
 #define tlbia \
-	li	r4,64; \
-	mtspr	CTR,r4; \
-	lis	r4,0x9000; \
+	li	r4,128; \
+	mtctr	r4; \
+	lis	r4,0xC000; \
 0:	tlbie	r4; \
 	addi	r4,r4,0x1000; \
 	bdnz	0b
 
-/* Validate kernel stack - check for overflow */
-/* all regs are considered scratch since the C function will stomp them */
-#define CHECK_STACK() \
-	/*lis	r3,current_set@ha; \
-	lwz	r3,current_set@l(r3); \
-	bl	_EXTERN(check_stack)*/
-#if 0
-#define _CHECK_STACK() \
-	mtspr	SPR0,r3; \
-	mtspr	SPR1,r4;    /* use r3,4 as scratch */ \
-	lis	r2,current_set@ha; \
-	lwz	r2,current_set@l(r2); \
-	lwz	r2,KERNEL_STACK_PAGE(r2); \
-	/* if kernel stack is sys_stack skip check */ \
-	/*lis	r3,sys_stack@h; \
-	ori	r3,r3,sys_stack@l; \
-	cmpl	0,r1,r3;*/ \
-	/* check for STACK_MAGIC on kernel stack page */ \
-	lis	r3, 0xdead; /* STACK_MAGIC */ \
-	ori	r3,r3,0xbeef; \
-	lwz	r4,0(r2);      /* get *kernel_stack_page */ \
-	cmpl	0,r4,r3; \
-	bne	01f; \
-	/* check that ksp is > kernel page */ \
-	/*li	r3,0x0FFF; \
-	andc	r2,r2,r3; \
-	andc	r3,r1,r3; \
-	cmp	0,r3,r2; \
-	beq	02f;*/ \
-	/* check that ksp and kernel stack page are on same page */ \
-	cmp	0,r1,r2; \
-	bge	02f; \
-01:	mr	r6,r1; /* setup info for call to bad_stack() */ \
-	mr	r5,r2; \
-	bl	_EXTERN(bad_stack); \
-02:	mfspr	r4,SPR1; \
-	mfspr	r3,SPR0
-#endif
+#define TOPHYS(x)	(x - KERNELBASE)
+
+
+/* this is a very kludgey way of loading up the BATs on the
+   prep system.  I'll kill this horrible macro and write
+   something clean when I have a chance -- Cort
+ */	
+#define LOAD_BATS(RA,RB) \
+	mfspr	RA,PVR		; \
+	srwi	r5,r5,16	; \
+	cmpi	0,RA,1		; \
+	beq	199f		; \
+	/* load bats for 60x */	; \
+	lis	RA,BAT0@h	; \
+	ori	RA,RA,BAT0@l	; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT0U,RB	; \
+	mtspr	DBAT0U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT0L,RB	; \
+	mtspr	DBAT0L,RB	; \
+	lis	RA,BAT1@h	; \
+	ori	RA,RA,BAT1@l	; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT1U,RB	; \
+	mtspr	DBAT1U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT1L,RB	; \
+	mtspr	DBAT1L,RB	; \
+	lis	RA,BAT2@h	; \
+	ori	RA,RA,BAT2@l	; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT2U,RB	; \
+	mtspr	DBAT2U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT2L,RB	; \
+	mtspr	DBAT2L,RB	; \
+	lis	RA,BAT3@h	; \
+	ori	RA,RA,BAT3@l	; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT3U,RB	; \
+	mtspr	DBAT3U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT3L,RB	; \
+	mtspr	DBAT3L,RB	; \
+	b	200f		; \
+199:	/*load bats for 601 */	; \
+	lis	RA,BAT0_601@h	; \
+	ori	RA,RA,BAT0_601@l; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT0U,RB	; \
+	mtspr	DBAT0U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT0L,RB	; \
+	mtspr	DBAT0L,RB	; \
+	lis	RA,BAT1_601@h	; \
+	ori	RA,RA,BAT1_601@l; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT1U,RB	; \
+	mtspr	DBAT1U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT1L,RB	; \
+	mtspr	DBAT1L,RB	; \
+	lis	RA,BAT2_601@h	; \
+	ori	RA,RA,BAT2_601@l; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT2U,RB	; \
+	mtspr	DBAT2U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT2L,RB	; \
+	mtspr	DBAT2L,RB	; \
+	lis	RA,BAT3_601@h	; \
+	ori	RA,RA,BAT3_601@l; \
+	addis	RA,RA,-KERNELBASE@h;\
+	lwz	RB,0(RA)	; \
+	mtspr	IBAT3U,RB	; \
+	mtspr	DBAT3U,RB	; \
+	lwz	RB,4(RA)	; \
+	mtspr	IBAT3L,RB	; \
+	mtspr	DBAT3L,RB	; \
+200:
 	
-/* save fp regs if fp is used */
-/* assumes that r1 contains ptr to regs of task and r2 is scratch 
-	  -- Cort  */
-#define SAVE_FP_REGS() \
-       	/* check if fp has been used by checking msr_fp bit */ \
-	lwz	r2,_MSR(r1);  \
-	andi.	r2,r2,MSR_FP; \
-	bne	00f; \
-	/* floating point has been used -- save fp regs */ \
-	lis	r2,current_set@h; \
-	ori	r2,r2,current_set@l; \
-	addi	r2,r2,TSS; \
-	/*mr	r2,r1;*/ \
-	stfd	fr0,TSS_FPR0(r2); \
-	stfd	fr1,TSS_FPR1(r2); \
-	stfd	fr2,TSS_FPR2(r2); \
-	stfd	fr3,TSS_FPR3(r2); \
-	stfd	fr4,TSS_FPR4(r2); \
-	stfd	fr5,TSS_FPR5(r2); \
-	stfd	fr6,TSS_FPR6(r2); \
-	stfd	fr7,TSS_FPR7(r2); \
-	stfd	fr8,TSS_FPR8(r2); \
-	stfd	fr9,TSS_FPR9(r2); \
-	stfd	fr10,TSS_FPR10(r2); \
-	stfd	fr11,TSS_FPR11(r2); \
-	stfd	fr12,TSS_FPR12(r2); \
-	stfd	fr13,TSS_FPR13(r2); \
-	stfd	fr14,TSS_FPR14(r2); \
-	stfd	fr15,TSS_FPR15(r2); \
-	stfd	fr16,TSS_FPR16(r2); \
-	stfd	fr17,TSS_FPR17(r2); \
-	stfd	fr18,TSS_FPR18(r2); \
-	stfd	fr19,TSS_FPR19(r2); \
-	stfd	fr20,TSS_FPR20(r2); \
-	stfd	fr21,TSS_FPR21(r2); \
-	stfd	fr22,TSS_FPR22(r2); \
-	stfd	fr23,TSS_FPR23(r2); \
-	stfd	fr24,TSS_FPR24(r2); \
-	stfd	fr25,TSS_FPR25(r2); \
-	stfd	fr26,TSS_FPR26(r2); \
-	stfd	fr27,TSS_FPR27(r2); \
-	stfd	fr28,TSS_FPR28(r2); \
-	stfd	fr29,TSS_FPR29(r2); \
-	stfd	fr30,TSS_FPR30(r2); \
-	stfd	fr31,TSS_FPR31(r2); \
-00:
-
-
-/* restores fp regs if fp has been used -- always restores fpscr */
-/* assumes that r1 contains ptr to regs, r2 is scratch and srr1 holds
-   what will become the msr when this process executes 	-- Cort*/
-#define RESTORE_FP_REGS(mark) \
-	/* check if restoring from _switch() */ \
-	li	r2, mark; \
-	cmpi	0,r2,0x0f0f; \
-	bne	00f; /* only need to save if called from _switch() with 0x0f0f */\
-       	/* check if fp has been used by checking msr_fp bit */ \
-	/* srr1 contains msr */ \
-	mfspr	r2,SRR1; \
-	andi.	r2,r2,MSR_FP; \
-	bne	00f; \
-	/* floating point has been used -- restore fp regs */ \
-	/* Hey, Rocky!  Watch me pull fp regs from my stack! */ \
-	lis	r2,current_set@h; \
-	ori	r2,r2,current_set@l; \
-	addi	r2,r2,TSS; \
-	/*mr	r2,r1;*/\
-	lfd	fr0,TSS_FPR0(r2); \
-	lfd	fr1,TSS_FPR1(r2); \
-	lfd	fr2,TSS_FPR2(r2); \
-	lfd	fr3,TSS_FPR3(r2); \
-	lfd	fr4,TSS_FPR4(r2); \
-	lfd	fr5,TSS_FPR5(r2); \
-	lfd	fr6,TSS_FPR6(r2); \
-	lfd	fr7,TSS_FPR7(r2); \
-	lfd	fr8,TSS_FPR8(r2); \
-	lfd	fr9,TSS_FPR9(r2); \
-	lfd	fr10,TSS_FPR10(r2); \
-	lfd	fr11,TSS_FPR11(r2); \
-	lfd	fr12,TSS_FPR12(r2); \
-	lfd	fr13,TSS_FPR13(r2); \
-	lfd	fr14,TSS_FPR14(r2); \
-	lfd	fr15,TSS_FPR15(r2); \
-	lfd	fr16,TSS_FPR16(r2); \
-	lfd	fr17,TSS_FPR17(r2); \
-	lfd	fr18,TSS_FPR18(r2); \
-	lfd	fr19,TSS_FPR19(r2); \
-	lfd	fr20,TSS_FPR20(r2); \
-	lfd	fr21,TSS_FPR21(r2); \
-	lfd	fr22,TSS_FPR22(r2); \
-	lfd	fr23,TSS_FPR23(r2); \
-	lfd	fr24,TSS_FPR24(r2); \
-	lfd	fr25,TSS_FPR25(r2); \
-	lfd	fr26,TSS_FPR26(r2); \
-	lfd	fr27,TSS_FPR27(r2); \
-	lfd	fr28,TSS_FPR28(r2); \
-	lfd	fr29,TSS_FPR29(r2); \
-	lfd	fr30,TSS_FPR30(r2); \
-	lfd	fr31,TSS_FPR31(r2); \
-00:
-
-/* save all registers */
-#define SAVE_ALL_REGS(mark) \
-	subi	r1,r1,INT_FRAME_SIZE;	/* Make room for frame */ \
-	stmw	r3,GPR3(r1);	/* Save R3..R31 */ \
-	stw	r3,ORIG_GPR3(r1); \
-	stw	r0,GPR0(r1); \
-	mfspr	r2,SPR0; \
-	stw	r2,GPR1(r1); \
-	mfspr	r2,SPR1; \
-	stw	r2,GPR2(r1); \
-	mfspr	r2,SPR2; \
-	stw	r2,_NIP(r1); \
-	mfspr	r2,SPR3; \
-	stw	r2,_MSR(r1); \
-	mfctr	r2; \
-	stw	r2,_CTR(r1); \
-	mflr	r2; \
-	stw	r2,_LINK(r1); \
-	mfcr	r2; \
-	stw	r2,_CCR(r1); \
-	mfspr	r2,XER; \
-	stw	r2,_XER(r1); \
-	mffs	fr0; \
-	stfd	fr0,FPCSR(r1); \
-	lis	r2,_break_lwarx@h; \
-	ori	r2,r2,_break_lwarx@l; \
-	stwcx.	r2,0,r2; \
-	li	r2,mark; \
-	stw	r2,TRAP(r1); \
-	lis	r2,0xDEAD; \
-	ori	r2,r2,0xDEAD; \
-	stw	r2,MARKER(r1); \
-	li	r2,0; \
-	stw	r2,RESULT(r1)
-
-
-/* save registers clobbered by a page fault handler */
-#define SAVE_PAGE_FAULT_REGS(offset) \
-	mfspr	r2,DAR; \
- 	stw	r2,_DAR(r1); \
-	mfspr	r2,DSISR; \
-	stw	r2,_DSISR(r1); \
-	mfspr	r2,PVR;			/* Check for 603/603e */ \
-	srwi	r2,r2,16; \
-	cmpi	0,r2,3;			/* 603 */ \
-	beq	22f; \
-	cmpi	0,r2,6;			/* 603e */ \
-	bne	24f; \
-22:	mfspr	r2,HASH1; 		/* Note: these registers exist only on 603 */ \
-	stw	r2,_HASH1(r1); \
-	mfspr	r2,HASH2; \
-	stw	r2,_HASH2(r1); \
-	mfspr	r2,IMISS; \
-	stw	r2,_IMISS(r1); \
-	mfspr	r2,DMISS; \
-	stw	r2,_DMISS(r1); \
-	mfspr	r2,ICMP; \
-	stw	r2,_ICMP(r1); \
-	mfspr	r2,DCMP; \
-	stw	r2,_DCMP(r1); \
-24:	
-
-#define SAVE_INT_REGS(mark) \
-	mtspr	SPR0,r1;	/* Save current stack pointer */ \
-	mtspr	SPR1,r2;	/* Scratch */ \
-	mfcr	r2; \
-	mtspr	SPR2,r2; \
-	mfspr	r2,SRR1;	/* Interrupt from user/system mode */ \
-	andi.	r2,r2,MSR_PR; \
-	beq+	10f;		/* Jump if system - already have stack */ \
-	mfspr	r2,SPR2;	/* Restore CCR */ \
-	mtcrf	0xFF,r2; \
-	mfspr	r2,SRR0;	/* Preserve interrupt registers */ \
-	mtspr	SPR2,r2; \
-	mfspr	r2,SRR1; \
-	mtspr	SPR3,r2; \
-	lis	r2,05f@h; \
-	ori	r2,r2,05f@l; \
-	mtspr	SRR0,r2; \
-	mfmsr	r2; \
-	ori	r2,r2,MSR_|MSR_DR|MSR_IR; \
-	mtspr	SRR1,r2; \
-	rfi; \
-05:	lis	r2,current_set@ha; \
-	lwz	r2,current_set@l(r2); \
-	mfspr	r1,SPR2; \
-	stw	r1,TSS+LAST_PC(r2); \
-	mfspr	r1,SPR0; \
-	stw	r1,TSS+USER_STACK(r2); \
-	lwz	r1,TSS+KSP(r2); \
-	subi	r1,r1,INT_FRAME_SIZE;	/* Make room for frame */ \
-	stw	r1,TSS+PT_REGS(r2); 	/* Save regs pointer for 'ptrace' */ \
-	lwz	r1,TSS+KSP(r2); \
-	b	20f; \
-10:	mfspr	r2,SPR2;	/* Restore CCR */ \
-	mtcrf	0xFF,r2; \
-	mfspr	r2,SRR0;	/* Preserve interrupt registers */ \
-	mtspr	SPR2,r2; \
-	mfspr	r2,SRR1; \
-	mtspr	SPR3,r2; \
-	lis	r2,20f@h; \
-	ori	r2,r2,20f@l; \
-	mtspr	SRR0,r2; \
-	mfmsr	r2; \
-	ori	r2,r2,MSR_|MSR_DR|MSR_IR; \
-	mtspr	SRR1,r2; \
-	SYNC(); \
-	rfi; \
-20:	SAVE_ALL_REGS(mark); \
-	CHECK_STACK()
-
-#define RETURN_FROM_INT(mark) \
-90:	mfmsr	r0;		/* Disable interrupts */ \
-	li	r4,0; \
-	ori	r4,r4,MSR_EE; \
-	andc	r0,r0,r4; \
-	sync; 			/* Some chip revs need this... */ \
-	mtmsr	r0; \
-	lis	r2,intr_count@ha; /* Need to run 'bottom half' */ \
-	lwz	r3,intr_count@l(r2); \
-	cmpi	0,r3,0; \
-	bne	00f; \
-	lis	r4,bh_mask@ha; \
-	lwz	r4,bh_mask@l(r4); \
-	lis	r5,bh_active@ha; \
-	lwz	r5,bh_active@l(r5); \
-	and.	r4,r4,r5; \
-	beq	00f; \
-	addi	r3,r3,1; \
-	stw	r3,intr_count@l(r2); \
-	bl	_EXTERN(_do_bottom_half); \
-	lis	r2,intr_count@ha; \
-	lwz	r3,intr_count@l(r2); \
-	subi	r3,r3,1; \
-	stw	r3,intr_count@l(r2); \
-00:	lwz	r2,_MSR(r1); /* Returning to user mode? */ \
-	andi.	r2,r2,MSR_PR; \
-	beq+	10f;		/* no - no need to mess with stack */ \
-/*	lis	r2,kernel_pages_are_copyback@ha; \
-	lwz	r2,kernel_pages_are_copyback@l(r2); \
-	cmpi	0,r2,0; \
-	beq	05f; \
-	bl	_EXTERN(flush_instruction_cache); */ \
-05:	lis	r3,current_set@ha;	/* need to save kernel stack pointer */ \
-	lwz	r3,current_set@l(r3); \
-	/*addi	r4,r1,INT_FRAME_SIZE*/;	/* size of frame */ \
-	lwz	r4, KERNEL_STACK_PAGE(r3); \
-	addi	r4,r4,KERNEL_STACK_SIZE; /* reset stack pointer to top of stack page */ \
-	/* stack isn't 0'd so show_task():sched.c shows highwater of stack */ \
-	stw	r4,TSS+KSP(r3); \
-	lwz	r4,STATE(r3);	/* If state != 0, can't run */ \
-	cmpi	0,r4,0; \
-	beq	06f; \
-	bl	_EXTERN(schedule); \
-	b	90b; \
-06:	lwz	r4,COUNTER(r3);	/* Time quantum expired? */ \
-	cmpi	0,r4,0; \
-	bne	07f; \
-	bl	_EXTERN(schedule); \
-	b	90b; \
-07:	lwz	r4,BLOCKED(r3);	/* Check for pending unblocked signals */ \
-	lwz	r5,SIGNAL(r3); \
-	andc.	r0,r5,r4;	/* Lets thru any unblocked */ \
-	beq	10f; \
-	mr	r3,r4; \
-	mr	r4,r1; \
-	bl	_EXTERN(do_signal); \
-10:	lwz	r2,_NIP(r1);	/* Restore environment */ \
-	mtspr	SRR0,r2; \
-	lwz	r2,_MSR(r1); \
-	mtspr	SRR1,r2; \
-	lmw	r3,GPR3(r1); \
-	lwz	r2,_CTR(r1); \
-	mtctr	r2; \
-	lwz	r2,_LINK(r1); \
-	mtlr	r2; \
-	lwz	r2,_XER(r1); \
-	mtspr	XER,r2; \
-	lfd	fr0,FPCSR(r1); \
-	mtfsf	0xFF,fr0; \
-	RESTORE_FP_REGS(mark) ; \
-	lwz	r2,_CCR(r1); \
-	mtcrf	0xFF,r2; \
-	lwz	r0,GPR0(r1); \
-	lwz	r2,GPR2(r1); \
-	lwz	r1,GPR1(r1); \
-	SYNC(); \
-	rfi
+
 
 	
-_TEXT()
-/*
- * This code may be executed by a bootstrap process.  If so, the
- * purpose is to relocate the loaded image to it's final location
- * in memory.
- *    R3: End of image
- *    R4: Start of image - 0x400
- *   R11: Start of command line string
- *   R12: End of command line string
- *   R30: 'BeBx' if this is a BeBox
- *
- */
-	.globl	_start
+	.text
 	.globl	_stext
 _stext:
-_start:
-	addi	r4,r4,0x400	/* Point at start of image */
-	li	r5,0		/* Load address */
-	subi	r4,r4,4		/* Adjust for auto-increment */
-	subi	r5,r5,4
-	subi	r3,r3,4
-00:	lwzu	r0,4(r4)	/* Fast move */
-	stwu	r0,4(r5)
-	cmp	0,r3,r4
-	bne	00b
-	li	r5,0x100	/* Actual code starts here */
-	mtlr	r5
-	blr
 
-hang:
-	ori	r0,r0,0
-	b	hang
+#ifdef CONFIG_PREP	
+	. = 0x100
+_GLOBAL(HardReset)
+	b	_start
 
-/*
- * BeBox CPU #1 vector & code
- */	
-_ORG(0x0080)
-	.globl	BeBox_CPU1_vector
-BeBox_CPU1_vector:
-	.long	0
-BeBox_CPU1_reset:
-	li	r1,BeBox_CPU1_vector@l
-	li	r2,0
-	stw	r2,0(r1)
-00:	lwz	r2,0(r1)
-	cmpi	0,r2,0
-	bne	10f
-	li	r2,10000
-	mtctr	r2
-02:	nop
-	bdnz	02b
-	b	00b
-10:	mtlr	r1
-	blr	
-	
-_ORG(0x0100)
+#endif /* CONFIG_PREP */
 
-/* Hard Reset */
-	.globl	HardReset
-HardReset:
-	b	Reset
+#ifdef CONFIG_PMAC
+/*
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
+ */
+	.text
+	.globl	_start
+_start:
+	.long	TOPHYS(__start),0,0
 
-_ORG(0x0200)
-	b	MachineCheck
+/*
+ * Enter here with the kernel text, data and bss loaded starting at
+ * 0, running with virtual == physical mapping.
+ * r5 points to the prom entry point (the client interface handler
+ * address).  Address translation is turned on, with the prom
+ * managing the hash table.  Interrupts are disabled.  The stack
+ * pointer (r1) points to just below the end of the half-meg region
+ * from 0x380000 - 0x400000, which is mapped in already.
+ */
+	.globl	__start
+__start:
+
+/*
+ * Use the first pair of BAT registers to map the 1st 8MB
+ * of RAM to KERNELBASE.
+ */
+	mfspr	r9,PVR
+	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
+	cmpi	0,r9,1
+	lis	r7,KERNELBASE@h
+	bne	4f
+	ori	r7,r7,4			/* set up BAT registers for 601 */
+	li	r8,0x7f
+	b	5f
+4:	ori	r7,r7,0xff		/* set up BAT registers for 604 */
+	li	r8,2
+	mtspr	DBAT0U,r7
+	mtspr	DBAT0L,r8
+5:	mtspr	IBAT0U,r7
+	mtspr	IBAT0L,r8
+	isync
+
+/*
+ * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
+ * refer to addresses of data items, procedures, etc. normally.
+ */
+	lis	r7,start_here@ha	/* jump up to our copy at KERNELBASE */
+	addi	r7,r7,start_here@l
+	mtlr	r7
+	blr
+#endif /* CONFIG_PMAC */
 
-_ORG(0x0300)
-	b	DataAccess
 
-_ORG(0x0400)
-	b	InstructionAccess
 
-_ORG(0x0500)
-	b	HardwareInterrupt
 	
-_ORG(0x0600)
-	b	Alignment
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)	stw	n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)	lwz	n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)	stfd	n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)	lfd	n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
+/*
+ * Exception entry code.  This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
+ */
+#define EXCEPTION_PROLOG	\
+0:	mtspr	SPRG0,r20;	\
+	mtspr	SPRG1,r21;	\
+	mfcr	r20;		\
+	mfspr	r21,SRR1;		/* test whether from user or kernel */\
+	andi.	r21,r21,MSR_PR;	\
+	mr	r21,r1;			/* from kernel - use current sp */\
+	beq	1f;		\
+	mfspr	r21,SPRG3;		/* from user - load kernel sp */\
+	lwz	r21,KSP(r21);	\
+1:	addis	r21,r21,-KERNELBASE@h;	/* convert sp to physical */	\
+	subi	r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD;	/* alloc exc. frame */\
+	stw	r1,GPR1(r21);	\
+	stw	r1,0(r21);	\
+	addis	r1,r21,KERNELBASE@h;	/* set new kernel sp */		\
+	stw	r20,_CCR(r21);		/* save registers */		\
+	stw	r22,GPR22(r21);	\
+	stw	r23,GPR23(r21);	\
+	mfspr	r20,SPRG0;	\
+	stw	r20,GPR20(r21);	\
+	mfspr	r22,SPRG1;	\
+	stw	r22,GPR21(r21);	\
+	mflr	r20;		\
+	stw	r20,_LINK(r21);	\
+	mfctr	r22;		\
+	stw	r22,_CTR(r21);	\
+	mfspr	r20,XER;	\
+	stw	r20,_XER(r21);	\
+	mfspr	r22,SRR0;	\
+	mfspr	r23,SRR1;		/* we can now take exceptions */\
+	stw	r0,GPR0(r21);	\
+	stw	r2,GPR2(r21);	\
+	SAVE_4GPRS(3, r21);
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
+ */
+
+/*
+ * Exception vectors.
+ */
+#define STD_EXCEPTION(n, label, hdlr)		\
+	. = n;					\
+label:						\
+	EXCEPTION_PROLOG;			\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;	\
+	li	r20,MSR_KERNEL;			\
+	bl	transfer_to_handler; 		\
+	.long	hdlr;				\
+	.long	int_return
+
+#ifndef CONFIG_PREP
+/* System reset */
+	STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif /* ndef CONFIG_PREP */
 
-_ORG(0x0700)
-	b	ProgramCheck
+/* Machine check */
+	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
 
-_ORG(0x0800)
-	b	FloatingPointCheck
+/* Data access exception */
+	. = 0x300
+DataAccess:
+	EXCEPTION_PROLOG
+	mfspr	r20,DSISR
+	andis.	r0,r20,0x8470		/* weird error? */
+	bne	1f			/* if not, try to put a PTE */
+	mfspr	r3,DAR			/* into the hash table */
+	rlwinm	r4,r23,32-13,30,30	/* MSR_PR -> _PAGE_USER */
+	rlwimi	r4,r20,32-23,29,29	/* DSISR_STORE -> _PAGE_RW */
+	mfspr	r5,SPRG3		/* phys addr of TSS */
+	bl	hash_page
+1:	stw	r20,_DSISR(r21)
+	mr	r5,r20
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	bl	transfer_to_handler
+	.long	do_page_fault
+	.long	int_return
+
+/* Instruction access exception */
+	. = 0x400
+InstructionAccess:	
+	EXCEPTION_PROLOG
+	andis.	r0,r23,0x4000		/* no pte found? */
+	beq	1f			/* if so, try to put a PTE */
+	mr	r3,r22			/* into the hash table */
+	rlwinm	r4,r23,32-13,30,30	/* MSR_PR -> _PAGE_USER */
+	mr	r20,r23			/* SRR1 has reason bits */
+	mfspr	r5,SPRG3		/* phys addr of TSS */
+	bl	hash_page
+1:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	mr	r4,r22
+	mr	r5,r23
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	bl	transfer_to_handler
+	.long	do_page_fault
+	.long	int_return
+
+/* External interrupt */
+	STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+
+/* Alignment exception */
+	. = 0x600
+Alignment:
+	EXCEPTION_PROLOG
+	mfspr	r4,DAR
+	stw	r4,_DAR(r21)
+	mfspr	r5,DSISR
+	stw	r5,_DSISR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	bl	transfer_to_handler
+	.long	AlignmentException
+	.long	int_return
 
-/* Decrementer register - ignored for now... */
+/* Program check exception */
+	. = 0x700
+ProgramCheck:
+	EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	bl	transfer_to_handler
+	.long	ProgramCheckException
+	.long	int_return
+
+/* Floating-point unavailable */
+	. = 0x800
+FPUnavailable:
+	EXCEPTION_PROLOG
+	bne	load_up_fpu		/* if from user, just load it up */
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler	/* if from kernel, take a trap */
+	.long	KernelFP
+	.long	int_return
+
+/* Decrementer */
+#ifdef CONFIG_PREP
+/* - ignored for now... */
 _ORG(0x0900)
-/* TRACE_TRAP(0x900) */
-	mtspr	SPR0,r1
+	mtspr	SPRG0,r1
 	lis	r1,0x7FFF
 	ori	r1,r1,0xFFFF
 	mtspr	DEC,r1
-	mfspr	r1,SPR0
-#if 0	
-	SYNC
-#endif	
+	mfspr	r1,SPRG0
 	rfi
-	
-_ORG(0x0A00)
-DEFAULT_TRAP(0x0A00)	
-_ORG(0x0B00)
-DEFAULT_TRAP(0x0B00)
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
+	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+#endif /* CONFIG_PMAC */
 
-/*
- * System call
- */
-_ORG(0x0C00)
-	b	SystemCall
+	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
 
-_ORG(0x0D00)
-	b	SingleStep
+/* System call */
+	. = 0xc00
+SystemCall:
+	EXCEPTION_PROLOG
+	stw	r3,ORIG_GPR3(r21)
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* copy EE bit from saved MSR */
+	bl	transfer_to_handler
+	.long	DoSyscall
+	.long	int_return
+
+/* Single step - not used on 601 */
+	STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
 
-_ORG(0x0E00)
-DEFAULT_TRAP(0x0E00)	
-_ORG(0x0F00)
-DEFAULT_TRAP(0x0F00)	
+	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
 
 /*
- * Handle TLB Miss on an instruction load
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
  */
-_ORG(0x1000)
-/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
-/* could be a 'trace' in progress when the TLB miss occurs.          */
-/* TRACE_TRAP(0x1000) */
-	b	InstructionTLBMiss
+	. = 0x1000
+InstructionTLBMiss:
+	mfctr	r0		/* Need to save this - CTR can't be touched! */
+	mfspr	r2,HASH1	/* Get PTE pointer */
+	mfspr	r3,ICMP		/* Partial item compare value */
+00:	li	r1,8		/* 8 items / bucket */
+	mtctr	r1
+	subi	r2,r2,8		/* Preset pointer */
+10:	lwzu	r1,8(r2)	/* Get next PTE */
+	cmp	0,r1,r3		/* Found entry yet? */
+	bdnzf	2,10b		/* Jump back if not, until CTR==0 */
+	bne	30f		/* Try secondary hash if CTR==0 */
+	lwz	r1,4(r2)	/* Get second word of entry */
+20:	mtctr	r0		/* Restore CTR */
+	mfspr	r3,SRR1		/* Need to restore CR0 */
+	mtcrf	0x80,r3
+	mfspr	r0,IMISS	/* Set to update TLB */
+	mtspr	RPA,r1
+	tlbli	r0
+	rfi			/* All done */
+/* Secondary hash */
+30:	andi.	r1,r3,0x40	/* Already doing secondary hash? */
+	bne	InstructionAddressInvalid /* Yes - item not in hash table */
+	mfspr	r2,HASH2	/* Get hash table pointer */
+	ori	r3,r3,0x40	/* Set secondary hash */
+	b	00b		/* Try lookup again */
+InstructionAddressInvalid:
+	mfspr	r3,SRR1
+	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
+	addis	r1,r1,0x4000	/* Set bit 1 -> PTE not found */
+	mtspr	DSISR,r1
+	mtctr	r0		/* Restore CTR */
+	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
+	or	r2,r2,r1
+	mtspr	SRR1,r2
+	mfspr	r1,IMISS	/* Get failing address */
+	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
+	beq	20f		/* Jump if big endian */
+	xori	r1,r1,3
+20:	mtspr	DAR,r1		/* Set fault address */
+	mfmsr	r0		/* Restore "normal" registers */
+	xoris	r0,r0,MSR_TGPR>>16
+	mtcrf	0x80,r3		/* Restore CR0 */
+	sync			/* Some chip revs have problems here... */
+	mtmsr	r0
+	b	InstructionAccess
 
 /*
- * Handle TLB Miss on a data item load
+ * Handle TLB miss for DATA Load operation on 603/603e
  */
-_ORG(0x1100)
-/* TRACE_TRAP(0x1100) */
-	b	DataLoadTLBMiss
+	. = 0x1100
+DataLoadTLBMiss:
+	mfctr	r0		/* Need to save this - CTR can't be touched! */
+	mfspr	r2,HASH1	/* Get PTE pointer */
+	mfspr	r3,DCMP		/* Partial item compare value */
+00:	li	r1,8		/* 8 items / bucket */
+	mtctr	r1
+	subi	r2,r2,8		/* Preset pointer */
+10:	lwzu	r1,8(r2)	/* Get next PTE */
+	cmp	0,r1,r3		/* Found entry yet? */
+	bdnzf	2,10b		/* Jump back if not, until CTR==0 */
+	bne	30f		/* Try secondary hash if CTR==0 */
+	lwz	r1,4(r2)	/* Get second word of entry */
+20:	mtctr	r0		/* Restore CTR */
+	mfspr	r3,SRR1		/* Need to restore CR0 */
+	mtcrf	0x80,r3
+	mfspr	r0,DMISS	/* Set to update TLB */
+	mtspr	RPA,r1
+	tlbld	r0
+	rfi			/* All done */
+/* Secondary hash */
+30:	andi.	r1,r3,0x40	/* Already doing secondary hash? */
+	bne	DataAddressInvalid /* Yes - item not in hash table */
+	mfspr	r2,HASH2	/* Get hash table pointer */
+	ori	r3,r3,0x40	/* Set secondary hash */
+	b	00b		/* Try lookup again */
+DataAddressInvalid:
+	mfspr	r3,SRR1
+	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
+	addis	r1,r1,0x4000	/* Set bit 1 -> PTE not found */
+	mtspr	DSISR,r1
+	mtctr	r0		/* Restore CTR */
+	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
+	mtspr	SRR1,r2
+	mfspr	r1,DMISS	/* Get failing address */
+	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
+	beq	20f		/* Jump if big endian */
+	xori	r1,r1,3
+20:	mtspr	DAR,r1		/* Set fault address */
+	mfmsr	r0		/* Restore "normal" registers */
+	xoris	r0,r0,MSR_TGPR>>16
+	mtcrf	0x80,r3		/* Restore CR0 */
+	sync			/* Some chip revs have problems here... */
+	mtmsr	r0
+	b	DataAccess
 
 /*
- * Handle TLB Miss on a store operation
+ * Handle TLB miss for DATA Store on 603/603e
  */
-_ORG(0x1200)
-/* TRACE_TRAP(0x1200) */
-	b	DataStoreTLBMiss
+	. = 0x1200
+DataStoreTLBMiss:
+	mfctr	r0		/* Need to save this - CTR can't be touched! */
+	mfspr	r2,HASH1	/* Get PTE pointer */
+	mfspr	r3,DCMP		/* Partial item compare value */
+00:	li	r1,8		/* 8 items / bucket */
+	mtctr	r1
+	subi	r2,r2,8		/* Preset pointer */
+10:	lwzu	r1,8(r2)	/* Get next PTE */
+	cmp	0,r1,r3		/* Found entry yet? */
+	bdnzf	2,10b		/* Jump back if not, until CTR==0 */
+	bne	30f		/* Try secondary hash if CTR==0 */
+	lwz	r1,4(r2)	/* Get second word of entry */
+20:	mtctr	r0		/* Restore CTR */
+	mfspr	r3,SRR1		/* Need to restore CR0 */
+	mtcrf	0x80,r3
+	mfspr	r0,DMISS	/* Set to update TLB */
+	mtspr	RPA,r1
+	tlbld	r0
+	rfi			/* All done */	
+/* Secondary hash */
+30:	andi.	r1,r3,0x40	/* Already doing secondary hash? */
+	bne	DataAddressInvalid /* Yes - item not in hash table */
+	mfspr	r2,HASH2	/* Get hash table pointer */
+	ori	r3,r3,0x40	/* Set secondary hash */
+	b	00b			/* Try lookup again */
 
-_ORG(0x1300)
-InstructionAddressBreakpoint:
-	DEFAULT_TRAP(0x1300)
+/* Instruction address breakpoint exception (on 603/604) */
+	STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
 
-_ORG(0x1400)
-SystemManagementInterrupt:
-	DEFAULT_TRAP(0x1400)
+/* System management exception (603?) */
+	STD_EXCEPTION(0x1400, Trap_14, UnknownException)
 
-_ORG(0x1500)
+	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+
+/* Run mode exception */
+	STD_EXCEPTION(0x2000, RunMode, RunModeException)
+
+	STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+	STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+	STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+	STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+	STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+	STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+	STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+	STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+	STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+	. = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception, turning
+ * on address translation.
+ */
+	.globl	transfer_to_handler
+transfer_to_handler:
+	stw	r22,_NIP(r21)
+	stw	r23,_MSR(r21)
+	SAVE_GPR(7, r21)
+	SAVE_4GPRS(8, r21)
+	SAVE_8GPRS(12, r21)
+	SAVE_8GPRS(24, r21)
+	andi.	r23,r23,MSR_PR
+	mfspr	r23,SPRG3		/* if from user, fix up tss */
+	beq	2f
+#ifdef CONFIG_PMAC	
+	lwz	r24,GPR1(r21)
+	stw	r22,LAST_PC(r23)
+	stw	r24,USER_STACK(r23)
+#endif /* CONFIG_PMAC */
+	addi	r24,r1,STACK_FRAME_OVERHEAD
+	stw	r24,PT_REGS(r23)
+2:	addi	r2,r23,-TSS		/* set r2 to current */
+	addis	r2,r2,KERNELBASE@h
+	mflr	r23
+	andi.	r24,r23,0x3f00		/* get vector offset */
+	stw	r24,TRAP(r21)
+	li	r22,0
+	stw	r22,RESULT(r21)
+	lwz	r24,0(r23)		/* virtual address of handler */
+	lwz	r23,4(r23)		/* where to go when done */
+	mtspr	SRR0,r24
+	mtspr	SRR1,r20
+	mtlr	r23
+	SYNC
+	rfi				/* jump to handler, enable MMU */
 
 /*
- * This space [buffer] is used to forceably flush the data cache when
- * running in copyback mode.  This is necessary IFF the data cache could
- * contain instructions for which the instruction cache has stale data.
- * Since the instruction cache NEVER snoops the data cache, memory must
- * be made coherent with the data cache to insure that the instruction
- * cache gets a valid instruction stream.  Note that this flushing is
- * only performed when switching from system to user mode since this is
- * the only juncture [as far as the OS goes] where the data cache may
- * contain instructions, e.g. after a disk read.
+ * Continuation of the floating-point unavailable handler.
  */
-#define NUM_CACHE_LINES 128*4
-#define CACHE_LINE_SIZE 32 
-cache_flush_buffer:
-	.space	NUM_CACHE_LINES*CACHE_LINE_SIZE	/* CAUTION! these need to match hardware */
+load_up_fpu:
+	bl	giveup_fpu_unmapped
+	ori	r23,r23,MSR_FP		/* enable use of FP after return */
+	mfspr	r5,SPRG3		/* current task's TSS (phys) */
+	lfd	fr0,TSS_FPSCR-4(r5)
+	mtfsf	0xff,fr0
+	REST_32FPRS(0, r5)
+
+/* use last_task_used_math instead of fpu_tss */
+	lis	r3,last_task_used_math@h/*a*/
+	addis	r3,r3,-KERNELBASE@h
+	subi	r4,r5,TSS
+	addis	r4,r4,KERNELBASE@h
+	stw	r4,last_task_used_math@l(r3)
+#if 0	
+	lis	r3,fpu_tss@ha
+	addis	r4,r5,KERNELBASE@h
+	addis	r3,r3,-KERNELBASE@h
+	stw	r4,fpu_tss@l(r3)
+#endif	
+	/* restore registers and return */
+	lwz	r3,_CCR(r21)
+	lwz	r4,_LINK(r21)
+	mtcrf	0xff,r3
+	mtlr	r4
+	REST_GPR(1, r21)
+	REST_4GPRS(3, r21)
+	/* we haven't used ctr or xer */
+	mtspr	SRR1,r23
+	mtspr	SRR0,r22
+	REST_GPR(20, r21)
+	REST_2GPRS(22, r21)
+	lwz	r21,GPR21(r21)
+ 	SYNC
+	rfi
 
-#if NUM_CACHE_LINES < 512	
-_ORG(0x4000)
-#endif
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r3, and r4 contains access flags:
+ * _PAGE_USER (4) if a user-mode access, ored with
+ * _PAGE_RW (2) if a write.  r20 contains DSISR or SRR1,
+ * so bit 1 (0x40000000) is set if the exception was due
+ * to no matching PTE being found in the hash table.
+ * r5 contains the physical address of the current task's tss.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address.  Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r2 - r6, ctr, lr.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known.  These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0x180000
+Hash_bits = 12				/* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+	.globl	hash_page
+hash_page:
+	/* Get PTE (linux-style) and check access */
+	lwz	r5,PG_TABLES(r5)	/* task's page tables */
+	lis	r2,-KERNELBASE@h
+	add	r5,r5,r2		/* convert to phys addr */
+	rlwimi	r5,r3,12,20,29		/* insert top 10 bits of address */
+	lwz	r5,0(r5)		/* get pmd entry */
+	rlwinm.	r5,r5,0,0,19		/* extract address of pte page */
+	beqlr-				/* return if no mapping */
+	add	r2,r5,r2
+	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
+	lwz	r6,0(r2)		/* get linux-style pte */
+	ori	r4,r4,1			/* set _PAGE_PRESENT bit in access */
+	andc.	r0,r4,r6		/* check access & ~permission */
+	bnelr-				/* return if access not permitted */
+	ori	r6,r6,0x100		/* set _PAGE_ACCESSED in pte */
+	rlwinm	r5,r4,5,24,24		/* _PAGE_RW access -> _PAGE_DIRTY */
+	rlwimi	r5,r4,7,22,22		/* _PAGE_RW -> _PAGE_HWWRITE */
+	or	r6,r6,r5
+	stw	r6,0(r2)		/* update PTE (accessed/dirty bits) */
+
+	/* Convert linux-style PTE to low word of PPC-style PTE */
+	rlwinm	r4,r6,32-9,31,31	/* _PAGE_HWWRITE -> PP lsb */
+	rlwimi	r6,r6,32-1,31,31	/* _PAGE_USER -> PP (both bits now) */
+	ori	r4,r4,0xe04		/* clear out reserved bits */
+	andc	r6,r6,r4		/* PP=2 or 0, when _PAGE_HWWRITE */
+
+	/* Construct the high word of the PPC-style PTE */
+	mfsrin	r5,r3			/* get segment reg for segment */
+	rlwinm	r5,r5,7,1,24		/* put VSID in 0x7fffff80 bits */
+	oris	r5,r5,0x8000		/* set V (valid) bit */
+	rlwimi	r5,r3,10,26,31		/* put in API (abbrev page index) */
+
+	/* Get the address of the primary PTE group in the hash table */
+	.globl	hash_page_patch_A
+hash_page_patch_A:
+	lis	r4,Hash_base@h		/* base address of hash table */
+	rlwimi	r4,r5,32-1,26-Hash_bits,25	/* (VSID & hash_mask) << 6 */
+	rlwinm	r0,r3,32-6,26-Hash_bits,25	/* (PI & hash_mask) << 6 */
+	xor	r4,r4,r0		/* make primary hash */
+
+	/* See whether it was a PTE not found exception or a
+	   protection violation. */
+	andis.	r0,r20,0x4000
+	li	r2,8			/* PTEs/group */
+	bne	10f			/* no PTE: go look for an empty slot */
+	tlbie	r3			/* invalidate TLB entry */
+
+	/* Search the primary PTEG for a PTE whose 1st word matches r5 */
+	mtctr	r2
+	addi	r3,r4,-8
+1:	lwzu	r0,8(r3)		/* get next PTE */
+	cmp	0,r0,r5
+	bdnzf	2,1b			/* loop while ctr != 0 && !cr0.eq */
+	beq+	found_slot
+
+	/* Search the secondary PTEG for a matching PTE */
+	ori	r5,r5,0x40		/* set H (secondary hash) bit */
+	.globl	hash_page_patch_B
+hash_page_patch_B:
+	xoris	r3,r4,Hash_msk>>16	/* compute secondary hash */
+	xori	r3,r3,0xffc0
+	addi	r3,r3,-8
+	mtctr	r2
+2:	lwzu	r0,8(r3)
+	cmp	0,r0,r5
+	bdnzf	2,2b
+	beq+	found_slot
+	xori	r5,r5,0x40		/* clear H bit again */
+
+	/* Search the primary PTEG for an empty slot */
+10:	mtctr	r2
+	addi	r3,r4,-8		/* search primary PTEG */
+1:	lwzu	r0,8(r3)		/* get next PTE */
+	cmpi	0,r0,0			/* empty? */
+	bdnzf	2,1b			/* loop while ctr != 0 && !cr0.eq */
+	beq+	found_empty
+
+	/* Search the secondary PTEG for an empty slot */
+	ori	r5,r5,0x40		/* set H (secondary hash) bit */
+	.globl	hash_page_patch_C
+hash_page_patch_C:
+	xoris	r3,r4,Hash_msk>>16	/* compute secondary hash */
+	xori	r3,r3,0xffc0
+	addi	r3,r3,-8
+	mtctr	r2
+2:	lwzu	r0,8(r3)
+	cmpi	0,r0,0
+	bdnzf	2,2b
+	beq+	found_empty
+
+	/* Choose an arbitrary slot in the primary PTEG to overwrite */
+	xori	r5,r5,0x40		/* clear H bit again */
+	lwz	r2,next_slot@l(0)
+	addi	r2,r2,8
+	andi.	r2,r2,0x38
+	stw	r2,next_slot@l(0)
+	add	r3,r4,r2
+
+	/* Store PTE in PTEG */
+found_empty:
+	stw	r5,0(r3)
+found_slot:
+	stw	r6,4(r3)
+	SYNC
+	/* Return from the exception */
+	lwz	r3,_CCR(r21)
+	lwz	r4,_LINK(r21)
+	lwz	r5,_CTR(r21)
+	mtcrf	0xff,r3
+	mtlr	r4
+	mtctr	r5
+	REST_GPR(0, r21)
+	REST_2GPRS(1, r21)
+	REST_4GPRS(3, r21)
+	/* we haven't used xer */
+	mtspr	SRR1,r23
+	mtspr	SRR0,r22
+	REST_GPR(20, r21)
+	REST_2GPRS(22, r21)
+	lwz	r21,GPR21(r21)
+	SYNC
+	rfi
 
+next_slot:
+	.long	0
 
-/* changed to use r3 as residual pointer (as firmware does), that's all -- Cort */
 /*
- * Hardware reset [actually from bootstrap]
- * Initialize memory management & call secondary init
- * Registers initialized by bootstrap:
- *   R11: Start of command line string
- *   R12: End of command line string
- *   R28: Residual data
- *   R29: Total Memory Size
- *   R30: 'BeBx' if this is a BeBox
- */	
-Reset:
-	lis	r7,0xF000		/* To mask upper 4 bits */
-/* set pointer to residual data */
-	lis	r1,resptr@h
-	ori	r1,r1,resptr@l
-	andc	r1,r1,r7
-/* changed to use r3 as residual pointer (as firmware does) -- Cort */
-/* this is only a ptr, the actual data is copied in mmu_init */
-	stw	r3,0(r1)
-	
-/* Copy argument string */
-	li	r0,0		/* Null terminate string */
-	stb	r0,0(r12)
-	lis	r1,cmd_line@h
-	ori	r1,r1,cmd_line@l
-	andc	r1,r1,r7	/* No MMU yet - need unmapped address */
-	subi	r1,r1,1
-	subi	r11,r11,1
-00:	lbzu	r0,1(r11)
-	cmpi	0,r0,0
-	stbu	r0,1(r1)
-	bne	00b
+ * This is where the main kernel code starts.
+ */
 
-#define IS_BE_BOX	0x42654278	/* 'BeBx' */
-	lis	r1,isBeBox@h
-	ori	r1,r1,isBeBox@l
-	andc	r1,r1,r7
-/* See if this is a CPU other than CPU#1 */
-/* This [currently] happens on the BeBox */
-	lwz	r2,0(r1)
-	cmpi	0,r2,0
-	bne	Reset_BeBox_CPU1
-/* Save machine type indicator */
-	li	r2,0
-	lis	r3,IS_BE_BOX>>16
-	ori	r3,r3,IS_BE_BOX&0xFFFF
-	cmp	0,r30,r3
-	bne	00f
-	li	r2,1
-	mr	r11,r28
-	mr	r12,r29
-	lis	r5,BeBox_CPU1_vector@h
-	ori	r5,r5,BeBox_CPU1_vector@l
-	andc	r5,r5,r7		/* Tell CPU #1 where to go */
-00:	stw	r2,0(r1)
-	stw	r30,4(r1)
-	
+start_here:
+	/*
+	 * Enable caches and 604-specific features if necessary.
+	 */
+	mfspr	r9,PVR
+	rlwinm	r9,r9,16,16,31
+	cmpi	0,r9,1
+	beq	4f			/* not needed for 601 */
+	mfspr	r7,HID0
+	andi.	r0,r7,HID0_DCE
+	ori	r7,r7,HID0_ICE|HID0_DCE
+	ori	r8,r7,HID0_ICFI
+	bne	3f			/* don't invalidate the D-cache */
+	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
+3:	sync
+	mtspr	HID0,r8			/* enable and invalidate caches */
+	sync
+	mtspr	HID0,r7			/* enable caches */
+	sync
+	isync
+	cmpi	0,r9,4			/* check for 604 */
+	cmpi	1,r9,9			/* or 604e */
+	cror	2,2,6
+	bne	4f
+	ori	r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+	mtspr	HID0,r7			/* superscalar exec & br history tbl */
+4:
+	/* ptr to current */
+	lis	r2,init_task_union@h
+	ori	r2,r2,init_task_union@l
+	/* ptr to phys current tss */
+	addis	r3,r2,-KERNELBASE@h
+	addi	r3,r3,TSS	/* init task's TSS */
+	mtspr	SPRG3,r3
+	/* stack */
+	addi	r1,r2,TASK_UNION_SIZE
+	li	r0,0
+	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
 
-#if 0	
-	lis	r1,sys_stack@h
-	ori	r1,r1,sys_stack@l
-#else
-	lis	r1,init_kernel_stack@h
-	ori	r1,r1,init_kernel_stack@l
-#endif
-	addi	r1,r1,0x1000	/* top of stack */
-#if 0	
-	li	r2,0x0FFF	/* Mask stack address down to page boundary */
-#endif
-	andc	r1,r1,r2
-	subi	r1,r1,INT_FRAME_SIZE	/* Padding for first frame */
-	li	r2,0		/* TOC pointer for nanokernel */
-	li	r0,MSR_		/* Make sure FPU enabled */
-	mtmsr	r0
-	lis	r3,_edata@h	/* Clear BSS */
-	ori	r3,r3,_edata@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lis	r4,_end@h
-	ori	r4,r4,_end@l
-	andc	r4,r4,r7	/* make unmapped address */
-	subi	r3,r3,4
+	/* Clear out the BSS */
+	lis	r7,_end@ha
+	addi	r7,r7,_end@l
+	lis	r8,__bss_start@ha
+	addi	r8,r8,__bss_start@l
+	subf	r7,r8,r7
+	addi	r7,r7,3
+	rlwinm.	r7,r7,30,2,31
+	beq	2f
+	addi	r8,r8,-4
+	mtctr	r7
 	li	r0,0
-00:	stwu	r0,4(r3)
-	cmp	0,r3,r4
-	blt	00b
-#if 0	
-/* Save total memory size (passed from bootstrap) */
-	lis	r3,_TotalMemory@h
-	ori	r3,r3,_TotalMemory@l
-	andc	r3,r3,r7	/* make unmapped address */
-	stw	r29,0(r3)
-#endif	
-/* Initialize BAT registers */
-	lis	r3,BAT0@h
-	ori	r3,r3,BAT0@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
+3:	stwu	r0,4(r8)
+	bdnz	3b
+2:
+/*
+ * Initialize the prom stuff (powermacs only) and the MMU.
+ */
+#ifdef CONFIG_PMAC
+	bl	prom_init
+#endif /* CONFIG_PMAC */
+	bl	MMU_init
+
+/*
+ * Go back to running unmapped so we can load up new values
+ * for SDR1 (hash table pointer) and the segment registers
+ * and change to using our exception vectors.
+ */
+	lis	r6,_SDR1@ha
+	lwz	r6,_SDR1@l(r6)
+	li	r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+	lis	r4,2f@h
+	addis	r4,r4,-KERNELBASE@h
+	ori	r4,r4,2f@l
+	mtspr	SRR0,r4
+	mtspr	SRR1,r3
+	rfi
+/* Load up the kernel context */
+2:
+#ifdef CONFIG_PREP
+	/* reload the bats now that MMU_init() has setup them up -- Cort */
+	LOAD_BATS(r3,r0)
+#endif
+
+	SYNC			/* Force all PTE updates to finish */
+	tlbia			/* Clear all TLB entries */
+	mtspr	SDR1,r6
+	li	r0,16		/* load up segment register values */
+	mtctr	r0		/* for context 0 */
+	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1		/* increment VSID */
+	addis	r4,r4,0x1000	/* address of next segment */
+	bdnz	3b
+#ifdef CONFIG_PMAC
+	li	r0,0		/* zot the BATs */
+#if 1
 	mtspr	IBAT0U,r0
-	mtspr	DBAT0U,r0
-	lwz	r0,4(r3)
 	mtspr	IBAT0L,r0
+	mtspr	DBAT0U,r0
 	mtspr	DBAT0L,r0
-	lis	r3,BAT1@h
-	ori	r3,r3,BAT1@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
+#endif
 	mtspr	IBAT1U,r0
-	mtspr	DBAT1U,r0
-	lwz	r0,4(r3)
 	mtspr	IBAT1L,r0
+	mtspr	DBAT1U,r0
 	mtspr	DBAT1L,r0
-/* this BAT mapping will cover all of kernel space */
-#ifdef NEWMM
-	lis	r3,BAT2@h
-	ori	r3,r3,BAT2@l
-#else
-	lis	r3,TMP_BAT2@h
-	ori	r3,r3,TMP_BAT2@l
-#endif
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
 	mtspr	IBAT2U,r0
-	mtspr	DBAT2U,r0
-	lwz	r0,4(r3)
 	mtspr	IBAT2L,r0
+	mtspr	DBAT2U,r0
 	mtspr	DBAT2L,r0
-#if 1
-	lis	r3,BAT3@h
-	ori	r3,r3,BAT3@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
 	mtspr	IBAT3U,r0
-	mtspr	DBAT3U,r0
-	lwz	r0,4(r3)
 	mtspr	IBAT3L,r0
+	mtspr	DBAT3U,r0
 	mtspr	DBAT3L,r0
-#endif	
-/* Now we can turn on the MMU */
-	mfmsr	r3
-	ori	r3,r3,MSR_DR|MSR_IR
-	mtspr	SRR1,r3
-	lis	r3,10f@h
-	ori	r3,r3,10f@l
-	mtspr	SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0000)	
-	SYNC
-	rfi				/* enables MMU */
-10:    	bl	_EXTERN(MMU_init)	/* initialize MMU environment */
-DO_RFI_TRACE_MAPPED(0xDEAD0100)	
-/* Withdraw BAT2->RAM mapping */
-	lis	r7,0xF000		/* To mask upper 4 bits */
-	lis	r3,20f@h
-	ori	r3,r3,20f@l
-	andc	r3,r3,r7	/* make unmapped address */
-	mtspr	SRR0,r3
-	mfmsr	r3
-	li	r4,MSR_DR|MSR_IR
-	andc	r3,r3,r4
-	mtspr	SRR1,r3
-	SYNC
-DO_RFI_TRACE_MAPPED(0xDEAD0200)	
-	SYNC
-	rfi
-20:
-
-DO_RFI_TRACE_UNMAPPED(0xDEAD0400)	
-20:	lis	r3,BAT2@h
-	ori	r3,r3,BAT2@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
-	mtspr	IBAT2U,r0
-	mtspr	DBAT2U,r0
-	lwz	r0,4(r3)
-	mtspr	IBAT2L,r0
-	mtspr	DBAT2L,r0
-/* Load up the kernel context */
-	lis	r2,init_task@h
-	ori	r2,r2,init_task@l
-	addi	r2,r2,TSS
-	andc	r2,r2,r7	/* make unmapped address */
-	SYNC			/* Force all PTE updates to finish */
-	tlbia			/* Clear all TLB entries */
-	lis	r3,_SDR1@h
-	ori	r3,r3,_SDR1@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r3,0(r3)
-	mtspr	SDR1,r3
-	lwz	r0,MMU_SEG0(r2)
-	mtsr	SR0,r0
-	lwz	r0,MMU_SEG1(r2)
-	mtsr	SR1,r0
-	lwz	r0,MMU_SEG2(r2)
-	mtsr	SR2,r0
-	lwz	r0,MMU_SEG3(r2)
-	mtsr	SR3,r0
-	lwz	r0,MMU_SEG4(r2)
-	mtsr	SR4,r0
-	lwz	r0,MMU_SEG5(r2)
-	mtsr	SR5,r0
-	lwz	r0,MMU_SEG6(r2)
-	mtsr	SR6,r0
-	lwz	r0,MMU_SEG7(r2)
-	mtsr	SR7,r0
-	lwz	r0,MMU_SEG8(r2)
-	mtsr	SR8,r0
-	lwz	r0,MMU_SEG9(r2)
-	mtsr	SR9,r0
-	lwz	r0,MMU_SEG10(r2)
-	mtsr	SR10,r0
-	lwz	r0,MMU_SEG11(r2)
-	mtsr	SR11,r0
-	lwz	r0,MMU_SEG12(r2)
-	mtsr	SR12,r0
-	lwz	r0,MMU_SEG13(r2)
-	mtsr	SR13,r0
-	lwz	r0,MMU_SEG14(r2)
-	mtsr	SR14,r0
-	lwz	r0,MMU_SEG15(r2)
-	mtsr	SR15,r0
+#endif
 /* Now turn on the MMU for real! */
-	mfmsr	r3
-	ori	r3,r3,MSR_DR|MSR_IR
-	mtspr	SRR1,r3
-	lis	r3,30f@h
-	ori	r3,r3,30f@l
+	li	r4,MSR_KERNEL
+	lis	r3,start_kernel@h
+	ori	r3,r3,start_kernel@l
 	mtspr	SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0500)	
-	SYNC
-	rfi				/* enables MMU */
-30:
-/* Turn on L1 Data Cache */
-	mfspr	r3,HID0		/* Caches are controlled by this register */
-	ori	r4,r3,(HID0_ICE|HID0_ICFI)
-	ori	r3,r3,(HID0_ICE)
-	ori	r4,r4,(HID0_DCE|HID0_DCI)
-	ori	r3,r3,(HID0_DCE)
-	sync
-	mtspr	HID0,r4
-	mtspr	HID0,r3
-/* L1 cache enable */
-	mfspr	r2,PVR			/* Check for 603/603e */
-	srwi	r2,r2,16
-	cmpi	0,r2,4			/* 604 */
-	bne	40f
-	mfspr	r3,HID0			/* Turn on 604 specific features */
-	ori	r3,r3,(HID0_SIED|HID0_BHTE)
-	mtspr	HID0,r3
-40:	b	_EXTERN(start_kernel)		/* call main code */
-	.long	0		# Illegal!
+	mtspr	SRR1,r4
+	rfi			/* enable MMU and jump to start_kernel */
 
+#ifdef CONFIG_PREP
 /*
- * BeBox CPU #2 runs here
- */
-Reset_BeBox_CPU1:	
-	lis	r1,CPU1_stack@h
-	ori	r1,r1,CPU1_stack@l
-	li	r2,0x0FFF	/* Mask stack address down to page boundary */
-	andc	r1,r1,r2
-	subi	r1,r1,INT_FRAME_SIZE	/* Padding for first frame */
-	lis	r30,CPU1_trace@h
-	ori	r30,r30,CPU1_trace@l
-	andc	r30,r30,r7
-	li	r5,1
-	stw	r5,0(r30)
-	li	r2,0		/* TOC pointer for nanokernel */
-	li	r0,MSR_		/* Make sure FPU enabled */
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader.  The expected layout
+ * of the regs is:	
+ *   R3: End of image
+ *   R4: Start of image - 0x400
+ *   R11: Start of command line string
+ *   R12: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort	
+ */
+	.globl __start
+__start:	
+	.globl _start
+_start:	
+	lis	r7,0xF000		/* To mask upper 4 bits */
+/* save pointer to residual data */
+	lis	r1,resptr@h
+	ori	r1,r1,resptr@l
+	addis	r1,r1,-KERNELBASE@h
+	stw	r3,0(r1)
+/* save argument string */
+	li	r0,0		/* Null terminate string */
+	stb	r0,0(r12)
+	lis	r1,cmd_line@h
+	ori	r1,r1,cmd_line@l
+	addis	r1,r1,-KERNELBASE@h
+	subi	r1,r1,1
+	subi	r11,r11,1
+00:	lbzu	r0,1(r11)
+	cmpi	0,r0,0
+	stbu	r0,1(r1)
+	bne	00b
+/* setup the msr with sane values */
+	li	r0,MSR_
 	mtmsr	r0
-/* Initialize BAT registers */
-	lis	r3,BAT0@h
-	ori	r3,r3,BAT0@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
-	mtspr	IBAT0U,r0
-	mtspr	DBAT0U,r0
-	lwz	r0,4(r3)
-	mtspr	IBAT0L,r0
-	mtspr	DBAT0L,r0
-	lis	r3,BAT1@h
-	ori	r3,r3,BAT1@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
-	mtspr	IBAT1U,r0
-	mtspr	DBAT1U,r0
-	lwz	r0,4(r3)
-	mtspr	IBAT1L,r0
-	mtspr	DBAT1L,r0
-	lis	r3,TMP_BAT2@h
-	ori	r3,r3,TMP_BAT2@l
-	andc	r3,r3,r7	/* make unmapped address */
-	lwz	r0,0(r3)
-	mtspr	IBAT2U,r0
-	mtspr	DBAT2U,r0
-	lwz	r0,4(r3)
-	mtspr	IBAT2L,r0
-	mtspr	DBAT2L,r0
-/* Now we can turn on the MMU */
+/* turn on the mmu with bats covering kernel enough to get started */
+	LOAD_BATS(r3,r0)
 	mfmsr	r3
 	ori	r3,r3,MSR_DR|MSR_IR
 	mtspr	SRR1,r3
 	lis	r3,10f@h
 	ori	r3,r3,10f@l
 	mtspr	SRR0,r3
-	li	r5,2
-	stw	r5,0(r30)
 	SYNC
 	rfi				/* enables MMU */
-10:
-	lis	r30,CPU1_trace@h
-	ori	r30,r30,CPU1_trace@l
-	li	r5,3
-	stw	r5,0(r30)
-	bl	_EXTERN(BeBox_CPU1)
-
-/*
- * Machine Check (Bus Errors, etc)
- */
-MachineCheck:	
-	TRACE_TRAP(0x0200)
-	SAVE_INT_REGS(0x0200)
-	mr	r3,r1		/* Set pointer to saved regs */
-	bl	_EXTERN(MachineCheckException)
-	RETURN_FROM_INT(0x0200)
-
-/*
- * Data Access exception
- */
-DataAccess:
-	SAVE_INT_REGS(0x0300)
-#if 1
-	mfspr	r3, DAR
-	mfspr	r4, DSISR
-	li	r5, 0		/* not a text fault */
-	mr	r6, r1
-	bl	_EXTERN(new_page_fault)
-#else
-	SAVE_PAGE_FAULT_REGS(0x0D00)	
-	mr	r3,r1
-	bl	_EXTERN(DataAccessException)
-#endif	
-	RETURN_FROM_INT(0x0300)
-
-/*
- * Instruction Access Exception
- */
-InstructionAccess:
-	SAVE_INT_REGS(0x0400)
-#if 1
-	mfspr	r3, SPR2 /* srr0 was saved here */
-	mfspr	r4, SPR3 /* srr1 was saved here */
-	li	r5, 1	 /* a text fault */
-	mr	r6, r1
-	bl	_EXTERN(new_page_fault)
-#else
-	SAVE_PAGE_FAULT_REGS(0x0D00)	
-	mr	r3,r1
-	bl	_EXTERN(InstructionAccessException)
-#endif	
-	RETURN_FROM_INT(0x0400)
-
-/*
- * Hardware Interrupt
- */
-HardwareInterrupt:	
-	SAVE_INT_REGS(0x0500)
-	BUMP(__Hardware_Interrupts)
-	mr	r3,r1		/* Set pointer to saved regs */
-	bl	_EXTERN(handle_IRQ)
-	RETURN_FROM_INT(0x0500)
-
-/*
- * Alignment
- */
-Alignment:	
-	TRACE_TRAP(0x0600)
-	SAVE_INT_REGS(0x0600)
-	mr	r3,r1		/* Set pointer to saved regs */
-	bl	_EXTERN(AlignmentException)
-	RETURN_FROM_INT(0x0600)
-
+10:	lis	r7,start_here@ha	/* jump up to our copy at KERNELBASE */
+	addi	r7,r7,start_here@l
+	mtlr	r7
+	blr
+#endif /* CONFIG_PREP */
+	
 /*
- * Illegal instruction
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
  */
-ProgramCheck:
-	TRACE_TRAP(0x0700)
-	SAVE_INT_REGS(0x0700)
-	mr	r3,r1		/* Set pointer to saved regs */
-	bl	_EXTERN(ProgramCheckException)
-	RETURN_FROM_INT(0x0700)
-
-/*
- * Single Step Exception
- */
-SingleStep:
-	SAVE_INT_REGS(0x0D00)
-	SAVE_PAGE_FAULT_REGS(0x0D00)
-	mr	r3,r1		/* Set pointer to saved regs */
-	bl	_EXTERN(SingleStepException)
-#if 0
-	bl	_EXTERN(flush_instruction_cache)
+KernelFP:
+	lwz	r3,_MSR(r1)
+	ori	r3,r3,MSR_FP
+	stw	r3,_MSR(r1)		/* enable use of FP after return */
+	lis	r3,86f@h
+	ori	r3,r3,86f@l
+	mr	r4,r2			/* current */
+	lwz	r5,_NIP(r1)
+	bl	printk
+	b	int_return
+86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
+	.align	4
+
+/*
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * (If giveup_fpu_unmapped uses any integer registers other than
+ * r3 - r6, the return code at load_up_fpu above will have
+ * to be adjusted.)
+ */
+giveup_fpu_unmapped:
+	lis	r6,-KERNELBASE@h
+	b	1f
+
+	.globl	giveup_fpu
+giveup_fpu:
+	li	r6,0
+1:
+	addis	r3,r6,last_task_used_math@h/*a*/
+	lwz	r4,last_task_used_math@l(r3)
+#if 0		
+	addis	r3,r6,fpu_tss@ha
+	lwz	r4,fpu_tss@l(r3)
 #endif	
-	RETURN_FROM_INT(0x0D00)
-
-/*
- * Floating point [not available, etc]
- */
-FloatingPointCheck:	
-	SAVE_INT_REGS(0x0800)
-	mr	r3,r1		/* Set pointer to saved regs */
-	bl	_EXTERN(FloatingPointCheckException)
-	cmpi	0,r3,MSR_FP    /* check if fp was turned on by handler */
-	bne	00f
-	RETURN_FROM_INT(0x0f0f) /* 0xf0f tells to restore fp regs */
-00:	RETURN_FROM_INT(0x0200)
+	mfmsr	r5
+	ori	r5,r5,MSR_FP
+	SYNC
+	mtmsr	r5			/* enable use of fpu now */
+	SYNC
+	cmpi	0,r4,0
+	add	r4,r4,r6
+	beqlr				/* if no previous owner, done */
+	addi	r4,r4,TSS	        /* want TSS of last_task_used_math */
+	li	r5,0
+	stw	r5,last_task_used_math@l(r3)
+#if 0	
+	stw	r5,fpu_tss@l(r3)
+#endif
+	SAVE_32FPRS(0, r4)
+	mffs	fr0
+	stfd	fr0,TSS_FPSCR-4(r4)
+	lwz	r5,PT_REGS(r4)
+	lwz	r5,PT_REGS(r4)
+	add	r5,r5,r6
+	lwz	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r4,MSR_FP
+	andc	r3,r3,r4		/* disable FP for previous task */
+	stw	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+	blr
 
 /*
- * System Call exception
+ * Handle a system call.
  */
-SystemCall:
-	SAVE_INT_REGS(0x0C00)
-	lwz	r2,_CCR(r1)	/* Clear SO bit in CR */
-	lis	r9,0x1000
-	andc	r2,r2,r9
-	stw	r2,_CCR(r1)
+DoSyscall:
+	stw	r0,TSS+LAST_SYSCALL(r2)
+	lwz	r11,_CCR(r1)	/* Clear SO bit in CR */
+	lis	r10,0x1000
+	andc	r11,r11,r10
+	stw	r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+	lis	r31,show_syscalls_task@ha
+	lwz	r31,show_syscalls_task@l(r31)
+	cmp	0,r2,r31
+	bne	1f
+#endif
+	lis	r3,7f@ha
+	addi	r3,r3,7f@l
+	lwz	r4,GPR0(r1)
+	lwz	r5,GPR3(r1)
+	lwz	r6,GPR4(r1)
+	lwz	r7,GPR5(r1)
+	lwz	r8,GPR6(r1)
+	mr	r9,r2
+	bl	printk
+	lwz	r0,GPR0(r1)
+	lwz	r3,GPR3(r1)
+	lwz	r4,GPR4(r1)
+	lwz	r5,GPR5(r1)
+	lwz	r6,GPR6(r1)
+	lwz	r7,GPR7(r1)
+	lwz	r8,GPR8(r1)
+1:
+#endif /* SHOW_SYSCALLS */
 	cmpi	0,r0,0x7777	/* Special case for 'sys_sigreturn' */
-	bne+	10f
-	mr	r3,r1
-	bl	_EXTERN(sys_sigreturn)
-	cmpi	0,r3,0		/* Check for restarted system call */
-	bge	99f
-	b	20f
-10:	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	lwz	r2,TASK_FLAGS(r2)
-	andi.	r2,r2,PF_TRACESYS
-	bne	50f
-	
-	lis	r2,sys_call_table@h
-	ori	r2,r2,sys_call_table@l
+	beq-	10f
+	lwz	r10,TASK_FLAGS(r2)
+	andi.	r10,r10,PF_TRACESYS
+	bne-	50f
+	cmpli	0,r0,NR_syscalls
+	bge-	66f
+	lis	r10,sys_call_table@h
+	ori	r10,r10,sys_call_table@l
 	slwi	r0,r0,2
-	lwzx	r2,r2,r0	/* Fetch system call handler [ptr] */
-#if 1
-	cmpi	0,r2,0		/* make sure syscall handler not 0 */
-	beq	99f
-	cmpi	0,r0,NR_syscalls<<2 /* make sure syscallnum in bounds */
-	bgt	99f
-#endif	
-	mtlr	r2
-	mr	r9,r1
+	lwzx	r10,r10,r0	/* Fetch system call handler [ptr] */
+	cmpi	0,r10,0
+	beq-	66f
+	mtlr	r10
+	addi	r9,r1,STACK_FRAME_OVERHEAD
 	blrl			/* Call handler */
-	
-20:	stw	r3,RESULT(r1)	/* Save result */	
-	cmpi	0,r3,0
-	bge	30f
+	.globl	syscall_ret_1
+syscall_ret_1:
+20:	stw	r3,RESULT(r1)	/* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+	cmp	0,r2,r31
+	bne	91f
+#endif
+	mr	r4,r3
+	lis	r3,79f@ha
+	addi	r3,r3,79f@l
+	bl	printk
+	lwz	r3,RESULT(r1)
+91:
+#endif
+	li	r10,-_LAST_ERRNO
+	cmpl	0,r3,r10
+	blt	30f
 	neg	r3,r3
 	cmpi	0,r3,ERESTARTNOHAND
 	bne	22f
 	li	r3,EINTR
-22:	lwz	r2,_CCR(r1)	/* Set SO bit in CR */
-	oris	r2,r2,0x1000
-	stw	r2,_CCR(r1)
+22:	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
+	oris	r10,r10,0x1000
+	stw	r10,_CCR(r1)
 30:	stw	r3,GPR3(r1)	/* Update return value */
-	b	99f
+	b	int_return
+66:	li	r3,ENOSYS
+	b	22b
+/* sys_sigreturn */
+10:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	_EXTERN(sys_sigreturn)
+	cmpi	0,r3,0		/* Check for restarted system call */
+	bge	int_return
+	b	20b
 /* Traced system call support */
 50:	bl	_EXTERN(syscall_trace)
 	lwz	r0,GPR0(r1)	/* Restore original registers */
@@ -1045,369 +1149,371 @@
 	lwz	r7,GPR7(r1)
 	lwz	r8,GPR8(r1)
 	lwz	r9,GPR9(r1)
-	lis	r2,sys_call_table@h
-	ori	r2,r2,sys_call_table@l
+	cmpli	0,r0,NR_syscalls
+	bge-	66f
+	lis	r10,sys_call_table@h
+	ori	r10,r10,sys_call_table@l
 	slwi	r0,r0,2
-	lwzx	r2,r2,r0	/* Fetch system call handler [ptr] */
-	mtlr	r2
-	mr	r9,r1
+	lwzx	r10,r10,r0	/* Fetch system call handler [ptr] */
+	cmpi	0,r10,0
+	beq-	66f
+	mtlr	r10
+	addi	r9,r1,STACK_FRAME_OVERHEAD
 	blrl			/* Call handler */
+	.globl	syscall_ret_2
+syscall_ret_2:
 	stw	r3,RESULT(r1)	/* Save result */	
-	cmpi	0,r3,0
-	bge	60f
+	stw	r3,GPR0(r1)	/* temporary gross hack to make strace work */
+	li	r10,-_LAST_ERRNO
+	cmpl	0,r3,r10
+	blt	60f
 	neg	r3,r3
 	cmpi	0,r3,ERESTARTNOHAND
 	bne	52f
 	li	r3,EINTR
-52:	lwz	r2,_CCR(r1)	/* Set SO bit in CR */
-	oris	r2,r2,0x1000
-	stw	r2,_CCR(r1)
+52:	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
+	oris	r10,r10,0x1000
+	stw	r10,_CCR(r1)
 60:	stw	r3,GPR3(r1)	/* Update return value */
 	bl	_EXTERN(syscall_trace)
-99:
-	RETURN_FROM_INT(0x0C00)
-
-/*
- * Handle TLB miss for instruction
- */
-InstructionTLBMiss:
-	BUMP_UNMAPPED(__Instruction_TLB_Misses)
-	mfctr	r0		/* Need to save this - CTR can't be touched! */
-	mfspr	r2,HASH1	/* Get PTE pointer */
-	mfspr	r3,ICMP		/* Partial item compare value */
-00:	li	r1,8		/* 8 items / bucket */
-	mtctr	r1
-	subi	r2,r2,8		/* Preset pointer */
-10:	lwzu	r1,8(r2)	/* Get next PTE */
-	cmp	0,r1,r3		/* Found entry yet? */
-	bdne	10b		/* Jump back if not, until CTR==0 */
-	bne	30f		/* Try secondary hash if CTR==0 */
-	lwz	r1,4(r2)	/* Get second word of entry */
-#if 0	
-	andi.	r3,r1,0x08	/* Check guard bit - invalid access if set */
-	bne	InstructionFetchError
-#endif	
-	andi.	r3,r1,0x100	/* Check R bit (referenced) */
-	bne	20f		/* If set, all done */
-	ori	r1,r1,0x100	/* Set bit */
-	stw	r1,4(r2)	/* Update memory image */
-20:	mtctr	r0		/* Restore CTR */
-	mfspr	r3,SRR1		/* Need to restore CR0 */
-	mtcrf	0x80,r3
-	mfspr	r0,IMISS	/* Set to update TLB */
-	mtspr	RPA,r1
-	tlbli	r0
-#if 0	
-	SYNC
+	b	int_return
+66:	li	r3,ENOSYS
+	b	52b
+#ifdef SHOW_SYSCALLS
+7:	.string	"syscall %d(%x, %x, %x, %x), current=%p\n"
+79:	.string	" -> %x\n"
+	.align	2
 #endif
-	rfi			/* All done */
-/* Secondary hash */
-30:	andi.	r1,r3,0x40	/* Already doing secondary hash? */
-	bne	InstructionAddressInvalid /* Yes - item not in hash table */
-	mfspr	r2,HASH2	/* Get hash table pointer */
-	ori	r3,r3,0x40	/* Set secondary hash */
-	b	00b			/* Try lookup again */
 
 /*
- * Handle TLB miss for DATA Load operation
+ * This routine switches between two different tasks.  The process
+ * state of one is saved on its kernel stack.  Then the state
+ * of the other is restored from its kernel stack.  The memory
+ * management hardware is updated to the second process's state.
+ * Finally, we can return to the second process, via int_return.
+ * On entry, r3 points to the TSS for the current task, r4
+ * points to the TSS for the new task, and r5 contains the
+ * MMU context number for the new task.
+ *
+ * Note: there are two ways to get to the "going out" portion
+ * of this code; either by coming in via the entry (_switch)
+ * or via "fork" which must set up an environment equivalent
+ * to the "_switch" path.  If you change this (or in particular, the
+ * SAVE_REGS macro), you'll have to change the fork code also.
+ *
+ * The code which creates the new task context is in 'copy_thread'
+ * in arch/ppc/kernel/process.c
  */	
-DataLoadTLBMiss:
-	mfctr	r0		/* Need to save this - CTR can't be touched! */
-	mfspr	r2,HASH1	/* Get PTE pointer */
-	mfspr	r3,DCMP		/* Partial item compare value */
-00:	li	r1,8		/* 8 items / bucket */
-	mtctr	r1
-	subi	r2,r2,8		/* Preset pointer */
-10:	lwzu	r1,8(r2)	/* Get next PTE */
-	cmp	0,r1,r3		/* Found entry yet? */
-	bdne	10b		/* Jump back if not, until CTR==0 */
-	bne	30f		/* Try secondary hash if CTR==0 */
-	lwz	r1,4(r2)	/* Get second word of entry */
-	andi.	r3,r1,0x100	/* Check R bit (referenced) */
-	ori	r1,r1,0x100	/* Set bit */
-	bne	20f		/* If set, all done */
-	stw	r1,4(r2)	/* Update memory image */
-20:	mtctr	r0		/* Restore CTR */
-	mfspr	r3,SRR1		/* Need to restore CR0 */
-	mtcrf	0x80,r3
-	mfspr	r0,DMISS	/* Set to update TLB */
-	mtspr	RPA,r1
-/*	SYNC() */
-	tlbld	r0
-#if 0	
+_GLOBAL(_switch)
+	stwu	r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+	stw	r0,GPR0(r1)
+	lwz	r0,0(r1)
+	stw	r0,GPR1(r1)
+	SAVE_10GPRS(2, r1)
+	SAVE_10GPRS(12, r1)
+	SAVE_10GPRS(22, r1)
+	mflr	r20		/* Return to switch caller */
+	mfmsr	r22
+	li	r0,MSR_FP	/* Disable floating-point */
+	andc	r22,r22,r0
+	stw	r20,_NIP(r1)
+	stw	r22,_MSR(r1)
+	stw	r20,_LINK(r1)
+	mfcr	r20
+	mfctr	r22
+	mfspr	r23,XER
+	stw	r20,_CCR(r1)
+	stw	r22,_CTR(r1)
+	stw	r23,_XER(r1)
+	li	r0,0x0ff0
+	stw	r0,TRAP(r1)
+	stw	r1,KSP(r3)	/* Set old stack pointer */
+	sync
+	addis	r0,r4,-KERNELBASE@h
+	mtspr	SPRG3,r0	/* Update current TSS phys addr */
 	SYNC
-#endif	
-	rfi			/* All done */
-/* Secondary hash */
-30:	andi.	r1,r3,0x40	/* Already doing secondary hash? */
-	bne	DataAddressInvalid /* Yes - item not in hash table */
-	mfspr	r2,HASH2	/* Get hash table pointer */
-	ori	r3,r3,0x40	/* Set secondary hash */
-	b	00b			/* Try lookup again */
+	lwz	r1,KSP(r4)	/* Load new stack pointer */
+	addi	r2,r4,-TSS	/* Update current */
+	/* Set up segment registers for new task */
+	rlwinm	r5,r5,4,8,27	/* VSID = context << 4 */
+	addis	r5,r5,0x6000	/* Set Ks, Ku bits */
+	li	r0,8		/* TASK_SIZE / SEGMENT_SIZE */
+	mtctr	r0
+	li	r3,0
+3:	mtsrin	r5,r3
+	addi	r5,r5,1		/* next VSID */
+	addis	r3,r3,0x1000	/* address of next segment */
+	bdnz	3b
+	SYNC
+
+/* FALL THROUGH into int_return */
 
 /*
- * Handle TLB miss for DATA STORE
+ * Trap exit.
  */
-DataStoreTLBMiss:
-	BUMP_UNMAPPED(__DataStore_TLB_Misses)
-	mfctr	r0		/* Need to save this - CTR can't be touched! */
-	mfspr	r2,HASH1	/* Get PTE pointer */
-	mfspr	r3,DCMP		/* Partial item compare value */
-00:	li	r1,8		/* 8 items / bucket */
-	mtctr	r1
-	subi	r2,r2,8		/* Preset pointer */
-10:	lwzu	r1,8(r2)	/* Get next PTE */
-	cmp	0,r1,r3		/* Found entry yet? */
-	bdne	10b		/* Jump back if not, until CTR==0 */
-	bne	30f		/* Try secondary hash if CTR==0 */
-	lwz	r1,4(r2)	/* Get second word of entry */
-	andi.	r3,r1,0x80	/* Check C bit (changed) */
-#if 0 /* Note: no validation */
-	beq	40f		/* If not set (first time) validate access */
-#else
-	ori	r1,r1,0x180	/* Set changed, accessed */
-	bne	20f
-	stw	r1,4(r2)
-#endif	
-20:	mtctr	r0		/* Restore CTR */
-	mfspr	r3,SRR1		/* Need to restore CR0 */
-	mtcrf	0x80,r3
-	mfspr	r0,DMISS	/* Set to update TLB */
-	mtspr	RPA,r1
-	tlbld	r0
-#if 0	
+	.globl	int_return
+int_return:
+0:	mfmsr	r30		/* Disable interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r30,r30,r4
+	SYNC			/* Some chip revs need this... */
+	mtmsr	r30
 	SYNC
-#endif	
-	rfi			/* All done */	
-/* Secondary hash */
-30:	andi.	r1,r3,0x40	/* Already doing secondary hash? */
-	bne	DataAddressInvalid /* Yes - item not in hash table */
-	mfspr	r2,HASH2	/* Get hash table pointer */
-	ori	r3,r3,0x40	/* Set secondary hash */
-	b	00b			/* Try lookup again */
-/* PTE found - validate access */
-40:	rlwinm. r3,r1,30,0,1	/* Extract PP bits */
-	bge-	50f		/* Jump if PP=0,1 */
-	andi.	r3,r1,1
-	beq+	70f		/* Access OK */
-	b	WriteProtectError	/* Not OK - fail! */
-50:	mfspr	r3,SRR1		/* Check privilege */
+	lwz	r5,_MSR(r1)
+	and.	r5,r5,r4
+	beq	2f
+3:	lis	r4,lost_interrupts@ha
+	lwz	r4,lost_interrupts@l(r4)
+	cmpi	0,r4,0
+	beq+	1f
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	handle_IRQ
+	b	3b
+1:	lis	r4,bh_mask@ha
+	lwz	r4,bh_mask@l(r4)
+	lis	r5,bh_active@ha
+	lwz	r5,bh_active@l(r5)
+	and.	r4,r4,r5
+	beq+	2f
+	ori	r31,r30,MSR_EE	/* re-enable interrupts */
+	SYNC
+	mtmsr	r31
+	SYNC
+	bl	_EXTERN(do_bottom_half)
+	SYNC
+	mtmsr	r30		/* disable interrupts again */
+	SYNC
+2:	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r3,r3,MSR_PR
-	beq+	60f		/* Jump if supervisor mode */
-	mfspr	r3,DMISS	/* Get address */
-	mfsrin	r3,r3		/* Get segment register */
-	andis.	r3,r3,0x2000	/* If Kp==0, OK */
-	beq+	70f
-	b	WriteProtectError	/* Bad access */
-60:	mfspr	r3,DMISS	/* Get address */
-	mfsrin	r3,r3		/* Get segment register */
-	andis.	r3,r3,0x4000	/* If Ks==0, OK */
-	beq+	70f
-	b	WriteProtectError	/* Bad access */
-70:	ori	r1,r1,0x180	/* Set changed, accessed */
-	stw	r1,4(r2)	/* Update PTE in memory */
-	b	20b
-	
-/*
- * These routines are error paths/continuations of the exception
- * handlers above.  They are placed here to avoid the problems
- * of only 0x100 bytes per exception handler.
- */
- 
-/* Invalid address */
-InstructionAddressInvalid:
-	mfspr	r3,SRR1
-	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
-	addis	r1,r1,0x4000	/* Set bit 1 -> PTE not found */
-	b	10f
-
-/* Fetch from guarded or no-access page */
-InstructionFetchError:
-	mfspr	r3,SRR1
-	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
-	addis	r1,r1,0x0800	/* Set bit 4 -> protection error */
-10:	mtspr	DSISR,r1
-	mtctr	r0		/* Restore CTR */
-	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
-	mtspr	SRR1,r2
-	mfspr	r1,IMISS	/* Get failing address */
-	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
-	beq	20f		/* Jump if big endian */
-	xori	r1,r1,3
-20:	mtspr	DAR,r1		/* Set fault address */
-	mfmsr	r0		/* Restore "normal" registers */
-	xoris	r0,r0,MSR_TGPR>>16
-	mtcrf	0x80,r3		/* Restore CR0 */
-	ori	r0,r0,MSR_FP	/* Need to keep FP enabled */
-	sync			/* Some chip revs have problems here... */
-	mtmsr	r0
-	b	InstructionAccess
+	beq+	10f		/* no - no need to mess with stack */
+	lis	r3,need_resched@ha
+	lwz	r3,need_resched@l(r3)
+	cmpi	0,r3,0		/* check need_resched flag */
+	beq+	7f
+	bl	_EXTERN(schedule)
+	b	0b
+7:	lwz	r3,BLOCKED(r2)	/* Check for pending unblocked signals */
+	lwz	r5,SIGNAL(r2)
+	andc.	r0,r5,r3	/* Lets thru any unblocked */
+	beq+	8f
+	addi	r4,r1,STACK_FRAME_OVERHEAD
+	bl	_EXTERN(do_signal)
+	b	0b
+8:	addi	r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD	/* size of frame */
+	stw	r4,TSS+KSP(r2)	/* save kernel stack pointer */
+10:
+	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	REST_10GPRS(3, r1)
+	REST_10GPRS(13, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
 
-/* Invalid address */
-DataAddressInvalid:
-	mfspr	r3,SRR1
-	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
-	addis	r1,r1,0x4000	/* Set bit 1 -> PTE not found */
-	b	10f
+/*
+ * Fake an interrupt from kernel mode.
+ * This is used when enable_irq loses an interrupt.
+ * We only fill in the stack frame minimally.
+ */
+_GLOBAL(fake_interrupt)
+	mflr	r0
+	stw	r0,4(r1)
+	stwu	r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+	stw	r0,_NIP(r1)
+	stw	r0,_LINK(r1)
+	mfmsr	r3
+	stw	r3,_MSR(r1)
+	li	r0,0x0fac
+	stw	r0,TRAP(r1)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	handle_IRQ
+	addi	r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+	lwz	r0,4(r1)
+	mtlr	r0
+	blr
 
-/* Write to read-only space */
-WriteProtectError:
-	mfspr	r3,SRR1
-	rlwinm	r1,r3,9,6,6	/* Get load/store bit */
-	addis	r1,r1,0x0800	/* Set bit 4 -> protection error */
-10:	mtspr	DSISR,r1
-	mtctr	r0		/* Restore CTR */
-	andi.	r2,r3,0xFFFF	/* Clear upper bits of SRR1 */
-	mtspr	SRR1,r2
-	mfspr	r1,DMISS	/* Get failing address */
-	rlwinm.	r2,r2,0,31,31	/* Check for little endian access */
-	beq	20f		/* Jump if big endian */
-	xori	r1,r1,3
-20:	mtspr	DAR,r1		/* Set fault address */
-	mfmsr	r0		/* Restore "normal" registers */
-	xoris	r0,r0,MSR_TGPR>>16
-	mtcrf	0x80,r3		/* Restore CR0 */
-	ori	r0,r0,MSR_FP	/* Need to keep FP enabled */
-	sync			/* Some chip revs have problems here... */
-	mtmsr	r0
-	b	DataAccess
+/*
+ * Set up the segment registers for a new context.
+ */
+_GLOBAL(set_context)
+	rlwinm	r3,r3,4,8,27	/* VSID = context << 4 */
+	addis	r3,r3,0x6000	/* Set Ks, Ku bits */
+	li	r0,8		/* TASK_SIZE / SEGMENT_SIZE */
+	mtctr	r0
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1		/* next VSID */
+	addis	r4,r4,0x1000	/* address of next segment */
+	bdnz	3b
+	SYNC
+	blr
 
 /*
- * Flush instruction cache
- * *** I'm really paranoid here!
+ * Flush instruction cache.
+ * This is a no-op on the 601.
  */
 _GLOBAL(flush_instruction_cache)
-	mflr	r5
-	bl	_EXTERN(flush_data_cache)
-	mfspr	r3,HID0	/* Caches are controlled by this register */
-	li	r4,0
-	ori	r4,r4,(HID0_ICE|HID0_ICFI)
-	or	r3,r3,r4	/* Need to enable+invalidate to clear */
+	mfspr	r3,PVR
+	rlwinm	r3,r3,16,16,31
+	cmpi	0,r3,1
+	beqlr			/* for 601, do nothing */
+	/* 603/604 processor - use invalidate-all bit in HID0 */
+	mfspr	r3,HID0
+	ori	r3,r3,HID0_ICFI
 	mtspr	HID0,r3
-	andc	r3,r3,r4
-	ori	r3,r3,HID0_ICE	/* Enable cache */
-	mtspr	HID0,r3
-	mtlr	r5
+	SYNC
 	blr
 
 /*
- * Flush data cache
- * *** I'm really paranoid here!
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * store_cache_range(unsigned long start, unsigned long stop)
  */
-_GLOBAL(flush_data_cache)
-	BUMP(__Cache_Flushes)
-	lis	r3,cache_is_copyback@ha
-	lwz	r3,cache_is_copyback@l(r3)
-	cmpi	0,r3,0
-	beq	10f
-/* When DATA CACHE is copy-back */
-	lis	r3,cache_flush_buffer@h
-	ori	r3,r3,cache_flush_buffer@l
-	li	r4,NUM_CACHE_LINES
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+_GLOBAL(store_cache_range)
+	mfspr	r5,PVR
+	rlwinm	r5,r5,16,16,31
+	cmpi	0,r5,1
+	beqlr				/* for 601, do nothing */
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+	mr	r6,r3
+1:	dcbst	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
 	mtctr	r4
-00:	dcbz	0,r3			/* Flush cache line with minimal BUS traffic */
-	addi	r3,r3,CACHE_LINE_SIZE	/* Next line, please */
-	bdnz	00b	
-10:	blr
+2:	icbi	0,r6
+	addi	r6,r6,CACHE_LINE_SIZE
+	bdnz	2b
+	sync
+	isync
+	blr
 
 /*
  * Flush a particular page from the DATA cache
  * Note: this is necessary because the instruction cache does *not*
  * snoop from the data cache.
- *	void flush_page(void *page)
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ *	void flush_page_to_ram(void *page)
  */
-_GLOBAL(flush_page)
+_GLOBAL(flush_page_to_ram)
+	mfspr	r5,PVR
+	rlwinm	r5,r5,16,16,31
+	cmpi	0,r5,1
+	beqlr				/* for 601, do nothing */
 	li	r4,0x0FFF
 	andc	r3,r3,r4		/* Get page base address */
 	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
 	mtctr	r4
-00:	dcbf	0,r3			/* Clear line */
-	icbi	0,r3
+	mr	r6,r3
+0:	dcbst	0,r3			/* Write line to ram */
 	addi	r3,r3,CACHE_LINE_SIZE
-	bdnz	00b
+	bdnz	0b
+	sync
+	mtctr	r4
+1:	icbi	0,r6
+	addi	r6,r6,CACHE_LINE_SIZE
+	bdnz	1b
+	sync
+	isync
 	blr
 
 /*
- * This routine switches between two different tasks.  The process
- * state of one is saved on its kernel stack.  Then the state
- * of the other is restored from its kernel stack.  The memory
- * management hardware is updated to the second process's state.
- * Finally, we can return to the second process, via the 'return'.
- *
- * Note: there are two ways to get to the "going out" portion
- * of this code; either by coming in via the entry (_switch)
- * or via "fork" which must set up an environment equivalent
- * to the "_switch" path.  If you change this (or in particular, the
- * SAVE_ALL_REGS macro), you'll have to change the fork code also.
+ * Flush entries from the hash table with VSIDs in the range
+ * given.
+ */
+_GLOBAL(flush_hash_segments)
+	rlwinm	r3,r3,7,1,24		/* put VSID lower limit in position */
+	oris	r3,r3,0x8000		/* set V bit */
+	rlwinm	r4,r4,7,1,24		/* put VSID upper limit in position */
+	oris	r4,r4,0x8000
+	ori	r4,r4,0x7f
+	lis	r5,Hash@ha
+	lwz	r5,Hash@l(r5)		/* base of hash table */
+	lis	r6,Hash_size@ha
+	lwz	r6,Hash_size@l(r6)	/* size in bytes */
+	srwi	r6,r6,3			/* # PTEs */
+	mtctr	r6
+	addi	r5,r5,-8
+	li	r0,0
+1:	lwzu	r6,8(r5)		/* get next tag word */
+	cmplw	0,r6,r3
+	cmplw	1,r6,r4
+	cror	0,0,5			/* set cr0.lt if out of range */
+	blt	2f			/* branch if out of range */
+	stw	r0,0(r5)		/* invalidate entry */
+2:	bdnz	1b			/* continue with loop */
+	sync
+	tlbia
+	isync
+	blr
+
+/*
+ * Flush the entry for a particular page from the hash table.
  *
- * The code which creates the new task context is in 'copy_thread'
- * in arch/ppc/kernel/process.c
- */	
-_GLOBAL(_switch)
-	mtspr	SPR0,r1		/* SAVE_ALL_REGS prologue */
-	mtspr	SPR1,r2
-	mflr	r2		/* Return to switch caller */
-	mtspr	SPR2,r2
-	mfmsr	r2
-	mtspr	SPR3,r2
-	SAVE_ALL_REGS(0x0FF0)
-	SAVE_FP_REGS()
-	CHECK_STACK()
-	SYNC()
-	stw	r1,KSP(r3)	/* Set old stack pointer */
-	BUMP(__Context_Switches)
-	lwz	r1,KSP(r4)	/* Load new stack pointer */
-	lwz	r0,MMU_SEG0(r4)
-	mtsr	SR0,r0
-	lwz	r0,MMU_SEG1(r4)
-	mtsr	SR1,r0
-	lwz	r0,MMU_SEG2(r4)
-	mtsr	SR2,r0
-	lwz	r0,MMU_SEG3(r4)
-	mtsr	SR3,r0
-	lwz	r0,MMU_SEG4(r4)
-	mtsr	SR4,r0
-	lwz	r0,MMU_SEG5(r4)
-	mtsr	SR5,r0
-	lwz	r0,MMU_SEG6(r4)
-	mtsr	SR6,r0
-	lwz	r0,MMU_SEG7(r4)
-	mtsr	SR7,r0
-#if 0
-	/* segs 8-15 are shared by everyone -- don't need to be changed */
-	lwz	r0,MMU_SEG8(r4)
-	mtsr	SR8,r0
-	lwz	r0,MMU_SEG9(r4)
-	mtsr	SR9,r0
-	lwz	r0,MMU_SEG10(r4)
-	mtsr	SR10,r0
-	lwz	r0,MMU_SEG11(r4)
-	mtsr	SR11,r0
-	lwz	r0,MMU_SEG12(r4)
-	mtsr	SR12,r0
-	lwz	r0,MMU_SEG13(r4)
-	mtsr	SR13,r0
-	lwz	r0,MMU_SEG14(r4)
-	mtsr	SR14,r0
-	lwz	r0,MMU_SEG15(r4)
-	mtsr	SR15,r0
-#endif
-	/* no need to invalidate tlb since each process has a distinct
-	   set of vsid's.	 -- Cort */
-#if 0	  
-	tlbia				/* Invalidate entire TLB */
-	BUMP(__TLBIAs)
-#endif	
-	/* p5.2 603 users manual - with addr transl. enabled, 
-	   the memory access is performed under the control of 
-	   the page table entry.  I interpret this to mean that
-	   it is tagged with the vsid -- so no need to flush here
-	   since each process has a distinct set of vsid's.
-	   Of course, my intepretation may be wrong.
-	              -- Cort */
-	/*bl	_EXTERN(flush_instruction_cache)*/
-	RETURN_FROM_INT(0x0f0f)
-	
+ * flush_hash_page(unsigned context, unsigned long va)
+ */
+_GLOBAL(flush_hash_page)
+	rlwinm	r3,r3,11,1,20		/* put context into vsid */
+	rlwimi	r3,r4,11,21,24		/* put top 4 bits of va into vsid */
+	oris	r3,r3,0x8000		/* set V (valid) bit */
+	rlwimi	r3,r4,10,26,31		/* put in API (abbrev page index) */
+	rlwinm	r7,r4,32-6,10,25	/* get page index << 6 */
+	rlwinm	r5,r3,32-1,7,25		/* vsid << 6 */
+	xor	r7,r7,r5		/* primary hash << 6 */
+	lis	r5,Hash_mask@ha
+	lwz	r5,Hash_mask@l(r5)	/* hash mask */
+	slwi	r5,r5,6			/*  << 6 */
+	and	r7,r7,r5
+	lis	r6,Hash@ha
+	lwz	r6,Hash@l(r6)		/* hash table base */
+	add	r6,r6,r7		/* address of primary PTEG */
+	li	r8,8
+	mtctr	r8
+	addi	r7,r6,-8
+1:	lwzu	r0,8(r7)		/* get next PTE */
+	cmpw	0,r0,r3			/* see if tag matches */
+	bdnzf	2,1b			/* while --ctr != 0 && !cr0.eq */
+	beq	3f			/* if we found it */
+	ori	r3,r3,0x40		/* set H (alt. hash) bit */
+	xor	r6,r6,r5		/* address of secondary PTEG */
+	mtctr	r8
+	addi	r7,r6,-8
+2:	lwzu	r0,8(r7)		/* get next PTE */
+	cmpw	0,r0,r3			/* see if tag matches */
+	bdnzf	2,2b			/* while --ctr != 0 && !cr0.eq */
+	bne	4f			/* if we didn't find it */
+3:	li	r0,0
+	stw	r0,0(r7)		/* invalidate entry */
+4:	sync
+	tlbie	r4			/* in hw tlb too */
+	isync
+	blr
 
 /*
  * This routine is just here to keep GCC happy - sigh...
@@ -1415,18 +1521,212 @@
 _GLOBAL(__main)
 	blr
 
+#ifdef CONFIG_PMAC
+/*
+ * These exception handlers are used when we have called a prom
+ * routine after we have taken over the exception vectors and MMU.
+ */
+	.globl	prom_exc_table
+prom_exc_table:
+	.long	TOPHYS(prom_exception)		/* 0 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 400 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 800 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* c00 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1000 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1400 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1800 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1c00 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1000 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1400 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1800 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)		/* 1c00 */
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+	.long	TOPHYS(prom_exception)
+
+/*
+ * When we come in to these prom exceptions, r1 and lr have been
+ * saved in sprg1 and sprg2, and lr points to a word containing
+ * the vector offset.
+ */
+prom_exception:
+	mr	r1,r21			/* save r21 */
+	lis	r21,prom_sp@ha		/* get a stack to use */
+	addis	r21,r21,-KERNELBASE@h
+	lwz	r21,prom_sp@l(r21)
+	addis	r21,r21,-KERNELBASE@h	/* convert to physical addr */
+	subi	r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD
+	stw	r0,GPR0(r21)
+	stw	r2,GPR2(r21)
+	stw	r3,GPR3(r21)
+	stw	r4,GPR4(r21)
+	stw	r5,GPR5(r21)
+	stw	r6,GPR6(r21)
+	stw	r20,GPR20(r21)
+	stw	r1,GPR21(r21)
+	stw	r22,GPR22(r21)
+	stw	r23,GPR23(r21)
+	mfspr	r1,SPRG1
+	stw	r1,GPR1(r21)
+	mfcr	r3
+	mfspr	r4,SPRG2
+	stw	r3,_CCR(r21)
+	stw	r4,_LINK(r21)
+	mfctr	r3
+	mfspr	r4,XER
+	stw	r3,_CTR(r21)
+	stw	r4,_XER(r21)
+	mfspr	r22,SRR0
+	mfspr	r23,SRR1
+
+	/* at this point we have set things up pretty much exactly
+	   how EXCEPTION_PROLOG does */
+	mflr	r3
+	lwz	r3,0(r3)		/* get exception vector */
+	stw	r3,TRAP(r21)
+	cmpi	0,r3,0x300		/* was it a dsi? */
+	bne	1f
+
+	mfspr	r20,DSISR		/* here on data access exc. */
+	andis.	r0,r20,0x8470		/* weird error? */
+	bne	3f			/* if not, try to put a PTE */
+	mfspr	r3,DAR			/* into the hash table */
+	rlwinm	r4,r23,32-13,30,30	/* MSR_PR -> _PAGE_USER */
+	rlwimi	r4,r20,32-23,29,29	/* DSISR_STORE -> _PAGE_RW */
+	b	2f
+
+1:	cmpi	0,r3,0x400		/* was it an isi? */
+	bne	3f
+	andis.	r0,r23,0x4000		/* if so, check if no pte found */
+	beq	3f			/* if so, try to put a PTE */
+	mr	r3,r22			/* into the hash table */
+	rlwinm	r4,r23,32-13,30,30	/* MSR_PR -> _PAGE_USER */
+	mr	r20,r23			/* SRR1 has reason bits */
+2:	lis	r5,prom_tss@ha		/* phys addr of TSS */
+	addis	r5,r5,-KERNELBASE@h
+	lwz	r5,prom_tss@l(r5)
+	bl	hash_page
+
+3:	addis	r1,r21,KERNELBASE@h	/* restore kernel stack ptr */
+	addi	r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+	stw	r3,0(r21)		/* set stack chain pointer */
+	lis	r5,prom_tss@ha
+	addis	r5,r5,-KERNELBASE@h
+	lwz	r5,prom_tss@l(r5)
+	mtspr	SPRG3,r5		/* reset phys TSS pointer */
+	lwz	r4,TRAP(r21)		/* the real exception vector */
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler
+	.long	PromException
+	.long	prom_int_return
+
+	.comm	prom_sp,4
+	.comm	prom_tss,4
+
+	.globl	prom_int_return
+prom_int_return:
+	lis	r3,prom_exc_table@ha	/* restore sprg3 for prom vectors */
+	addi	r3,r3,prom_exc_table@l
+	addis	r3,r3,-KERNELBASE@h
+	mtspr	SPRG3,r3
+	b	int_return
+
+/*
+ * When entering the prom, we have to change to using a different
+ * set of exception vectors.
+ */
+	.globl	enter_prom
+enter_prom:
+	stwu	r1,-32(r1)
+	mflr	r0
+	stw	r0,36(r1)
+	stw	r29,20(r1)
+	stw	r30,24(r1)
+	stw	r31,28(r1)
+	lis	r8,prom_entry@ha
+	lwz	r8,prom_entry@l(r8)
+	mfmsr	r31
+	andi.	r0,r31,MSR_IP		/* using our own vectors yet? */
+	beq	1f			/* if so, have to switch */
+	mtlr	r8
+	blrl				/* if not, can just charge ahead */
+	b	2f
+1:	lis	r9,prom_sp@ha		/* save sp for exception handler */
+	stw	r1,prom_sp@l(r9)
+	mfspr	r29,SPRG3		/* save physical tss pointer */
+	lis	r9,prom_tss@ha
+	stw	r29,prom_tss@l(r9)
+	li	r9,0
+	ori	r9,r9,MSR_EE
+	andc	r30,r31,r9
+	lis	r9,prom_exc_table@ha	/* set pointer to exception table */
+	addi	r9,r9,prom_exc_table@l
+	addis	r9,r9,-KERNELBASE@h
+	ori	r0,r31,MSR_IP
+	sync
+	mtmsr	r30			/* disable interrupts */
+	mtspr	SPRG3,r9		/* while we update MSR_IP and sprg3 */
+	sync
+	mtmsr	r0			/* start using exc. vectors in prom */
+	mtlr	r8
+	blrl				/* call prom */
+	sync
+	mtmsr	r30			/* disable interrupts again */
+	mtspr	SPRG3,r29		/* while we restore MSR_IP and sprg3 */
+	sync
+	mtmsr	r31			/* reenable interrupts */
+2:	lwz	r0,36(r1)
+	mtlr	r0
+	lwz	r29,20(r1)
+	lwz	r30,24(r1)
+	lwz	r31,28(r1)
+	lwz	r1,0(r1)
+	blr
+#endif
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
 	.data
 	.globl	sdata
 sdata:
 	.space	2*4096
-
-#if 0
-_GLOBAL(sys_stack)
-sys_stack:
-	.space	4096
-#endif
-CPU1_stack:	
-
 	.globl	empty_zero_page
 empty_zero_page:
 	.space	4096
@@ -1435,6 +1735,7 @@
 swapper_pg_dir:
 	.space	4096	
 
+#ifdef CONFIG_PREP
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
@@ -1442,54 +1743,5 @@
 	.globl	cmd_line
 cmd_line:
 	.space	512
-	
-#ifdef STATS	
-/*
- * Miscellaneous statistics - gathered just for performance info
- */
- 	.globl	_INTR_stats
-_INTR_stats:
-	.globl __Instruction_TLB_Misses
-__Instruction_TLB_Misses:
-	.long	0,0	/* Instruction TLB misses */
-	.globl __DataLoad_TLB_Misses
-__DataLoad_TLB_Misses:
-	.long	0,0	/* Data [load] TLB misses */
-	.globl __DataStore_TLB_Misses
-__DataStore_TLB_Misses:
-	.long	0,0	/* Data [store] TLB misses */
-	.globl __Instruction_Page_Faults
-__Instruction_Page_Faults:	
-	.long	0,0	/* Instruction page faults */
-	.globl __Data_Page_Faults
-__Data_Page_Faults:	
-	.long	0,0	/* Data page faults */
-	.globl __Cache_Flushes
-__Cache_Flushes:	
-	.long	0,0	/* Explicit cache flushes */
-	.globl __Context_Switches
-__Context_Switches:	
-	.long	0,0	/* Context switches */
-	.globl __Hardware_Interrupts
-__Hardware_Interrupts:	
-	.long	0,0	/* I/O interrupts (disk, timer, etc) */
-	.globl	__TLBIAs
-	.globl __TLBIAs
-__TLBIAs:
-	.long	0,0	/* TLB cache forceably flushed */
-	.globl	__TLBIEs
-__TLBIEs:
-	.long	0,0	/* Specific TLB entry flushed */	
-#endif
-
-	.globl	_TotalMemory
-_TotalMemory:
-	.long	0,0	
-	
-/*
- * This location is used to break any outstanding "lock"s when
- * changing contexts.
- */
-_break_lwarx:	.long	0
-	
+#endif /* CONFIG_PREP */
 
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.1.47/linux/arch/ppc/kernel/irq.c	Mon Apr 14 16:28:06 1997
+++ linux/arch/ppc/kernel/irq.c	Thu Jul 31 13:09:17 1997
@@ -1,9 +1,13 @@
 /*
- *	linux/arch/ppc/kernel/irq.c
+ *  arch/ppc/kernel/irq.c
  *
- *	Copyright (C) 1992 Linus Torvalds
- *      Adapted from arch/i386 by Gary Thomas
- *      Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *  Power Macintosh version
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from arch/i386/kernel/irq.c
+ *    Copyright (C) 1992 Linus Torvalds
+ *  Adapted from arch/i386 by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) 
  *
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
@@ -11,7 +15,7 @@
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
  */
-
+	
 /*
  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
  * Naturally it's not a 1:1 relation, but there are similarities.
@@ -25,323 +29,300 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
+#include <linux/config.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
-inline int get_irq_list(char *);
-void check_irq(void);
-void BeBox_CPU1(void);
-void BeBox_state(void);
-int BeBox_irq(void);
-void show_BeBox_state(void);
-void BeBox_enable_irq(int );
-void BeBox_disable_irq(int );
-void BeBox_init_IRQ(void);
-void _do_bottom_half(void);
-static _NOP(void);
-static _delay(void);
-void hard_disk_LED(int state);
+#define IRQ_FLAG	((unsigned *)0xf3000020)
+#define IRQ_ENABLE	((unsigned *)0xf3000024)
+#define IRQ_ACK		((unsigned *)0xf3000028)
+#define IRQ_LEVEL	((unsigned *)0xf300002c)
+
+#define KEYBOARD_IRQ	20	/* irq number for command-power interrupt */
 
+#undef SHOW_IRQ 1
 
-#define SHOW_IRQ
-#undef  SHOW_IRQ
+unsigned lost_interrupts = 0;
+
+unsigned int local_irq_count[NR_CPUS];
+static struct irqaction irq_action[32];
 
 /*
- * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
- * and 16..31 for other BeBox motherboard type interrupts.
+ * This contains the irq mask for both irq controllers
  */
- 
-unsigned long isBeBox[];
-unsigned char *BeBox_IO_page;
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21	(((char *)(&cached_irq_mask))[0])
+#define cached_A1	(((char *)(&cached_irq_mask))[1])
+
 
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
+int __ppc_bh_counter;
 
-void disable_irq(unsigned int irq_nr)
+void *null_handler(int,void *,struct pt_regs *);
+
+/*
+ * disable and enable intrs in software.  This is used
+ * from the non-realtime parts of Linux to disable interrupts.
+ * The realtime part disables/enables intrs in the hardware.
+ * -- Cort
+ */
+unsigned long soft_intr_enable = 1;
+void _soft_cli(void)
 {
-	unsigned char mask;
-	int s = _disable_interrupts();
+	soft_intr_enable = 0;
+}
 
-	if (isBeBox[0] && (irq_nr >= 16))
-	{
-		BeBox_disable_irq(irq_nr);
-	} else
+void _soft_sti(void)
+{
+	soft_intr_enable = 1;
+	if ( lost_interrupts )
 	{
-		mask = 1 << (irq_nr & 7);
-		if (irq_nr < 8)
-		{
-			cache_21 |= mask;
-			outb(cache_21,0x21);
-		} else
-		{
-			cache_A1 |= mask;
-			outb(cache_A1,0xA1);
-		}
+		printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
+		fake_interrupt();
 	}
-	_enable_interrupts(s);
 }
 
-void enable_irq(unsigned int irq_nr)
+void *
+null_handler(int a, void *b, struct pt_regs *regs)
+{
+	/*printk("irq.c: null_handler() called.  Should not have happened.\n");*/
+}
+
+void
+disable_irq(unsigned int irq_nr)
 {
-	unsigned char mask;
 	int s = _disable_interrupts();
+	unsigned char mask;
 
-	if (isBeBox[0] && (irq_nr >= 16))
+#ifdef CONFIG_PMAC
+	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+#else /* CONFIG_PMAC */
+	mask = 1 << (irq_nr & 7);
+	if (irq_nr < 8)
 	{
-		BeBox_enable_irq(irq_nr);
-		_enable_interrupts(s);
-		return;
+		cached_21 |= mask;
+		outb(cached_21,0x21);
 	} else
 	{
-		mask = ~(1 << (irq_nr & 7));
-		if (irq_nr < 8) {
-			cache_21 &= mask;
-			outb(cache_21,0x21);
-		} else
-		{
-			cache_A1 &= mask;
-			outb(cache_A1,0xA1);
-		}
-	}
+		cached_A1 |= mask;
+		outb(cached_A1,0xA1);
+	}	
+#endif	/* CONFIG_PMAC */
 	_enable_interrupts(s);
 }
 
-/*
- * Irq handlers.
- */
-struct irq_action {
-	void (*handler)(int, void *dev, struct pt_regs *);
-	unsigned long flags;
-	unsigned long mask;
-	const char *name;
-	int notified;
-	void *dev_id;
-};
-
-static struct irq_action irq_action[32] = {
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
-	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
-
-
-inline int get_irq_list(char *buf)
-{
-  int i, len = 0;
-  struct irq_action * action = irq_action;
-  
-  for (i = 0;  i < 32;  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;
-}
-
-inline void
-process_IRQ(int irq, int _irq, struct pt_regs *regs)
-{
-  struct irq_action *action;
-  atomic_inc(&intr_count);
-  if (irq < 16)
-  {
-    /* Mask interrupt */
-    if (irq > 7)
-    {
-      cache_A1 |= (1<<(irq-8));
-      outb(cache_A1, 0xA1);
-    } else
-    {
-      cache_21 |= (1<<irq);
-      outb(cache_21, 0x21);
-    }
-  }
-  action = irq + irq_action;
-  kstat.interrupts[irq]++;
-  /* TEMP */
-  /* On the Nobis, the keyboard interrupt "edge" gets lost - why? */
-  if (irq == 0)
-  {
-    static int count;
-    if (++count == 500)
-    {
-      if (inb(0x64) & 0x01)
-      {
-	struct irq_action *action;
-	action = irq_action + 1;  /* Keyboard */
-	printk("Reset KBD, KBSTAT = %x, ELCR = %x/%x, MASK = %x/%x\n",
-	       inb(0x64), inb(0x4D0), inb(0x4D1), cache_21, cache_A1);
-	action->handler(1, action->dev_id, regs);
-      }
-      count = 0;
-    }
-  }
-  if (action->handler)
-  {	
-    action->handler(irq, action->dev_id, regs);
-  } else
-  {
-    printk("Bogus interrupt %d/%x, pc %x regs %x\n",
-	   irq, _irq,regs->nip,regs);
-#if 0
-    printk("BeBox[] = %x/%x\n", isBeBox[0], isBeBox[1]);
-    show_BeBox_state();
-    cnpause();
-#endif
-  }
-  if (_disable_interrupts() && !action->notified)
-  {
-    action->notified = 1;
-    printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n",
-	   action->name, irq);
-  }
-  if (irq < 16)
-  {
-    /* Issue EOI to interrupt controller */
-    if (irq > 7)
-    {
-      outb(0xE0|(irq-8), 0xA0);
-      outb(0xE2, 0x20);
-    } else
-    {
-      outb(0xE0|irq, 0x20);
-    }
-    if (!(action->flags & SA_ONESHOT))
-    {
-      /* Re-enable interrupt */
-      if (irq > 7)
-      {
-	cache_A1 &= ~(1<<(irq-8));
-	outb(cache_A1, 0xA1);
-      } else
-      {
-	cache_21 &= ~(1<<irq);
-	outb(cache_21, 0x21);
-      }
-    }
-  } else
-  {
-    BeBox_enable_irq(irq);
-  }
-  atomic_dec(&intr_count);
-}
-
-asmlinkage inline void handle_IRQ(struct pt_regs *regs)
-{
-  int irq, _irq, s;
-  struct irq_action *action;
-  static int _ints;
-  
-  if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
-  {
-    /* Figure out IRQ#, etc. */
-    outb(0x0C, 0x20);  /* Poll interrupt controller */
-    irq = _irq = inb(0x20);
-    irq &= 0x07;  /* Caution! */
-    if (irq == 2)
-    { /* Cascaded interrupt -> IRQ8..IRQ15 */
-      outb(0x0C, 0xA0);
-      irq = (_irq = inb(0xA0)) & 0x07;
-      irq += 8;
-    }
-  }
-  process_IRQ(irq, _irq, regs);
-  
-  /* Sometimes, the cascaded IRQ controller get's "stuck" */
-  if ((irq == 0) && (_ints++ == 100))
-  {
-    _ints = 0;
-    outb(0x0A, 0xA0);  _irq = inb(0xA0);
-    if (_irq & ~cache_A1)
-    {  /* Figure out which IRQs are present */
-      _irq &= ~cache_A1;
-      for (irq = 0;  irq < 7;  irq++)
-      {
-	if (_irq & (1<<irq))
+void
+enable_irq(unsigned int irq_nr)
+{
+	int s = _disable_interrupts();
+#ifdef CONFIG_PMAC
+	unsigned bit = 1U << irq_nr;
+	
+	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
+
+	/*
+	 * Unfortunately, setting the bit in the enable register
+	 * when the device interrupt is already on *doesn't* set
+	 * the bit in the flag register or request another interrupt.
+	 */
+	if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
+		lost_interrupts |= bit;
+#else /* CONFIG_PMAC */
+	if (irq_nr < 8) {
+		cached_21 &= ~(1 << (irq_nr & 7));
+		outb(cached_21,0x21);
+	} else
 	{
-#if 0
-	  printk("Dropped IRQ #%d\n", irq+8);
-#endif
-	  process_IRQ(irq+8, _irq, regs);
-	}
-      }
-    }
-  }
+		cached_A1 &= ~(1 << (irq_nr-8 & 7));
+		outb(cached_A1,0xA1);
+	}	
+#endif	/* CONFIG_PMAC */
+
+	_enable_interrupts(s);
 }
 
-/*
- * Display current IRQ state
- */
 
-void
-show_irq_state(void)
+int get_irq_list(char *buf)
 {
-  unsigned char state_21, state_A1;
-  outb(0x0A, 0x20);  state_21 = inb(0x20);
-  outb(0x0A, 0xA0);  state_A1 = inb(0xA0);
-  printk("IRQ State = %x/%x, Edge = %x/%x, Processor = %d\n", state_21, state_A1, inb(0x4D0), inb(0x4D1), _Processor);
-}
+	int i, len = 0;
+	struct irqaction * action;
 
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = irq_action + i;
+		if (!action || !action->handler) 
+			continue;
+		len += sprintf(buf+len, "%2d: %10u   %s",
+			i, kstat.interrupts[i], action->name);
+		for (action=action->next; action; action = action->next) {
+			len += sprintf(buf+len, ", %s", action->name);
+		}
+		len += sprintf(buf+len, "\n");
+	}
 /*
- * Initialize interrupt controllers to a well-known state.
+ *	Linus - should you add NMI counts here ?????
  */
+#ifdef __SMP_PROF__
+	len+=sprintf(buf+len, "IPI: %8lu received\n",
+		ipi_count);
+#endif		
+	return len;
+}
 
-static void
-reset_int_controllers(void)
+asmlinkage void handle_IRQ(struct pt_regs *regs)
 {
-	/* Initialize interrupt controllers */
-	outb(0x11, 0x20); /* Start init sequence */
-	outb(0x40, 0x21); /* Vector base */
-	outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
-	outb(0x01, 0x21); /* Select 8086 mode */
-	outb(0xFF, 0x21); /* Mask all */
-	outb(0x11, 0xA0); /* Start init sequence */
-	outb(0x48, 0xA1); /* Vector base */
-	outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
-	outb(0x01, 0xA1); /* Select 8086 mode */
-	outb(0xFF, 0xA1); /* Mask all */
-#if 0
-	outb(0x00, 0x4D0); /* All edge triggered */
-	outb(0xCF, 0x4D1); /* Trigger mode */
+	int irq;
+	unsigned bits;
+	struct irqaction *action;
+	int cpu = smp_processor_id();
+
+	hardirq_enter(cpu);
+
+#ifdef CONFIG_PMAC 
+	bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+	lost_interrupts = 0;
+	
+	for (irq = NR_IRQS; irq >= 0; --irq)
+		if (bits & (1U << irq))
+			break;
+#else /* CONFIG_PMAC */
+#if 1
+	if ( lost_interrupts )
+	{
+		irq = ffz(~lost_interrupts);
+		lost_interrupts &= ~irq;
+		goto retry;
+	}
+	outb(0x0C, 0x20);
+	irq = inb(0x20) & 7;
+	if (irq == 2)
+	{
+retry_cascade:		
+		outb(0x0C, 0xA0);
+		irq = inb(0xA0);
+		/* if no intr left */
+		if ( !(irq & 128 ) )
+			goto out;
+		irq = (irq&7) + 8;
+	}
+retry:
+#else
+	/* get the irr from the intr controller */
+	outb(0x0A, 0x20);
+	bits = inb(0x20);
+	/* handle cascade */
+	if ( bits  ) 
+	{
+		bits &= 4;
+		outb(0x0A, 0xA0);
+		bits = inb(0xA0)<<8;
+	}
+	/* get lost interrupts */
+	bits |= lost_interrupts;
+	/* save intrs that are masked out */
+	lost_interrupts = bits & cached_irq_mask;
+	/* get rid of intrs being masked */
+	bits &= ~cached_irq_mask;
+        /* non-specifc eoi */
+	outb(0x20,0x20);
+	if ( bits & 0xff00 )
+		outb(0x20,0xA0);
+	
+	printk("bits %04X lost %04X mask %04x\n",
+	       bits, lost_interrupts,cached_irq_mask);
+	
+	for (irq = NR_IRQS; irq >= 0; --irq)
+		if (bits & (1U << irq))
+			break;
 #endif
-	outb(cache_A1, 0xA1);
-	outb(cache_21, 0x21);
-	enable_irq(2);  /* Enable cascade interrupt */
+#endif	/* CONFIG_PMAC */
+	
+	if (irq < 0) {
+		printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+		goto out;
+	}
+
+#ifdef CONFIG_PMAC 
+	out_le32(IRQ_ACK, 1U << irq);
+#else /* CONFIG_PMAC */
+        /* mask out the irq while handling it */	
+	disable_irq(irq); 
+	/*
+	 * send eoi to interrupt controller right away or lower
+	 * priority intrs would be ignored even if with intrs enabled
+	 */
+	if (irq > 7)
+	{
+		outb(0xE0|(irq-8), 0xA0);
+		outb(0xE2, 0x20);
+	} else
+	{
+		outb(0xE0|irq, 0x20);
+	}
+#endif /* !CONFIG_PMAC */
+
+	/*
+	 * now that we've acked the irq, if intrs are disabled in software
+	 * we're in the real-time system and non-rt linux has disabled them
+	 * so we just queue it up and return -- Cort
+	 */
+	if ( ! soft_intr_enable ) 
+	{
+		lost_interrupts |= 1UL << irq;
+		/* can't printk - kernel expects intrs off! */
+		/*printk("irq %d while intrs soft disabled\n", irq);*/
+		goto out;
+	}
+	
+	action = irq + irq_action;
+	kstat.interrupts[irq]++;
+	if (action->handler) {
+		action->handler(irq, action->dev_id, regs);
+		_disable_interrupts(); /* in case the handler turned them on */
+	} else {
+		disable_irq( irq );
+	}
+#ifdef CONFIG_PREP
+	/* re-enable if the interrupt was good and isn't one-shot */
+	if ( action->handler && !(action->flags & SA_ONESHOT) )
+		enable_irq(irq);
+	/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
+	if ( irq > 7 )
+		goto retry_cascade;
+#endif
+	
+	hardirq_exit(cpu);
+	/*
+	 * This should be conditional: we should really get
+	 * a return code from the irq handler to tell us
+	 * whether the handler wants us to do software bottom
+	 * half handling or not..
+	 */
+	if (1)
+		if (bh_active & bh_mask)
+			do_bottom_half();
+        return;
+out:
+	hardirq_exit(cpu);
+
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, const char * devname, void *dev_id)
+	unsigned long irqflags, const char * devname, void *dev_id)
 {
-	struct irq_action * action;
+	struct irqaction * action;
 	unsigned long flags;
-
-#ifdef SHOW_IRQ
-if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
-#endif
-	if (irq > 15)
-	{
-		if (!isBeBox[0] || (irq > 31))
-			return -EINVAL;
-	}
+	
+#ifdef SHOW_IRQ	
+	printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
+	       irq,handler,devname,dev_id);
+#endif /* SHOW_IRQ */
+	
+	if (irq > NR_IRQS)
+		return -EINVAL;
 	action = irq + irq_action;
 	if (action->handler)
 		return -EBUSY;
@@ -361,10 +342,14 @@
 		
 void free_irq(unsigned int irq, void *dev_id)
 {
-	struct irq_action * action = irq + irq_action;
+	struct irqaction * action = irq + irq_action;
 	unsigned long flags;
 
-	if (irq > 31) {
+#ifdef SHOW_IRQ	
+	printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
+#endif /* SHOW_IRQ */
+	
+	if (irq > NR_IRQS) {
 		printk("Trying to free IRQ%d\n",irq);
 		return;
 	}
@@ -383,15 +368,6 @@
 	restore_flags(flags);
 }
 
-#define SA_PROBE SA_ONESHOT
-
-static void no_action(int irq, void *dev, struct pt_regs * regs)
-{
-#ifdef DEBUG
-	printk("Probe got IRQ: %d\n", irq);
-#endif
-}
-
 unsigned long probe_irq_on (void)
 {
 	unsigned int i, irqs = 0, irqmask;
@@ -399,7 +375,7 @@
 
 	/* first, snaffle up any unassigned irqs */
 	for (i = 15; i > 0; i--) {
-		if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
+		if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
 			enable_irq(i);
 			irqs |= (1 << i);
 		}
@@ -409,7 +385,7 @@
 	for (delay = jiffies + 2; delay > jiffies; );	/* min 10ms delay */
 
 	/* now filter out any obviously spurious interrupts */
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+	irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
 	for (i = 15; i > 0; i--) {
 		if (irqs & (1 << i) & irqmask) {
 			irqs ^= (1 << i);
@@ -426,13 +402,13 @@
 {
 	unsigned int i, irqmask;
 
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+	irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
 	for (i = 15; i > 0; i--) {
 		if (irqs & (1 << i)) {
 			free_irq(i, NULL);
 		}
 	}
-#ifdef DEBUG
+#ifdef SHOW_IRQ
 	printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 #endif
 	irqs &= irqmask;
@@ -443,209 +419,65 @@
 		i = -i;
 	return i;
 }
- 
-void init_IRQ(void)
-{
-  int i;
-
-  if ((_get_PVR()>>16) == 1)  /* PPC 601 */
-  { /* Nobis? */
-    reset_int_controllers();
-  }
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-  /* set the clock to 100 Hz */
-  outb_p(0x34,TIMER_CONTROL);		/* binary, mode 2, LSB/MSB, ch 0 */
-  outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
-  outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
-  if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
-    printk("Unable to get IRQ2 for cascade\n");
-  request_region(0x20,0x20,"pic1");
-  request_region(0xa0,0x20,"pic2");
-  
-  /* Make sure IRQ2 (cascade) interrupt is "level" based */
-  outb(inb(0x4D0)|0x04, 0x4D0); /* IRQ2 level based */
-  
-  /* Set up PCI interrupts */
-  route_PCI_interrupts();
-  
-  if (isBeBox[0])
-  {
-    BeBox_init_IRQ();
-  }
-}
-
-/*
- * Wrapper for "bottom 1/2" of interrupt processing.  This routine
- * is called whenever an interrupt needs non-interrupt-time service.
- */
-
-void _do_bottom_half(void)
-{
-  _enable_interrupts(1);
-  do_bottom_half();
-  _disable_interrupts();
-}
 
-void hard_disk_LED(int state)
-{
-  if (_Processor == _PROC_IBM) {
-    outb(state, IBM_HDD_LED);
-  }
-}
- 
-
-/*
- * Support for interrupts on the BeBox
- */
-
-#define CPU0_INT_MASK	(volatile unsigned long *)(BeBox_IO_page+0x0F0)
-#define CPU1_INT_MASK	(volatile unsigned long *)(BeBox_IO_page+0x1F0)
-#define INT_SOURCE	(volatile unsigned long *)(BeBox_IO_page+0x2F0)
-#define CPU_RESET	(volatile unsigned long *)(BeBox_IO_page+0x4F0)
-
-#define _CPU0_INT_MASK	(volatile unsigned long *)(0xA0000000+0x0F0)
-#define _CPU1_INT_MASK	(volatile unsigned long *)(0xA0000000+0x1F0)
-#define _INT_SOURCE	(volatile unsigned long *)(0xA0000000+0x2F0)
-#define _CPU_RESET	(volatile unsigned long *)(0xA0000000+0x4F0)
-
-#define CPU_HRESET	0x20000000
-#define CPU_SRESET	0x40000000
-
-#define SCSI_IRQ	16
-
-#define INT_SCSI	(1<<21)
-#define INT_8259	(1<<5)
-
-/*
- * Map of pseudo IRQs to actual bits
- * Note: We give out IRQ #16..31 for all interrupt sources which are
- * not found in the 8259 PIC.
- */
- 
-unsigned long BeBox_IRQ_map[] =
-   {
-   	INT_SCSI,	/* 16 - SCSI */
-   	0x00000000,	/* 17 - Unused */
-   	0x00000000,	/* 18 - Unused */
-   	0x00000000,	/* 19 - Unused */
-   	0x00000000,	/* 20 - Unused */
-   	0x00000000,	/* 21 - Unused */
-   	0x00000000,	/* 22 - Unused */
-   	0x00000000,	/* 23 - Unused */
-   	0x00000000,	/* 24 - Unused */
-   	0x00000000,	/* 25 - Unused */
-   	0x00000000,	/* 26 - Unused */
-   	0x00000000,	/* 27 - Unused */
-   	0x00000000,	/* 28 - Unused */
-   	0x00000000,	/* 29 - Unused */
-   	0x00000000,	/* 30 - Unused */
-   	0x00000000,	/* 31 - Unused */
-   };
-
-volatile int CPU1_alive;
-volatile int CPU1_trace;
-
-static
-_NOP(void)
-{
-}
-
-static
-_delay(void)
+void init_IRQ(void)
 {
-	int i;
-	for (i = 0;  i < 100;  i++) _NOP();
-}
+#ifdef CONFIG_PMAC  
+	extern void xmon_irq(int, void *, struct pt_regs *);
 
-void
-BeBox_init_IRQ(void)
-{
-	int tmr;
-	volatile extern long BeBox_CPU1_vector;
-	*CPU0_INT_MASK = 0x0FFFFFFC;  /* Clear all bits? */	
-	*CPU0_INT_MASK = 0x80000003 | INT_8259;
-	*CPU1_INT_MASK = 0x0FFFFFFC;  
-printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
-	BeBox_CPU1_vector = 0x0100;  /* Reset */
-	tmr = 0;
-	while (CPU1_alive == 0)
-	{
-		if (++tmr == 1000)
-		{
-printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
-			break;
-		}
-		_delay();
-	}
-printk("CPU #1 running!\n");
-}
+	*IRQ_ENABLE = 0;
+	request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#else /* CONFIG_PMAC */
+	/* Initialize interrupt controllers */
+	outb(0x11, 0x20); /* Start init sequence */
+	outb(0x40, 0x21); /* Vector base */
+#if 1
+	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+#else
+	outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif	
+	
+	outb(0x01, 0x21); /* Select 8086 mode */
+	outb(0xFF, 0x21); /* Mask all */
 
-void
-BeBox_disable_irq(int irq)
-{
-	/* Note: this clears the particular bit */
-	*CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
-}
+	outb(0x11, 0xA0); /* Start init sequence */
+	outb(0x48, 0xA1); /* Vector base */
+#if 1
+	outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+#else
+	outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif
+	outb(0x01, 0xA1); /* Select 8086 mode */
+	outb(0xFF, 0xA1); /* Mask all */
 
-void
-BeBox_enable_irq(int irq)
-{
-	int s = _disable_interrupts();
-	/* Sets a single bit */
+	/*
+	 * Program level mode for irq's that 'can' be level triggered.
+	 * This does not effect irq's 0,1,2 and 8 since they must be
+	 * edge triggered. This is not the PIC controller.  The default
+	 * here is for edge trigger mode.  -- Cort
+	 */
 #if 0	
-printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
+	outb(0xf8, 0x4d0); /* level triggered */
+	outb(0xff, 0x4d1);
 #endif
-	*CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
-#if 0
-printk("/%x\n", *CPU0_INT_MASK);
-#endif	
-	_enable_interrupts(s);	
-}
-
-void
-show_BeBox_state(void)
-{
-	unsigned long cpu0_int_mask;
-	unsigned long int_state;
-	cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
-	int_state = cpu0_int_mask & *INT_SOURCE;
-	printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-}
-
-int
-BeBox_irq(void)
-{
-	int i;
-	unsigned long cpu0_int_mask;
-	unsigned long int_state;
-	cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
-	int_state = cpu0_int_mask & *INT_SOURCE;
-	if (int_state)
-	{ /* Determine the pseudo-interrupt # */
 #if 0	
-		printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-#endif		
-		for (i = 0;  i < 16;  i++)
-		{
-			if (BeBox_IRQ_map[i] & int_state)
-			{
-				return (i+16);
-			}
-		}
-printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-printk("Can't find BeBox IRQ!\n");
-	}
-	return (0);
-}
-
-void BeBox_state(void)
-{
-	printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
-}
+	outb(0x00, 0x4D0); /* All edge triggered */
+	outb(0xCF, 0x4D1); /* Trigger mode */
+#endif
+	outb(cached_A1, 0xA1);
+	outb(cached_21, 0x21);
+	if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
+		printk("Unable to get IRQ2 for cascade\n");
+	enable_irq(2);  /* Enable cascade interrupt */
+	
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+	/* set timer to periodic mode */
+	outb_p(0x34,TIMER_CONTROL);		/* binary, mode 2, LSB/MSB, ch 0 */
+	/* set the clock to ~100 Hz */
+	outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
+	outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
 
-void BeBox_CPU1(void)
-{
-	CPU1_alive++;
-	while (1) ;
+	route_pci_interrupts();
+#endif	/* CONFIG_PMAC */
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/ksyms.c linux/arch/ppc/kernel/ksyms.c
--- v2.1.47/linux/arch/ppc/kernel/ksyms.c	Fri Dec 27 02:03:20 1996
+++ linux/arch/ppc/kernel/ksyms.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,40 @@
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void handle_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+unsigned long sys_call_table[];
+
+extern struct task_struct *current_set[1];
 
 /* platform dependent support */
+EXPORT_SYMBOL(current_set);
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(handle_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(FloatingPointCheckException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(sys_call_table);
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.1.47/linux/arch/ppc/kernel/misc.S	Tue May 13 22:41:03 1997
+++ linux/arch/ppc/kernel/misc.S	Thu Jul 31 13:09:17 1997
@@ -1,234 +1,40 @@
 /*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  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.
+ *
  */
 
-#include "ppc_asm.tmpl"
+#include <linux/config.h>
 #include <linux/sys.h>
+#include <asm/unistd.h>
 #include <asm/errno.h>
-#include "ppc_defs.h"
 #include <asm/processor.h>
-		
-/* Keep track of low-level exceptions - rather crude, but informative */	
-#define STATS
-
-/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
- */
-#define BUMP(ctr) \
-	lis	r2,ctr@h; \
-	ori	r2,r2,ctr@l; \
-	lwz	r3,4(r2); \
-	addic	r3,r3,1; \
-	stw	r3,4(r2); \
-	lwz	r3,0(r2); \
-	addze	r3,r3; \
-	stw	r3,0(r2)
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
 
-/*#ifdef CONFIG_603*/
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 601 or 603 */
 #define tlbia \
-	li	r4,64; \
+	li	r4,128; \
 	mtspr	CTR,r4; \
 	li	r4,0; \
 0:	tlbie	r4; \
 	addi	r4,r4,0x1000; \
 	bdnz	0b
-/*#endif*/ /* CONFIG_603*/
 	
 _TEXT()
-#define CPU_CTL     0x80000092
-_GLOBAL(hard_reset_now)
-        mfmsr   r3              /* Disable interrupts */
-        li      r4,0            
-        ori     r4,r4,MSR_EE    
-        andc    r3,r3,r4        
-        ori     r3,r3,MSR_IP    /* Set FLASH/ROM interrupt handlers */
-        sync
-        mtmsr   r3
-        lis     r3,CPU_CTL>>16
-        ori     r3,r3,(CPU_CTL&0xFFFF)
-        lbz     r4,0(r3)        /* Turn on SRESET */
-        li      r5,1
-        andc    r4,r4,r5        /* Make sure we go from 0->1 */
-        stb     r4,0(r3)
-        ori     r4,r4,1
-        stb     r4,0(r3)        /* This should do it! */
-99:     nop
-        b       99b
-
-#if 0	
-/*
-  unsigned short
-     le16_to_cpu(unsigned short val)
-*/
-_GLOBAL(le16_to_cpu)
-	lis	r4,_le_scratch@h
-	ori	r4,r4,_le_scratch@l
-	sth	r3,0(r4)
-	li	r5,0
-	lhbrx	r3,r4,r5
-	blr
-
-_GLOBAL(le32_to_cpu)
-	lis	r4,_le_scratch@h
-	ori	r4,r4,_le_scratch@l
-	stw	r3,0(r4)
-	li	r5,0
-	lwbrx	r3,r4,r5
-	blr
-_GLOBAL(_le_scratch)
-	.space 4
-#endif	
-#if 1
-/*	
-extern int __put_user_8(char, char *);
-extern int __put_user_16(short, short *);
-extern int __put_user_32(long, long *);
-*/
-_GLOBAL(__put_user_8)
-	/* setup exception stuff */
-	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	/* increment excount */
-	lwz	r6,TSS+TSS_EXCOUNT(r2)
-	addi	r6,r6,1
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	/* set expc */
-	lis	r6,1f@h
-	ori	r6,r6,1f@l
-	stw	r6,TSS+TSS_EXPC(r2)
-	
-	stb	r3,0(r4)
-	li	r3,0		/* successful return */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-1:	li	r3,-EFAULT	/* bad access */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-		
-_GLOBAL(__put_user_16)
-	/* setup exception stuff */
-	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	/* increment excount */
-	lwz	r6,TSS+TSS_EXCOUNT(r2)
-	addi	r6,r6,1
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	/* set expc */
-	lis	r6,1f@h
-	ori	r6,r6,1f@l
-	stw	r6,TSS+TSS_EXPC(r2)
-	
-	sth	r3,0(r4)
-	li	r3,0		/* successful return */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-1:	li	r3,-EFAULT	/* bad access */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-
-_GLOBAL(__put_user_32)
-	/* setup exception stuff */
-	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	/* increment excount */
-	lwz	r6,TSS+TSS_EXCOUNT(r2)
-	addi	r6,r6,1
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	/* set expc */
-	lis	r6,1f@h
-	ori	r6,r6,1f@l
-	stw	r6,TSS+TSS_EXPC(r2)
-	
-	stw	r3,0(r4)
-	li	r3,0		/* successful return */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-1:	li	r3,-EFAULT	/* bad access */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-	
-_GLOBAL(__get_user_8)
-	/* setup exception stuff */
-	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	/* increment excount */
-	lwz	r6,TSS+TSS_EXCOUNT(r2)
-	addi	r6,r6,1
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	/* set expc */
-	lis	r6,1f@h
-	ori	r6,r6,1f@l
-	stw	r6,TSS+TSS_EXPC(r2)
-	
-	lbz	r3,0(r4)
-	li	r4,0		/* successful return */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-1:	li	r4,-EFAULT	/* bad access */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-	
-_GLOBAL(__get_user_16)
-	/* setup exception stuff */
-	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	/* increment excount */
-	lwz	r6,TSS+TSS_EXCOUNT(r2)
-	addi	r6,r6,1
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	/* set expc */
-	lis	r6,1f@h
-	ori	r6,r6,1f@l
-	stw	r6,TSS+TSS_EXPC(r2)
-	
-	lhz	r3,0(r4)
-	li	r4,0		/* successful return */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-1:	li	r4,-EFAULT	/* bad access */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-	
-_GLOBAL(__get_user_32)
-	/* setup exception stuff */
-	lis	r2,current_set@ha
-	lwz	r2,current_set@l(r2)
-	/* increment excount */
-	lwz	r6,TSS+TSS_EXCOUNT(r2)
-	addi	r6,r6,1
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	/* set expc */
-	lis	r6,1f@h
-	ori	r6,r6,1f@l
-	stw	r6,TSS+TSS_EXPC(r2)
-	lwz	r3,0(r4)
-	li	r4,0		/* successful return */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-1:	li	r4,-EFAULT	/* bad access */
-	li	r6,0
-	stw	r6,TSS+TSS_EXCOUNT(r2)
-	blr
-#endif	
+
 /*
  * Disable interrupts
  *	rc = _disable_interrupts()
  */
 _GLOBAL(_disable_interrupts)
+_GLOBAL(__cli)
+_GLOBAL(_hard_cli)
 	mfmsr	r0		/* Get current interrupt state */
 	rlwinm	r3,r0,16+1,32-1,31	/* Extract old value of 'EE' */
 	li	r4,0		/* Need [unsigned] value of MSR_EE */
@@ -244,20 +50,18 @@
  * turns on interrupts if state = 1.
  */
 _GLOBAL(_enable_interrupts)
-	mfmsr	r0		/* Get current state */
-	rlwimi	r0,r3,16-1,32-16,32-16	/* Insert bit */
+	cmpi	0,r3,0		/* turning them on? */
+	beqlr			/* nothing to do if state == 0 */
+_GLOBAL(__sti)
+_GLOBAL(_hard_sti)
+	lis	r4,lost_interrupts@ha
+	lwz	r4,lost_interrupts@l(r4)
+	mfmsr	r3		/* Get current state */
+	ori	r3,r3,MSR_EE	/* Turn on 'EE' bit */
+	cmpi	0,r4,0		/* lost interrupts to process first? */
+	bne-	do_lost_interrupts
 	sync			/* Some chip revs have problems here... */
-	mtmsr	r0		/* Update machine state */
-	blr
-
-/*
- * Get 'flags' (aka machine status register)
- *	__save_flags(long *ptr)
- */
-_GLOBAL(__save_flags)
-	mfmsr	r0		/* Get current state */
-	stw	r0,0(r3)
-	mr	r3,r0
+	mtmsr	r3		/* Update machine state */
 	blr
 
 /*
@@ -265,34 +69,37 @@
  *	__restore_flags(long val)
  */
 _GLOBAL(__restore_flags)
-	sync			/* Some chip revs have problems here... */
+	andi.	r0,r3,MSR_EE	/* enabling interrupts? */
+	beq	2f
+	lis	r4,lost_interrupts@ha
+	lwz	r4,lost_interrupts@l(r4)
+	cmpi	0,r4,0
+	bne	do_lost_interrupts
+2:	sync			/* Some chip revs have problems here... */
 	mtmsr	r3
 	isync
 	blr
 
 /*
- * Disable interrupts - like an 80x86
- *	cli()
- */
-_GLOBAL(cli)
-	mfmsr	r0		/* Get current interrupt state */
-	rlwinm	r3,r0,16+1,32-1,31	/* Extract old value of 'EE' */
-	li	r4,0		/* Need [unsigned] value of MSR_EE */
-	ori	r4,r4,MSR_EE	/* Set to turn off bit */
-	andc	r0,r0,r4	/* Clears bit in (r4) */
-	sync			/* Some chip revs have problems here... */
-	mtmsr	r0		/* Update machine state */
-	blr			/* Done */
-
-/*
- * Enable interrupts - like an 80x86
- *	sti()
+ * We were about to enable interrupts but we have to simulate
+ * some interrupts that were lost by enable_irq first.
  */
-_GLOBAL(sti)
-	mfmsr	r0		/* Get current state */
-	ori	r0,r0,MSR_EE	/* Turn on 'EE' bit */
-	sync			/* Some chip revs have problems here... */
-	mtmsr	r0		/* Update machine state */
+do_lost_interrupts:
+	stwu	r1,-16(r1)
+	mflr	r0
+	stw	r0,20(r1)
+	stw	r3,8(r1)
+1:	bl	fake_interrupt
+	lis	r4,lost_interrupts@ha
+	lwz	r4,lost_interrupts@l(r4)
+	cmpi	0,r4,0
+	bne-	1b
+	lwz	r3,8(r1)
+	sync
+	mtmsr	r3
+	lwz	r0,20(r1)
+	mtlr	r0
+	addi	r1,r1,16
 	blr
 
 /*
@@ -300,7 +107,6 @@
  */
 _GLOBAL(_tlbia)
 	tlbia
-	BUMP(__TLBIAs)
 	blr	
 
 /*
@@ -308,17 +114,7 @@
  */
 _GLOBAL(_tlbie)
 	tlbie	r3
-	BUMP(__TLBIEs)
 	blr
-
-/*
- * Fetch the current SR register
- *   get_SR(int index)
- */
-_GLOBAL(get_SR)
-	mfsrin	r3,r3
-	blr	
-
 /*
  * Atomic [test&set] exchange
  *
@@ -340,7 +136,11 @@
  * void atomic_sub(int c, int *v)
  * void atomic_inc(int *v)
  * void atomic_dec(int *v)
- * void atomic_dec_and_test(int *v)
+ * int atomic_dec_and_test(int *v)
+ * int atomic_inc_return(int *v)
+ * int atomic_dec_return(int *v)
+ * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
+ * void atomic_set_mask(atomic_t mask, atomic_t *addr);
  */
 _GLOBAL(atomic_add)
 10:	lwarx	r5,0,r4		/* Fetch old value & reserve */
@@ -360,69 +160,46 @@
 	stwcx.	r5,0,r3		/* Update with new value */
 	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
 	blr
+_GLOBAL(atomic_inc_return)
+10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
+	addi	r5,r5,1		/* Perform 'add' operation */
+	stwcx.	r5,0,r3		/* Update with new value */
+	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
+	mr	r3,r5		/* Return new value */
+	blr
 _GLOBAL(atomic_dec)
 10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
 	subi	r5,r5,1		/* Perform 'add' operation */
 	stwcx.	r5,0,r3		/* Update with new value */
 	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
 	blr
+_GLOBAL(atomic_dec_return)
+10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
+	subi	r5,r5,1		/* Perform 'add' operation */
+	stwcx.	r5,0,r3		/* Update with new value */
+	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
+	mr	r3,r5		/* Return new value */
+	blr
 _GLOBAL(atomic_dec_and_test)
 10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
 	subi	r5,r5,1		/* Perform 'add' operation */
 	stwcx.	r5,0,r3		/* Update with new value */
 	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
 	cmpi	0,r5,0		/* Return 'true' IFF 0 */
-	bne	15f
 	li	r3,1
+	beqlr
+	li	r3,0
 	blr
-15:	li	r3,0
-	blr	
-	
-
-/*
- * Delay for a specific # of "loops"
- *	__delay(int loops)
- */
-_GLOBAL(__delay)
-	mtctr	r3
-00:	addi	r3,r3,0		/* NOP */
-	bdnz	00b
-	blr
-
-/*
- * Delay for a number of microseconds
- *	udelay(int usecs)
- */
-_GLOBAL(udelay)
-00:	li	r0,86	/* Instructions / microsecond? */
-	mtctr	r0
-10:	addi	r0,r0,0 /* NOP */
-	bdnz	10b
-	subic.	r3,r3,1
-	bne	00b
-	blr
-
-/*
- * Atomically increment [intr_count]
- */
-_GLOBAL(start_bh_atomic)
-	lis	r3,intr_count@h
-	ori	r3,r3,intr_count@l
-10:	lwarx	r4,0,r3
-	addi	r4,r4,1
-	stwcx.	r4,0,r3
+_GLOBAL(atomic_clear_mask)
+10:	lwarx	r5,0,r4
+	andc	r5,r5,r3
+	stwcx.	r5,0,r4
 	bne-	10b
 	blr
-
-/*
- * Atomically decrement [intr_count]
- */
-_GLOBAL(end_bh_atomic)
-	lis	r3,intr_count@h
-	ori	r3,r3,intr_count@l
-10:	lwarx	r4,0,r3
-	subic	r4,r4,1
-	stwcx.	r4,0,r3
+_GLOBAL(atomic_set_mask)
+10:	lwarx	r5,0,r4
+	or	r5,r5,r3
+	stwcx.	r5,0,r4
 	bne-	10b
 	blr
 
@@ -431,6 +208,8 @@
  *
  * insw(port, buf, len)
  * outsw(port, buf, len)
+ * insl(port, buf, len)
+ * outsl(port, buf, len)
  */
 _GLOBAL(_insw)
 	mtctr	r5
@@ -448,135 +227,39 @@
 	bdnz	00b
 	blr	
 
-#if 0	
-/*
- *extern inline int find_first_zero_bit(void * vaddr, unsigned size)
- *{
- *	unsigned long res;
- *	unsigned long *p;
- *	unsigned long *addr = vaddr;
- *
- *	if (!size)
- *		return 0;
- *	__asm__ __volatile__ ("    moveq #-1,d0\n\t"
- *			      "1:"
- *			      "    cmpl  %1@+,d0\n\t"
- *			      "    bne   2f\n\t"
- *			      "    subql #1,%0\n\t"
- *			      "    bne   1b\n\t"
- *			      "    bra   5f\n\t"
- *			      "2:"
- *			      "    movel %1@-,d0\n\t"
- *			      "    notl  d0\n\t"
- *			      "    bfffo d0{#0,#0},%0\n\t"
- *			      "5:"
- *			      : "=d" (res), "=a" (p)
- *			      : "0" ((size + 31) >> 5), "1" (addr)
- *			      : "d0");
- *	return ((p - addr) << 5) + res;
- *}
- */
-_GLOBAL(find_first_zero_bit)
-	li	r5,0		/* bit # */
-	subi	r3,r3,4		/* Adjust pointer for auto-increment */
-00:	lwzu	r0,4(r3)	/* Get next word */
-	not.	r7,r0		/* Complement to find ones */
-	beq	10f		/* Jump if all ones */
-02:	andi.	r7,r0,1		/* Check low-order bit */
-	beq	20f		/* All done when zero found */
-	srawi	r0,r0,1
-	addi	r5,r5,1
-	b	02b
-10:	addi	r5,r5,32	/* Update bit # */
-	subic.	r4,r4,32	/* Any more? */
-	bgt	00b
-20:	mr	r3,r5		/* Compute result */	
-	blr
- 
-/*
- *static inline int find_next_zero_bit (void *vaddr, int size,
- *				      int offset)
- *{
- *	unsigned long *addr = vaddr;
- *	unsigned long *p = addr + (offset >> 5);
- *	int set = 0, bit = offset & 31, res;
- *
- *	if (bit) {
- *		// Look for zero in first longword 
- *		__asm__("bfffo %1{#0,#0},%0"
- *			: "=d" (set)
- *			: "d" (~*p << bit));
- *		if (set < (32 - bit))
- *			return set + offset;
- *                set = 32 - bit;
- *		p++;
- *	}
- *	// No zero yet, search remaining full bytes for a zero 
- *	res = find_first_zero_bit (p, size - 32 * (p - addr));
- *	return (offset + set + res);
- *}
- */
-_GLOBAL(find_next_zero_bit)
-	addi	r5,r5,1		/* bump offset to start */
-	srawi	r6,r5,5		/* word offset */
-	add	r6,r6,r6	/* byte offset */
-	add	r6,r6,r6	/* byte offset */
-	add	r3,r3,r6	/* compute byte position */
-	sub	r4,r4,r5	/* adjust size by starting index */
-	andi.	r0,r5,0x1F	/* offset in current word? */
-	beq	10f		/* at start of word */
-	lwz	r0,0(r3)	/* get word */
-	sraw	r0,r0,r5	/* shift right */
-	not.	r7,r0
-	beq	07f		/* jump if only ones remain */
-05:	andi.	r7,r0,1		/* found zero? */
-	beq	90f		/* yes - all done */
-	srawi	r0,r0,1
-	addi	r5,r5,1
-	b	05b
-07:	andi.	r6,r5,0x1F
-	subfic	r0,r6,32
-	add	r5,r5,r0
-	sub	r4,r4,r0
-	b	20f
-10:	subi	r3,r3,4		/* Adjust pointer for auto-increment */
-20:	lwzu	r0,4(r3)	/* Get next word */
-	not.	r7,r0		/* Complement to find ones */
-	beq	40f		/* Jump if all ones */
-30:	andi.	r7,r0,1		/* Check low-order bit */
-	beq	90f		/* All done when zero found */
-	srawi	r0,r0,1
-	addi	r5,r5,1
-	b	30b
-40:	addi	r5,r5,32	/* Update bit # */
-	subic.	r4,r4,32	/* Any more? */
-	bgt	20b
-90:	mr	r3,r5		/* Compute result */	
+_GLOBAL(_insl)
+	mtctr	r5
+	subi	r4,r4,4
+00:	lwbrx	r5,0,r3
+	stwu	r5,4(r4)
+	bdnz	00b
 	blr
+
+_GLOBAL(_outsl)
+	mtctr	r5
+	subi	r4,r4,4
+00:	lwzu	r5,4(r4)
+	stwbrx	r5,0,r3	
+	bdnz	00b
+	blr	
+
+#ifdef CONFIG_PMAC
+_GLOBAL(ide_insw)
+	mtctr	r5
+	subi	r4,r4,2
+00:	lhzx	r5,0,r3
+	sthu	r5,2(r4)
+	bdnz	00b
+	blr
+
+_GLOBAL(ide_outsw)
+	mtctr	r5
+	subi	r4,r4,2
+00:	lhzu	r5,2(r4)
+	sthx	r5,0,r3	
+	bdnz	00b
+	blr	
 #endif
- 
-/*
- *
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- *
- *extern inline unsigned long ffz(unsigned long word)
- *{
- *	__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
- *			      : "=d" (word)
- *			      : "d" (~(word)));
- *	return word;
- *}
- */
-_GLOBAL(ffz)
-	mr	r4,r3
-	li	r3,0
-10:	andi.	r0,r4,1		/* Find the zero we know is there */
-	srawi	r4,r4,1
-	beq	90f
-	addi	r3,r3,1
-	b	10b
-90:	blr
 
 /*
  * Extended precision shifts
@@ -605,43 +288,7 @@
 	slw	r3,r3,r5	/* YYY--- */
 	or	r3,r3,r7	/* YYYZZZ */
 	blr
-	
-_GLOBAL(abort)
-	.long	0
-	
-/* in include/asm/string.h now -- Cort */
-#if 0
-_GLOBAL(bzero)
-#define bufp r3
-#define len  r4
-#define pat  r5
-/* R3 has buffer */
-/* R4 has length */
-/* R5 has pattern */
-	cmpi	0,len,0		/* Exit if len <= 0 */
-	ble	99f
-	andi.	r0,bufp,3	/* Must be on longword boundary */
-	bne	10f		/* Use byte loop if not aligned */
-	andi.	r0,len,3	/* Check for overrage */
-	subi	bufp,bufp,4	/* Adjust pointer */
-	srawi	len,len,2	/* Divide by 4 */
-	blt	99f		/* If negative - bug out! */
-	mtspr	CTR,len		/* Set up counter */
-	li	pat,0
-00:	stwu	pat,4(bufp)	/* Store value */
-	bdnz	00b		/* Loop [based on counter] */
-	mr	len,r0		/* Get remainder (bytes) */
-10:	cmpi	0,len,0		/* Any bytes left */
-	ble	99f		/* No - all done */
-	mtspr	CTR,len		/* Set up counter */
-	subi	bufp,bufp,1	/* Adjust pointer */
-	li	pat,0
-20:	stbu	pat,1(bufp)	/* Store value */
-	bdnz	20b		/* Loop [based on counter] */
-99:	blr
-#endif
 
-	
 _GLOBAL(abs)
 	cmpi	0,r3,0
 	bge	10f
@@ -651,39 +298,72 @@
 _GLOBAL(_get_SP)
 	mr	r3,r1		/* Close enough */
 	blr
-
-_GLOBAL(_get_SDR1)
-	mfspr	r3,SDR1
+	
+_GLOBAL(_get_PVR)
+	mfspr	r3,PVR
 	blr
 
-_GLOBAL(_get_SRx)
-	mfsrin	r3,r3
+_GLOBAL(cvt_fd)
+cvt_fd:
+	lfs	0,0(r3)
+	stfd	0,0(r4)
+	blr
+/*
+ * Fetch the current SR register
+ *   get_SR(int index)
+ */
+_GLOBAL(get_SR)
+	mfsrin	r4,r3
+	mr	r3,r4
 	blr
 
-_GLOBAL(_get_PVR)
-	mfspr	r3,PVR
+	
+_GLOBAL(cvt_df)
+cvt_df:
+	lfd	0,0(r3)
+	stfs	0,0(r4)
 	blr
 
 /*
  * Create a kernel thread
  *   __kernel_thread(flags, fn, arg)
  */
-#if 1
-#define SYS_CLONE 	120
 _GLOBAL(__kernel_thread)
-__kernel_thread:
-	li	r0,SYS_CLONE
+	li	r0,__NR_clone
 	sc
 	cmpi	0,r3,0		/* parent or child? */
 	bnelr			/* return if parent */
 	mtlr	r4              /* fn addr in lr */
 	mr	r3,r5	        /* load arg and call fn */
-	blr
-	li	0, 1 		/* exit after child exits */
-        li	3, 0
+	blrl
+	li	r0,__NR_exit	/* exit after child exits */
+        li	r3,0
 	sc
-#endif
-	
+
+#define SYSCALL(name) \
+_GLOBAL(name) \
+	li	r0,__NR_##name; \
+	sc; \
+	bnslr; \
+	lis	r4,errno@ha; \
+	stw	r3,errno@l(r4); \
+	li	r3,-1; \
+	blr
+
+#define __NR__exit __NR_exit
+
+SYSCALL(idle)
+SYSCALL(setup)
+SYSCALL(sync)
+SYSCALL(setsid)
+SYSCALL(write)
+SYSCALL(dup)
+SYSCALL(execve)
+SYSCALL(open)
+SYSCALL(close)
+SYSCALL(waitpid)
+
+
 /* Why isn't this a) automatic, b) written in 'C'? */	
 	.data
 	.align 4
@@ -694,12 +374,12 @@
 	.long sys_fork
 	.long sys_read
 	.long sys_write
-	.long sys_open			/* 5 */
+	.long sys_open		/* 5 */
 	.long sys_close
 	.long sys_waitpid
 	.long sys_creat
 	.long sys_link
-	.long sys_unlink		/* 10 */
+	.long sys_unlink	/* 10 */
 	.long sys_execve
 	.long sys_chdir
 	.long sys_time
@@ -709,7 +389,7 @@
 	.long sys_break
 	.long sys_stat
 	.long sys_lseek
-	.long sys_getpid		/* 20 */
+	.long sys_getpid	/* 20 */
 	.long sys_mount
 	.long sys_umount
 	.long sys_setuid
@@ -734,12 +414,12 @@
 	.long sys_pipe
 	.long sys_times
 	.long sys_prof
-	.long sys_brk			/* 45 */
+	.long sys_brk		/* 45 */
 	.long sys_setgid
 	.long sys_getgid
 	.long sys_signal
 	.long sys_geteuid
-	.long sys_getegid		/* 50 */
+	.long sys_getegid	/* 50 */
 	.long sys_acct
 	.long sys_phys
 	.long sys_lock
@@ -754,57 +434,57 @@
 	.long sys_ustat
 	.long sys_dup2
 	.long sys_getppid
-	.long sys_getpgrp		/* 65 */
+	.long sys_getpgrp	/* 65 */
 	.long sys_setsid
 	.long sys_sigaction
 	.long sys_sgetmask
 	.long sys_ssetmask
-	.long sys_setreuid		/* 70 */
+	.long sys_setreuid	/* 70 */
 	.long sys_setregid
 	.long sys_sigsuspend
 	.long sys_sigpending
 	.long sys_sethostname
-	.long sys_setrlimit		/* 75 */
+	.long sys_setrlimit	/* 75 */
 	.long sys_getrlimit
 	.long sys_getrusage
 	.long sys_gettimeofday
 	.long sys_settimeofday
-	.long sys_getgroups		/* 80 */
+	.long sys_getgroups	/* 80 */
 	.long sys_setgroups
-	.long sys_select
+	.long ppc_select
 	.long sys_symlink
 	.long sys_lstat
-	.long sys_readlink		/* 85 */
+	.long sys_readlink	/* 85 */
 	.long sys_uselib
 	.long sys_swapon
 	.long sys_reboot
 	.long old_readdir		/* was sys_readdir */
-	.long sys_mmap			/* 90 */
+	.long sys_mmap		/* 90 */
 	.long sys_munmap
 	.long sys_truncate
 	.long sys_ftruncate
 	.long sys_fchmod
-	.long sys_fchown		/* 95 */
+	.long sys_fchown	/* 95 */
 	.long sys_getpriority
 	.long sys_setpriority
 	.long sys_profil
 	.long sys_statfs
-	.long sys_fstatfs		/* 100 */
+	.long sys_fstatfs	/* 100 */
 	.long sys_ioperm
 	.long sys_socketcall
 	.long sys_syslog
 	.long sys_setitimer
-	.long sys_getitimer		/* 105 */
+	.long sys_getitimer	/* 105 */
 	.long sys_newstat
 	.long sys_newlstat
 	.long sys_newfstat
 	.long sys_uname
-	.long sys_iopl			/* 110 */
+	.long sys_iopl		/* 110 */
 	.long sys_vhangup
 	.long sys_idle
 	.long sys_vm86
 	.long sys_wait4
-	.long sys_swapoff		/* 115 */
+	.long sys_swapoff	/* 115 */
 	.long sys_sysinfo
 	.long sys_ipc
 	.long sys_fsync
@@ -814,7 +494,7 @@
 	.long sys_newuname
 	.long sys_modify_ldt
 	.long sys_adjtimex
-	.long sys_mprotect		/* 125 */
+	.long sys_mprotect	/* 125 */
 	.long sys_sigprocmask
 	.long sys_create_module
 	.long sys_init_module
@@ -829,9 +509,9 @@
 	.long 0				/* for afs_syscall */
 	.long sys_setfsuid
 	.long sys_setfsgid
-	.long sys_llseek		/* 140 */
+	.long sys_llseek	/* 140 */
         .long sys_getdents
-	.long sys_newselect
+	.long ppc_select
 	.long sys_flock
 	.long sys_msync
 	.long sys_readv		/* 145 */
@@ -844,7 +524,7 @@
 	.long sys_mlockall
 	.long sys_munlockall
 	.long sys_sched_setparam
-	.long sys_sched_getparam   /* 155 */
+	.long sys_sched_getparam	/* 155 */
 	.long sys_sched_setscheduler
 	.long sys_sched_getscheduler
 	.long sys_sched_yield
@@ -853,8 +533,11 @@
 	.long sys_sched_rr_get_interval
 	.long sys_nanosleep
 	.long sys_mremap
-	.long SYMBOL_NAME(sys_setresuid)
-	.long SYMBOL_NAME(sys_getresuid)
-	.long SYMBOL_NAME(sys_nfsservctl)
-	.space (NR_syscalls-166)*4
+	.long sys_setresuid
+	.long sys_getresuid		/* 165 */
+	.long sys_query_module
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_debug
+	.space (NR_syscalls-170)*4
 
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.1.47/linux/arch/ppc/kernel/mk_defs.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/mk_defs.c	Thu Jul 31 13:09:17 1997
@@ -1,11 +1,14 @@
 /*
  * This program is used to generate definitions needed by
  * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
  */
-#define MK_DEFS
-#include <stdio.h> 
 
-#include <linux/config.h>
+#include <stddef.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/head.h>
@@ -16,156 +19,114 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/processor.h>
 
-extern int errno;
+#define DEFINE(sym, val) \
+	asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
 
-main(int argc, char *argv[])
+void
+main(void)
 {
-	FILE *out;
-	struct task_struct task;
-	struct thread_struct tss;
-	int i;
-	char s[256];
-	struct pt_regs regs;
-	if (!(out = fopen(argv[1], "w")))
-	{
-		fprintf(stderr, "Can't create output file: %s\n", strerror(errno));
-		exit(1);
-	}
-	fprintf(out, "/*\n");
-	fprintf(out, " * WARNING! This file is automatically generated - DO NOT EDIT!\n");
-	fprintf(out, " */\n");
-	put_line(out, "STATE", (int)&task.state-(int)&task);
-	put_line(out, "COUNTER", (int)&task.counter-(int)&task);
-	put_line(out, "BLOCKED", (int)&task.blocked-(int)&task);
-	put_line(out, "SIGNAL", (int)&task.signal-(int)&task);
-	put_line(out, "KERNEL_STACK_PAGE", (int)&task.kernel_stack_page-(int)&task);
-	put_line(out, "TSS", (int)&task.tss-(int)&task);
-	put_line(out, "KSP", (int)&tss.ksp-(int)&tss);
-	put_line(out, "LAST_PC", (int)&tss.last_pc-(int)&tss);
-	put_line(out, "USER_STACK", (int)&tss.user_stack-(int)&tss);
-	put_line(out, "PT_REGS", (int)&tss.regs-(int)&tss);
-	put_line(out, "PF_TRACESYS", PF_TRACESYS);
-	put_line(out, "TASK_FLAGS", (int)&task.flags-(int)&task);
-	put_line(out, "MMU_SEG0", (int)&tss.segs[0]-(int)&tss);
-	put_line(out, "MMU_SEG1", (int)&tss.segs[1]-(int)&tss);
-	put_line(out, "MMU_SEG2", (int)&tss.segs[2]-(int)&tss);
-	put_line(out, "MMU_SEG3", (int)&tss.segs[3]-(int)&tss);
-	put_line(out, "MMU_SEG4", (int)&tss.segs[4]-(int)&tss);
-	put_line(out, "MMU_SEG5", (int)&tss.segs[5]-(int)&tss);
-	put_line(out, "MMU_SEG6", (int)&tss.segs[6]-(int)&tss);
-	put_line(out, "MMU_SEG7", (int)&tss.segs[7]-(int)&tss);
-	put_line(out, "MMU_SEG8", (int)&tss.segs[8]-(int)&tss);
-	put_line(out, "MMU_SEG9", (int)&tss.segs[9]-(int)&tss);
-	put_line(out, "MMU_SEG10", (int)&tss.segs[10]-(int)&tss);
-	put_line(out, "MMU_SEG11", (int)&tss.segs[11]-(int)&tss);
-	put_line(out, "MMU_SEG12", (int)&tss.segs[12]-(int)&tss);
-	put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss);
-	put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss);
-	put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss);
-	put_line(out, "TSS_EXPC", (int)&tss.expc-(int)&tss);
-	put_line(out, "TSS_EXCOUNT", (int)&tss.excount-(int)&tss);		
-	put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss);
-	put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss);
-	put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss);
-	put_line(out, "TSS_FPR3", (int)&tss.fpr[3]-(int)&tss);
-	put_line(out, "TSS_FPR4", (int)&tss.fpr[4]-(int)&tss);
-	put_line(out, "TSS_FPR5", (int)&tss.fpr[5]-(int)&tss);
-	put_line(out, "TSS_FPR6", (int)&tss.fpr[6]-(int)&tss);
-	put_line(out, "TSS_FPR7", (int)&tss.fpr[7]-(int)&tss);
-	put_line(out, "TSS_FPR8", (int)&tss.fpr[8]-(int)&tss);
-	put_line(out, "TSS_FPR9", (int)&tss.fpr[9]-(int)&tss);
-	put_line(out, "TSS_FPR10", (int)&tss.fpr[10]-(int)&tss);
-	put_line(out, "TSS_FPR11", (int)&tss.fpr[11]-(int)&tss);
-	put_line(out, "TSS_FPR12", (int)&tss.fpr[12]-(int)&tss);
-	put_line(out, "TSS_FPR13", (int)&tss.fpr[13]-(int)&tss);
-	put_line(out, "TSS_FPR14", (int)&tss.fpr[14]-(int)&tss);
-	put_line(out, "TSS_FPR15", (int)&tss.fpr[15]-(int)&tss);
-	put_line(out, "TSS_FPR16", (int)&tss.fpr[16]-(int)&tss);
-	put_line(out, "TSS_FPR17", (int)&tss.fpr[17]-(int)&tss);
-	put_line(out, "TSS_FPR18", (int)&tss.fpr[18]-(int)&tss);
-	put_line(out, "TSS_FPR19", (int)&tss.fpr[19]-(int)&tss);
-	put_line(out, "TSS_FPR20", (int)&tss.fpr[20]-(int)&tss);
-	put_line(out, "TSS_FPR21", (int)&tss.fpr[21]-(int)&tss);
-	put_line(out, "TSS_FPR22", (int)&tss.fpr[22]-(int)&tss);
-	put_line(out, "TSS_FPR23", (int)&tss.fpr[23]-(int)&tss);
-	put_line(out, "TSS_FPR24", (int)&tss.fpr[24]-(int)&tss);
-	put_line(out, "TSS_FPR25", (int)&tss.fpr[25]-(int)&tss);
-	put_line(out, "TSS_FPR26", (int)&tss.fpr[26]-(int)&tss);
-	put_line(out, "TSS_FPR27", (int)&tss.fpr[27]-(int)&tss);
-	put_line(out, "TSS_FPR28", (int)&tss.fpr[28]-(int)&tss);
-	put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss);
-	put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss);
-	put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss);
-	put_line(out, "TSS_FP_USED", (int)&tss.fp_used-(int)&tss);
-	/* Interrupt register frame */
-	put_line(out, "INT_FRAME_SIZE", sizeof(regs));
-	put_line(out, "GPR0", (int)&regs.gpr[0]-(int)&regs);
-	put_line(out, "GPR1", (int)&regs.gpr[1]-(int)&regs);
-	put_line(out, "GPR2", (int)&regs.gpr[2]-(int)&regs);
-	put_line(out, "GPR3", (int)&regs.gpr[3]-(int)&regs);
-	put_line(out, "GPR4", (int)&regs.gpr[4]-(int)&regs);
-	put_line(out, "GPR5", (int)&regs.gpr[5]-(int)&regs);
-	put_line(out, "GPR6", (int)&regs.gpr[6]-(int)&regs);
-	put_line(out, "GPR7", (int)&regs.gpr[7]-(int)&regs);
-	put_line(out, "GPR8", (int)&regs.gpr[8]-(int)&regs);
-	put_line(out, "GPR9", (int)&regs.gpr[9]-(int)&regs);
-	put_line(out, "GPR10", (int)&regs.gpr[10]-(int)&regs);
-	put_line(out, "GPR11", (int)&regs.gpr[11]-(int)&regs);
-	put_line(out, "GPR12", (int)&regs.gpr[12]-(int)&regs);
-	put_line(out, "GPR13", (int)&regs.gpr[13]-(int)&regs);
-	put_line(out, "GPR14", (int)&regs.gpr[14]-(int)&regs);
-	put_line(out, "GPR15", (int)&regs.gpr[15]-(int)&regs);
-	put_line(out, "GPR16", (int)&regs.gpr[16]-(int)&regs);
-	put_line(out, "GPR17", (int)&regs.gpr[17]-(int)&regs);
-	put_line(out, "GPR18", (int)&regs.gpr[18]-(int)&regs);
-	put_line(out, "GPR19", (int)&regs.gpr[19]-(int)&regs);
-	put_line(out, "GPR20", (int)&regs.gpr[20]-(int)&regs);
-	put_line(out, "GPR21", (int)&regs.gpr[21]-(int)&regs);
-	put_line(out, "GPR22", (int)&regs.gpr[22]-(int)&regs);
-	put_line(out, "GPR23", (int)&regs.gpr[23]-(int)&regs);
-	put_line(out, "GPR24", (int)&regs.gpr[24]-(int)&regs);
-	put_line(out, "GPR25", (int)&regs.gpr[25]-(int)&regs);
-	put_line(out, "GPR26", (int)&regs.gpr[26]-(int)&regs);
-	put_line(out, "GPR27", (int)&regs.gpr[27]-(int)&regs);
-	put_line(out, "GPR28", (int)&regs.gpr[28]-(int)&regs);
-	put_line(out, "GPR29", (int)&regs.gpr[29]-(int)&regs);
-	put_line(out, "GPR30", (int)&regs.gpr[30]-(int)&regs);
-	put_line(out, "GPR31", (int)&regs.gpr[31]-(int)&regs);
-#if 0	
-	for ( i = 0 ; i <= 31 ; i++)
-	{
-	  sprintf(s,"FPR%d",i);
-	  put_line(out, s, (int)&regs.fpr[i]-(int)&regs);
-	}
+	/*DEFINE(KERNELBASE, KERNELBASE);*/
+	DEFINE(STATE, offsetof(struct task_struct, state));
+	DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
+	DEFINE(COUNTER, offsetof(struct task_struct, counter));
+	DEFINE(BLOCKED, offsetof(struct task_struct, blocked));
+	DEFINE(SIGNAL, offsetof(struct task_struct, signal));
+	DEFINE(TSS, offsetof(struct task_struct, tss));
+	DEFINE(KSP, offsetof(struct thread_struct, ksp));
+	DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
+#ifdef CONFIG_PMAC	
+	DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
+	DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
+#endif	
+	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
+	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+	DEFINE(PF_TRACESYS, PF_TRACESYS);
+	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+	DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
+#if 0
+	DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
+	DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
+	DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
+	DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
+	DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
+	DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
+	DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
+	DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
+	DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
+	DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
+	DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
+	DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
+	DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
+	DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
+	DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
+	DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
+	DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
+	DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
+	DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
+	DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
+	DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
+	DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
+	DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
+	DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
+	DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
+	DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
+	DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
+	DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
+	DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
+	DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
+	DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
 #endif
-	put_line(out, "FPCSR", (int)&regs.fpcsr-(int)&regs);
-	/* Note: these symbols include "_" because they overlap with special register names */
-	put_line(out, "_NIP", (int)&regs.nip-(int)&regs);
-	put_line(out, "_MSR", (int)&regs.msr-(int)&regs);
-	/*		put_line(out, "_SRR1", (int)&regs.srr1-(int)&regs);	
-	put_line(out, "_SRR0", (int)&regs.srr0-(int)&regs);	*/
-	put_line(out, "_CTR", (int)&regs.ctr-(int)&regs);
-	put_line(out, "_LINK", (int)&regs.link-(int)&regs);
-	put_line(out, "_CCR", (int)&regs.ccr-(int)&regs);
-	put_line(out, "_XER", (int)&regs.xer-(int)&regs);
-	put_line(out, "_DAR", (int)&regs.dar-(int)&regs);
-	put_line(out, "_DSISR", (int)&regs.dsisr-(int)&regs);
-	put_line(out, "_HASH1", (int)&regs.hash1-(int)&regs);
-	put_line(out, "_HASH2", (int)&regs.hash2-(int)&regs);
-	put_line(out, "_IMISS", (int)&regs.imiss-(int)&regs);
-	put_line(out, "_DMISS", (int)&regs.dmiss-(int)&regs);
-	put_line(out, "_ICMP", (int)&regs.icmp-(int)&regs);
-	put_line(out, "_DCMP", (int)&regs.dcmp-(int)&regs);
-	put_line(out, "ORIG_GPR3", (int)&regs.orig_gpr3-(int)&regs);
-	put_line(out, "RESULT", (int)&regs.result-(int)&regs);
-	put_line(out, "TRAP", (int)&regs.trap-(int)&regs);
-	put_line(out, "MARKER", (int)&regs.marker-(int)&regs);
-	exit(0);
-}
-
-put_line(FILE *out, char *name, int offset)
-{
-	fprintf(out, "#define %s %d\n", name, offset);
+	DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+	/* Interrupt register frame */
+	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
+	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+	DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
+	DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
+	DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
+	DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
+	DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
+	DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
+	DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
+	DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
+	DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
+	DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
+	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+	DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
+	DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
+	DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
+	DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
+	DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
+	DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
+	DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
+	DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
+	/* Note: these symbols include _ because they overlap with special register names */
+	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+	DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.1.47/linux/arch/ppc/kernel/pci.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/pci.c	Thu Jul 31 13:09:17 1997
@@ -11,14 +11,18 @@
 #include <linux/bios32.h>
 #include <linux/pci.h>
 
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
 /*
  * PCI interrupt configuration.  This is motherboard specific.
  */
- 
- 
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
 unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
 
 /* How is the 82378 PIRQ mapping setup? */
 unsigned char *Motherboard_routes;
@@ -27,7 +31,7 @@
 
 /* Motorola PowerStack */
 static char Blackhawk_pci_IRQ_map[16] =
-  {
+{
   	0,	/* Slot 0  - unused */
   	0,	/* Slot 1  - unused */
   	0,	/* Slot 2  - unused */
@@ -44,20 +48,20 @@
   	0,	/* Slot 13 - unused */
   	1,	/* Slot 14 - Ethernet */
   	0,	/* Slot 15 - unused */
-  };
+};
 
 static char Blackhawk_pci_IRQ_routes[] =
-   {
+{
    	0,	/* Line 0 - Unused */
    	9,	/* Line 1 */
    	11,	/* Line 2 */
    	14,	/* Line 3 */
    	15	/* Line 4 */
-   };
+};
    
 /* Motorola MVME16xx */
 static char Genesis_pci_IRQ_map[16] =
-  {
+{
   	0,	/* Slot 0  - unused */
   	0,	/* Slot 1  - unused */
   	0,	/* Slot 2  - unused */
@@ -74,20 +78,20 @@
   	0,	/* Slot 13 - unused */
   	1,	/* Slot 14 - Ethernet */
   	0,	/* Slot 15 - unused */
-  };
+};
 
 static char Genesis_pci_IRQ_routes[] =
-   {
+{
    	0,	/* Line 0 - Unused */
    	10,	/* Line 1 */
    	11,	/* Line 2 */
    	14,	/* Line 3 */
    	15	/* Line 4 */
-   };
+};
    
 /* Motorola Series-E */
 static char Comet_pci_IRQ_map[16] =
-  {
+{
   	0,	/* Slot 0  - unused */
   	0,	/* Slot 1  - unused */
   	0,	/* Slot 2  - unused */
@@ -104,20 +108,20 @@
   	0,	/* Slot 13 - unused */
   	1,	/* Slot 14 - Ethernet */
   	0,	/* Slot 15 - unused */
-  };
+};
 
 static char Comet_pci_IRQ_routes[] =
-   {
+{
    	0,	/* Line 0 - Unused */
    	10,	/* Line 1 */
    	11,	/* Line 2 */
    	14,	/* Line 3 */
    	15	/* Line 4 */
-   };
+};
 
 /* BeBox */
 static char BeBox_pci_IRQ_map[16] =
-  {
+{
   	0,	/* Slot 0  - unused */
   	0,	/* Slot 1  - unused */
   	0,	/* Slot 2  - unused */
@@ -134,20 +138,20 @@
   	0,	/* Slot 13 - unused */
   	0,	/* Slot 14 - unused */
   	0,	/* Slot 15 - unused */
-  };
+};
 
 static char BeBox_pci_IRQ_routes[] =
-   {
+{
    	0,	/* Line 0 - Unused */
    	9,	/* Line 1 */
    	11,	/* Line 2 */
    	14,	/* Line 3 */
    	15	/* Line 4 */
-   };
+};
 
 /* IBM Nobis */
 static char Nobis_pci_IRQ_map[16] =
-  {
+{
   	0,	/* Slot 0  - unused */
   	0,	/* Slot 1  - unused */
   	0,	/* Slot 2  - unused */
@@ -164,54 +168,83 @@
   	0,	/* Slot 13 - unused */
   	0,	/* Slot 14 - unused */
   	0,	/* Slot 15 - unused */
-  };
+};
 
 static char Nobis_pci_IRQ_routes[] =
-   {
+{
    	0,	/* Line 0 - Unused */
    	13,	/* Line 1 */
    	13,	/* Line 2 */
    	13,	/* Line 3 */
    	13      /* Line 4 */
-   };
+};
+
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral */
+        4, /* Slot 12 - Ethernet  PCIINTD# */
+        2, /* Slot 13 - PCI Slot #2 */
+        2, /* Slot 14 - S3 Video PCIINTD# */
+        0, /* Slot 15 - onboard SCSI (INDI) [1] */
+        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+static char ibm8xx_pci_IRQ_routes[] = {
+        0,      /* Line 0 - unused */
+        13,     /* Line 1 */
+        10,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
+ * it really needs some logic to set them to unique IRQ's, or even
+ * add some logic to the drivers to ask an irq.c routine to re-map
+ * the IRQ if it needs one to itself...
+ */
+static char Carolina_PIRQ_routes[] = {
+   0xad,	/* INTB# = 10, INTA# = 13 */
+   0xff		/* INTD# = 15, INTC# = 15 */
+};
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+#define CAROLINA_IRQ_EDGE_MASK_LO   0x00  /* IRQ's 0-7  */
+#define CAROLINA_IRQ_EDGE_MASK_HI   0xA4  /* IRQ's 8-15 [10,13,15] */
+#define PCI_DEVICE_ID_IBM_CORAL		0x000a
 
-#define PCI_DEBUG
 #undef  PCI_DEBUG
 
 #ifdef PCI_STATS
 int PCI_conversions[2];
 #endif
 
-unsigned long pcibios_init(unsigned long mem_start,
-			   unsigned long mem_end)
-{
-	return mem_start;
-}
 
 unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
 {
-  return mem_start;
-}
-
-
-unsigned long
-_LE_to_BE_long(unsigned long val)
-{
-	unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
-	PCI_conversions[0]++;
-#endif	
-	return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0] << 0));
-}
-
-unsigned short
-_LE_to_BE_short(unsigned long val)
-{
-	unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
-	PCI_conversions[1]++;
-#endif	
-	return ((p[3] << 8) | (p[2] << 0));
+	return mem_start;
 }
 
 int
@@ -225,7 +258,7 @@
 
 int
 pcibios_read_config_dword (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned int *val)
+			   unsigned char dev, unsigned char offset, unsigned int *val)
 {
 	unsigned long _val;
 	unsigned long *ptr;
@@ -243,7 +276,7 @@
 #ifdef PCI_DEBUG	
 		printk("[%x] ", ptr);
 #endif		
-		_val = _LE_to_BE_long(*ptr);
+		_val = le32_to_cpu(*ptr);
 	}
 #ifdef PCI_DEBUG	
 	printk("%x\n", _val);
@@ -254,27 +287,27 @@
 
 int
 pcibios_read_config_word (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned short *val)
+			  unsigned char dev, unsigned char offset, unsigned short *val)
 {
 	unsigned short _val;
 	unsigned short *ptr;
 	dev >>= 3;
-#ifdef PCI_DEBUG	
+#ifdef PCI_DEBUG
 	printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
 #endif	
 	if ((bus != 0) || (dev < 11) || (dev > 16))
 	{
-		*val = 0xFFFFFFFF;
+		*val = (unsigned short)0xFFFFFFFF;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	} else
 	{
 		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG	
+#ifdef PCI_DEBUG
 		printk("[%x] ", ptr);
 #endif		
-		_val = _LE_to_BE_short(*ptr);
+		_val = le16_to_cpu(*ptr);
 	}
-#ifdef PCI_DEBUG	
+#ifdef PCI_DEBUG
 	printk("%x\n", _val);
 #endif		
 	*val = _val;
@@ -283,7 +316,7 @@
 
 int
 pcibios_read_config_byte (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned char *val)
+			  unsigned char dev, unsigned char offset, unsigned char *val)
 {
 	unsigned char _val;
 	volatile unsigned char *ptr;
@@ -294,6 +327,9 @@
 		if (Motherboard_map[dev] <= 4)
 		{
 			*val = Motherboard_routes[Motherboard_map[dev]];
+			/*printk("dev %d map %d route %d\n",
+			  dev,Motherboard_map[dev],
+			  Motherboard_routes[Motherboard_map[dev]]);*/
 		} else
 		{ /* Pseudo interrupts [for BeBox] */
 			*val = Motherboard_map[dev];
@@ -327,12 +363,12 @@
 
 int
 pcibios_write_config_dword (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned int val)
+			    unsigned char dev, unsigned char offset, unsigned int val)
 {
 	unsigned long _val;
 	unsigned long *ptr;
 	dev >>= 3;
-	_val = _LE_to_BE_long(val);
+	_val = le32_to_cpu(val);
 #ifdef PCI_DEBUG	
 	printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
 #endif		
@@ -349,12 +385,12 @@
 
 int
 pcibios_write_config_word (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned short val)
+			   unsigned char dev, unsigned char offset, unsigned short val)
 {
 	unsigned short _val;
 	unsigned short *ptr;
 	dev >>= 3;
-	_val = _LE_to_BE_short(val);
+	_val = le16_to_cpu(val);
 #ifdef PCI_DEBUG	
 	printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
 #endif		
@@ -371,7 +407,7 @@
 
 int
 pcibios_write_config_byte (unsigned char bus,
-    unsigned char dev, unsigned char offset, unsigned char val)
+			   unsigned char dev, unsigned char offset, unsigned char val)
 {
 	unsigned char _val;
 	unsigned char *ptr;
@@ -420,7 +456,7 @@
 
 int
 pcibios_find_class (unsigned int class_code, unsigned short index, 
-    unsigned char *bus, unsigned char *dev)
+		    unsigned char *bus, unsigned char *dev)
 {
 	int dev_nr, class, indx;
 	indx = 0;
@@ -437,7 +473,7 @@
 				*bus = 0;
 				*dev = dev_nr<<3;
 #ifdef PCI_DEBUG
-	printk(" - device: %x\n", dev_nr);
+				printk(" - device: %x\n", dev_nr);
 #endif	
 				return (0);
 			}
@@ -455,22 +491,22 @@
 	static char buf[32];
 	switch (error)
 	{	case PCIBIOS_SUCCESSFUL:
-			return ("PCI BIOS: no error");
-		case PCIBIOS_FUNC_NOT_SUPPORTED:
-			return ("PCI BIOS: function not supported");
-		case PCIBIOS_BAD_VENDOR_ID:
-			return ("PCI BIOS: bad vendor ID");
-		case PCIBIOS_DEVICE_NOT_FOUND:
-			return ("PCI BIOS: device not found");
-		case PCIBIOS_BAD_REGISTER_NUMBER:
-			return ("PCI BIOS: bad register number");
-		case PCIBIOS_SET_FAILED:
-			return ("PCI BIOS: set failed");
-		case PCIBIOS_BUFFER_TOO_SMALL:
-			return ("PCI BIOS: buffer too small");
-		default:
-			sprintf(buf, "PCI BIOS: invalid error #%d", error);
-			return(buf);
+		return ("PCI BIOS: no error");
+	case PCIBIOS_FUNC_NOT_SUPPORTED:
+		return ("PCI BIOS: function not supported");
+	case PCIBIOS_BAD_VENDOR_ID:
+		return ("PCI BIOS: bad vendor ID");
+	case PCIBIOS_DEVICE_NOT_FOUND:
+		return ("PCI BIOS: device not found");
+	case PCIBIOS_BAD_REGISTER_NUMBER:
+		return ("PCI BIOS: bad register number");
+	case PCIBIOS_SET_FAILED:
+		return ("PCI BIOS: set failed");
+	case PCIBIOS_BUFFER_TOO_SMALL:
+		return ("PCI BIOS: buffer too small");
+	default:
+		sprintf(buf, "PCI BIOS: invalid error #%d", error);
+		return(buf);
 	}
 }
 
@@ -478,42 +514,112 @@
  * Note: This routine has to access the PCI configuration space
  * for the PCI bridge chip (Intel 82378).
  */
- 
-void route_PCI_interrupts(void)
+unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
+{
+	return mem_start;
+}
+
+unsigned long route_pci_interrupts(void)
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
 	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
 	extern unsigned long isBeBox[];
 	int i;
-	/* Decide which motherboard this is & how the PCI interrupts are routed */
-	if (isBeBox[0])
-	{
-		Motherboard_map = BeBox_pci_IRQ_map;
-		Motherboard_routes = BeBox_pci_IRQ_routes;
-	} else
-	if ((_get_PVR()>>16) == 1)
-	{ /* Nobis */
-		Motherboard_map = Nobis_pci_IRQ_map;
-		Motherboard_routes = Nobis_pci_IRQ_routes;
-	} else
-	{ /* Motorola hardware */
+	
+	if ( _machine == _MACH_Motorola)
+	{ 
 		switch (inb(0x800) & 0xF0)
 		{
-			case 0x10: /* MVME16xx */
-				Motherboard_map = Genesis_pci_IRQ_map;
-				Motherboard_routes = Genesis_pci_IRQ_routes;
-				break;
-			case 0x20: /* Series E */
-				Motherboard_map = Comet_pci_IRQ_map;
-				Motherboard_routes = Comet_pci_IRQ_routes;
-				break;
-			case 0x40: /* PowerStack */
-			default: /* Can't hurt, can it? */
-				Motherboard_map = Blackhawk_pci_IRQ_map;
-				Motherboard_routes = Blackhawk_pci_IRQ_routes;
-				break;
+		case 0x10: /* MVME16xx */
+			Motherboard_map_name = "Genesis";
+			Motherboard_map = Genesis_pci_IRQ_map;
+			Motherboard_routes = Genesis_pci_IRQ_routes;
+			break;
+		case 0x20: /* Series E */
+			Motherboard_map_name = "Series E";
+			Motherboard_map = Comet_pci_IRQ_map;
+			Motherboard_routes = Comet_pci_IRQ_routes;
+			break;
+		case 0x40: /* PowerStack */
+		default: /* Can't hurt, can it? */
+			Motherboard_map_name = "Blackhawk (Powerstack)";
+			Motherboard_map = Blackhawk_pci_IRQ_map;
+			Motherboard_routes = Blackhawk_pci_IRQ_routes;
+			break;
+		}
+	} else
+	{
+		if ( _machine == _MACH_IBM )
+		{
+			unsigned char pl_id;
+			unsigned long flags;
+			unsigned index;
+			unsigned char fn, bus;
+			unsigned int addr;
+			unsigned char dma_mode, ide_mode;
+			int i;
+			
+			Motherboard_map_name = "IBM 8xx (Carolina)";
+			Motherboard_map = ibm8xx_pci_IRQ_map;
+			Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ll_printk("before loop\n");			
+			
+			for (index = 0;
+			     !pcibios_find_device (PCI_VENDOR_ID_IBM, 
+						   PCI_DEVICE_ID_IBM_CORAL, 
+						   index, &bus, &fn); ++index)
+			{
+				pcibios_read_config_dword(bus, fn, 0x10, &addr);
+				addr &= ~0x3;
+				outb(0x26, addr);
+				dma_mode = inb(addr+4);
+				outb(0x25, addr);
+				ide_mode = inb(addr+4);
+				/*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x", 
+				       addr, dma_mode, ide_mode);*/
+				/* Make CDROM non-DMA */
+				ide_mode = (ide_mode & 0x0F) | 0x20;
+				outb(0x25, addr);
+				outb(ide_mode, addr+4);
+				dma_mode = dma_mode & ~0x80;
+				outb(0x26, addr);
+				outb(dma_mode, addr+4);
+				outb(0x26, addr);
+				dma_mode = inb(addr+4);
+				outb(0x25, addr);
+				ide_mode = inb(addr+4);
+				/*printk("=> DMA mode: %x, IDE mode: %x\n", 
+				       dma_mode, ide_mode);*/
+			}
+			
+			/* Setup the PCI INT mappings for the Carolina */
+			/* These are PCI Interrupt Route Control [1|2] Register */
+			outb(Carolina_PIRQ_routes[0], 0x0890);
+			outb(Carolina_PIRQ_routes[1], 0x0891);
+			
+			pl_id=inb(0x0852);
+			/*printk("CPU Planar ID is %#0x\n", pl_id);*/
+			
+			if (pl_id == 0x0C) {
+				/* INDI */
+				Motherboard_map[12] = 1;
+			}
+ll_printk("before edge/level\n");			
+#if 0			
+			/*printk("Changing IRQ mode\n");*/
+			pl_id=inb(0x04d0);
+			/*printk("Low mask is %#0x\n", pl_id);*/
+			outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
+			
+			pl_id=inb(0x04d1);
+			/*printk("Hi mask is  %#0x\n", pl_id);*/
+			outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
+			pl_id=inb(0x04d1);
+			/*printk("Hi mask now %#0x\n", pl_id);*/
+#endif			
 		}
 	}
+	
 	/* Set up mapping from slots */
 	for (i = 1;  i <= 4;  i++)
 	{
@@ -521,4 +627,4 @@
 	}
 	/* Enable PCI interrupts */
 	*ibc_pcicon |= 0x20;
-} 
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.1.47/linux/arch/ppc/kernel/pmac_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_setup.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,260 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from "arch/alpha/kernel/setup.c"
+ *    Copyright (C) 1995 Linus Torvalds
+ *
+ *  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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+
+extern int root_mountflags;
+
+extern char command_line[];
+char saved_command_line[256];
+
+unsigned char aux_device_present;	/* XXX */
+unsigned char kbd_read_mask;
+unsigned char drive_info;
+
+#define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
+
+extern unsigned long find_available_memory(void);
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+	return memory_start;
+}
+
+void setup_arch(char **cmdline_p,
+	unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+	extern unsigned long *end_of_DRAM;
+	struct device_node *cpu;
+	int *fp;
+
+	strcpy(saved_command_line, command_line);
+	*cmdline_p = command_line;
+
+	*memory_start_p = find_available_memory();
+	*memory_end_p = (unsigned long) end_of_DRAM;
+
+	set_prom_callback();
+
+	*memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p);
+
+	/* Set loops_per_sec to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0) {
+			switch (_get_PVR() >> 16) {
+			case 4:		/* 604 */
+				loops_per_sec = *fp;
+				break;
+			default:	/* 601, 603, etc. */
+				loops_per_sec = *fp / 2;
+			}
+		} else
+			loops_per_sec = 50000000;
+	}
+}
+
+char *bootpath;
+char bootdevice[256];
+void *boot_host;
+int boot_target;
+int boot_part;
+kdev_t boot_dev;
+
+unsigned long
+pmac_find_devices(unsigned long mem_start, unsigned long mem_end)
+{
+	struct device_node *chosen_np;
+
+	nvram_init();
+	via_cuda_init();
+	read_rtc_time();
+	pmac_find_display();
+	bootpath = NULL;
+	chosen_np = find_devices("chosen");
+	if (chosen_np != NULL)
+		bootpath = (char *) get_property(chosen_np, "bootpath", NULL);
+	if (bootpath != NULL) {
+		/*
+		 * There's a bug in the prom.  (Why am I not surprised.)
+		 * If you pass a path like scsi/sd@1:0 to canon, it returns
+		 * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+		 * That is, the scsi target number doesn't get preserved.
+		 */
+		call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice));
+	}
+	return mem_start;
+}
+
+void
+note_scsi_host(struct device_node *node, void *host)
+{
+	int l;
+	char *p;
+
+	l = strlen(node->full_name);
+	if (strncmp(node->full_name, bootdevice, l) == 0
+	    && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+		boot_host = host;
+		p = strstr(bootpath, "/sd@");
+		if (p != NULL) {
+			p += 4;
+			boot_target = simple_strtoul(p, NULL, 10);
+			p = strchr(p, ':');
+			if (p != NULL)
+				boot_part = simple_strtoul(p + 1, NULL, 10);
+		}
+	}
+}
+
+void find_scsi_boot()
+{
+	int dev;
+
+	if (kdev_t_to_nr(ROOT_DEV) != 0)
+		return;
+	ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+	if (boot_host == NULL)
+		return;
+	dev = sd_find_target(boot_host, boot_target);
+	if (dev == 0)
+		return;
+	boot_dev = to_kdev_t(dev + boot_part);
+}
+
+void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+	struct device_node *np;
+	int i;
+	static struct device_node *atas;
+	static int atas_valid;
+
+	*p = 0;
+	*irq = 0;
+	if (!atas_valid) {
+		atas = find_devices("ATA");
+		atas_valid = 1;
+	}
+	for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
+		;
+	if (np == NULL)
+		return;
+	if (np->n_addrs == 0) {
+		printk("ide: no addresses for device %s\n", np->full_name);
+		return;
+	}
+	if (np->n_intrs == 0) {
+		printk("ide: no intrs for device %s, using 13\n",
+		       np->full_name);
+		np->intrs[0] = 13;
+	}
+	base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
+	for (i = 0; i < 8; ++i)
+		*p++ = base + i * 0x10;
+	*p = base + 0x160;
+	*irq = np->intrs[0];
+}
+
+int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+	return -EIO;
+}
+
+#if 0
+extern char builtin_ramdisk_image;
+extern long builtin_ramdisk_size;
+#endif
+
+void
+builtin_ramdisk_init(void)
+{
+#if 0
+	if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
+	{
+		rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
+	} else
+#endif
+	{  /* Not ramdisk - assume root needs to be mounted read only */
+		root_mountflags |= MS_RDONLY;
+	}
+}
+
+int
+get_cpuinfo(char *buffer)
+{
+	int pvr = _get_PVR();
+	char *model;
+	struct device_node *cpu;
+	int l, *fp;
+
+	l = 0;
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			l += sprintf(buffer, "%dMHz ", *fp / 1000000);
+	}
+
+	switch (pvr>>16) {
+	case 1:
+		model = "601";
+		break;
+	case 3:
+		model = "603";
+		break;
+	case 4:
+		model = "604";
+		break;
+	case 6:
+		model = "603e";
+		break;
+	case 7:
+		model = "603ev";
+		break;
+	default:
+		model = "unknown";
+		break;
+	}
+	return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
+			   (pvr & 0xff) >> 8, pvr & 0xff);
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- v2.1.47/linux/arch/ppc/kernel/pmac_support.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_support.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,82 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+
+void hard_reset_now(void)
+{
+	struct cuda_request req;
+
+	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+	for (;;)
+		cuda_poll();
+}
+
+void poweroff_now(void)
+{
+	struct cuda_request req;
+
+	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+	for (;;)
+		cuda_poll();
+}
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+
+void nvram_init(void)
+{
+	struct device_node *dp;
+
+	dp = find_devices("nvram");
+	if (dp == NULL)
+		panic("Can't find NVRAM device");
+	nvram_naddrs = dp->n_addrs;
+	if (nvram_naddrs == 1)
+		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+	else if (nvram_naddrs == 2) {
+		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+	} else {
+		printk("Found %d addresses for NVRAM\n", nvram_naddrs);
+		panic("don't understand NVRAM");
+	}
+}
+
+int nvram_readb(int addr)
+{
+	switch (nvram_naddrs) {
+	case 1:
+		return nvram_data[(addr & 0x1fff) << 4];
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		return nvram_data[(addr & 0x1f) << 4];
+	}
+	return -1;
+}
+
+void nvram_writeb(int addr, int val)
+{
+	switch (nvram_naddrs) {
+	case 1:
+		nvram_data[(addr & 0x1fff) << 4] = val;
+		break;
+	case 2:
+		*nvram_addr = addr >> 5;
+		eieio();
+		nvram_data[(addr & 0x1f) << 4] = val;
+		break;
+	}
+	eieio();
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- v2.1.47/linux/arch/ppc/kernel/pmac_time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_time.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,168 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * At present, we use the decrementer register in the 601 CPU
+ * for our periodic interrupts.  This will probably have to be
+ * changed for other processors.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+static int get_dec(void);
+static void set_dec(int);
+static unsigned long get_rtc_time(void);
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET	2082844800
+
+/* Accessor functions for the decrementer register. */
+static inline int
+get_dec()
+{
+    int ret;
+
+    asm volatile("mfspr %0,22" : "=r" (ret) :);
+    return ret;
+}
+
+static inline void
+set_dec(int val)
+{
+    asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601	(1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601	1
+#define COUNT_PERIOD_DEN_601	1000
+
+unsigned decrementer_count;	/* count value for 1e6/HZ microseconds */
+unsigned count_period_num;	/* 1 decrementer count equals */
+unsigned count_period_den;	/* count_period_num / count_period_den us */
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	*tv = xtime;
+	tv->tv_usec += (decrementer_count - get_dec())
+	    * count_period_num / count_period_den;
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+	restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	int frac_tick;
+
+	frac_tick = tv->tv_usec % (1000000 / HZ);
+	save_flags(flags);
+	cli();
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_usec = tv->tv_usec - frac_tick;
+	set_dec(frac_tick * count_period_den / count_period_num);
+	restore_flags(flags);
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+	int dval, d;
+
+	while ((dval = get_dec()) < 0) {
+		/*
+		 * Wait for the decrementer to change, then jump
+		 * in and add decrementer_count to its value
+		 * (quickly, before it changes again!)
+		 */
+		while ((d = get_dec()) == dval)
+			;
+		set_dec(d + decrementer_count);
+		do_timer(regs);
+	}
+
+}
+
+void
+time_init(void)
+{
+	struct device_node *cpu;
+	int freq, *fp, divisor;
+
+	if ((_get_PVR() >> 16) == 1) {
+		/* 601 processor: dec counts down by 128 every 128ns */
+		decrementer_count = DECREMENTER_COUNT_601;
+		count_period_num = COUNT_PERIOD_NUM_601;
+		count_period_den = COUNT_PERIOD_DEN_601;
+	} else {
+		/*
+		 * The cpu node should have a timebase-frequency property
+		 * to tell us the rate at which the decrementer counts.
+		 */
+		cpu = find_type_devices("cpu");
+		if (cpu == 0)
+			panic("can't find cpu node in time_init");
+		fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+		if (fp == 0)
+			panic("can't get cpu timebase frequency");
+		freq = *fp * 60;	/* try to make freq/1e6 an integer */
+		divisor = 60;
+		printk("time_init: decrementer frequency = %d/%d\n",
+		       freq, divisor);
+		decrementer_count = freq / HZ / divisor;
+		count_period_num = divisor;
+		count_period_den = freq / 1000000;
+	}
+	set_dec(decrementer_count);
+}
+
+/*
+ * We can't do this in time_init, because via_cuda_init hasn't
+ * been called at that stage.
+ */
+void
+read_rtc_time(void)
+{
+	xtime.tv_sec = get_rtc_time();
+	xtime.tv_usec = 0;
+}
+
+static unsigned long
+get_rtc_time()
+{
+	struct cuda_request req;
+
+	/* Get the time from the RTC */
+	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+	while (!req.got_reply)
+		cuda_poll();
+	if (req.reply_len != 7)
+		panic("get_rtc_time: didn't expect %d byte reply",
+		      req.reply_len);
+	return (req.reply[3] << 24) + (req.reply[4] << 16)
+		+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/port_io.c linux/arch/ppc/kernel/port_io.c
--- v2.1.47/linux/arch/ppc/kernel/port_io.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/port_io.c	Thu Jul 31 13:09:17 1997
@@ -1,149 +1,146 @@
 /*
  * I/O 'port' access routines
  */
+#include <asm/byteorder.h>
+#include <asm/io.h>
 
-/* This is really only correct for the MVME16xx (PreP)? */
+#define inb_asm(port) {( \
+  unsigned char ret; \
+  asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
+  return ret; \
+})
 
-#define _IO_BASE ((unsigned long)0x80000000)
-
-unsigned char
+inline unsigned char
 inb(int port)
 {
-	return (*((unsigned  char *)(_IO_BASE+port)));
+  unsigned char ret;
+  asm("/*inb*/\n");
+  asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
+  return ret;
 }
 
-unsigned short
+inline unsigned short
 inw(int port)
 {
-	return (_LE_to_BE_short(*((unsigned short *)(_IO_BASE+port))));
+  unsigned short ret;
+  asm("/*inw*/\n");
+  asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+  return ret;
 }
 
-unsigned long
+inline unsigned long
 inl(int port)
 {
-	return (_LE_to_BE_long(*((unsigned  long *)(_IO_BASE+port))));
+  unsigned long ret;
+  asm("/*inl*/\n");
+  asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+  return ret;
 }
 
-void insb(int port, char *ptr, int len)
+inline unsigned char
+outb(unsigned char val,int port)
 {
-	unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*ptr++ = *io_ptr;
-	}
+  asm("/*outb*/\n");
+  asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
+  return (val);
 }
 
-#if 0
-void insw(int port, short *ptr, int len)
-{
-	unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*ptr++ = _LE_to_BE_short(*io_ptr);
-	}
-}
-#else
-void insw(int port, short *ptr, int len)
+inline unsigned short
+outw(unsigned short val,int port)
 {
-	unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-	_insw(io_ptr, ptr, len);
+  asm("/*outw*/\n");
+  asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+  return (val);
 }
-#endif
 
-void insw_unswapped(int port, short *ptr, int len)
+inline unsigned long
+outl(unsigned long val,int port)
 {
-	unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*ptr++ = *io_ptr;
-	}
+  asm("/*outl*/\n");
+  asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+  return (val);
 }
 
-void insl(int port, long *ptr, int len)
+void insb(int port, char *ptr, int len)
 {
-	unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*ptr++ = _LE_to_BE_long(*io_ptr);
-	}
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
 }
 
-unsigned char  inb_p(int port) {return (inb(port)); }
-unsigned short inw_p(int port) {return (inw(port)); }
-unsigned long  inl_p(int port) {return (inl(port)); }
-
-unsigned char
-outb(unsigned char val,int port)
+void insw(int port, short *ptr, int len)
 {
-	*((unsigned  char *)(_IO_BASE+port)) = (val);
-	return (val);
+  asm ("mtctr	%2 \n\t"
+       "subi	%1,%1,2 \n\t"
+       "00:\n\t"
+       "lhbrx	%2,0,%0 \n\t"
+       "sthu	%2,2(%1) \n\t"
+       "bdnz 00b \n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
 
-unsigned short
-outw(unsigned short val,int port)
+void insw_unswapped(int port, short *ptr, int len)
 {
-	*((unsigned  short *)(_IO_BASE+port)) = _LE_to_BE_short(val);
-	return (val);
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
 }
 
-unsigned long
-outl(unsigned long val,int port)
+void insl(int port, long *ptr, int len)
 {
-	*((unsigned  long *)(_IO_BASE+port)) = _LE_to_BE_long(val);
-	return (val);
+  asm ("mtctr	%2 \n\t"
+       "subi	%1,%1,4 \n\t"
+       "00:\n\t"
+       "lhbrx	%2,0,%0 \n\t"
+       "sthu	%2,4(%1) \n\t"
+       "bdnz 00b \n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
 
 void outsb(int port, char *ptr, int len)
 {
-	unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*io_ptr = *ptr++;
-	}
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
 }
 
-#if 0
 void outsw(int port, short *ptr, int len)
 {
-	unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*io_ptr = _LE_to_BE_short(*ptr++);
-	}
+  asm ("mtctr	%2\n\t"
+       "subi	%1,%1,2\n\t"
+       "00:lhzu	%2,2(%1)\n\t"
+       "sthbrx	%2,0,%0\n\t"
+       "bdnz	00b\n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
 }
-#else
-void outsw(int port, short *ptr, int len)
-{
-	unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-	_outsw(io_ptr, ptr, len);
-}
-#endif
 
 void outsw_unswapped(int port, short *ptr, int len)
 {
-	unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*io_ptr = *ptr++;
-	}
+  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );  
 }
 
 void outsl(int port, long *ptr, int len)
 {
-	unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-	while (len-- > 0)
-	{
-		*io_ptr = _LE_to_BE_long(*ptr++);
-	}
-}
-
-unsigned char  outb_p(unsigned char val,int port) { return (outb(val,port)); }
-unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-unsigned long  outl_p(unsigned long val,int port) { return (outl(val,port)); }
-
-
-/* makes writing to the ibm acorn power management stuff easier -- Cort */
-/* args in forn of PA.B as in tech spec for ibm carolina */
-void ibm_write(unsigned char val,unsigned int port)
-{
+  asm ("mtctr	%2\n\t"
+       "subi	%1,%1,4\n\t"
+       "00:lwzu	%2,4(%1)\n\t"
+       "sthbrx	%2,0,%0\n\t"
+       "bdnz	00b\n\t"
+       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
+}
+
+void insl_unswapped(int port, long *ptr, int len)
+{
+        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+        /* Ensure I/O operations complete */
+        __asm__ volatile("eieio");
+        while (len-- > 0)
+        {
+                *ptr++ = (*io_ptr);
+        }
+}
+
+void outsl_unswapped(int port, long *ptr, int len)
+{
+        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+        /* Ensure I/O operations complete */
+        __asm__ volatile("eieio");
+        while (len-- > 0)
+        {
+                *io_ptr = (*ptr++);
+        }
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl
--- v2.1.47/linux/arch/ppc/kernel/ppc_asm.tmpl	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/ppc_asm.tmpl	Thu Jul 31 13:09:17 1997
@@ -2,19 +2,10 @@
  * This file contains all the macros and symbols which define
  * a PowerPC assembly language environment.
  */
-
+#include <linux/config.h>	
 #define _TEXT()\
 	.text
 
-#if 0 /* Old way */	
-#define _EXTERN(n) .##n	
-
-#define _GLOBAL(n)\
-	.globl n;\
-n:	.long	_EXTERN(n);\
-	.globl _EXTERN(n);\
-_EXTERN(n):
-#else
 #define _EXTERN(n) n	
 
 #define SYMBOL_NAME(x) x
@@ -22,7 +13,6 @@
 #define _GLOBAL(n)\
 	.globl n;\
 n:
-#endif
 
 #ifndef FALSE
 #define FALSE	0
@@ -136,9 +126,13 @@
 #define SDR1	25	/* MMU hash base register */
 #define DAR	19	/* Data Address Register */
 #define SPR0	272	/* Supervisor Private Registers */
+#define SPRG0   272
 #define SPR1	273
+#define SPRG1   273
 #define SPR2	274
+#define SPRG2   274
 #define SPR3	275
+#define SPRG3   275
 #define DSISR	18
 #define SRR0	26	/* Saved Registers (exception) */
 #define SRR1	27
@@ -164,7 +158,36 @@
 #define SR14	14
 #define SR15	15
 
+#define curptr r2
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)	stw	n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)	lwz	n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)	stfd	n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)	lfd	n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
 /* Missing instructions */
 #define bdne	bc 0,2,
 
-#include "asm/ppc_machine.h"
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/ppc_defs.h linux/arch/ppc/kernel/ppc_defs.h
--- v2.1.47/linux/arch/ppc/kernel/ppc_defs.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc_defs.h	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,63 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+#define	STATE	0
+#define	NEXT_TASK	68
+#define	COUNTER	4
+#define	BLOCKED	16
+#define	SIGNAL	12
+#define	TSS	544
+#define	KSP	0
+#define	PG_TABLES	4
+#define	LAST_SYSCALL	288
+#define	PT_REGS	280
+#define	PF_TRACESYS	32
+#define	TASK_FLAGS	20
+#define	TSS_FPR0	16
+#define	TSS_FPSCR	12
+#define	TASK_UNION_SIZE	8192
+#define	STACK_FRAME_OVERHEAD	16
+#define	INT_FRAME_SIZE	192
+#define	GPR0	16
+#define	GPR1	20
+#define	GPR2	24
+#define	GPR3	28
+#define	GPR4	32
+#define	GPR5	36
+#define	GPR6	40
+#define	GPR7	44
+#define	GPR8	48
+#define	GPR9	52
+#define	GPR10	56
+#define	GPR11	60
+#define	GPR12	64
+#define	GPR13	68
+#define	GPR14	72
+#define	GPR15	76
+#define	GPR16	80
+#define	GPR17	84
+#define	GPR18	88
+#define	GPR19	92
+#define	GPR20	96
+#define	GPR21	100
+#define	GPR22	104
+#define	GPR23	108
+#define	GPR24	112
+#define	GPR25	116
+#define	GPR26	120
+#define	GPR27	124
+#define	GPR28	128
+#define	GPR29	132
+#define	GPR30	136
+#define	GPR31	140
+#define	_NIP	144
+#define	_MSR	148
+#define	_CTR	152
+#define	_LINK	156
+#define	_CCR	160
+#define	_XER	164
+#define	_DAR	168
+#define	_DSISR	172
+#define	ORIG_GPR3	176
+#define	RESULT	180
+#define	TRAP	184
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/ppc_defs.head linux/arch/ppc/kernel/ppc_defs.head
--- v2.1.47/linux/arch/ppc/kernel/ppc_defs.head	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc_defs.head	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,3 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.1.47/linux/arch/ppc/kernel/prep_setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/prep_setup.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,368 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;	/* starting block # of image */
+#endif
+
+/* copy of the residual data */
+RESIDUAL res;
+/* ptr to residual data from hw, must be initialized so not in bss (gets cleared )*/
+unsigned long resptr = 0;
+int _machine;
+extern unsigned long _TotalMemory;
+
+#define COMMAND_LINE_SIZE 256
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+char saved_command_line[COMMAND_LINE_SIZE];
+#ifdef HASHSTATS
+unsigned long evicts;
+#endif
+
+struct screen_info screen_info = {
+	0, 25,			/* orig-x, orig-y */
+	{ 0, 0 },		/* unused */
+	0,			/* orig-video-page */
+	0,			/* orig-video-mode */
+	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 */
+};
+
+void machine_halt(void)
+{
+	machine_restart(NULL);
+}
+
+void machine_power_off(void)
+{
+	machine_restart(NULL);
+}
+
+void machine_restart(char *cmd)
+{
+	unsigned char ctl;
+	unsigned long flags;
+	unsigned long i = 10000;
+	
+	_disable_interrupts();
+
+	/* set exception prefix high - to the prom */
+	save_flags( flags );
+	restore_flags( flags|MSR_IP );
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(0x92) & ~1L , 0x92 );
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(0x92) | 1 , 0x92 );
+
+	while ( i != 0 ) i++;
+	panic("restart failed\n");
+}
+
+int
+get_cpuinfo(char *buffer)
+{
+	extern char *Motherboard_map_name;
+	int i;
+	int pvr = _get_PVR();
+	int len;
+	char *model;
+	PTE *ptr;
+	unsigned long kptes = 0, uptes = 0, overflow = 0;
+	unsigned int ti;
+  
+  
+	switch (pvr>>16)
+	{
+	case 1:
+		model = "601";
+		break;
+	case 3:
+		model = "603";
+		break;
+	case 4:
+		model = "604";
+		break;
+	case 6:
+		model = "603e";
+		break;
+	case 7:
+		model = "603ev";
+		break;
+	default:
+		model = "unknown";
+		break;
+	}
+  
+#ifdef __SMP__
+#define CD(X)		(cpu_data[n].X)  
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+  
+	len = sprintf(buffer,"processor\t: %d\n"
+		      "cpu\t\t: %s\n"
+		      "revision\t: %d.%d\n"
+		      "upgrade\t\t: %s\n"
+		      "clock\t\t: %dMHz\n"
+		      "bus clock\t: %dMHz\n"
+		      "machine\t\t: %s (sn %s)\n"
+		      "pci map\t\t: %s\n",
+		      CPUN,
+		      model,
+		      MAJOR(pvr), MINOR(pvr),
+		      (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade",
+		      (res.VitalProductData.ProcessorHz > 1024) ?
+		      res.VitalProductData.ProcessorHz>>20 :
+		      res.VitalProductData.ProcessorHz,
+		      (res.VitalProductData.ProcessorBusHz > 1024) ?
+		      res.VitalProductData.ProcessorBusHz>>20 :
+		      res.VitalProductData.ProcessorBusHz,
+		      res.VitalProductData.PrintableModel,
+		      res.VitalProductData.Serial,
+		      Motherboard_map_name
+		);
+  
+	/* print info about SIMMs */
+	len += sprintf(buffer+len,"simms\t\t: ");
+	for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
+	{
+		if ( res.Memories[i].SIMMSize != 0 )
+			len += sprintf(buffer+len,"%d:%dM ",i,
+				       (res.Memories[i].SIMMSize > 1024) ?
+				       res.Memories[i].SIMMSize>>20 :
+				       res.Memories[i].SIMMSize);
+	}
+	len += sprintf(buffer+len,"\n");
+
+	/* TLB */
+	len += sprintf(buffer+len,"tlb\t\t:");
+	switch(res.VitalProductData.TLBAttrib)
+	{
+	case CombinedTLB:
+		len += sprintf(buffer+len," %d entries\n",
+			       res.VitalProductData.TLBSize);
+		break;
+	case SplitTLB:
+		len += sprintf(buffer+len," (split I/D) %d/%d entries\n",
+			       res.VitalProductData.I_TLBSize,
+			       res.VitalProductData.D_TLBSize);
+		break;
+	case NoneTLB:
+		len += sprintf(buffer+len," not present\n");
+		break;
+	}
+
+	/* L1 */
+	len += sprintf(buffer+len,"l1\t\t: ");
+	switch(res.VitalProductData.CacheAttrib)
+	{
+	case CombinedCAC:
+		len += sprintf(buffer+len,"%dkB LineSize\n",
+			       res.VitalProductData.CacheSize,
+			       res.VitalProductData.CacheLineSize);
+		break;
+	case SplitCAC:
+		len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+			       res.VitalProductData.I_CacheSize,
+			       res.VitalProductData.D_CacheSize,
+			       res.VitalProductData.D_CacheLineSize,
+			       res.VitalProductData.D_CacheLineSize);
+		break;
+	case NoneCAC:
+		len += sprintf(buffer+len,"not present\n");
+		break;
+	}
+
+	/* L2 */
+	if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
+	{
+		int size;
+    
+		len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
+			       ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
+			       (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
+	}
+	else
+	{
+		len += sprintf(buffer+len,"l2\t\t: not present\n");
+	}
+
+
+	len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+		       CD(loops_per_sec+2500)/500000,
+		       (CD(loops_per_sec+2500)/5000) % 100);
+  
+	/*
+	 * Ooh's and aah's info about zero'd pages in idle task
+	 */ 
+	{
+		extern unsigned int zerocount, zerototal, zeropage_hits;
+		len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+			       "current: %u (%uKb) hits: %u\n",
+			       zerototal, (zerototal*PAGE_SIZE)>>10,
+			       zerocount, (zerocount*PAGE_SIZE)>>10,
+			       zeropage_hits);
+	}
+
+
+	/* ram/hash table info */
+	len += sprintf(buffer+len,"hash table\t: %dkB (%dk buckets)\n",
+		       Hash_size>>10,(Hash_size/(sizeof(PTE)*8)) >> 10);
+
+	/* if booted print info about hash table use (overflows, etc) */
+#ifdef HASHSTATS
+	for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr++)
+	{
+		if (ptr->v)
+		{
+			/* user not allowed read or write */
+			if (ptr->pp == PP_RWXX)
+				kptes++;
+			else
+				uptes++;
+			if (ptr->h == 1)
+				overflow++;
+		}
+	}
+	/*len+=sprintf(buffer+len,"Hash %x Hash+Hash_size %x MemEnd %x\n",
+	  Hash,Hash+Hash_size,KERNELBASE+_TotalMemory);*/
+	/*len += sprintf(buffer+len,"PTEs: (user/kernel/max) %d (%d%%)/%d "
+	  "(%d%%)/%d (%d%% full)\n",
+	  uptes,(uptes*100)/(Hash_size/sizeof(PTE)),
+	  kptes,(kptes*100)/(Hash_size/sizeof(PTE)),
+	  Hash_size/sizeof(PTE),
+	  ((uptes+kptes)*100)/(Hash_size/sizeof(PTE)));
+	  len += sprintf(buffer+len,"Current Ovflw PTE's: %d Total Evicts: %u\n",
+	  overflow,evicts);*/
+#endif /* HASHSTATS */
+	return len;
+}
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+	return memory_start;
+}
+
+__initfunc(void
+setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+	   unsigned long * memory_end_p))
+{
+	extern char cmd_line[];
+	extern char _etext[], _edata[], _end[];
+	unsigned char reg;
+	extern int panic_timeout;
+
+	/* Save unparsed command line copy for /proc/cmdline */
+	strcpy( saved_command_line, cmd_line );
+	*cmdline_p = cmd_line;
+  
+	*memory_start_p = (unsigned long) Hash+Hash_size;
+	(unsigned long *)*memory_end_p = (unsigned long *)(_TotalMemory+KERNELBASE);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_sec = 50000000;
+	
+	/* reboot on panic */	
+	/*panic_timeout = 180;*/
+	
+	init_task.mm->start_code = PAGE_OFFSET;
+	init_task.mm->end_code = (unsigned long) _etext;
+	init_task.mm->end_data = (unsigned long) _edata;
+	init_task.mm->brk = (unsigned long) _end;	
+	
+	aux_device_present = 0xaa;
+	
+	switch ( _machine )
+	{
+	case _MACH_IBM:
+		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+		break;
+	case _MACH_Motorola:
+		ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+		break;
+	}
+	/*ROOT_DEV = to_kdev_t(0x0811);*/ /* sdb1 */
+#if 0
+	strcpy(cmd_line+strlen(cmd_line),"console=1,9600,n8");
+#endif
+	
+#if 0  
+	if ( _machine == _MACH_Motorola )
+	{
+		/* get root via nfs from gordito -- only used for testing */
+		ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);	/* nfs */
+		/*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
+		strcpy(cmd_line+strlen(cmd_line),
+		       "nfsaddrs=129.138.6.13:129.138.6.101:129.138.6.1:255.255.255.0:"
+		       "pandora nfsroot=/usr/src/root/");
+	}
+#endif
+  
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+	ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
+	rd_prompt = 1;
+	rd_doload = 1;
+	rd_image_start = 0;
+#endif
+#endif
+	
+	request_region(0x20,0x20,"pic1");
+	request_region(0xa0,0x20,"pic2");
+	request_region(0x00,0x20,"dma1");
+	request_region(0x40,0x20,"timer");
+	request_region(0x80,0x10,"dma page reg");
+	request_region(0xc0,0x20,"dma2");
+}
+
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
--- v2.1.47/linux/arch/ppc/kernel/prep_time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/prep_time.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,315 @@
+/*
+ *  linux/arch/i386/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+static int set_rtc_mmss(unsigned long nowtime);
+unsigned long get_cmos_time(void);
+static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+				   unsigned int, unsigned int, unsigned int);
+#define TIMER_IRQ 0
+
+/* Cycle counter value at the previous timer interrupt.. */
+static unsigned long long last_timer_cc = 0;
+static unsigned long long init_timer_cc = 0;
+
+#define TICK_SIZE tick
+#define FEBRUARY	2
+#define	STARTOFTIME	1970
+#define SECDAY		86400L
+#define SECYR		(SECDAY * 365)
+#define	leapyear(year)		((year) % 4 == 0)
+#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
+#define	days_in_month(a) 	(month_days[(a) - 1])
+
+static int      month_days[12] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+	int count;
+	unsigned long offset = 0;
+
+	/* timer count may underflow right here */
+	outb_p(0x00, 0x43);	/* latch the count ASAP */
+	count = inb_p(0x40);	/* read the latched count */
+	count |= inb(0x40) << 8;
+	/* we know probability of underflow is always MUCH less than 1% */
+	if (count > (LATCH - LATCH/100)) {
+		/* check for pending timer interrupt */
+		outb_p(0x0a, 0x20);
+		if (inb(0x20) & 1)
+			offset = TICK_SIZE;
+	}
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	count = (count + LATCH/2) / LATCH;
+	return offset + count;
+}
+
+static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	*tv = xtime;
+	tv->tv_usec += do_gettimeoffset();
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+	restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	cli();
+	tv->tv_usec -= do_gettimeoffset();
+  
+	if (tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+  
+	xtime = *tv;
+	time_state = TIME_ERROR;
+	time_maxerror = 0x70000000;
+	time_esterror = 0x70000000;
+	sti();
+}
+
+void to_tm(int tim, struct rtc_time * tm)
+{
+	register int    i;
+	register long   hms, day;
+
+	day = tim / SECDAY;
+	hms = tim % SECDAY;
+
+	/* Hours, minutes, seconds are easy */
+	tm->tm_hour = hms / 3600;
+	tm->tm_min = (hms % 3600) / 60;
+	tm->tm_sec = (hms % 3600) % 60;
+
+	/* Number of years in days */
+	for (i = STARTOFTIME; day >= days_in_year(i); i++)
+		day -= days_in_year(i);
+	tm->tm_year = i;
+
+	/* Number of months in days left */
+	if (leapyear(tm->tm_year))
+		days_in_month(FEBRUARY) = 29;
+	for (i = 1; day >= days_in_month(i); i++)
+		day -= days_in_month(i);
+	days_in_month(FEBRUARY) = 28;
+	tm->tm_mon = i;
+
+	/* Days are what is left over (+1) from all that. */
+	tm->tm_mday = day + 1;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned char save_control, save_freq_select;
+	struct rtc_time tm;
+
+	to_tm(nowtime, &tm);
+
+	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+        tm.tm_year -= 1900;
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_mon);
+		BIN_TO_BCD(tm.tm_mday);
+		BIN_TO_BCD(tm.tm_year);
+	}
+	CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
+	CMOS_WRITE(tm.tm_min,RTC_MINUTES);
+	CMOS_WRITE(tm.tm_hour,RTC_HOURS);
+	CMOS_WRITE(tm.tm_mon,RTC_MONTH);
+	CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
+	CMOS_WRITE(tm.tm_year,RTC_YEAR);
+	
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+		time_state = TIME_OK;
+	return 0;
+}
+
+unsigned long get_cmos_time(void)
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int i;
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+	/* read RTC exactly on falling edge of update flag */
+	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+			break;
+	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+			break;
+	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+	} while (sec != CMOS_READ(RTC_SECONDS));
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	  {
+	    BCD_TO_BIN(sec);
+	    BCD_TO_BIN(min);
+	    BCD_TO_BIN(hour);
+	    BCD_TO_BIN(day);
+	    BCD_TO_BIN(mon);
+	    BCD_TO_BIN(year);
+	  }
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
+{
+	do_timer(regs);
+
+	/* update the hw clock if:
+	 * the time is marked out of sync (TIME_ERROR)
+	 * or ~11 minutes have expired since the last update -- Cort
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ( time_state == TIME_BAD ||
+	     xtime.tv_sec > last_rtc_update + 660 )
+	/*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 500000 - (tick >> 1) &&
+	    xtime.tv_usec < 500000 + (tick >> 1))*/
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+
+#ifdef CONFIG_HEARTBEAT
+	/* use hard disk LED as a heartbeat instead -- much more useful
+	   for debugging -- Cort */
+	switch(kstat.interrupts[0] % 101)
+	{
+	/* act like an actual heart beat -- ie thump-thump-pause... */
+	case 0:
+	case 20:
+		outb(1,IBM_HDD_LED);
+		break;
+	case 7:
+	case 27:
+		outb(0,IBM_HDD_LED);
+		break;
+	case 100:
+		break;
+	}
+#endif
+}
+
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+				   unsigned int day, unsigned int hour,
+				   unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+		(unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+		year*365 - 719499
+		)*24 + hour /* now have hours */
+		)*60 + min /* now have minutes */
+		)*60 + sec; /* finally seconds */
+}
+
+void time_init(void)
+{
+	void (*irq_handler)(int, void *,struct pt_regs *);
+	xtime.tv_sec = get_cmos_time();
+	xtime.tv_usec = 0;
+
+	/* If we have the CPU hardware time counters, use them */
+	irq_handler = timer_interrupt;
+	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.1.47/linux/arch/ppc/kernel/process.c	Tue May 13 22:41:03 1997
+++ linux/arch/ppc/kernel/process.c	Thu Jul 31 13:09:17 1997
@@ -1,13 +1,20 @@
 /*
  *  linux/arch/ppc/kernel/process.c
  *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted for PowerPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/kernel/process.c"
+ *    Copyright (C) 1995  Linus Torvalds
+ *
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) and
+ *  Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  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.
+ *
  */
 
 #include <linux/errno.h>
@@ -22,173 +29,449 @@
 #include <linux/malloc.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
+#include <linux/config.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/smp_lock.h>
+
+int dump_fpu(void);
+void switch_to(struct task_struct *, struct task_struct *);
+void print_backtrace(unsigned long *);
+void show_regs(struct pt_regs * regs);
+void inline zero_paged(void);
+extern unsigned long _get_SP(void);
 
-#include <asm/ppc_machine.h>
+#undef SHOW_TASK_SWITCHES 1
+#undef CHECK_STACK 1
+#undef IDLE_ZERO 1
 
-/*
- * Initial task structure. Make this a per-architecture thing,
- * because different architectures tend to have different
- * alignment requirements and potentially different initial
- * setup.
- */
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+unsigned long
+kernel_stack_top(struct task_struct *tsk)
+{
+	return ((unsigned long)tsk) + sizeof(union task_union);
+}
+
+unsigned long
+task_top(struct task_struct *tsk)
+{
+	return ((unsigned long)tsk) + sizeof(struct task_struct);
+}
+	
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 
 struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
-
-
-int dump_fpu(void);
-void hard_reset_now(void);
-void switch_to(struct task_struct *, struct task_struct *);
-void copy_thread(int,unsigned long,unsigned long,struct task_struct *,
-		 struct pt_regs *);
-void print_backtrace(unsigned long *);
+union task_union init_task_union = { INIT_TASK };
 
 int
 dump_fpu(void)
 {
-  return (1);
+	return (1);
 }
 
-
 /* check to make sure the kernel stack is healthy */
 int check_stack(struct task_struct *tsk)
 {
-  extern unsigned long init_kernel_stack[PAGE_SIZE/sizeof(long)];
-  int ret = 0;
-  int i;
-  
-  /* skip check in init_kernel_task -- swapper */
-  if ( tsk->kernel_stack_page == (unsigned long)&init_kernel_stack )
-    return;
-  /* check bounds on stack -- above/below kstack page */
-  if ( (tsk->tss.ksp-1 & KERNEL_STACK_MASK) != tsk->kernel_stack_page )
-  {
-    printk("check_stack(): not in bounds %s/%d ksp %x/%x\n",
-	   tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page);
-    ret |= 1;
-  }
-
-  /* check for magic on kstack */
-  if ( *(unsigned long *)(tsk->kernel_stack_page) != STACK_MAGIC)
-  {
-    printk("check_stack(): no magic %s/%d ksp %x/%x magic %x\n",
-	   tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
-	   *(unsigned long *)(tsk->kernel_stack_page));
-    ret |= 2;
-  }
-
-#ifdef KERNEL_STACK_BUFFER
-  /* check extra padding page under kernel stack */
-  for ( i = PAGE_SIZE/sizeof(long) ; i >= 1; i--)
-  {
-    struct pt_regs *regs;
-    
-    if ( *((unsigned long *)(tsk->kernel_stack_page)-1) )
-    {
-      printk("check_stack(): padding touched %s/%d ksp %x/%x value %x/%d\n",
-	     tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
-	     *(unsigned long *)(tsk->kernel_stack_page-i),i*sizeof(long));
-      regs = (struct pt_regs *)(tsk->kernel_stack_page-(i*sizeof(long)));
-      printk("marker %x trap %x\n", regs->marker,regs->trap);
-      print_backtrace((unsigned long *)(tsk->tss.ksp));
-      
-      ret |= 4;
-      break;
-    }
-  }
+	unsigned long stack_top = kernel_stack_top(tsk);
+	unsigned long tsk_top = task_top(tsk);
+	int ret = 0;
+	unsigned long *i;
+
+#if 0	
+	/* check tss magic */
+	if ( tsk->tss.magic != TSS_MAGIC )
+	{
+		ret |= 1;
+		printk("tss.magic bad: %08x\n", tsk->tss.magic);
+	}
 #endif
-  
-#if 0
-  if (ret)
-    panic("bad stack");
+	
+	if ( !tsk )
+		printk("check_stack(): tsk bad tsk %p\n",tsk);
+	
+	/* check if stored ksp is bad */
+	if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
+	{
+		printk("stack out of bounds: %s/%d\n"
+		       " tsk_top %08x ksp %08x stack_top %08x\n",
+		       tsk->comm,tsk->pid,
+		       tsk_top, tsk->tss.ksp, stack_top);
+		ret |= 2;
+	}
+	
+	/* check if stack ptr RIGHT NOW is bad */
+	if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
+	{
+		printk("current stack ptr out of bounds: %s/%d\n"
+		       " tsk_top %08x sp %08x stack_top %08x\n",
+		       current->comm,current->pid,
+		       tsk_top, _get_SP(), stack_top);
+		ret |= 4;
+	}
+
+#if 0	
+	/* check amount of free stack */
+	for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ )
+	{
+		if ( !i )
+			printk("check_stack(): i = %p\n", i);
+		if ( *i != 0 )
+		{
+			/* only notify if it's less than 900 bytes */
+			if ( (i - (unsigned long *)task_top(tsk))  < 900 )
+				printk("%d bytes free on stack\n",
+				       i - task_top(tsk));
+			break;
+		}
+	}
 #endif
-  return(ret);
-}
 
+	if (ret)
+	{
+		panic("bad kernel stack");
+	}
+	return(ret);
+}
 
 void
 switch_to(struct task_struct *prev, struct task_struct *new)
 {
-	struct pt_regs *regs;
 	struct thread_struct *new_tss, *old_tss;
 	int s = _disable_interrupts();
-	regs = (struct pt_regs *)(new->tss.ksp);
-#if 1
+	struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
+
+#if CHECK_STACK
 	check_stack(prev);
 	check_stack(new);
 #endif
- 	/* if a process has used fp 15 times, then turn
-	   on the fpu for good otherwise turn it on with the fp
-	   exception handler as needed.
-	   skip this for kernel tasks.
-	            -- Cort */
-	if ( (regs->msr & MSR_FP)&&(regs->msr & MSR_PR)&&(new->tss.fp_used < 15) )
-	{
-#if 0
-	  printk("turning off fpu: %s/%d fp_used %d\n",
-		 new->comm,new->pid,new->tss.fp_used);
-#endif
-	  regs->msr = regs->msr & ~MSR_FP;
-	}
-#if 0
-	printk("%s/%d -> %s/%d\n",prev->comm,prev->pid,new->comm,new->pid);
+        /* turn off fpu for task last to run */
+	/*prev->tss.regs->msr &= ~MSR_FP;*/
+	
+#ifdef SHOW_TASK_SWITCHES
+	printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
+	       prev->comm,prev->pid,prev->tss.regs->nip,
+	       new->comm,new->pid,new->tss.regs->nip,new->mm->context);
 #endif
 	new_tss = &new->tss;
 	old_tss = &current->tss;
-	current_set[0] = new;
-	_switch(old_tss, new_tss);
+	_switch(old_tss, new_tss, new->mm->context);
+        /* turn off fpu for task last to run */	
 	_enable_interrupts(s);
 }
+	
+#include <linux/mc146818rtc.h>
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
+{
+#if 1
+	struct task_struct *p;
+	printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
+	printk("last %x\n", last_task_used_math);
+	printk("cur %x regs %x/%x tss %x/%x\n",
+	       current, current->tss.regs,regs,&current->tss,current->tss);
+	for_each_task(p)
+	{
+		if ((long)p < KERNELBASE)
+		{
+			printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
+			print_mm_info();
+			__cli();
+			while(1);
+		}
+	}
+	return regs->gpr[3];
+#endif
+#if 0
+	/* set the time in the cmos clock */
+	unsigned long hwtime, nowtime;
+	struct rtc_time tm;
+	
+	hwtime = get_cmos_time();
+	to_tm(hwtime, &tm);
+	printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n", 
+	       tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
+	       tm.tm_mday, tm.tm_year);
+	return;
+#endif
+}
 
-asmlinkage int sys_debug(unsigned long r3)
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0;	/* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0;	/* pointer into the currently being zero'd page */
+unsigned long zerocount = 0;	/* # currently pre-zero'd pages */
+unsigned long zerototal = 0;	/* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0;	/* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
 {
-	lock_kernel();
-	if (!strcmp(current->comm,"crashme"))
-		printk("sys_debug(): r3 (syscall) %d\n", r3);
-	unlock_kernel();
+	unsigned long page;
+	unsigned long s;
+
+	if ( zero_list )
+	{
+		/* atomically remove this page from the list */
+		asm (	"101:lwarx  %1,0,%2\n"  /* reserve zero_list */
+			"    lwz    %0,0(%1)\n" /* get next -- new zero_list */
+			"    stwcx. %0,0,%2\n"  /* update zero_list */
+			"    bne-   101b\n"     /* if lost reservation try again */
+			: "=&r" (zero_list), "=&r" (page)
+			: "r" (&zero_list)
+			: "cc" );
+		/* we can update zerocount after the fact since it is not
+		 * used for anything but control of a loop which doesn't
+		 * matter since it won't effect anything if it zero's one
+		 * less page -- Cort
+		 */
+		atomic_inc((atomic_t *)&zeropage_hits);
+		atomic_dec((atomic_t *)&zerocount);
+		/* zero out the pointer to next in the page */
+		*(unsigned long *)page = 0;
+		return page;
+	}
 	return 0;
 }
 
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+void inline zero_paged(void)
+{
+	extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+	unsigned long tmp;
+	pte_t ptep;
+	pgd_t *dir;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	sprintf(current->comm, "zero_paged");
+	printk("Started zero_paged\n");
+	/* want priority over idle task and powerd */
+	current->priority = -98;
+	current->counter = -98;
+	__sti();
+	
+	while ( zerocount < 128 )
+	{
+		/*
+		 * Mark a page as reserved so we can mess with it
+		 * If we're interrupted we keep this page and our place in it
+		 * since we validly hold it and it's reserved for us.
+		 */
+		pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+		if ( !pageptr )
+		{
+			printk("!pageptr in zero_paged\n");
+			goto retry;
+		}
+		
+		if ( need_resched )
+			schedule();
+		
+		/*
+		 * Make the page no cache so we don't blow our cache with 0's
+		 */
+		dir = pgd_offset( init_task.mm, pageptr );
+		if (dir)
+		{
+			pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+			if (pmd && pmd_present(*pmd))
+			{
+				pte = pte_offset(pmd, pageptr & PAGE_MASK);
+				if (pte && pte_present(*pte))
+				{			
+					pte_uncache(*pte);
+					flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+				}
+			}
+		}
+	
+		/*
+		 * Important here to not take time away from real processes.
+		 */
+		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+		{
+			if ( need_resched )
+				schedule();
+			*(unsigned long *)(bytecount + pageptr) = 0;
+		}
+		
+		/*
+		 * If we finished zero-ing out a page add this page to
+		 * the zero_list atomically -- we can't use
+		 * down/up since we can't sleep in idle.
+		 * Disabling interrupts is also a bad idea since we would
+		 * steal time away from real processes.
+		 * We can also have several zero_paged's running
+		 * on different processors so we can't interfere with them.
+		 * So we update the list atomically without locking it.
+		 * -- Cort
+		 */
+		/* turn cache on for this page */
+		pte_cache(*pte);
+		flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+		
+		/* atomically add this page to the list */
+		asm (	"101:lwarx  %0,0,%1\n"  /* reserve zero_list */
+			"    stw    %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+			"    sync\n"            /* let store settle */
+#endif			
+			"    mr     %0,%2\n"    /* update zero_list in reg */
+			"    stwcx. %2,0,%1\n"  /* update zero_list in mem */
+			"    bne-   101b\n"     /* if lost reservation try again */
+			: "=&r" (zero_list)
+			: "r" (&zero_list), "r" (pageptr)
+			: "cc" );
+		/*
+		 * This variable is used in the above loop and nowhere
+		 * else so the worst that could happen is we would
+		 * zero out one more or one less page than we want
+		 * per processor on the machine.  This is because
+		 * we could add our page to the list but not have
+		 * zerocount updated yet when another processor
+		 * reads it.  -- Cort
+		 */
+		atomic_inc((atomic_t *)&zerocount);
+		atomic_inc((atomic_t *)&zerototal);
+retry:	
+		schedule();
+	}
+}
+
+void powerd(void)
+{
+	unsigned long msr, hid0;
+
+	sprintf(current->comm, "powerd");
+	__sti();
+	while (1)
+	{
+		/* want priority over idle task 'swapper' -- Cort */
+		current->priority = -99;
+		current->counter = -99;
+		asm volatile(
+			/* clear powersaving modes and set nap mode */
+			"mfspr %3,1008 \n\t"
+			"andc  %3,%3,%4 \n\t"
+			"or    %3,%3,%5 \n\t"
+			"mtspr 1008,%3 \n\t"
+			/* enter the mode */
+			"mfmsr %0 \n\t"
+			"oris  %0,%0,%2 \n\t"
+			"sync \n\t"
+			"mtmsr %0 \n\t"
+			"isync \n\t"
+			: "=&r" (msr)
+			: "0" (msr), "i" (MSR_POW>>16),
+			"r" (hid0),
+			"r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+			"r" (HID0_NAP));
+		if ( need_resched )
+			schedule();
+		/*
+		 * The ibm carolina spec says that the eagle memory
+		 * controller will detect the need for a snoop
+		 * and wake up the processor so we don't need to
+		 * check for cache operations that need to be
+		 * snooped.  The ppc book says the run signal
+		 * must be asserted while napping for this though.
+		 * -- Cort
+		 */
+	}
+}
+	
 asmlinkage int sys_idle(void)
 {
 	int ret = -EPERM;
-
-	lock_kernel();
 	if (current->pid != 0)
 		goto out;
 
-	/* endless idle loop with no priority at all */
+#ifdef IDLE_ZERO
+	/*
+	 * want one per cpu since it would be nice to have all
+	 * processors who aren't doing anything
+	 * zero-ing pages since this daemon is lock-free
+	 * -- Cort
+	 */
+	kernel_thread(zero_paged, NULL, 0);
+#endif /* IDLE_ZERO */
+
+#ifdef CONFIG_POWERSAVING
+	/* no powersaving modes on 601 - one per processor */
+	if(  (_get_PVR()>>16) != 1 )
+		kernel_thread(powerd, NULL, 0);
+#endif /* CONFIG_POWERSAVING */
+	
+	/* endless loop with no priority at all */
+	current->priority = -100;
 	current->counter = -100;
-	for (;;) {
+	for (;;) 
+	{
 		schedule();
 	}
 	ret = 0;
 out:
-	unlock_kernel();
 	return ret;
 }
 
 void show_regs(struct pt_regs * regs)
 {
+	int i;
+
+	printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+	       regs->nip, regs->xer, regs->link, regs,regs->trap);
+	printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+	       regs->msr&MSR_IR ? 1 : 0,
+	       regs->msr&MSR_DR ? 1 : 0);
+	printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+	       current, current->pid, current->comm, current->mm->pgd);
+	printk("Last syscall: %d ", current->tss.last_syscall);
+	printk("\nlast math %08X\n", last_task_used_math);
+	for (i = 0;  i < 32;  i++)
+	{
+		long r;
+		if ((i % 8) == 0)
+		{
+			printk("GPR%02d: ", i);
+		}
+
+		if ( get_user(r, &(regs->gpr[i])) )
+		    goto out;
+		printk("%08X ", r);
+		if ((i % 8) == 7)
+		{
+			printk("\n");
+		}
+	}
+out:
 }
 
 void exit_thread(void)
 {
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
 }
 
 void flush_thread(void)
 {
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
 }
 
 void
@@ -197,50 +480,25 @@
 }
 
 /*
- * Copy a thread..
- */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
-	struct task_struct * p, struct pt_regs * regs)
+  * Copy a thread..
+  */
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+	    struct task_struct * p, struct pt_regs * regs)
 {
 	int i;
-	SEGREG *segs;
 	struct pt_regs * childregs;
-	
-	/* Construct segment registers */
-	segs = (SEGREG *)(p->tss.segs);
-	for (i = 0;  i < 8;  i++)
-	{
-		segs[i].ks = 0;
-		segs[i].kp = 1;
-#if 0
-		segs[i].vsid = i | (nr << 4);
-#else
-		segs[i].vsid = i | ((nr * 10000) << 4);		
-#endif
-	}
-	if ((p->mm->context == 0) || (p->mm->count == 1))
-	{
-#if 0
-	  p->mm->context = ((nr)<<4);
-#else	  
-	  p->mm->context = ((nr*10000)<<4);	  
-#endif
-	}
-	
-	/* Last 8 are shared with kernel & everybody else... */
-	for (i = 8;  i < 16;  i++)
-	{
-		segs[i].ks = 0;
-		segs[i].kp = 1;
-		segs[i].vsid = i;
-	}
-	
 	/* Copy registers */
-	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 2;
+	childregs = ((struct pt_regs *)
+		     ((unsigned long)p + sizeof(union task_union)
+		      - STACK_FRAME_OVERHEAD)) - 2;
+	*childregs = *regs;
 
-	*childregs = *regs;	/* STRUCT COPY */
+	if ((childregs->msr & MSR_PR) == 0)
+		childregs->gpr[2] = (unsigned long) p;	/* `current' in new task */
 	childregs->gpr[3] = 0;  /* Result from fork() */
-	p->tss.ksp = (unsigned long)(childregs);
+	p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
+	p->tss.regs = (struct pt_regs *)(childregs);
 	if (usp >= (unsigned long)regs)
 	{ /* Stack is in kernel space - must adjust */
 		childregs->gpr[1] = (long)(childregs+1);
@@ -248,23 +506,29 @@
 	{ /* Provided stack is in user space */
 		childregs->gpr[1] = usp;
 	}
-	p->tss.fp_used = 0;
 
-	return 0;
-}
+	p->tss.last_syscall = -1;
 
-/*
- * fill in the user structure for a core dump..
- */
-void dump_thread(struct pt_regs * regs, struct user * dump)
-{
+	/*
+	 * copy fpu info - assume lazy fpu switch now always
+	 * this should really be conditional on whether or
+	 * not the process has used the fpu
+	 *  -- Cort
+	 */
+	if ( last_task_used_math == current )
+		giveup_fpu();
+	
+	memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
+	p->tss.fpscr = current->tss.fpscr;
+	childregs->msr &= ~MSR_FP;
+	
+	return 0;
 }
 
-
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+			struct pt_regs *regs)
 {
 	int ret;
-
 	lock_kernel();
 	ret = do_fork(SIGCHLD, regs->gpr[1], regs);
 	unlock_kernel();
@@ -272,46 +536,21 @@
 }
 
 asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
-	unsigned long a3, unsigned long a4, unsigned long a5,
-	struct pt_regs *regs)
+			  unsigned long a3, unsigned long a4, unsigned long a5,
+			  struct pt_regs *regs)
 {
 	int error;
 	char * filename;
-
-	lock_kernel();
-	/* getname does it's own verification of the address
-	   when it calls get_max_filename() but
-	   it will assume it's valid if get_fs() == KERNEL_DS
-	   which is always true on the ppc so we check
-	   it here
-	   
-	   this doesn't completely check any of these data structures,
-	   it just makes sure that the 1st long is in a good area
-	   and from there we assume that it's safe then
-	   -- Cort
-	   */
-	/* works now since get_fs/set_fs work properly */
-#if 0
-	if ( verify_area(VERIFY_READ,(void *)a0,1)
-	     && verify_area(VERIFY_READ,(void *)a1,1)
-	     && verify_area(VERIFY_READ,(void *)a2,1)
-	     )
-	{
-	  return -EFAULT;
-	}
-#endif
-	error = getname((char *) a0, &filename);
-	if (error)
+	filename = (int) getname((char *) a0);
+	error = PTR_ERR(filename);
+	if(IS_ERR(filename))
 		goto out;
-	flush_instruction_cache();
+	if ( last_task_used_math == current )
+		last_task_used_math = NULL;
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
-#if 0
-if (error)
-{	
-printk("EXECVE - file = '%s', error = %d\n", filename, error);
-}
-#endif
+
 	putname(filename);
+
 out:
 	unlock_kernel();
 	return error;
@@ -321,7 +560,7 @@
 {
 	unsigned long clone_flags = p1;
 	int res;
-
+	
 	lock_kernel();
 	res = do_fork(clone_flags, regs->gpr[1], regs);
 	unlock_kernel();
@@ -331,13 +570,17 @@
 void
 print_backtrace(unsigned long *sp)
 {
-#if 0
 	int cnt = 0;
-	printk("... Call backtrace:\n");
-	while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
+	int i;
+	printk("Call backtrace: ");
+	while ( !get_user(i, sp) && i)
 	{
-		printk("%08X ", sp[1]);
-		sp = (unsigned long *)*sp;
+		if ( get_user( i, &sp[1] ) )
+			return;
+		printk("%08X ", i);
+		if ( get_user( (ulong)sp, sp) )
+		    return;
+		if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
 		if (++cnt == 8)
 		{
 			printk("\n");
@@ -345,43 +588,66 @@
 		if (cnt > 32) break;
 	}
 	printk("\n");
-#endif
-}
-
-void
-print_user_backtrace(unsigned long *sp)
-{
-#if 0
-	int cnt = 0;
-	printk("... [User] Call backtrace:\n");
-	while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
-	{
-		printk("%08X ", sp[1]);
-		sp = (unsigned long *)*sp;
-		if (++cnt == 8)
-		{
-			printk("\n");
-		}
-		if (cnt > 16) break;
-	}
-	printk("\n");
-#endif
 }
 
-void
-print_kernel_backtrace(void)
-{
-#if 0
-	unsigned long *_get_SP(void);
-	print_backtrace(_get_SP());
-#endif
-}
 inline void start_thread(struct pt_regs * regs,
                          unsigned long eip, unsigned long esp)
 {
+	set_fs(USER_DS);
 	regs->nip = eip;
 	regs->gpr[1] = esp;
 	regs->msr = MSR_USER;
-	set_fs(USER_DS);
 }
 
+/*
+ * Low level print for debugging - Cort
+ */
+int ll_printk(const char *fmt, ...)
+{
+        va_list args;
+	char buf[256];
+        int i;
+
+        va_start(args, fmt);
+        i=sprintf(buf,fmt,args);
+	ll_puts(buf);
+        va_end(args);
+        return i;
+}
+
+char *vidmem = (char *)0xC00B8000;
+int lines = 24, cols = 80;
+int orig_x = 0, orig_y = 0;
+
+void ll_puts(const char *s)
+{
+	int x,y;
+	char c;
+
+	x = orig_x;
+	y = orig_y;
+
+	while ( ( c = *s++ ) != '\0' ) {
+		if ( c == '\n' ) {
+			x = 0;
+			if ( ++y >= lines ) {
+				/*scroll();*/
+				/*y--;*/
+				y = 0;
+			}
+		} else {
+			vidmem [ ( x + cols * y ) * 2 ] = c; 
+			if ( ++x >= cols ) {
+				x = 0;
+				if ( ++y >= lines ) {
+					/*scroll();*/
+					/*y--;*/
+					y = 0;
+				}
+			}
+		}
+	}
+
+	orig_x = x;
+	orig_y = y;
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.1.47/linux/arch/ppc/kernel/ptrace.c	Tue May 13 22:41:03 1997
+++ linux/arch/ppc/kernel/ptrace.c	Thu Jul 31 13:09:17 1997
@@ -1,12 +1,14 @@
 /*
  *  linux/arch/ppc/kernel/ptrace.c
  *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/m68k/kernel/ptrace.c"
  *  Copyright (C) 1994 by Hamish Macdonald
  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  *
- * Adapted from 'linux/arch/m68k/kernel/ptrace.c'
- * PowerPC version by Gary Thomas (gdt@linuxppc.org)
  * Modified by Cort Dougan (cort@cs.nmt.edu) 
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -34,52 +36,13 @@
  * in exit.c or in signal.c.
  */
 
-/* Find the stack offset for a register, relative to tss.ksp. */
-#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static int regoff[] = {
-};
-
 /*
  * Get contents of register REGNO in task TASK.
  */
 static inline long get_reg(struct task_struct *task, int regno)
 {
-	struct pt_regs *regs = task->tss.regs;
-	if (regno <= PT_R31)
-	{
-		return (regs->gpr[regno]);
-	} else
-	if (regno == PT_NIP)
-	{
-		return (regs->nip);
-	} else
-	if (regno == PT_MSR)
-	{
-		return (regs->msr);
-	} else
-	if (regno == PT_ORIG_R3)
-	{
-		return (regs->orig_gpr3);
-	} else
-	if (regno == PT_CTR)
-	{
-		return (regs->ctr);
-	} else
-	if (regno == PT_LNK)
-	{
-		return (regs->link);
-	} else
-	if (regno == PT_XER)
-	{
-		return (regs->xer);
-	} else
-	if (regno == PT_CCR)
-	{
-		return (regs->ccr);
-	}
+	if (regno <= PT_CCR)
+		return ((unsigned long *)task->tss.regs)[regno];
 	return (0);
 }
 
@@ -89,52 +52,21 @@
 static inline int put_reg(struct task_struct *task, int regno,
 			  unsigned long data)
 {
-	struct pt_regs *regs = task->tss.regs;
-	if (regno <= PT_R31)
-	{
-		regs->gpr[regno] = data;
-	} else
-	if (regno == PT_NIP)
-	{
-		regs->nip = data;
-	} else
-	if (regno == PT_MSR)
-	{
-		regs->msr = data;
-	} else
-	if (regno == PT_CTR)
-	{
-		regs->ctr = data;
-	} else
-	if (regno == PT_LNK)
-	{
-		regs->link = data;
-	} else
-	if (regno == PT_XER)
-	{
-		regs->xer = data;
-	} else
-	if (regno == PT_CCR)
-	{
-		regs->ccr = data;
-	} else
-	{ /* Invalid register */
-		return (-1);
+	if (regno <= PT_CCR) {
+		((unsigned long *)task->tss.regs)[regno] = data;
+		return 0;
 	}
-	return (0);
+	return -1;
 }
 
-static inline
+static inline void
 set_single_step(struct task_struct *task)
 {
 	struct pt_regs *regs = task->tss.regs;
-printk("Set single step - Task: %x, Regs: %x", task, regs);
-printk(", MSR: %x/", regs->msr);	
 	regs->msr |= MSR_SE;
-printk("%x\n", regs->msr);	
 }
 
-static inline
+static inline void
 clear_single_step(struct task_struct *task)
 {
 	struct pt_regs *regs = task->tss.regs;
@@ -159,33 +91,32 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
 		pgd_clear(pgdir);
 		return 0;
 	}
 	pgmiddle = pmd_offset(pgdir,addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page directory %08lx\n",
-		       pmd_val(*pgmiddle));
+		printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
 		pmd_clear(pgmiddle);
 		return 0;
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 0);
+		handle_mm_fault(tsk, vma, addr, 0);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (page >= high_memory)
+	if (MAP_NR(page) >= max_mapnr)
 		return 0;
 	page += addr & ~PAGE_MASK;
 	return *(unsigned long *) page;
@@ -200,8 +131,8 @@
  * Now keeps R/W state of page so that a text page stays readonly
  * even if a debugger scribbles breakpoints into it.  -M.U-
  */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
-	unsigned long data)
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+		     unsigned long addr, unsigned long data)
 {
 	pgd_t *pgdir;
 	pmd_t *pgmiddle;
@@ -211,42 +142,40 @@
 repeat:
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (!pgd_present(*pgdir)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
 		pgd_clear(pgdir);
 		return;
 	}
 	pgmiddle = pmd_offset(pgdir,addr);
 	if (pmd_none(*pgmiddle)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page directory %08lx\n",
-		       pmd_val(*pgmiddle));
+		printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
 		pmd_clear(pgmiddle);
 		return;
 	}
 	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
-		do_no_page(tsk, vma, addr, 1);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 	page = pte_page(*pgtable);
 	if (!pte_write(*pgtable)) {
-		do_wp_page(tsk, vma, addr, 2);
+		handle_mm_fault(tsk, vma, addr, 1);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (page < high_memory) {
+	if (MAP_NR(page) < max_mapnr)
 		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
-	}
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
-	*pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	flush_tlb_all();
 }
 
@@ -366,7 +295,6 @@
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
-	struct user * dummy = NULL;
 	int ret = -EPERM;
 
 	lock_kernel();
@@ -436,8 +364,10 @@
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
 			
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				return -EIO;
+			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+				ret = -EIO;
+				goto out;
+			}
 			
 			ret = verify_area(VERIFY_WRITE, (void *) data,
 					  sizeof(long));
@@ -445,15 +375,19 @@
 				goto out;
 			tmp = 0;  /* Default return condition */
 			addr = addr >> 2; /* temporary hack. */
-			if (addr < PT_FPR0)
+			if (addr < PT_FPR0) {
 				tmp = get_reg(child, addr);
-#if 0			
-			else if (addr >= PT_FPR0 && addr < PT_FPR31)
-				tmp = child->tss.fpr[addr - PT_FPR0];
-#endif				
+			}
+#if 1
+			else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+				if (last_task_used_math == child)
+					giveup_fpu();
+				tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
+			}
+#endif
 			else
 				ret = -EIO;
-			if(!ret)
+			if (!ret)
 				put_user(tmp,(unsigned long *) data);
 			goto out;
 		}
@@ -486,13 +420,13 @@
 				ret = 0;
 				goto out;
 			}
-#if 0			
-			if (addr >= 21 && addr < 48) {
-				child->tss.fp[addr - 21] = data;
+			if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+				if (last_task_used_math == child)
+					giveup_fpu();
+				((long *)child->tss.fpr)[addr - PT_FPR0] = data;
 				ret = 0;
 				goto out;
 			}
-#endif			
 			goto out;
 
 		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.1.47/linux/arch/ppc/kernel/setup.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/setup.c	Wed Dec 31 16:00:00 1969
@@ -1,409 +0,0 @@
-/*
- *  linux/arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-
-extern unsigned long *end_of_DRAM;
-extern PTE *Hash;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-unsigned long empty_zero_page[1024];
-
-unsigned char aux_device_present;
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;	/* starting block # of image */
-#endif
-
-#undef HASHSTATS
-
-extern unsigned long isBeBox[];
-
-/* copy of the residual data */
-RESIDUAL res;
-unsigned long resptr = 0; /* ptr to residual data from hw */
-
-/*
- * 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.
- */
- /* this is changed only in minor ways from the original
-        -- Cort
- */
-struct screen_info screen_info = {
-  0, 25,			/* orig-x, orig-y */
-  { 0, 0 },		/* unused */
-  0,			/* orig-video-page */
-  0,			/* orig-video-mode */
-  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 */
-};
-
-
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-  return memory_start;
-}
-
-#ifdef HASHSTATS
-unsigned long *hashhits;
-#endif
-
-extern unsigned long _TotalMemory;
-/* find the physical size of RAM and setup hardware hash table */
-unsigned long *find_end_of_memory(void)
-{
-  extern BAT BAT2;
-  _TotalMemory = res.TotalMemory;
-  
-  if (_TotalMemory == 0 )
-  {
-    printk("Ramsize from residual data was 0 -- Probing for value\n");
-    /* this needs be done differently since the bats actually map
-       addresses beyond physical memory! -- Cort */
-#if 0
-    probingmem = 1;
-    while ( probingmem )
-    {
-	_TotalMemory += 0x00800000; /* 8M */
-	*(unsigned long *)_TotalMemory+KERNELBASE;
-    }
-    _TotalMemory -= 0x00800000;
-#else    
-    _TotalMemory = 0x03000000;
-#endif
-    printk("Ramsize probed to be %dM\n", _TotalMemory>>20);
-  }
-  
-  /* setup BAT2 mapping so that it covers kernelbase to kernelbase+ramsize */
-  switch(_TotalMemory)
-  {
-    case 0x01000000:		/* 16M */
-      BAT2.batu.bl = BL_16M;
-      Hash_size = HASH_TABLE_SIZE_128K;
-      Hash_mask = HASH_TABLE_MASK_128K;
-      break;
-    case 0x00800000:		/* 8M */
-      BAT2.batu.bl = BL_8M;
-      Hash_size = HASH_TABLE_SIZE_64K;
-      Hash_mask = HASH_TABLE_MASK_64K;
-      break;
-    case 0x01800000:		/* 24M */
-    case 0x02000000:		/* 32M */
-      BAT2.batu.bl = BL_32M;
-      Hash_size = HASH_TABLE_SIZE_256K;
-      Hash_mask = HASH_TABLE_MASK_256K;
-      break;
-    case 0x03000000:		/* 48M */
-    case 0x04000000:		/* 64M */
-      BAT2.batu.bl = BL_64M;
-      Hash_size = HASH_TABLE_SIZE_512K;
-      Hash_mask = HASH_TABLE_MASK_512K;
-      break;
-    case 0x05000000:		/* 80M */
-      BAT2.batu.bl = BL_128M;
-      Hash_size = HASH_TABLE_SIZE_1M;
-      Hash_mask = HASH_TABLE_MASK_1M;
-      break;    
-    default:
-      printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n",
-	     _TotalMemory);
-      break;
-  }
-  
-  Hash = (PTE *)((_TotalMemory-Hash_size)+KERNELBASE);
-  bzero(Hash, Hash_size);
-  
- 
-#ifdef HASHSTATS
-  hashhits = (unsigned long *)Hash - (Hash_size/sizeof(struct _PTE))/2;
-  bzero(hashhits, (Hash_size/sizeof(struct _PTE))/2);
-  return ((unsigned long *)hashhits);
-#else
-  return ((unsigned long *)Hash);
-#endif
-}
-
-int size_memory;
-
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#ifdef CONFIG_APM
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
-#endif
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
-
-#define RAMDISK_IMAGE_START_MASK  	0x07FF
-#define RAMDISK_PROMPT_FLAG		0x8000
-#define RAMDISK_LOAD_FLAG		0x4000	
-
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
-
-
-void
-setup_arch(char **cmdline_p, unsigned long * memory_start_p,
-	   unsigned long * memory_end_p)
-{
-  extern int _end;
-  extern char cmd_line[];
-  unsigned char reg;
-  extern int panic_timeout;
-  char inf[512];
-  int i;
-
-  if (isBeBox[0])
-    _Processor = _PROC_Be;
-  else
-  {
-    if (strncmp(res.VitalProductData.PrintableModel,"IBM",3))
-    {
-      _Processor = _PROC_Motorola;
-    }
-    else
-      _Processor = _PROC_IBM;
-  }
-  
-  get_cpuinfo(&inf);
-  printk("%s",inf);
-  
-  /* Set up floppy in PS/2 mode */
-  outb(0x09, SIO_CONFIG_RA);
-  reg = inb(SIO_CONFIG_RD);
-  reg = (reg & 0x3F) | 0x40;
-  outb(reg, SIO_CONFIG_RD);
-  outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
-
-  switch ( _Processor )
-  {
-    case _PROC_IBM:
-        ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
-	break;
-    case _PROC_Motorola:
-        ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
-        break;
-  }
-  aux_device_present = 0xaa;
-
-  panic_timeout = 300;		/* reboot on panic */
-  
-#if 0
-  /* get root via nfs from charon -- was only used for testing */
-  ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);	/* nfs */
-  /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
-  strcpy(cmd_line,
-	 "nfsaddrs=129.138.6.101:129.138.6.90:129.138.6.1:255.255.255.0:gordito nfsroot=/joplin/ppc/root/");
-#endif
-  *cmdline_p = cmd_line;
-  *memory_start_p = (unsigned long) &_end;
-  (unsigned long *)*memory_end_p = (unsigned long *)end_of_DRAM;
-  size_memory = *memory_end_p - KERNELBASE;  /* Relative size of memory */
-
-#ifdef CONFIG_BLK_DEV_RAM
-  rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-  rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-  rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#if 1
-  rd_prompt = 1;
-  rd_doload = 1;
-  rd_image_start = 0;
-#endif
-#endif
-
-  /* Save unparsed command line copy for /proc/cmdline */
-  memcpy(saved_command_line, cmd_line,strlen(cmd_line)+1);
-  printk("Command line: %s\n", cmd_line);
-}
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-  return -EIO;
-}
-
-
-int
-get_cpuinfo(char *buffer)
-{
-  extern unsigned long loops_per_sec;
-  int i;
-  int pvr = _get_PVR();
-  int len;
-  char *model;
-  unsigned long full = 0, overflow = 0;
-  unsigned int ti;
-  PTE *ptr;  
-  
-  switch (pvr>>16)
-    {
-    case 3:
-      model = "603";
-      break;
-    case 4:
-      model = "604";
-      break;
-    case 6:
-      model = "603e";
-      break;
-    case 7:
-      model = "603ev";
-      break;
-    default:
-      model = "unknown";
-      break;
-    }
-  
-#ifdef __SMP__
-#define CD(X)		(cpu_data[n].X)  
-#else
-#define CD(X) (X)
-#define CPUN 0
-#endif
-  
-  len = sprintf(buffer, "PowerPC %s/%dMHz revision %d.%d %s\n",
-		model,
-		(res.VitalProductData.ProcessorHz > 1024) ?
-		res.VitalProductData.ProcessorHz>>20 :
-		res.VitalProductData.ProcessorHz,
-		MAJOR(pvr), MINOR(pvr),
-		(inb(IBM_EQUIP_PRESENT) & 2) ? "" : "upgrade");
-#if 1
-  if ( res.VitalProductData.PrintableModel[0] )
-    len += sprintf(buffer+len,"%s\n",res.VitalProductData.PrintableModel);
-  
-  len += sprintf(buffer+len,"Bus %dMHz\n",
-		(res.VitalProductData.ProcessorBusHz > 1024) ?
-		res.VitalProductData.ProcessorBusHz>>20 :
-		res.VitalProductData.ProcessorBusHz);
-  
-  /* make sure loops_per_sec has been setup -- ie not at boottime -- Cort */
-  if ( CD(loops_per_sec+2500)/500000 > 0)
-    len += sprintf(buffer+len,
-		   "bogomips: %lu.%02lu\n",
-		   CD(loops_per_sec+2500)/500000,
-		   (CD(loops_per_sec+2500)/5000) % 100);
-
-
-  len += sprintf(buffer+len,"Total Ram: %dM Hash Table: %dkB (%dk buckets)\n",
-	 _TotalMemory>>20, Hash_size>>10,
-	 (Hash_size/(sizeof(PTE)*8)) >> 10);
-  
-  for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
-  {
-    if (i == 0)
-      len += sprintf(buffer+len,"SIMM Banks: ");
-    if ( res.Memories[i].SIMMSize != 0 )
-      len += sprintf(buffer+len,"%d:%dM ",i,
-		     (res.Memories[i].SIMMSize > 1024) ?
-		     res.Memories[i].SIMMSize>>20 :
-		     res.Memories[i].SIMMSize);
-    if ( i == MAX_MEMS-1)
-      len += sprintf(buffer+len,"\n");
-  }
-
-  /* TLB */
-  len += sprintf(buffer+len,"TLB");
-  switch(res.VitalProductData.TLBAttrib)
-  {
-    case CombinedTLB:
-      len += sprintf(buffer+len,": %d entries\n",
-		     res.VitalProductData.TLBSize);
-      break;
-    case SplitTLB:
-      len += sprintf(buffer+len,": (split I/D) %d/%d entries\n",
-		     res.VitalProductData.I_TLBSize,
-		     res.VitalProductData.D_TLBSize);
-      break;
-    case NoneTLB:
-      len += sprintf(buffer+len,": not present\n");
-      break;
-  }
-
-  /* L1 */
-  len += sprintf(buffer+len,"L1: ");
-  switch(res.VitalProductData.CacheAttrib)
-  {
-    case CombinedCAC:
-      len += sprintf(buffer+len,"%dkB LineSize\n",
-		     res.VitalProductData.CacheSize,
-		     res.VitalProductData.CacheLineSize);
-      break;
-    case SplitCAC:
-      len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
-		     res.VitalProductData.I_CacheSize,
-		     res.VitalProductData.D_CacheSize,
-		     res.VitalProductData.D_CacheLineSize,
-		     res.VitalProductData.D_CacheLineSize);
-      break;
-    case NoneCAC:
-      len += sprintf(buffer+len,"not present\n");
-      break;
-  }
-
-  /* L2 */
-  if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
-  {
-    int size;
-    
-    len += sprintf(buffer+len,"L2: %dkB %s\n",
-		   ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
-                   (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
-  }
-  else
-  {
-    len += sprintf(buffer+len,"L2: not present\n");
-  }
-#if 0  
-  len+= sprintf(buffer+len,"Equip register %x\n",
-		inb(IBM_EQUIP_PRESENT));
-  len+= sprintf(buffer+len,"L2Status register %x\n",
-		inb(IBM_L2_STATUS));
-#endif
-#endif
-
-  
-  return len;
-}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.1.47/linux/arch/ppc/kernel/signal.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/ppc/kernel/signal.c	Thu Jul 31 13:09:17 1997
@@ -1,9 +1,17 @@
 /*
  *  linux/arch/ppc/kernel/signal.c
  *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Adapted for PowerPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/kernel/signal.c"
+ *    Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *  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.
+ *
  */
 
 #include <linux/sched.h>
@@ -22,6 +30,12 @@
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
+#define DEBUG_SIGNALS
+#undef  DEBUG_SIGNALS
+
+#define PAUSE_AFTER_SIGNAL
+#undef  PAUSE_AFTER_SIGNAL
+
 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 
 /*
@@ -30,79 +44,85 @@
 asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
 {
 	unsigned long mask;
-	int ret = -EINTR;
 
-	lock_kernel();
+	spin_lock_irq(&current->sigmask_lock);
 	mask = current->blocked;
 	current->blocked = set & _BLOCKABLE;
+	spin_unlock_irq(&current->sigmask_lock);
+
 	regs->gpr[3] = -EINTR;
-#if 0
+#ifdef DEBUG_SIGNALS
 printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);	
 #endif
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(mask,regs))
-			goto out;
+		if (do_signal(mask,regs)) {
+			/*
+			 * If a signal handler needs to be called,
+			 * do_signal() has set R3 to the signal number (the
+			 * first argument of the signal handler), so don't
+			 * overwrite that with EINTR !
+			 * In the other cases, do_signal() doesn't touch 
+			 * R3, so it's still set to -EINTR (see above).
+			 */
+			return regs->gpr[3];
+		}
 	}
-out:
-	unlock_kernel();
-	return ret;
 }
 
+/*
+ * This sets regs->esp even though we don't actually use sigstacks yet..
+ */
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
 	struct sigcontext_struct *sc;
 	struct pt_regs *int_regs;
 	int signo, ret;
 
-	lock_kernel();
 #if 1 	
 	if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
-	    || (regs->gpr[1] >=KERNELBASE))
+	    || (regs->gpr[1] >= KERNELBASE))
 		goto badframe;
 #endif	
-	sc = (struct sigcontext_struct *)regs->gpr[1];
-	current->blocked = sc->oldmask & _BLOCKABLE;
-	int_regs = sc->regs;
-	signo = sc->signal;
-	sc++;  /* Pop signal 'context' */
+	sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
+	get_user(current->blocked, &sc->oldmask);
+	current->blocked &= _BLOCKABLE;
+	get_user(int_regs, &sc->regs);
+	get_user(signo, &sc->signal);
+	sc++;			/* Pop signal 'context' */
+#ifdef DEBUG_SIGNALS
+printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+#endif
 	if (sc == (struct sigcontext_struct *)(int_regs)) {
 		/* Last stacked signal */
-#if 0	
-		/* This doesn't work - it blows away the return address! */
 		memcpy(regs, int_regs, sizeof(*regs));
-#else
-		/* Don't mess up 'my' stack frame */
-		memcpy(&regs->gpr, &int_regs->gpr, sizeof(*regs)-sizeof(regs->_overhead));
-#endif		
-		if ((int)regs->orig_gpr3 >= 0 &&
+		if (regs->trap == 0x0C00 /* System Call! */ &&
 		    ((int)regs->result == -ERESTARTNOHAND ||
 		     (int)regs->result == -ERESTARTSYS ||
-		     (int)regs->result == -ERESTARTNOINTR))
-		{
+		     (int)regs->result == -ERESTARTNOINTR)) {
 			regs->gpr[3] = regs->orig_gpr3;
 			regs->nip -= 4; /* Back up & retry system call */
 			regs->result = 0;
 		}
-		ret = (regs->result);
-	} else { /* More signals to go */
-		regs->gpr[1] = (unsigned long)sc;
-		regs->gpr[3] = sc->signal;
-		regs->gpr[4] = sc->regs;
-		regs->link = (unsigned long)((sc->regs)+1);
-		regs->nip = sc->handler;
-		ret = sc->signal;
+		ret = regs->result;
+	} else {
+		/* More signals to go */
+		regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+		get_user(regs->gpr[3], &sc->signal);
+		get_user(int_regs, (struct pt_regs **) &sc->regs);
+		regs->gpr[4] = (unsigned long) int_regs;
+		regs->link = (unsigned long) (int_regs+1);
+		get_user(regs->nip, &sc->handler);
+		ret = regs->gpr[3];
 	}
-	goto out;
+	return ret;
 
 badframe:
-	/*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
-	 regs,current->comm,current->pid);*/
+	lock_kernel();
 	do_exit(SIGSEGV);
-out:
 	unlock_kernel();
-	return ret;
+	return -EFAULT;
 }
 
 
@@ -120,21 +140,24 @@
 	unsigned long mask;
 	unsigned long handler_signal = 0;
 	unsigned long *frame = NULL;
-	unsigned long *trampoline, *regs_ptr;
+	unsigned long *trampoline;
+	unsigned long *regs_ptr;
 	unsigned long nip = 0;
 	unsigned long signr;
 	struct sigcontext_struct *sc;
 	struct sigaction * sa;
-	int bitno, s, ret;
+	int bitno;
 
-	lock_kernel();
 	mask = ~current->blocked;
 	while ((signr = current->signal & mask)) {
+#if 0
+		signr = ffz(~signr);  /* Compute bit # */
+#else
 		for (bitno = 0;  bitno < 32;  bitno++)
 			if (signr & (1<<bitno))
 				break;
 		signr = bitno;
-
+#endif
 		current->signal &= ~(1<<signr);  /* Clear bit */
 		sa = current->sig->action + signr;
 		signr++;
@@ -150,6 +173,8 @@
 				continue;
 			if (_S(signr) & current->blocked) {
 				current->signal |= _S(signr);
+				spin_lock_irq(&current->sigmask_lock);
+				spin_unlock_irq(&current->sigmask_lock);
 				continue;
 			}
 			sa = current->sig->action + signr - 1;
@@ -169,32 +194,45 @@
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
-			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+			case SIGSTOP:
 				if (current->flags & PF_PTRACED)
 					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
-				      SA_NOCLDSTOP))
+						SA_NOCLDSTOP))
 					notify_parent(current);
 				schedule();
 				continue;
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGIOT: case SIGFPE: case SIGSEGV:
+				lock_kernel();
 				if (current->binfmt && current->binfmt->core_dump) {
 					if (current->binfmt->core_dump(signr, regs))
 						signr |= 0x80;
 				}
+				unlock_kernel();
 				/* fall through */
 			default:
+				spin_lock_irq(&current->sigmask_lock);
 				current->signal |= _S(signr & 0x7f);
+				spin_unlock_irq(&current->sigmask_lock);
+
+				current->flags |= PF_SIGNALED;
+
+				lock_kernel(); /* 8-( */
 				do_exit(signr);
+				unlock_kernel();
 			}
 		}
-
-		/* handle signal */
-		if ((int)regs->orig_gpr3 >= 0) {
+		/*
+		 * OK, we're invoking a handler
+		 */
+		if (regs->trap == 0x0C00 /* System Call! */) {
 			if ((int)regs->result == -ERESTARTNOHAND ||
 			    ((int)regs->result == -ERESTARTSYS &&
 			     !(sa->sa_flags & SA_RESTART)))
@@ -203,9 +241,18 @@
 		handler_signal |= 1 << (signr-1);
 		mask &= ~sa->sa_mask;
 	}
-	ret = 0;
-	if (!handler_signal)		/* no handler will be called - return 0 */
-		goto out;
+
+	if (regs->trap == 0x0C00 /* System Call! */ &&
+	    ((int)regs->result == -ERESTARTNOHAND ||
+	     (int)regs->result == -ERESTARTSYS ||
+	     (int)regs->result == -ERESTARTNOINTR)) {
+		regs->gpr[3] = regs->orig_gpr3;
+		regs->nip -= 4; /* Back up & retry system call */
+		regs->result = 0;
+	}
+
+	if (!handler_signal)	/* no handler will be called - return 0 */
+		return 0;
 
 	nip = regs->nip;
 	frame = (unsigned long *) regs->gpr[1];
@@ -213,20 +260,18 @@
 	/* Build trampoline code on stack */
 	frame -= 2;
 	trampoline = frame;
-#if 1
 	/* verify stack is valid for writing regs struct */
 	if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
-	    || (frame >= KERNELBASE ))
+	    || ((unsigned long) frame >= KERNELBASE ))
 		goto badframe;
-#endif
-	trampoline[0] = 0x38007777;  /* li r0,0x7777 */
-	trampoline[1] = 0x44000002;  /* sc           */
+	put_user(0x38007777UL, trampoline);      /* li r0,0x7777 */
+	put_user(0x44000002UL, trampoline+1);    /* sc           */
 	frame -= sizeof(*regs) / sizeof(long);
 	regs_ptr = frame;
-	memcpy(regs_ptr, regs, sizeof(*regs));
+	copy_to_user(regs_ptr, regs, sizeof(*regs));
 	signr = 1;
 	sa = current->sig->action;
-  
+
 	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 		if (mask > handler_signal)
 			break;
@@ -234,50 +279,39 @@
 			continue;
 
 		frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-#if 1
 		if (verify_area(VERIFY_WRITE,(void *)frame,
 				sizeof(struct sigcontext_struct)/sizeof(long)))
 			goto badframe;
-#endif    
 		sc = (struct sigcontext_struct *)frame;
 		nip = (unsigned long) sa->sa_handler;
-#if 0 /* Old compiler */		
-		nip = *(unsigned long *)nip;
-#endif		
 		if (sa->sa_flags & SA_ONESHOT)
 			sa->sa_handler = NULL;
-		sc->handler = nip;
-		sc->oldmask = current->blocked;
-		sc->regs = (unsigned long)regs_ptr;
-		sc->signal = signr;
+		put_user(nip, &sc->handler);
+		put_user(oldmask, &sc->oldmask); /* was current->blocked */
+		put_user(regs_ptr, &sc->regs);
+		put_user(signr, &sc->signal);
 		current->blocked |= sa->sa_mask;
 		regs->gpr[3] = signr;
 		regs->gpr[4] = (unsigned long)regs_ptr;
 	}
 	regs->link = (unsigned long)trampoline;
 	regs->nip = nip;
-	regs->gpr[1] = (unsigned long)sc;
+	regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
 
-	/* The DATA cache must be flushed here to insure coherency
-	 * between the DATA & INSTRUCTION caches.  Since we just
-	 * created an instruction stream using the DATA [cache] space
-	 * and since the instruction cache will not look in the DATA
-	 * cache for new data, we have to force the data to go on to
-	 * memory and flush the instruction cache to force it to look
-	 * there.  The following function performs this magic
-	 */
-	flush_instruction_cache();
-	ret = 1;
-	goto out;
+	/* The DATA cache must be flushed here to insure coherency */
+	/* between the DATA & INSTRUCTION caches.  Since we just */
+	/* created an instruction stream using the DATA [cache] space */
+	/* and since the instruction cache will not look in the DATA */
+	/* cache for new data, we have to force the data to go on to */
+	/* memory and flush the instruction cache to force it to look */
+	/* there.  The following function performs this magic */
+	store_cache_range((unsigned long) trampoline,
+			  (unsigned long) (trampoline + 2));
+	return 1;
 
 badframe:
-#if 0
-	printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
-	       signr, frame, regs, current->comm, current->pid);
-#endif
+	lock_kernel();
 	do_exit(SIGSEGV);
-
-out:
 	unlock_kernel();
-	return ret;
+	return 0;
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/strcase.c linux/arch/ppc/kernel/strcase.c
--- v2.1.47/linux/arch/ppc/kernel/strcase.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/strcase.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,12 @@
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while (c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/stubs.c linux/arch/ppc/kernel/stubs.c
--- v2.1.47/linux/arch/ppc/kernel/stubs.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/ppc/kernel/stubs.c	Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-/*#include <linux/in.h>*/
-#include <linux/autoconf.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-void sys_iopl(void)
-{
-	lock_kernel();
-	panic("sys_iopl");
-	unlock_kernel();
-}
-void sys_vm86(void)
-{
-	lock_kernel();
-	panic("sys_vm86");
-	unlock_kernel();
-}
-void sys_modify_ldt(void)
-{
-	lock_kernel();
-	panic("sys_modify_ldt");
-	unlock_kernel();
-}
-
-void sys_ipc(void)
-{
-	lock_kernel();
-	panic("sys_ipc");
-	unlock_kernel();
-}
-
-void sys_newselect(void)
-{
-	lock_kernel();
-	panic("sys_newselect");
-	unlock_kernel();
-}
-
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
-	lock_kernel();
-	panic("scsi_register_module");
-	unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
-	lock_kernel();
-	panic("scsi_unregister_module");
-	unlock_kernel();
-}
-#endif
-
-
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/support.c linux/arch/ppc/kernel/support.c
--- v2.1.47/linux/arch/ppc/kernel/support.c	Mon May 27 21:46:04 1996
+++ linux/arch/ppc/kernel/support.c	Wed Dec 31 16:00:00 1969
@@ -1,84 +0,0 @@
-/*
- * Miscellaneous support routines
- */
-
-#include <asm/bitops.h>
-
-/*extern __inline__*/ int find_first_zero_bit(void *add, int len)
-{
-	int	mask, nr, i;
-	BITFIELD *addr = add;
-	nr = 0;
-	while (len)
-	{
-		if (~*addr != 0)
-		{ /* Contains at least one zero */
-			for (i = 0;  i < 32;  i++, nr++)
-			{
-				mask = BIT(nr);
-				if ((mask & *addr) == 0)
-				{
-					return (nr);
-				}
-			}
-		}
-		len -= 32;
-		addr++;
-		nr += 32;
-	}
-	return (0);  /* Shouldn't happen */
-}
-
-/*extern __inline__*/ int find_next_zero_bit(void *add, int last_bit, int nr)
-{
-	int	mask, i;
-	BITFIELD *addr = add;
-#if 0	
-printk("Find next (%x, %x)", addr, nr);
-#endif
-	addr += nr >> 5;
-#if 0	
-printk(" - Pat: %x(%08X)\n", addr, *addr);
-#endif
-	if ((nr & 0x1F) != 0)
-	{ 
-		if (*addr != 0xFFFFFFFF)
-		{ /* At least one more bit available in this longword */
-			for (i = (nr&0x1F);  i < 32;  i++, nr++)
-			{
-				mask = BIT(nr);
-				if ((mask & *addr) == 0)
-				{
-#if 0					
-printk("(1)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
-					return (nr);
-				}
-			}
-		}
-		addr++;
-		nr = (nr + 0x1F) & ~0x1F;
-	}
-	while (nr < last_bit)
-	{
-		if (*addr != 0xFFFFFFFF)
-		{ /* Contains at least one zero */
-			for (i = 0;  i < 32;  i++, nr++)
-			{
-				mask = BIT(nr);
-				if ((mask & *addr) == 0)
-				{
-#if 0					
-printk("(2)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
-					return (nr);
-				}
-			}
-		}
-		addr++;
-		nr += 32;
-	}
-	return (nr);  /* Shouldn't happen */
-}
-
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.1.47/linux/arch/ppc/kernel/syscalls.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/ppc/kernel/syscalls.c	Thu Jul 31 13:09:17 1997
@@ -9,6 +9,7 @@
  * platform.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -19,105 +20,45 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/ipc.h>
 #include <asm/uaccess.h>
+#include <asm/ipc.h>
 
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix traditionally does this, though.
- */
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
-	int error;
 
-	lock_kernel();
-	error = verify_area(VERIFY_WRITE,fildes,8);
-	if (error)
-		goto out;
-	error = do_pipe(fildes);
-out:
-	unlock_kernel();
-	return error;
+void
+check_bugs(void)
+{
 }
 
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
-                                  int flags, int fd, off_t offset)
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	struct file * file = NULL;
-	int ret = -EBADF;
+	printk("sys_ioperm()\n");
+	return -EIO;
+}
 
+int sys_iopl(int a1, int a2, int a3, int a4)
+{
 	lock_kernel();
-	if (!(flags & MAP_ANONYMOUS)) {
-		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			goto out;
-	}
-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	ret = do_mmap(file, addr, len, prot, flags, offset);
-out:
+	printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
 	unlock_kernel();
-	return ret;
+	return (ENOSYS);
 }
 
-/*
- * 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 sys_vm86(int a1, int a2, int a3, int a4)
 {
-	int error;
-	unsigned long flags;
-	long a,b,c,d,e;
-	struct file * file = NULL;
-
 	lock_kernel();
-	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
-	if (error)
-		goto out;
-	get_user(flags,buffer+3);
-	if (!(flags & MAP_ANONYMOUS)) {
-		unsigned long fd;
-		get_user(fd,buffer+4);
-		error = -EBADF;
-		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			goto out;
-	}
-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	error = -EFAULT;
-	if ( get_user(a,buffer) || get_user(b,buffer+1) ||
-	     get_user(c,buffer+2)||get_user(d,buffer+5)	)
-		goto out;
-	error = do_mmap(file,a,b,c, flags, d);
-out:
+	printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
 	unlock_kernel();
-	return error;
+	return (ENOSYS);
 }
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
-asmlinkage int old_select(unsigned long *buffer)
+int sys_modify_ldt(int a1, int a2, int a3, int a4)
 {
-	int n;
-	fd_set *inp;
-	fd_set *outp;
-	fd_set *exp;
-	struct timeval *tvp;
-
-	lock_kernel();
-	n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
-	if (n)
-		goto out;
-	get_user(n,buffer);
-	get_user(inp,buffer+1);
-	get_user(outp,buffer+2);
-	get_user(exp,buffer+3);
-	get_user(tvp,buffer+4);
-	n = sys_select(n, inp, outp, exp, tvp);
-out:
+	lock_kernel();
+	printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
 	unlock_kernel();
-	return n;
+	return (ENOSYS);
 }
-#if 0
 
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
@@ -145,12 +86,12 @@
 			ret = -EINVAL;
 			if (!ptr)
 				goto out;
-			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
-				goto out;
-			fourth.__pad = (void *) get_fs_long(ptr);
+			ret = -EFAULT;
+			if (get_user(fourth.__pad, (void **) ptr))
+				goto out;	
 			ret = sys_semctl (first, second, third, fourth);
 			goto out;
-			}
+		}
 		default:
 			ret = -EINVAL;
 			goto out;
@@ -168,13 +109,13 @@
 				ret = -EINVAL;
 				if (!ptr)
 					goto out;
-				if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
-					goto out;
-				memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
-					       sizeof (tmp));
+				ret = -EFAULT;
+				if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, 
+						   sizeof (tmp)))
+					goto out; 	
 				ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
 				goto out;
-				}
+			}
 			case 1: default:
 				ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
 				goto out;
@@ -195,15 +136,12 @@
 			switch (version) {
 			case 0: default: {
 				ulong raddr;
-				if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
-					goto out;
 				ret = sys_shmat (first, (char *) ptr, second, &raddr);
 				if (ret)
 					goto out;
-				put_fs_long (raddr, (ulong *) third);
-				ret = 0;
+				ret = put_user (raddr, (ulong *) third);
 				goto out;
-				}
+			}
 			case 1:	/* iBCS2 emulator entry point */
 				ret = -EINVAL;
 				if (get_fs() != get_ds())
@@ -230,4 +168,81 @@
 	unlock_kernel();
 	return ret;
 }
+
+
+#ifndef CONFIG_MODULES
+void
+scsi_register_module(void)
+{
+	lock_kernel();
+	panic("scsi_register_module");
+	unlock_kernel();
+}
+
+void
+scsi_unregister_module(void)
+{
+	lock_kernel();
+	panic("scsi_unregister_module");
+	unlock_kernel();
+}
 #endif
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally 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_user(fd[0],0+fildes);
+	put_user(fd[1],1+fildes);
+	return 0;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+				  unsigned long prot, unsigned long flags,
+				  unsigned long fd, off_t offset)
+{
+	struct file * file = NULL;
+	if (!(flags & MAP_ANONYMOUS)) {
+		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+			return -EBADF;
+	}
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	return do_mmap(file, addr, len, prot, flags, offset);
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+/*
+ * Due to some executables calling the wrong select we sometimes
+ * get wrong args.  This determines how the args are being passed
+ * (a single ptr to them all args passed) then calls
+ * sys_select() with the appropriate args. -- Cort
+ */
+asmlinkage int 
+ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
+{
+	int err;
+	if ( (unsigned long)n >= 4096 )
+	{
+		unsigned long *buffer = (unsigned long *)n;
+		if ( get_user(n, buffer) ||
+		     get_user(inp,buffer+1) ||
+		     get_user(outp,buffer+2) ||
+		     get_user(exp,buffer+3) ||
+		     get_user(tvp,buffer+4) )
+			return -EFAULT;
+	}
+	return sys_select(n, inp, outp, exp, tvp);
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.1.47/linux/arch/ppc/kernel/time.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/time.c	Wed Dec 31 16:00:00 1969
@@ -1,465 +0,0 @@
-/*
- *  linux/arch/i386/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- *
- * This file contains the PC-specific time handling details:
- * reading the RTC at bootup, etc..
- * 1994-07-02    Alan Modra
- *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1995-03-26    Markus Kuhn
- *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
- *      precision CMOS clock update
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/nvram.h>
-#include <asm/mc146818rtc.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-#include <linux/config.h>
-
-extern int isBeBox[];
-
-#define TIMER_IRQ 0
-
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
-
-static inline int CMOS_READ(int addr)
-{
-	outb(addr>>8, NVRAM_AS1);
-	outb(addr, NVRAM_AS0);
-	return (inb(NVRAM_DATA));
-}
-
-static inline int CMOS_WRITE(int addr, int val)
-{
-	outb(addr>>8, NVRAM_AS1);
-	outb(addr, NVRAM_AS0);
-	return (outb(val, NVRAM_DATA));
-}
-
-/* This function must be called with interrupts disabled 
- * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought....		pjsg (1993-08-28)
- * 
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
- */
-
-#define TICK_SIZE tick
-
-static unsigned long do_slow_gettimeoffset(void)
-{
-	int count;
-	unsigned long offset = 0;
-
-	/* timer count may underflow right here */
-	outb_p(0x00, 0x43);	/* latch the count ASAP */
-	count = inb_p(0x40);	/* read the latched count */
-	count |= inb(0x40) << 8;
-	/* we know probability of underflow is always MUCH less than 1% */
-	if (count > (LATCH - LATCH/100)) {
-		/* check for pending timer interrupt */
-		outb_p(0x0a, 0x20);
-		if (inb(0x20) & 1)
-			offset = TICK_SIZE;
-	}
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	count = (count + LATCH/2) / LATCH;
-	return offset + count;
-}
-
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
-	if (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}
-	restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
-{
-	cli();
-	/* This is revolting. We need to set the xtime.tv_usec
-	 * correctly. However, the value in this location is
-	 * is value at the last tick.
-	 * Discover what correction gettimeofday
-	 * would have done, and then undo it!
-	 */
-	tv->tv_usec -= do_gettimeoffset();
-
-	if (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-
-	xtime = *tv;
-	time_state = TIME_BAD;
-	time_maxerror = 0x70000000;
-	time_esterror = 0x70000000;
-	set_rtc(xtime.tv_sec);
-	sti();
-}
-
-static int      month_days[12] = {
-	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define FEBRUARY	2
-#define	STARTOFTIME	1970
-#define SECDAY		86400L
-#define SECYR		(SECDAY * 365)
-#define	leapyear(year)		((year) % 4 == 0)
-#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
-#define	days_in_month(a) 	(month_days[(a) - 1])
-
-struct _tm
-{
-	int             tm_sec;
-	int             tm_min;
-	int             tm_hour;
-	int             tm_day;
-	int             tm_month;
-	int             tm_year;
-};
-
-static _to_tm(int tim, struct _tm * tm)
-{
-	register int    i;
-	register long   hms, day;
-
-	day = tim / SECDAY;
-	hms = tim % SECDAY;
-
-	/* Hours, minutes, seconds are easy */
-	tm->tm_hour = hms / 3600;
-	tm->tm_min = (hms % 3600) / 60;
-	tm->tm_sec = (hms % 3600) % 60;
-
-	/* Number of years in days */
-	for (i = STARTOFTIME; day >= days_in_year(i); i++)
-		day -= days_in_year(i);
-	tm->tm_year = i;
-
-	/* Number of months in days left */
-	if (leapyear(tm->tm_year))
-		days_in_month(FEBRUARY) = 29;
-	for (i = 1; day >= days_in_month(i); i++)
-		day -= days_in_month(i);
-	days_in_month(FEBRUARY) = 28;
-	tm->tm_month = i;
-
-	/* Days are what is left over (+1) from all that. */
-	tm->tm_day = day + 1;
-}
-
-/*
- * Set the time into the CMOS
- */
-static void set_rtc(unsigned long nowtime)
-{
-  int retval = 0;
-  struct _tm tm;
-  unsigned char save_control, save_freq_select;
-  
-  /*if (_Processor != _PROC_IBM) return;*/
-  
-  _to_tm(nowtime, &tm);
-  
-  /* tell the clock it's being set */  
-  save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); 
-  CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
-  /* stop and reset prescaler */  
-  save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT);
-  CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
-  printk("Set RTC H:M:S M/D/Y %d:%02d:%02d %d/%d/%d\n", 
-       tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_month, tm.tm_day, tm.tm_year);
-	if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
-		BIN_TO_BCD(tm.tm_sec);
-		BIN_TO_BCD(tm.tm_min);
-		BIN_TO_BCD(tm.tm_hour);
-		BIN_TO_BCD(tm.tm_month);
-		BIN_TO_BCD(tm.tm_day);
-		BIN_TO_BCD(tm.tm_year);
-	}
-
-	CMOS_MCRTC_WRITE(tm.tm_sec,  MCRTC_SECONDS);
-	CMOS_MCRTC_WRITE(tm.tm_min,  MCRTC_MINUTES);
-	CMOS_MCRTC_WRITE(tm.tm_hour, MCRTC_HOURS);
-	CMOS_MCRTC_WRITE(tm.tm_month,  MCRTC_MONTH);
-	CMOS_MCRTC_WRITE(tm.tm_day,  MCRTC_MINUTES);
-	CMOS_MCRTC_WRITE(tm.tm_year - 1900, MCRTC_MINUTES);
-
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
-	CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- */
-static int set_rtc_mmss(unsigned long nowtime)
-{
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
-	unsigned char save_control, save_freq_select;
-
-#ifdef __powerpc__
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
-return (-1);  /* Not implemented */
-#else	
-
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
-	save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); /* tell the clock it's being set */
-	CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
-
-	save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
-	cmos_minutes = CMOS_MCRTC_READ(MCRTC_MINUTES);
-	if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD)
-		BCD_TO_BIN(cmos_minutes);
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-		real_minutes += 30;		/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
-			BIN_TO_BCD(real_seconds);
-			BIN_TO_BCD(real_minutes);
-		}
-		CMOS_MCRTC_WRITE(real_seconds,MCRTC_SECONDS);
-		CMOS_MCRTC_WRITE(real_minutes,MCRTC_MINUTES);
-	} else
-		retval = -1;
-
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
-	CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-
-	return retval;
-#endif	
-}
-
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
-{
-  static int timeints = 0;
-  
-  do_timer(regs);
-
-  /*
-   * If we have an externally synchronized Linux clock, then update
-   * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-   * called as close as possible to 500 ms before the new second starts.
-   */
-  if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
-      xtime.tv_usec > 500000 - (tick >> 1) &&
-      xtime.tv_usec < 500000 + (tick >> 1))
-    if (set_rtc_mmss(xtime.tv_sec) == 0)
-      last_rtc_update = xtime.tv_sec;
-    else
-      last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-
-
-  /* use hard disk LED as a heartbeat instead -- much more useful
-     -- Cort */
-  switch(timeints)
-  {
-    /* act like an actual heart beat -- ie thump-thump-pause... */
-    case 0:
-    case 20:
-      hard_disk_LED(1);
-      break;
-    case 7:
-    case 27:
-      hard_disk_LED(0);
-      break;
-    case 100:
-      timeints = -1;
-      break;
-  }
-  timeints++;
-}
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
-	unsigned int day, unsigned int hour,
-	unsigned int min, unsigned int sec)
-{
-	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
-		mon += 12;	/* Puts Feb last since it has leap day */
-		year -= 1;
-	}
-	return (((
-	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
-	      year*365 - 719499
-	    )*24 + hour /* now have hours */
-	   )*60 + min /* now have minutes */
-	  )*60 + sec; /* finally seconds */
-}
-
-unsigned long get_cmos_time(void)
-{
-  unsigned int year, mon, day, hour, min, sec;
-  int i;
-  
-  if (_Processor == _PROC_IBM)
-  {
-    do { /* Isn't this overkill ? UIP above should guarantee consistency */
-      sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
-      min = CMOS_MCRTC_READ(MCRTC_MINUTES);
-      hour = CMOS_MCRTC_READ(MCRTC_HOURS);
-      day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
-      mon = CMOS_MCRTC_READ(MCRTC_MONTH);
-      year = CMOS_MCRTC_READ(MCRTC_YEAR);
-    } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
-    BCD_TO_BIN(sec);
-    BCD_TO_BIN(min);
-    BCD_TO_BIN(hour);
-    BCD_TO_BIN(day);
-    BCD_TO_BIN(mon);
-    BCD_TO_BIN(year);
-  } else
-    if (_Processor == _PROC_Be)
-      {
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-	  sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
-	  min = CMOS_MCRTC_READ(MCRTC_MINUTES);
-	  hour = CMOS_MCRTC_READ(MCRTC_HOURS);
-	  day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
-	  mon = CMOS_MCRTC_READ(MCRTC_MONTH);
-	  year = CMOS_MCRTC_READ(MCRTC_YEAR);
-	} while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
-      } else
-	{ /* Motorola PowerStack etc. */
-	  do { /* Isn't this overkill ? UIP above should guarantee consistency */
-	    sec = CMOS_READ(RTC_SECONDS);
-	    min = CMOS_READ(RTC_MINUTES);
-	    hour = CMOS_READ(RTC_HOURS);
-	    day = CMOS_READ(RTC_DAY_OF_MONTH);
-	    mon = CMOS_READ(RTC_MONTH);
-	    year = CMOS_READ(RTC_YEAR);
-	  } while (sec != CMOS_READ(RTC_SECONDS));
-	  BCD_TO_BIN(sec);
-	  BCD_TO_BIN(min);
-	  BCD_TO_BIN(hour);
-	  BCD_TO_BIN(day);
-	  BCD_TO_BIN(mon);
-	  BCD_TO_BIN(year);
-	}
-#if 0	
-printk("CMOS TOD - M/D/Y H:M:S = %d/%d/%d %d:%02d:%02d\n", mon, day, year, hour, min, sec);
-#endif
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-void time_init(void)
-{
-  void (*irq_handler)(int, struct pt_regs *);
-  xtime.tv_sec = get_cmos_time();
-  xtime.tv_usec = 0;
-  
-  /* If we have the CPU hardware time counters, use them */
-  irq_handler = timer_interrupt;
-  if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
-    panic("Could not allocate timer IRQ!");
-}
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.1.47/linux/arch/ppc/kernel/traps.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/traps.c	Thu Jul 31 13:09:17 1997
@@ -20,14 +20,14 @@
 #include <linux/malloc.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
 
 #include <asm/pgtable.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <asm/ppc_machine.h>
-
 /*
  * Trap & Exception support
  */
@@ -40,122 +40,98 @@
 void
 _exception(int signr, struct pt_regs *regs)
 {
-  /*	dump_regs(regs);*/
-  force_sig(signr, current);
-  if (!user_mode(regs))
-    {
-      printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
-      while (1) ;
-    }
+	if (!user_mode(regs))
+	{
+		show_regs(regs);
+		print_backtrace(regs->gpr[1]);
+		panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+	}
+	force_sig(signr, current);
 }
 
 MachineCheckException(struct pt_regs *regs)
 {
-  printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
-  _exception(SIGSEGV, regs);	
-}
-
-ProgramCheckException(struct pt_regs *regs)
-{
-#if 0
-  printk("Program check at PC: %x[%x], SR: %x\n",
-	 regs->nip, va_to_phys(regs->nip), regs->msr);
-  #endif
-  if (current->flags & PF_PTRACED)
-  {
-    _exception(SIGTRAP, regs);
-  } else
-  {
-    _exception(SIGILL, regs);
-  }
+	if ( !user_mode(regs) )
+	{
+		printk("Machine check in kernel mode.\n");
+		printk("Caused by (from msr): ");
+		printk("regs %08x ",regs);
+		switch( regs->msr & 0x0000F000)
+		{
+		case (1<<12) :
+			printk("Machine check signal - probably due to mm fault\n"
+				"with mmu off\n");
+		break;
+		case (1<<13) :
+			printk("Transfer error ack signal\n");
+		break;
+		case (1<<14) :
+			printk("Data parity signal\n");
+		break;
+		case (1<<15) :
+			printk("Address parity signal\n");
+		break;
+		default:
+			printk("Unknown values in msr\n");
+		}
+		show_regs(regs);
+		print_backtrace(regs->gpr[1]);
+		panic("");
+	}
+	_exception(SIGSEGV, regs);	
 }
 
-SingleStepException(struct pt_regs *regs)
+void
+UnknownException(struct pt_regs *regs)
 {
-	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+	       regs->nip, regs->msr, regs->trap);
 	_exception(SIGTRAP, regs);	
 }
 
-FloatingPointCheckException(struct pt_regs *regs)
+void
+InstructionBreakpoint(struct pt_regs *regs)
 {
-  /* if fpu already on -- then exception was generated by an error */
-  if ( (unsigned long)(regs->msr) & (unsigned long)MSR_FP )
-  {
-    _exception(SIGFPE, regs);
-    return 0;
-  }
-
-#if 0
-  printk("fpu off -- turning on: %s pc %x fpscr %x msr %x ksp %x r1 %x\n",
-	 current->comm,regs->nip,regs->fpcsr,regs->msr,regs,regs->gpr[1]);
+#ifdef CONFIG_XMON
+	if (xmon_iabr_match(regs))
+		return;
 #endif
+	_exception(SIGTRAP, regs);
+}
 
-  /* if the fpu is off then turn it on and return */
-  regs->msr |= MSR_FP;
-  current->tss.fp_used++;
-  /* tells return_from_int to restore fp regs since fp was turned on
-     see head.S -- Cort */  
-  return MSR_FP;		
+void
+RunModeException(struct pt_regs *regs)
+{
+	_exception(SIGTRAP, regs);	
 }
 
-AlignmentException(struct pt_regs *regs)
+ProgramCheckException(struct pt_regs *regs)
 {
-/*	printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr);
-	dump_regs(regs);
-	printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
-	_exception(SIGBUS, regs);	
+	if (current->flags & PF_PTRACED)
+		_exception(SIGTRAP, regs);
+	else
+		_exception(SIGILL, regs);
 }
 
+SingleStepException(struct pt_regs *regs)
+{
+	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+	_exception(SIGTRAP, regs);	
+}
 
-/* see CHECK_STACK macro in head.S for argument definitions */
-bad_stack(unsigned int r3, unsigned int r4, unsigned int r5, unsigned int r6)
+AlignmentException(struct pt_regs *regs)
 {
-  /* r6 (was r1) kernel stack pointer */
-  /* r5 (was r2) kernel stack page */
-  /* r4 kernel stack magic */
-  /* r3 stack magic or ksp masked to page boundary */
-  printk("bad_stack(): Kernel stack bad.\n");
-  printk("ksp %x kpage %x stack magic %x r3 %x\n",
-	 r6,r5,r4,r3);
-  printk("current: %s/%d\n",
-	 current->comm,current->pid);
-  while(1);
-}
-
-dump_regs(struct pt_regs *regs)
-{
-	int i;
-	printk("NIP: %08X, MSR: %08X, XER: %08X, LR: %08X, FRAME: %08X\n", regs->nip, regs->msr, regs->xer, regs->link, regs);
-#if 0	
-	printk("HASH = %08X/%08X, MISS = %08X/%08X, CMP = %08X/%08X\n", regs->hash1, regs->hash2, regs->imiss, regs->dmiss, regs->icmp, regs->dcmp);
-#endif	
-	printk("TASK = %x[%d] '%s'\n", current, current->pid, current->comm);
-	for (i = 0;  i < 32;  i++)
-	{
-		if ((i % 8) == 0)
-		{
-			printk("GPR%02d: ", i);
-		}
-		printk("%08X ", regs->gpr[i]);
-		if ((i % 8) == 7)
-		{
-			printk("\n");
-		}
-	}
-#if 0	
-	if (regs->nip >= 0x1000)
-		dump_buf(regs->nip-32, 64);
-	dump_buf((regs->nip&0x0FFFFFFF)|KERNELBASE, 32);
-#endif
+	_exception(SIGBUS, regs);	
 }
 
 trace_syscall(struct pt_regs *regs)
 {
 	static int count;
-	printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
+	printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+	       current, current->pid, regs->nip, regs->link, regs->gpr[0],
+	       regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
 	if (++count == 20)
 	{
 		count = 0;
 	}
 }
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/usercpy.c linux/arch/ppc/kernel/usercpy.c
--- v2.1.47/linux/arch/ppc/kernel/usercpy.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/usercpy.c	Wed Dec 31 16:00:00 1969
@@ -1,116 +0,0 @@
-#include <linux/types.h>
-#include <asm/string.h>
-#include <asm/errno.h>
-#include <linux/sched.h>
-
-/*
- * bad data accesses from these functions should be handled specially 
- * since they are to user areas and may or may not be valid.
- * on error -EFAULT should be returned.  -- Cort
- */
-int __copy_tofrom_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-
-int __copy_tofrom_user(unsigned long to, unsigned long from, int size)
-{
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )__copy_tofrom_user_failure;
-  
-  if (memcpy( (void *)to, (void *)from, (size_t) size) == -EFAULT )
-  {
-    /* take down exception handler stuff */
-    current->tss.excount = 0;
-    return -EFAULT;
-  }
-  current->tss.excount = 0;
-  return 0; /* successful return */
-}
-
-/* Just like strncpy except in the return value:
- *
- * -EFAULT       if an exception occurs before the terminator is copied.
- * N             if the buffer filled.
- *
- * Otherwise the length of the string is returned.
- */
-asmlinkage int __strncpy_from_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-
-int __strncpy_from_user(unsigned long dest, unsigned long src, int count)
-{
-  int i = 0;
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )__strncpy_from_user_failure;
-  
-  while ( i != count )
-  {
-    *(char *)(dest+i) = *(char *)(src+i);
-    if ( *(char *)(src+i) == 0 )
-    {
-      return i;
-    }
-    i++;
-  }
-  *(char *)(dest+i) = (char)0;
-  /* take down exception handler stuff */
-  current->tss.excount = 0;
-  return i;
-}
-
-int __clear_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-int __clear_user(unsigned long addr, int size)
-{
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )__clear_user_failure;
-
-  if ((int)memset((void *)addr,(int)0, (__kernel_size_t)size) == -EFAULT )
-    {
-      /* take down exception handler stuff */
-      current->tss.excount = 0;
-      return -EFAULT;
-    }
-  /* take down exception handler stuff */
-  current->tss.excount = 0;
-  return size;
-}
-
-/*
- * Return the length of the string including the NUL terminator
- * (strlen+1) or zero if an error occured.
- */
-size_t strlen_user_failure(void)
-{
-  current->tss.excount = 0;
-  return -EFAULT;
-}
-size_t strlen_user(char * s)
-{
-  size_t i;
-  /* setup exception handling stuff */
-  current->tss.excount++;
-  current->tss.expc = (unsigned long )strlen_user_failure;
-  
-  i = strlen(s)+1;
-  
-  if ( i == -EFAULT)
-    return -EFAULT;
-  
-  /* take down exception handler stuff */
-  current->tss.excount = 0;
-
-  return(i);
-}
-
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/ld.script linux/arch/ppc/ld.script
--- v2.1.47/linux/arch/ppc/ld.script	Mon May 27 02:00:58 1996
+++ linux/arch/ppc/ld.script	Thu Jul 31 13:09:17 1997
@@ -31,12 +31,16 @@
   .text      :
   {
     *(.text)
-    *(.rodata)
-    *(.rodata1)
+    *(.fixup)
     *(.got1)
   }
   _etext = .;
   PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
   .dtors     : { *(.dtors)   }
@@ -45,31 +49,33 @@
   .data    :
   {
     *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
     CONSTRUCTORS
   }
-  .data1   : { *(.data1) }
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
   _edata  =  .;
+/*
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+*/
+  __bss_start = .;		/* BSS */
   PROVIDE (edata = .);
   __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
   .bss       :
   {
+   *(.sbss) *(.scommon)
    *(.dynbss)
    *(.bss)
    *(COMMON)
   }
   _end = . ;
   PROVIDE (end = .);
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* These must appear regardless of  .  */
 }
 
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile
--- v2.1.47/linux/arch/ppc/lib/Makefile	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/lib/Makefile	Thu Jul 31 13:09:17 1997
@@ -1,12 +1,38 @@
-#
-# Makefile for i386-specific library files..
-#
+.c.s:
+	$(CC) $(CFLAGS) -S $<
+.s.o:
+	$(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+.S.s:
+	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+.S.o:
+	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+	$(AS) $(ASFLAGS) -o $*.o $*.s
+	rm $*.s
+
+HOST_CC = gcc
 
 L_TARGET = lib.o
-L_OBJS  = checksum.o cksum_support.o
-CC = gcc -I$(TOPDIR)/include
+L_OBJS  = checksum.o cksum_support.o string.o
 
 ${L_TARGET}: $(L_OBJS)
 	$(LD) -r -o ${L_TARGET} $(L_OBJS)
 
+
 fastdep:
+	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+	$(CPP) -M *.S *.c > .depend
+
+modules: 
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S
--- v2.1.47/linux/arch/ppc/lib/string.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/lib/string.S	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,328 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/errno.h>
+
+	.globl	strcpy
+strcpy:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strncpy
+strncpy:
+	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	blr
+
+	.globl	strcat
+strcat:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r5)
+	cmpwi	0,r0,0
+	bne	1b
+	addi	r5,r5,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strcmp
+strcmp:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r5)
+	cmpwi	1,r3,0
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	beqlr	1
+	beq	1b
+	blr
+
+	.globl	strlen
+strlen:
+	addi	r4,r3,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	bne	1b
+	subf	r3,r3,r4
+	blr
+
+	.globl	memset
+memset:
+	rlwimi	r4,r4,8,16,23
+	rlwimi	r4,r4,16,0,15
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	rlwinm	r0,r5,32-2,2,31
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+	.globl	bcopy
+bcopy:
+	mr	r6,r3
+	mr	r3,r4
+	mr	r4,r6
+	b	memcpy
+
+	.globl	memmove
+memmove:
+	cmplw	0,r3,r4
+	bgt	backwards_memcpy
+	/* fall through */
+
+	.globl	memcpy
+memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	addi	r6,r3,-4
+	addi	r4,r4,-4
+	beq	2f			/* if less than 8 bytes to do */
+	andi.	r0,r6,3			/* get dest word aligned */
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,4(r4)
+	lwzu	r8,8(r4)
+	stw	r7,4(r6)
+	stwu	r8,8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,4(r4)
+	addi	r5,r5,-4
+	stwu	r0,4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r4,r4,3
+	addi	r6,r6,3
+4:	lbzu	r0,1(r4)
+	stbu	r0,1(r6)
+	bdnz	4b
+	blr
+5:	subfic	r0,r0,4
+	mtctr	r0
+6:	lbz	r7,4(r4)
+	addi	r4,r4,1
+	stb	r7,4(r6)
+	addi	r6,r6,1
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	backwards_memcpy
+backwards_memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	add	r6,r3,r5
+	add	r4,r4,r5
+	beq	2f
+	andi.	r0,r6,3
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,-4(r4)
+	lwzu	r8,-8(r4)
+	stw	r7,-4(r6)
+	stwu	r8,-8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,-4(r4)
+	subi	r5,r5,4
+	stwu	r0,-4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+4:	lbzu	r0,-1(r4)
+	stbu	r0,-1(r6)
+	bdnz	4b
+	blr
+5:	mtctr	r0
+6:	lbzu	r7,-1(r4)
+	stbu	r7,-1(r6)
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+	
+	.globl	memcmp
+memcmp:
+	cmpwi	0,r5,0
+	blelr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r6)
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	bdnzt	2,1b
+	blr
+	.globl	__copy_tofrom_user
+__copy_tofrom_user:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	addi	r6,r3,-4
+	addi	r4,r4,-4
+	li	r3,0			/* success return value */
+	beq	2f			/* if less than 8 bytes to do */
+	andi.	r0,r6,3			/* get dest word aligned */
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,4(r4)
+11:	lwzu	r8,8(r4)
+12:	stw	r7,4(r6)
+13:	stwu	r8,8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+14:	lwzu	r0,4(r4)
+	addi	r5,r5,-4
+15:	stwu	r0,4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r4,r4,3
+	addi	r6,r6,3
+4:	lbzu	r0,1(r4)
+16:	stbu	r0,1(r6)
+	bdnz	4b
+	blr
+5:	subfic	r0,r0,4
+	mtctr	r0
+6:	lbz	r7,4(r4)
+	addi	r4,r4,1
+17:	stb	r7,4(r6)
+	addi	r6,r6,1
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+99:	li	r3,-EFAULT
+	blr
+.section __ex_table,"a"
+	.align	2
+	.long	1b,99b
+	.long	11b,99b
+	.long	12b,99b
+	.long	13b,99b
+	.long	14b,99b
+	.long	15b,99b
+	.long	4b,99b
+	.long	16b,99b
+	.long	6b,99b
+	.long	17b,99b
+.text
+
+	.globl	__clear_user
+__clear_user:
+	addi	r6,r3,-4
+	li	r3,0
+	li	r5,0
+	cmplwi	0,r4,4
+	blt	7f
+11:	stwu	r5,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r4,r0,r4
+	subf	r6,r0,r6
+	rlwinm	r0,r4,32-2,2,31
+	mtctr	r0
+	bdz	6f
+1:	stwu	r5,4(r6)
+	bdnz	1b
+6:	andi.	r4,r4,3
+7:	cmpwi	0,r4,0
+	beqlr
+	mtctr	r4
+	addi	r6,r6,3
+8:	stbu	r5,1(r6)
+	bdnz	8b
+	blr
+99:	li	r3,-EFAULT
+	blr
+.section __ex_table,"a"
+	.align	2
+	.long	11b,99b
+	.long	1b,99b
+	.long	8b,99b
+.text
+
+	.globl	__strncpy_from_user
+__strncpy_from_user:
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+	cmpwi	0,r5,0
+	beq	2f
+	mtctr	r5
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	beq	3f
+2:	addi	r6,r6,1
+3:	subf	r3,r3,r6
+	blr
+99:	li	r3,-EFAULT
+	blr
+.section __ex_table,"a"
+	.align	2
+	.long	1b,99b
+.text
+
+	.globl	strlen_user
+strlen_user:
+	addi	r4,r3,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	bne	1b
+	subf	r3,r3,r4
+	addi	r3,r3,1
+	blr
+99:	li	r3,0
+	blr
+.section __ex_table,"a"
+	.align	2
+	.long	1b,99b
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mkdiff linux/arch/ppc/mkdiff
--- v2.1.47/linux/arch/ppc/mkdiff	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mkdiff	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+echo Diff of: $N against $N.ORIG '->' $N-$date-ppc.patch 
+diff -uNr -X $N/arch/ppc/ignore $N.ORIG $N > dist/$N-$date-ppc.patch
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mkdist linux/arch/ppc/mkdist
--- v2.1.47/linux/arch/ppc/mkdist	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mkdist	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+N=`basename $PWD`
+V=`echo $N | sed 's/linux-//'`
+date=`date +'%y%m%d'`
+mkdir -p ../dist
+mv zImage ../dist/zImage-$V-$date
+mv System.map ../dist/System.map-$V-$date
+
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mktar linux/arch/ppc/mktar
--- v2.1.47/linux/arch/ppc/mktar	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mktar	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+tar -zcf dist/ppc$N-$date.tar.gz -X $N/arch/ppc/ignore $N
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mm/Makefile linux/arch/ppc/mm/Makefile
--- v2.1.47/linux/arch/ppc/mm/Makefile	Mon May 27 02:00:59 1996
+++ linux/arch/ppc/mm/Makefile	Thu Jul 31 13:09:17 1997
@@ -14,7 +14,7 @@
 .c.s:
 	$(CC) $(CFLAGS) -S $<
 
-OBJS	= fault.o init.o
+OBJS	= fault.o init.o extable.o
 
 mm.o: $(OBJS)
 	$(LD) -r -o mm.o $(OBJS)
@@ -22,9 +22,9 @@
 modules:
 
 dep:
-	$(CPP) -M *.c > .depend
-	
+
 fastdep:
+	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
 
 #
 # include a dependency file if one exists
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c
--- v2.1.47/linux/arch/ppc/mm/extable.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/extable.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,57 @@
+/*
+ * linux/arch/ppc/mm/extable.c
+ *
+ * from linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+		 const struct exception_table_entry *last,
+		 unsigned long value)
+{
+        while (first <= last) {
+		const struct exception_table_entry *mid;
+		long diff;
+
+		mid = (last - first) / 2 + first;
+		diff = mid->insn - value;
+                if (diff == 0)
+                        return mid->fixup;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+	unsigned long ret;
+
+#if 1 /*ndef CONFIG_MODULES*/
+	/* There is only the kernel to search.  */
+	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+	if (ret) return ret;
+#else
+	/* The kernel is the last "module" -- no need to treat it special.  */
+	struct module *mp;
+	for (mp = module_list; mp != NULL; mp = mp->next) {
+		if (mp->ex_table_start == NULL)
+			continue;
+		ret = search_one_table(mp->ex_table_start,
+				       mp->ex_table_end - 1, addr);
+		if (ret) return ret;
+	}
+#endif
+
+	return 0;
+}
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.1.47/linux/arch/ppc/mm/fault.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/mm/fault.c	Thu Jul 31 13:09:17 1997
@@ -1,9 +1,14 @@
 /*
- *  ARCH/ppc/mm/fault.c
+ *  arch/ppc/mm/fault.c
  *
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *  Ported to PPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *  Modified by Cort Dougan and Paul Mackerras.
+ *
+ *  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.
  */
 
 #include <linux/config.h>
@@ -17,132 +22,151 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/interrupt.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/mmu_context.h>
 
-extern void die_if_kernel(char *, struct pt_regs *, long);
-extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void new_page_fault(unsigned long address, unsigned long code, unsigned long text,
-		    struct pt_regs *regs);
-
+#ifdef CONFIG_PMAC
+extern void (*xmon_fault_handler)(void);
+#endif
+
+/* the linux norm for the function name is show_regs() so
+   make it call dump_regs() on the mac -- Cort */
+#ifdef CONFIG_PMAC 
+#define show_regs dump_regs
+#endif
 
-#undef SHOW_FAULTS
-#undef NOISY_INSTRFAULT
-#undef NOISY_DATAFAULT
-
-unsigned int probingmem = 0;
-#define NEWMM 1
+extern void die_if_kernel(char *, struct pt_regs *, long);
+void bad_page_fault(struct pt_regs *, unsigned long);
+void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+void print_pte(struct _PTE);
 
-void new_page_fault(unsigned long address, unsigned long ppc_code,
-		    unsigned long text, struct pt_regs *regs)
+void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)     
 {
-  struct vm_area_struct * vma;
-  struct mm_struct *mm = current->mm;
-
-  int intel_code = 0;
-  pgd_t *dir;
-  pmd_t *pmd;
-  pte_t *pte;
-  
-  /*
-   *	bit 0 == 0 means no page found, 1 means protection fault
-   *	bit 1 == 0 means read, 1 means write
-   *	bit 2 == 0 means kernel, 1 means user-mode
-   */
-  if (user_mode(regs)) intel_code |= 0x04;
-  if (!text && (ppc_code & 0x02000000)) intel_code |= 0x02;  /* Load/store */
-  if (!text && (ppc_code & 0x08000000))
-  {
-    intel_code |= 0x01;  /* prot viol */
-    goto do_page;
-  }
-  
-  dir = pgd_offset(mm, address & PAGE_MASK);
-  if (dir)
-  {
-    pmd = pmd_offset(dir, address & PAGE_MASK);
-    if (pmd && pmd_present(*pmd))
-    {
-      pte = pte_offset(pmd, address & PAGE_MASK);
-      if (pte && pte_present(*pte))
-      {
-	MMU_hash_page(&current->tss, address & PAGE_MASK, pte);
-	return;
-      }
-    }
-  }
-
+	struct task_struct *tsk = current;
+	extern unsigned _end[];
+	struct vm_area_struct * vma;
+	struct mm_struct *mm = current->mm;
+	pgd_t *dir;
+	pmd_t *pmd;
+	pte_t *pte;
+	
+	/*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
+	       current->comm,current->pid,address,regs->nip,regs,error_code);*/
+#ifdef CONFIG_PMAC
+	if (xmon_fault_handler && regs->trap == 0x300) {
+		xmon_fault_handler();
+		return;
+	}
+#endif
+	if (in_interrupt()) {
+		static int complained;
+		if (complained < 20) {
+			++complained;
+			printk("page fault in interrupt handler, addr=%lx\n",
+			       address);
+			show_regs(regs);
+		}
+	}
+	if (current == NULL)
+		goto bad_area;
+	
 do_page:
-  down(&mm->mmap_sem);
-  vma = find_vma(current->mm, address);
-  if (!vma)
-    goto bad_area;
-  if (vma->vm_start <= address)
-    goto good_area;
-  if (!(vma->vm_flags & VM_GROWSDOWN))
-    goto bad_area;
-  if (expand_stack(vma, address))
-    goto bad_area;
+	down(&mm->mmap_sem);
+	vma = find_vma(tsk->mm, address);
+	if (!vma)
+		goto bad_area;
+	if (vma->vm_start <= address)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+	if (expand_stack(vma, address))
+		goto bad_area;
   
 good_area:
-  /* a write */
-  if (intel_code & 2) {
-    if (!(vma->vm_flags & VM_WRITE))
-    {
-      goto bad_area;
-    }
-  /* a read */
-  } else {
-    /* protection fault */
-    if (intel_code & 1)
-    {
-      printk("prot fault\n");
-      goto bad_area;
-    }
-    if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-    {
-      printk("no read or exec\n");      
-      goto bad_area; 
-    }
-  }
-  handle_mm_fault(vma, address, intel_code & 2);
-  up(&mm->mmap_sem);  flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */  
-  return;
+	if (error_code & 0xb5700000)
+		/* an error such as lwarx to I/O controller space,
+		   address matching DABR, eciwx, etc. */
+		goto bad_area;
+	
+	/* a write */
+	if (error_code & 0x02000000) {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	/* a read */
+	} else {
+		/* protection fault */
+		if ( error_code & 0x08000000 )
+			goto bad_area;
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+			goto bad_area;
+	}
+	handle_mm_fault(current, vma, address, error_code & 0x02000000);
+        up(&mm->mmap_sem);
+	/*printk("do_page_fault() return %s/%d addr %x msr %x\n",
+	      current->comm,current->pid,address,regs->msr);*/
+	/* not needed since flush_page_to_ram() works */
+#if 0
+	flush_page(address);
+#endif
+	return;
   
 bad_area:
-  up(&mm->mmap_sem);
+	up(&current->mm->mmap_sem);
+	bad_page_fault(regs, address);
+}
+
 
-  /* Did we have an exception handler installed? */
-  if(current->tss.excount != 0) {
-    if(user_mode(regs)) {
-      printk("Exception signalled from user mode!\n");
-    } else {
-#if 0      
-      printk("Exception from kernel mode. pc %x expc %x count %d\n",
-	     regs->nip,current->tss.expc,current->tss.excount);
-#endif      
-      current->tss.excount = 0;
-      regs->gpr[3] = -EFAULT;
-      regs->nip = current->tss.expc;
-      return;
-    }
-  }
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address)
+{
+	extern unsigned int probingmem;
+	struct task_struct *tsk = current;
+	unsigned long fixup;
+	
+	
+	/* Are we prepared to handle this fault?  */
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		if ( user_mode(regs) )
+			printk("Exception from user mode\n");
+#if 0    
+		printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
+#endif    
+		regs->nip = fixup;
+		return;
+	}
+
+	if ( user_mode(regs) )
+	{
+		force_sig(SIGSEGV, tsk);
+		return;
+	}
   
-  if (user_mode(regs))
-  {
-    force_sig(SIGSEGV, current);
-    return;
-  }
-  panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
-	regs->nip,address,vma->vm_flags);
+bad_kernel_access:
+	/* make sure it's not a bootup probe test */
+	if ( probingmem )
+	{
+		probingmem = 0;
+		return;
+	}
+	/* kernel has accessed a bad area */
+	show_regs(regs);
+	print_backtrace( regs->gpr[1] );
+#ifdef CONFIG_PMAC
+	xmon(regs);
+#endif
+	panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
+	      regs->nip,address,tsk->comm,tsk->pid);
 }
 
-va_to_phys(unsigned long address)
+unsigned long va_to_phys(unsigned long address)
 {
 	pgd_t *dir;
 	pmd_t *pmd;
 	pte_t *pte;
+	
 	dir = pgd_offset(current->mm, address & PAGE_MASK);
 	if (dir)
 	{
@@ -165,8 +189,28 @@
 	return (0);
 }
 
-inline void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t _pte)
+void print_pte(struct _PTE p)
+{
+	printk(
+"%08x %08x vsid: %06x h: %01x api: %02x rpn: %05x rcwimg: %d%d%d%d%d%d pp: %02x\n",
+		*((unsigned long *)(&p)), *((long *)&p+1),
+		p.vsid, p.h, p.api, p.rpn,
+		p.r,p.c,p.w,p.i,p.m,p.g,p.pp);
+}
+
+/*
+ * Search the hw hash table for a mapping to the given physical
+ * address. -- Cort
+ */
+unsigned long htab_phys_to_va(unsigned long address)
 {
-   MMU_hash_page(&current->tss, address & PAGE_MASK, (pte *)&_pte);
+	extern PTE *Hash, *Hash_end;
+	PTE *ptr;
+
+	for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
+	{
+		if ( ptr->rpn == (address>>12) )
+			printk("phys %08X -> va ???\n",
+			       address);
+	}
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.47/linux/arch/ppc/mm/init.c	Tue May 13 22:41:03 1997
+++ linux/arch/ppc/mm/init.c	Thu Jul 31 13:09:17 1997
@@ -1,9 +1,21 @@
 /*
  *  arch/ppc/mm/init.c
  *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *  Ported to PPC by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  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.
+ *
  */
 
 #include <linux/config.h>
@@ -18,57 +30,354 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/stddef.h>
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#endif
+#include <asm/io.h>
+#include <asm/mmu_context.h>
 #include <asm/pgtable.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_PREP
 #include <asm/residual.h>
+#endif
 
-extern pgd_t swapper_pg_dir[1024];
-extern unsigned long empty_zero_page[1024];
+int next_mmu_context;
+extern pgd_t swapper_pg_dir[];
+extern char _start[], _end[];
+extern char etext[], _stext[];
+/* References to section boundaries */
+extern char __init_begin, __init_end;
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
-void flush_hash_table(void);
+extern unsigned long *find_end_of_memory(void);
 
-#undef HASHSTATS
+#undef MAP_RAM_WITH_SEGREGS 1
 
-unsigned long _SDR1;		/* Hardware SDR1 image */
-PTE *Hash;
-int Hash_size, Hash_mask;
+#ifdef CONFIG_PMAC
+void *find_mem_piece(unsigned, unsigned);
+static void mapin_ram(void);
+static void inherit_prom_translations(void);
+#endif
+#ifdef CONFIG_PREP
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
+int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);     
+#endif
+
+static void hash_init(void);
+static void *MMU_get_page(void);
+void map_page(struct thread_struct *, unsigned long va,
+		     unsigned long pa, int flags);
+
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
 unsigned long *end_of_DRAM;
-int cache_is_copyback = 1;
-int kernel_pages_are_copyback = 1;
-/* Note: these need to be in 'data' so they live over the boot */
-unsigned char *BeBox_IO_page = 0;
-unsigned long isBeBox[2] = {0, 0};
+int mem_init_done;
 
+#ifdef CONFIG_PREP
 #ifdef HASHSTATS
-extern unsigned long *hashhits;
-#endif
-
+extern unsigned long evicts;
+#endif /* HASHSTATS */
+/*
+ * these are used to setup the initial page tables
+ * They can waste up to an entire page since the
+ * I'll fix this shortly -- Cort
+ */
+#define MAX_MMU_PAGES	16
+unsigned int probingmem = 0;
+unsigned int mmu_pages_count = 0;
+char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
+unsigned long _TotalMemory;
+#endif /* CONFIG_PREP */
 
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+unsigned long empty_bad_page_table;
 
 pte_t * __bad_pagetable(void)
 {
-	panic("__bad_pagetable");
+	memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+	return (pte_t *) empty_bad_page_table;
 }
 
+unsigned long empty_bad_page;
+
 pte_t __bad_page(void)
 {
-	panic("__bad_page");
+	memset((void *)empty_bad_page, 0, PAGE_SIZE);
+	return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
 }
 
+#ifdef CONFIG_PMAC
+#define MAX_MEM_REGIONS	32
+phandle memory_pkg;
+
+struct mem_pieces {
+	int n_regions;
+	struct reg_property regions[MAX_MEM_REGIONS];
+};
+
+struct mem_pieces phys_mem;
+struct mem_pieces phys_avail;
+struct mem_pieces prom_mem;
+
+static void get_mem_prop(char *, struct mem_pieces *);
+static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+static void print_mem_pieces(struct mem_pieces *);
+
+unsigned long avail_start;
+int prom_trashed;
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+static void
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+	int s, i;
+
+	s = (int) call_prom("getprop", 4, 1, memory_pkg, name,
+			    mp->regions, sizeof(mp->regions));
+	if (s < sizeof(mp->regions[0])) {
+		printk("getprop /memory %s returned %d\n", name, s);
+		abort();
+	}
+	mp->n_regions = s / sizeof(mp->regions[0]);
+
+	/*
+	 * Make sure the pieces are sorted.
+	 */
+	for (i = 1; i < mp->n_regions; ++i) {
+		unsigned long a, s;
+		int j;
+
+		a = mp->regions[i].address;
+		s = mp->regions[i].size;
+		for (j = i - 1; j >= 0; --j) {
+			if (a >= mp->regions[j].address)
+				break;
+			mp->regions[j+1] = mp->regions[j];
+		}
+		mp->regions[j+1].address = a;
+		mp->regions[j+1].size = s;
+	}
+}
+
+/*
+ * Remove some memory from an array of pieces
+ */
+static void
+remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size,
+		 int must_exist)
+{
+	int i, j;
+	unsigned end, rs, re;
+	struct reg_property *rp;
+
+	end = start + size;
+	for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
+		if (end > rp->address && start < rp->address + rp->size)
+			break;
+	}
+	if (i >= mp->n_regions) {
+		if (must_exist)
+			printk("remove_mem_piece: [%x,%x) not in any region\n",
+			       start, end);
+		return;
+	}
+	for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
+		rs = rp->address;
+		re = rs + rp->size;
+		if (must_exist && (start < rs || end > re)) {
+			printk("remove_mem_piece: bad overlap [%x,%x) with",
+			       start, end);
+			print_mem_pieces(mp);
+			must_exist = 0;
+		}
+		if (start > rs) {
+			rp->size = start - rs;
+			if (end < re) {
+				/* need to split this entry */
+				if (mp->n_regions >= MAX_MEM_REGIONS)
+					panic("eek... mem_pieces overflow");
+				for (j = mp->n_regions; j > i + 1; --j)
+					mp->regions[j] = mp->regions[j-1];
+				++mp->n_regions;
+				rp[1].address = end;
+				rp[1].size = re - end;
+			}
+		} else {
+			if (end < re) {
+				rp->address = end;
+				rp->size = re - end;
+			} else {
+				/* need to delete this entry */
+				for (j = i; j < mp->n_regions - 1; ++j)
+					mp->regions[j] = mp->regions[j+1];
+				--mp->n_regions;
+				--i;
+				--rp;
+			}
+		}
+	}
+}
+
+static void
+print_mem_pieces(struct mem_pieces *mp)
+{
+	int i;
+
+	for (i = 0; i < mp->n_regions; ++i)
+		printk(" [%x, %x)", mp->regions[i].address,
+		       mp->regions[i].address + mp->regions[i].size);
+	printk("\n");
+}
+
+void *
+find_mem_piece(unsigned size, unsigned align)
+{
+	int i;
+	unsigned a, e;
+	struct mem_pieces *mp = &phys_avail;
+
+	for (i = 0; i < mp->n_regions; ++i) {
+		a = mp->regions[i].address;
+		e = a + mp->regions[i].size;
+		a = (a + align - 1) & -align;
+		if (a + size <= e) {
+			remove_mem_piece(mp, a, size, 1);
+			return __va(a);
+		}
+	}
+	printk("Couldn't find %u bytes at %u alignment\n", size, align);
+	abort();
+	return NULL;
+}
+
+/*
+ * Collect information about RAM and which pieces are already in use.
+ * At this point, we have the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long *find_end_of_memory(void)
+{
+	unsigned long a, total;
+	unsigned long h, kstart, ksize;
+	extern char _stext[], _end[];
+	int i;
+
+	memory_pkg = call_prom("finddevice", 1, 1, "/memory");
+	if (memory_pkg == (void *) -1)
+		panic("can't find memory package");
+
+	/*
+	 * Find out where physical memory is, and check that it
+	 * starts at 0 and is contiguous.  It seems that RAM is
+	 * always physically contiguous on Power Macintoshes,
+	 * because MacOS can't cope if it isn't.
+	 */
+	get_mem_prop("reg", &phys_mem);
+	if (phys_mem.n_regions == 0)
+		panic("No RAM??");
+	a = phys_mem.regions[0].address;
+	if (a != 0)
+		panic("RAM doesn't start at physical address 0");
+	total = phys_mem.regions[0].size;
+	for (i = 1; i < phys_mem.n_regions; ++i) {
+		a = phys_mem.regions[i].address;
+		if (a != total) {
+			printk("RAM starting at 0x%lx is not contiguous\n", a);
+			printk("Using RAM from 0 to 0x%lx\n", total-1);
+			phys_mem.n_regions = i;
+			break;
+		}
+		total += phys_mem.regions[i].size;
+	}
+
+	/* record which bits the prom is using */
+	get_mem_prop("available", &phys_avail);
+	prom_mem = phys_mem;
+	for (i = 0; i < phys_avail.n_regions; ++i)
+		remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
+				 phys_avail.regions[i].size, 1);
+
+	/*
+	 * phys_avail records memory we can use now.
+	 * prom_mem records memory allocated by the prom that we
+	 * don't want to use now, but we'll reclaim later.
+	 * Make sure the kernel text/data/bss is in neither.
+	 */
+	kstart = __pa(_stext);	/* should be 0 */
+	ksize = PAGE_ALIGN(_end - _stext);
+	remove_mem_piece(&phys_avail, kstart, ksize, 0);
+	remove_mem_piece(&prom_mem, kstart, ksize, 0);
+
+	/*
+	 * Allow 64k of hash table for every 16MB of memory,
+	 * up to a maximum of 2MB.
+	 */
+	for (h = 64<<10; h < total / 256 && h < 2<<20; h *= 2)
+		;
+	Hash_size = h;
+	Hash_mask = (h >> 6) - 1;
+
+	/* Find some memory for the hash table. */
+	Hash = find_mem_piece(Hash_size, Hash_size);
+	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+	       total >> 20, Hash_size >> 10, Hash);
+
+	return __va(total);
+}
+
+/*
+ * Find some memory for setup_arch to return.
+ * We use the last chunk of available memory as the area
+ * that setup_arch returns, making sure that there are at
+ * least 32 pages unused before this for MMU_get_page to use.
+ */
+unsigned long find_available_memory(void)
+{
+	int i;
+	unsigned long a, free;
+	unsigned long start, end;
+
+	free = 0;
+	for (i = 0; i < phys_avail.n_regions - 1; ++i) {
+		start = phys_avail.regions[i].address;
+		end = start + phys_avail.regions[i].size;
+		free += (end & PAGE_MASK) - PAGE_ALIGN(start);
+	}
+	a = PAGE_ALIGN(phys_avail.regions[i].address);
+	if (free < 32 * PAGE_SIZE)
+		a += 32 * PAGE_SIZE - free;
+	avail_start = (unsigned long) __va(a);
+	return avail_start;
+}
+#endif /* CONFIG_PMAC */
+
 void show_mem(void)
 {
+	int i,free = 0,total = 0,reserved = 0;
+	int shared = 0;
 	struct task_struct *p;
-	unsigned long i,free = 0,total = 0,reserved = 0;
-	unsigned long shared = 0;
-	PTE *ptr;
-	unsigned long full = 0, overflow = 0;
-	unsigned int ti;
 
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	i = MAP_NR(high_memory);
+	i = max_mapnr;
 	while (i-- > 0) {
 		total++;
 		if (PageReserved(mem_map+i))
@@ -78,105 +387,185 @@
 		else
 			shared += atomic_read(&mem_map[i].count) - 1;
 	}
-	printk("%lu pages of RAM\n",total);
-	printk("%lu free pages\n",free);
-	printk("%lu reserved pages\n",reserved);
-	printk("%lu pages shared\n",shared);
+	printk("%d pages of RAM\n",total);
+	printk("%d free pages\n",free);
+	printk("%d reserved pages\n",reserved);
+	printk("%d pages shared\n",shared);
 	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
-#ifdef HASHSTATS
-	printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
-	for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
-		if ( hashhits[i] >= 20 )
-			printk("[%lu] \t %lu\n", i,hashhits[i]);
-	}
-#endif
-  
-	for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
-		if (ptr->v) {
-			full++;
-			if (ptr->h == 1)
-				overflow++;
-		}
+	printk("%-8s %3s %3s %8s %8s %8s %9s %8s\n", "Process", "Pid", "Cnt",
+	       "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
+	for_each_task(p)
+	{	
+		printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+		       p->comm,p->pid,
+		       p->mm->count,p->mm->context,
+		       p->mm->context<<4, p->tss.last_syscall,
+		       user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
+		       p);
+		if ( p == current )
+			printk(" current");
+		printk("\n");
 	}
-	printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
-	       Hash_size>>10,	(Hash_size/(sizeof(PTE)*8)) >> 10,
-	       full,Hash_size/sizeof(PTE),
-	       (full*100)/(Hash_size/sizeof(PTE)),
-	       overflow);
-	printk(" Task  context    vsid0\n");
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		printk("%5d %8x %8x\n",
-		       p->pid,p->mm->context,
-		       ((SEGREG *)p->tss.segs)[0].vsid);
-	}
-	read_unlock(&tasklist_lock);
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
+/*
+ * paging_init() sets up the page tables - in fact we've already done this.
+ */
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-	return free_area_init(start_mem, end_mem);
+	/*
+	 * Grab some memory for bad_page and bad_pagetable to use.
+	 */
+	empty_bad_page = start_mem;
+	empty_bad_page_table = start_mem + PAGE_SIZE;
+	start_mem += 2 * PAGE_SIZE;
+
+	/* note: free_area_init uses its second argument
+	   to size the mem_map array. */
+	start_mem = free_area_init(start_mem, end_mem);
+	return start_mem;
 }
 
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
-  int codepages = 0;
-  int datapages = 0;
-  unsigned long tmp;
-  extern int etext;
+	unsigned long addr;
+#ifdef CONFIG_PMAC
+	int i;
+	unsigned long lim;
+#endif
+	int codepages = 0;
+	int datapages = 0;
+	int initpages = 0;
+
+	end_mem &= PAGE_MASK;
+	high_memory = (void *) end_mem;
+	num_physpages = max_mapnr = MAP_NR(high_memory);
 	
-  end_mem &= PAGE_MASK;
-  high_memory = (void *)end_mem;
-  max_mapnr = MAP_NR(end_mem);
-  /* clear the zero-page */
-  memset(empty_zero_page, 0, PAGE_SIZE);
+	/* clear the zero-page */
+	memset(empty_zero_page, 0, PAGE_SIZE);
 	
 	/* mark usable pages in the mem_map[] */
-  start_mem = PAGE_ALIGN(start_mem);
+	start_mem = PAGE_ALIGN(start_mem);
+	
+#ifdef CONFIG_PMAC
+	remove_mem_piece(&phys_avail, __pa(avail_start),
+			 start_mem - avail_start, 1);
+
+	for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
+		set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+
+	for (i = 0; i < phys_avail.n_regions; ++i) {
+		a = (unsigned long) __va(phys_avail.regions[i].address);
+		lim = a + phys_avail.regions[i].size;
+		a = PAGE_ALIGN(a);
+		for (; a < lim; a += PAGE_SIZE) {
+			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+			mem_map[MAP_NR(a)].count = 1;
+			free_page(a);
+		}
+	}
+	phys_avail.n_regions = 0;
 
-  for (tmp = KERNELBASE ; tmp < (long)high_memory ; tmp += PAGE_SIZE)
-    {
-      if (tmp < start_mem)
-	{
-	  set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-	  if (tmp < (unsigned long) &etext)
-	    {
-	      codepages++;
-	    } else
-	      {
-		datapages++;
-	      }
-	  continue;
-	}
-      clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-      atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
-      free_page(tmp);
-    }
-  tmp = nr_free_pages << PAGE_SHIFT;
-  printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
-	 tmp >> 10,
-	 ((int)high_memory - (int)KERNELBASE) >> 10,
-	 codepages << (PAGE_SHIFT-10),
-	 datapages << (PAGE_SHIFT-10));
-  /*	invalidate();*/
-  return;
+	/* free the prom's memory */
+	for (i = 0; i < prom_mem.n_regions; ++i) {
+		a = (unsigned long) __va(prom_mem.regions[i].address);
+		lim = a + prom_mem.regions[i].size;
+		a = PAGE_ALIGN(a);
+		for (; a < lim; a += PAGE_SIZE) {
+			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+			mem_map[MAP_NR(a)].count = 1;
+			free_page(a);
+		}
+	}
+	prom_trashed = 1;
+#endif /* CONFIG_PMAC */
+
+#ifdef CONFIG_PREP
+	/* mark mem used by kernel as reserved, mark other unreserved */
+	for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+	{
+		/* skip hash table gap */
+		if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+			continue;
+		if ( addr < (ulong) /*Hash_end*/ start_mem )
+			set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+		else
+			clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+	}
+
+	for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+		if(PageReserved(mem_map + MAP_NR(addr))) {
+			if (addr < (ulong) etext)
+				codepages++;
+			/*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+                                initpages++;*/
+                        else if (addr < (ulong) start_mem)
+				datapages++;
+			continue;
+		}
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (!initrd_start ||
+		    (addr < initrd_start || addr >= initrd_end))
+#endif /* CONFIG_BLK_DEV_INITRD */
+			free_page(addr);
+	}
+	
+#endif /* CONFIG_PREP */
+        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+	       (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+	       codepages << (PAGE_SHIFT-10),
+	       datapages << (PAGE_SHIFT-10), 
+	       initpages << (PAGE_SHIFT-10),
+	       PAGE_OFFSET, end_mem);
+	mem_init_done = 1;
 }
 
+/*
+ * this should reclaim gap between _end[] and hash table
+ * as well as unused mmu_pages[] on prep systems.
+ * When I get around to it, I'll put initialization functions
+ * (called only at boot) in their own .section and free that -- Cort
+ */
 void free_initmem(void)
 {
-	/* To be written */
+	unsigned long addr;
+	unsigned long a;
+	unsigned long num_freed_pages = 0;
+
+	/* free unused mmu_pages[] */
+	a = PAGE_ALIGN( (unsigned long) mmu_pages) + (mmu_pages_count*PAGE_SIZE);
+	for ( ; a < PAGE_ALIGN((unsigned long)mmu_pages)+(MAX_MMU_PAGES*PAGE_SIZE); a += PAGE_SIZE )
+	{
+		clear_bit( PG_reserved, &mem_map[MAP_NR(a)].flags );
+		atomic_set(&mem_map[MAP_NR(a)].count, 1);
+		free_page(a);
+		num_freed_pages++;
+	}
+
+#if 0
+	addr = (unsigned long)(&__init_begin);
+	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+		num_freed_pages++;
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		mem_map[MAP_NR(addr)].count = 1;
+		free_page(addr);
+	}
+#endif	
+	printk ("Freeing unused kernel memory: %dk freed\n",
+		(num_freed_pages * PAGE_SIZE) >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
 {
 	int i;
 
-	i = ((int)high_memory & 0x00FFFFFF) >> PAGE_SHIFT;
+	i = max_mapnr;
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
@@ -187,526 +576,637 @@
 		val->totalram++;
 		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += atomic_read(&mem_map[i].count) - 1;
+		val->sharedram += atomic_read(&mem_map[i].count)-1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
 	return;
 }
 
+/* Kernel MMU setup & lowest level hardware support */
+
+unsigned long _SDR1;		/* Hardware SDR1 image */
+
+#ifdef CONFIG_PREP
+
 BAT BAT0 =
-   {
-   	{
-   		0x80000000>>17, 	/* bepi */
-   		BL_256M,		/* bl */
-   		1,			/* vs -- supervisor mode valid */
-   		1,			/* vp -- user mode valid */
-   	},
-   	{
-   		0x80000000>>17,		/* brpn */
-   		1,			/* write-through */
-   		1,			/* cache-inhibited */
-   		0,			/* memory coherence */
-   		1,			/* guarded */
-   		BPP_RW			/* protection */
-   	}
-   };
+{
+  {
+    0x80000000>>17, 	/* bepi */
+    BL_256M,		/* bl */
+    1,			/* vs -- supervisor mode valid */
+    1,			/* vp -- user mode valid */
+  },
+  {
+    0x80000000>>17,		/* brpn */
+    1,			/* write-through */
+    1,			/* cache-inhibited */
+    0,			/* memory coherence */
+    1,			/* guarded */
+    BPP_RW		/* protection */
+  }
+};
 BAT BAT1 =
-   {
-   	{
-   		0xC0000000>>17, 	/* bepi */
-   		BL_256M,		/* bl */
-   		1,			/* vs */
-   		1,			/* vp */
-   	},
-   	{
-   		0xC0000000>>17,		/* brpn */
-   		1,			/* w */
-   		1,			/* i (cache disabled) */
-   		0,			/* m */
-   		1,			/* g */
-   		BPP_RW			/* pp */
-   	}
-   };
+{
+  {
+    0xC0000000>>17, 	/* bepi */
+    BL_256M,		/* bl */
+    1,			/* vs */
+    1,			/* vp */
+  },
+  {
+    0xC0000000>>17,		/* brpn */
+    1,			/* w */
+    1,			/* i (cache disabled) */
+    0,			/* m */
+    1,			/* g */
+    BPP_RW			/* pp */
+  }
+};
 BAT BAT2 =
-   {
-   	{
-   		0x90000000>>17, 	/* bepi */
-		BL_256M, /* this gets set to amount of phys ram */
-   		1,			/* vs */
-   		0,			/* vp */
-   	},
-   	{
-   		0x00000000>>17,		/* brpn */
-   		0,			/* w */
-   		0,			/* i */
-   		0,			/* m */
-   		0,			/* g */
-   		BPP_RW			/* pp */
-   	}
-   };
+{
+  {
+    0x90000000>>17, 	/* bepi */
+    BL_256M, /* this gets set to amount of phys ram */
+    1,			/* vs */
+    0,			/* vp */
+  },
+  {
+    0x00000000>>17,		/* brpn */
+    0,			/* w */
+    0,			/* i */
+    1,			/* m */
+    0,			/* g */
+    BPP_RW			/* pp */
+  }
+};
 BAT BAT3 =
-   {
-   	{
-   		0x00000000>>17, 	/* bepi */
-   		BL_256M,		/* bl */
-   		0,			/* vs */
-   		0,			/* vp */
-   	},
-   	{
-   		0x00000000>>17,		/* brpn */
-   		1,			/* w */
-   		1,			/* i (cache disabled) */
-   		0,			/* m */
-   		0,			/* g */
-   		BPP_RW			/* pp */
-   	}
-   };
-BAT TMP_BAT2 =
-   { /* 0x9XXXXXXX -> 0x0XXXXXXX */
-   	{
-   		0x90000000>>17, 	/* bepi */
-   		BL_256M,		/* bl */
-   		1,			/* vs */
-   		1,			/* vp */
-   	},
-   	{
-   		0x00000000>>17,		/* brpn */
-   		1,			/* w */
-   		0,			/* i (cache enabled) */
-   		0,			/* m */
-   		0,			/* g */
-   		BPP_RW			/* pp */
-   	}
-   };
-
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/*
- * This code is called to create a minimal mapped environment.
- * It is called with the MMU on, but with only a BAT register
- * set up to cover the code/data.  After this routine runs,
- * the BAT mapping is withdrawn and all mappings must be complete.
- */
+{
+  {
+    0x00000000>>17, 	/* bepi */
+    BL_256M,		/* bl */
+    0,			/* vs */
+    0,			/* vp */
+  },
+  {
+    0x00000000>>17,		/* brpn */
+    0,			/* w */
+    0,			/* i (cache disabled) */
+    1,			/* m */
+    0,			/* g */
+    BPP_RW			/* pp */
+  }
+};
 
+P601_BAT BAT0_601 =
+{
+  {
+    0x80000000>>17, 	/* bepi */
+    1,1,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0x80000000>>17,		/* brpn */
+    1, /* v */
+    BL_8M, /* bl */
+  }
+};
 
+P601_BAT BAT1_601 =
+{
+  {
+    0xC0000000>>17, 	/* bepi */
+    1,1,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0xC0000000>>17,		/* brpn */
+    1, /* v */
+    BL_8M, /* bl */
+  }
+};
 
+P601_BAT BAT2_601 =
+{
+  {
+    0x90000000>>17, 	/* bepi */
+    0,0,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0x00000000>>17,		/* brpn */
+    1, /* v */
+    BL_8M, /* bl */
+  }
+};
 
-extern char _start[], _end[];
- 
-void MMU_init(void)
+P601_BAT BAT3_601 =
 {
-  extern RESIDUAL res;
-  extern unsigned long resptr;
-  int i, p;
-  SEGREG *segs;
-  
-  /* copy residual data */
-  if ( resptr )
-    memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
-  else
-    bzero( &res, sizeof(RESIDUAL) ); /* clearing bss probably clears this but... */
-  
-  end_of_DRAM = (unsigned long *)find_end_of_memory();
-  _SDR1 = ((unsigned long)Hash - KERNELBASE) | Hash_mask;
-#if 0	
-  printk("Hash      %08x\n",(unsigned long)Hash);
-  printk("Hash_mask %08x\n",Hash_mask);
-  printk("Hash_size %08x\n",Hash_size);	
-  printk("SDR1      %08x\n",_SDR1);
-#endif
-  /* Segment registers */
-  segs = (SEGREG *)init_task.tss.segs;
-  for (i = 0;  i < 16;  i++)
-  {
-    segs[i].ks = 0;
-    segs[i].kp = 1;
-#if 1
-    if ( i < 8 )
-      segs[i].vsid = i+10000;
-    else
-#else
-    if ( i < 8 )
-      segs[i].vsid = i<<5;
-#endif		  
-      segs[i].vsid = i;
+  {
+    0x90800000>>17, 	/* bepi */
+    0,0,0, /* wim */
+    1, 0, /* vs, vp */
+    BPP_RW, /* pp */
+  },
+  {
+    0x00800000>>17,		/* brpn */
+    1, /* v */
+    BL_8M, /* bl */
   }
-  
-  
-	
-  /* Hard map in any special local resources */
-  if (isBeBox[0])
-    {
-      /* Map in one page for the BeBox motherboard I/O */
-      end_of_DRAM = (unsigned long *)((unsigned long)end_of_DRAM - PAGE_SIZE);
-#if 0		
-      BeBox_IO_page = (unsigned char *)0x7FFFF000;
-#endif
-		BeBox_IO_page = (unsigned char *)end_of_DRAM;
-		MMU_disable_cache_for_page(&init_task.tss, BeBox_IO_page);
-    }
-}
+};
 
 /*
- * Insert(create) a hardware page table entry
+ * This finds the amount of physical ram and does necessary
+ * setup for prep.  This is pretty architecture specific so
+ * this will likely stay seperate from the pmac.
+ * -- Cort
  */
-int inline MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg)
+unsigned long *find_end_of_memory(void)
 {
-  int hash, page_index, segment, i, h, _h, api, vsid, perms;
-  PTE *_pte, *empty, *slot;
-  PTE *slot0, *slot1;
-  extern char _etext;
-  page_index = ((int)va & 0x0FFFF000) >> 12;
-  segment = (unsigned int)va >> 28;
-  api = page_index >> 10;
-  vsid = ((SEGREG *)tss->segs)[segment].vsid;
-  empty = slot = (PTE *)NULL;
+	extern RESIDUAL res;
+	extern unsigned long resptr;
+	int i, p;
+	unsigned long h;
+
+	/* copy residual data */
+	if ( resptr )
+		memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
+	else
+		/* clearing bss probably clears this but... */
+		memset( &res, sizeof(RESIDUAL), 0 );
+	_TotalMemory = res.TotalMemory;
+	
+	/* this really has nothing to do with the mmu_init() but is
+	   necessary for early setup -- Cort */
+	if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+	{
+		_machine = _MACH_IBM;
+	}
+	else
+		_machine = _MACH_Motorola;
   
-  if ( (va <= _etext) && (va >= KERNELBASE))
-  {
-    printk("MMU_hash_page: called on kernel page mapped with bats va %x\n",
-	   va);
-  }
-
-  /* check first hash bucket */
-  h = 0;
-  hash = page_index ^ vsid;
-  hash &= 0x3FF | (Hash_mask << 10);
-  hash *= 8;			/* 8 entries in each bucket */
-  _pte = &Hash[hash];
-  slot0 = _pte;
-  for (i = 0;  i < 8;  i++, _pte++)
-    {
-      if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+	/* setup the hash table */
+	if (_TotalMemory == 0 )
 	{
-	  slot = _pte;
-	  goto found_it;
+		/*
+		 * I need a way to probe the amount of memory if the residual
+		 * data doesn't contain it. -- Cort
+		 */
+		printk("Ramsize from residual data was 0 -- Probing for value\n");
+		_TotalMemory = 0x03000000;
+		printk("Ramsize default to be %dM\n", _TotalMemory>>20);
 	}
-      if ((empty == NULL) && (!_pte->v))
+	
+#if 0
+	/* linux has trouble with > 64M ram -- Cort */
+	if ( _TotalMemory > 0x04000000 /* 64M */ )
 	{
-	  empty = _pte;
-	  _h = h;
+		printk("Only using first 64M of ram.\n");
+		_TotalMemory = 0x04000000;
 	}
-    }
-
-  /* check second hash bucket */
-  h = 1;
-  hash = page_index ^ vsid;
-  hash = ~hash;
-  hash &= 0x3FF | (Hash_mask << 10);
-  hash *= 8;			/* 8 entries in each bucket */
-  _pte = &Hash[hash];
-  slot1 = _pte;
-  for (i = 0;  i < 8;  i++, _pte++)
-    {
-      if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+#endif	
+	
+	/* setup the bat2 mapping to cover physical ram */
+	BAT2.batu.bl = 0x1; /* 256k mapping */
+	for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+	      h *= 2 )
+		BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
+	/*
+	 * Allow 64k of hash table for every 16MB of memory,
+	 * up to a maximum of 2MB.
+	 */
+	for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+		;
+	Hash_size = h;
+	Hash_mask = (h >> 6) - 1;
+	
+	/* align htab on a Hash_size boundry above _end[] */
+	Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
+	memset(Hash, Hash_size, 0 );
+
+	/*
+	 * if this is a 601, we can only map sizes of 8M with the BAT's
+	 * so we have to map what we can't map with the bats with the segregs
+	 * head.S will copy in the appropriate BAT's according to the processor
+	 * since the 601_BAT{2,3} structures are already setup to map
+	 * the first 16M correctly
+	 * -- Cort
+	 */
+#ifndef MAP_RAM_WITH_SEGREGS     /* don't need to do it twice */
+	if ( _get_PVR() == 1 )
 	{
-	  slot = _pte;
-	  goto found_it;
+		/* map in rest of ram with seg regs */
+		if ( _TotalMemory > 0x01000000 /* 16M */)
+		{
+			for (i = KERNELBASE+0x01000000;
+			     i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
+				map_page(&init_task.tss, i, __pa(i),
+					 _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+		}
 	}
-      if ((empty == NULL) && (!_pte->v))
+#endif /* MAP_RAM_WITH_SEGREGS */
+  
+#ifdef MAP_RAM_WITH_SEGREGS
+	/* turn off bat mapping kernel since being done with segregs */
+	memset(&BAT2, sizeof(BAT2), 0);
+	memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
+	memset(&BAT3_601, sizeof(BAT2), 0);
+	/* map all of ram for kernel with segregs */
+	for (i = KERNELBASE;  i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
 	{
-	  empty = _pte;
-	  _h = h;
+		if ( i < (unsigned long)etext )
+			map_page(&init_task.tss, i, __pa(i),
+				 _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
+		else
+			map_page(&init_task.tss, i, __pa(i),
+				 _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
 	}
-    }
-
-  if (empty == (PTE *)NULL)
-  { 
-#if 1
-    printk("Both hash buckets full! va %x vsid %x current %s (%d)\n",
-	   va,vsid,current->comm,current->pid);
-#endif
-    slot = slot1;
-    h = 1;
-  }
-  else
-  {
-    slot = empty;
-    h = _h;
-  }
-found_it:
-#ifdef HASHSTATS
-  hashhits[hash]++;
-#endif
-  _tlbie(va); /* Clear TLB */
-    /* Fill in table */
-      slot->v = 1;
-      slot->vsid = vsid;
-      slot->h = h;
-      slot->api = api;
-      if (((pg->page_num << 12) & 0xF0000000) == KERNELBASE)
-	{
-	  slot->rpn = pg->page_num - (KERNELBASE>>12);
-	} else
-	  {
-	    slot->rpn = pg->page_num;
-	  }
-      slot->r = 0;
-      slot->c = 0;
-      slot->i = 0;
-      slot->g = 0;
-      if (cache_is_copyback)
-	{
-	  if (kernel_pages_are_copyback || (pg->flags & _PAGE_USER) || (va < (unsigned long)&_etext))
-	    { /* All User & Kernel TEXT pages are copy-back */
-	      slot->w = 0;
-	      slot->m = 1;
-	    } else
-	      { /* Kernel DATA pages are write-thru */
-		slot->w = 1;
-		slot->m = 0;
-	      }
-	} else
-	  {
-	    slot->w = 1;
-	    slot->m = 0;
-	  }
-      if (pg->flags & _PAGE_USER)
-	{
-	  if (pg->flags & _PAGE_RW)
-	    { /* Read/write page */
-	      perms = PP_RWRW;
-	    } else
-	      { /* Read only page */
-		perms = PP_RWRX;
-		perms = PP_RXRX;
-	      }
-	} else
-	  { /* Kernel pages */
-	    perms = PP_RWRW;
-	    perms = PP_RWXX;
-	  }
-      slot->pp = perms;
-      return (0);
+#endif /* MAP_RAM_WITH_SEGREGS */
+	
+	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+	       _TotalMemory >> 20, Hash_size >> 10, Hash);
+	return ((unsigned long *)_TotalMemory);
 }
+#endif /* CONFIG_PREP */
 
+
+#ifdef CONFIG_PMAC
 /*
- * Disable cache for a particular page
+ * Map in all of physical memory starting at KERNELBASE.
  */
-MMU_disable_cache_for_page(struct thread_struct *tss, unsigned long va)
+extern int n_mem_regions;
+extern struct reg_property mem_regions[];
+
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+static void mapin_ram()
 {
-	int hash, page_index, segment, i, h, _h, api, vsid, perms;
-	PTE *_pte, *empty, *slot;
-	PTE *slot0, *slot1;
-	extern char _etext;
-	page_index = ((int)va & 0x0FFFF000) >> 12;
-	segment = (unsigned int)va >> 28;
-	api = page_index >> 10;
-	vsid = ((SEGREG *)tss->segs)[segment].vsid;
-	empty = slot = (PTE *)NULL;
-	for (_h = 0;  _h < 2;  _h++)
-	{
-		hash = page_index ^ vsid;		
-		if (_h)
-		{
-			hash = ~hash;  /* Secondary hash uses ones-complement */
-		}
-		hash &= 0x3FF | (Hash_mask << 10);
-		hash *= 8;  /* Eight entries / hash bucket */
-		_pte = &Hash[hash];
-		/* Save slot addresses in case we have to purge */
-		if (_h)
-		{
-			slot1 = _pte;
-		} else
-		{
-			slot0 = _pte;
-		}
-		for (i = 0;  i < 8;  i++, _pte++)
-		{
-			if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-			{ /* Found it! */
-				h = _h;
-				slot = _pte;
-				goto found_it;
-			}
-			if ((empty == (PTE *)NULL) && !_pte->v)
-			{
-				h = _h;
-				empty = _pte;
-			}
-		}
+    int i;
+    unsigned long v, p, s, f;
+
+    v = KERNELBASE;
+    for (i = 0; i < phys_mem.n_regions; ++i) {
+	p = phys_mem.regions[i].address;
+	for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+	    f = _PAGE_PRESENT | _PAGE_ACCESSED;
+	    if ((char *) v < _stext || (char *) v >= etext)
+		f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+	    map_page(&init_task.tss, v, p, f);
+	    v += PAGE_SIZE;
+	    p += PAGE_SIZE;
 	}
-found_it:	
-	_tlbie(va); /* Clear TLB */
-	slot->i = 1;
-	slot->m = 0;
+    }
 }
 
+#define MAX_PROM_TRANSLATIONS	64
+
+static struct translation_property prom_translations[MAX_PROM_TRANSLATIONS];
+int n_translations;
+phandle mmu_pkg;
+extern ihandle prom_chosen;
+
+static void inherit_prom_translations()
+{
+	int s, i, f;
+	unsigned long v, p, n;
+	struct translation_property *tp;
+	ihandle mmu_inst;
+
+	if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+			    &mmu_inst, sizeof(mmu_inst)) != sizeof(mmu_inst))
+		panic("couldn't get /chosen mmu property");
+	mmu_pkg = call_prom("instance-to-package", 1, 1, mmu_inst);
+	if (mmu_pkg == (phandle) -1)
+		panic("couldn't get mmu package");
+	s = (int) call_prom("getprop", 4, 1, mmu_pkg, "translations",
+			    &prom_translations, sizeof(prom_translations));
+	if (s < sizeof(prom_translations[0]))
+		panic("couldn't get mmu translations property");
+	n_translations = s / sizeof(prom_translations[0]);
+
+	for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
+		/* ignore stuff mapped down low */
+		if (tp->virt < 0x10000000)
+			continue;
+		/* map PPC mmu flags to linux mm flags */
+		f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
+				  | _PAGE_COHERENT | _PAGE_GUARDED))
+			| pgprot_val(PAGE_KERNEL);
+		/* add these pages to the mappings */
+		v = tp->virt;
+		p = tp->phys;
+		n = tp->size;
+		for (; n != 0; n -= PAGE_SIZE) {
+			map_page(&init_task.tss, v, p, f);
+			v += PAGE_SIZE;
+			p += PAGE_SIZE;
+		}
+	}
+}
+#endif
 
 /*
- * invalidate a hardware hash table pte
+ * Initialize the hash table and patch the instructions in head.S.
  */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
+static void hash_init(void)
 {
-	int hash, page_index, segment, i, h, _h, api, vsid, perms;
-	PTE *_pte, *slot;
-	int flags = 0;
-	page_index = ((int)va & 0x0FFFF000) >> 12;
-	segment = (unsigned int)va >> 28;
-	api = page_index >> 10;
-	vsid = mm->context | segment;
-	for (_h = 0;  _h < 2;  _h++)
-	{
-		hash = page_index ^ vsid;		
-		if (_h)
-		{
-			hash = ~hash;  /* Secondary hash uses ones-complement */
-		}
-		hash &= 0x3FF | (Hash_mask << 10);
-		hash *= 8;  /* Eight entries / hash bucket */
-		_pte = &Hash[hash];
-		for (i = 0;  i < 8;  i++, _pte++)
-		{
-			if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-			{ /* Found it! */
-				_tlbie(va); /* Clear TLB */
-				if (_pte->r) flags |= _PAGE_ACCESSED;
-				if (_pte->c) flags |= _PAGE_DIRTY;
-				_pte->v = 0;
-				return (flags);
-			}
-		}
-	}
-	_tlbie(va);
-	return (flags);
+	int Hash_bits;
+
+	extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
+		hash_page_patch_C[];
+
+	memset(Hash, 0, Hash_size);
+	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
+	/*
+	 * Patch up the instructions in head.S:hash_page
+	 */
+	Hash_bits = ffz(~Hash_size) - 6;
+	hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+		| (__pa(Hash) >> 16);
+	hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
+		| ((26 - Hash_bits) << 6);
+	if (Hash_bits > 16)
+		Hash_bits = 16;
+	hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
+		| ((26 - Hash_bits) << 6);
+	hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+		| (Hash_mask >> 10);
+	hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+		| (Hash_mask >> 10);
+
+	/*
+	 * Ensure that the locations we've patched have been written
+	 * out from the data cache and invalidated in the instruction
+	 * cache, on those machines with split caches.
+	 */
+	store_cache_range((unsigned long) hash_page_patch_A,
+			  (unsigned long) (hash_page_patch_C + 1));
 }
 
 
-inline void
-flush_cache_all(void)
+/*
+ * Do very early mm setup such as finding the size of memory
+ * and setting up the hash table.
+ * A lot of this is prep/pmac specific but a lot of it could
+ * still be merged.
+ * -- Cort
+ */
+void
+MMU_init(void)
 {
+        end_of_DRAM = find_end_of_memory();
+        hash_init();
+        _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+#ifdef CONFIG_PMAC
+        /* Force initial page tables */
+	/* this done by INIT_TSS in processor.h on prep -- Cort */
+        init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
+
+	/* Map in all of RAM starting at KERNELBASE */
+	mapin_ram();
+	/* Copy mappings from the prom */
+	inherit_prom_translations();
+#endif /* CONFIG_PMAC */
 }
-inline void
-flush_cache_mm(struct mm_struct *mm)
-{
-} 
-inline void
-flush_cache_page(struct vm_area_struct *vma, long va)
-{
-} 
-inline void
-flush_cache_range(struct mm_struct *mm, unsigned long va_start, unsigned long va_end)
-{
-} 
 
-inline void
-cache_mode(char *str, int *ints)
+static void *
+MMU_get_page()
 {
-	cache_is_copyback = ints[0];
+  void *p;
+  
+  if (mem_init_done) {
+    p = (void *) __get_free_page(GFP_KERNEL);
+    if (p == 0)
+      panic("couldn't get a page in MMU_get_page");
+  } else {
+#ifdef CONFIG_PREP
+    mmu_pages_count++;
+    if ( mmu_pages_count > MAX_MMU_PAGES )
+      printk("out of mmu pages!\n");
+    p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+		(mmu_pages_count+PAGE_SIZE));
+#endif
+#ifdef CONFIG_PMAC
+    p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+#endif
+  }
+  memset(p, 0, PAGE_SIZE);
+  return p;
+}
+
+#ifdef CONFIG_PMAC
+void *
+ioremap(unsigned long addr, unsigned long size)
+{
+	unsigned long p, end = addr + size;
+
+	for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
+		map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+	return (void *) addr;
+}
+#endif
+
+void
+map_page(struct thread_struct *tss, unsigned long va,
+	 unsigned long pa, int flags)
+{
+	pmd_t *pd;
+	pte_t *pg;
+
+	if (tss->pg_tables == NULL) {
+		/* Allocate upper level page map */
+		tss->pg_tables = (unsigned long *) MMU_get_page();
+	}
+	/* Use upper 10 bits of VA to index the first level map */
+	pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+	if (pmd_none(*pd)) {
+		/* Need to allocate second-level table */
+		pg = (pte_t *) MMU_get_page();
+		pmd_val(*pd) = (unsigned long) pg;
+	}
+	/* Use middle 10 bits of VA to index the second-level map */
+	pg = pte_offset(pd, va);
+	set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+	/*flush_hash_page(va >> 28, va);*/
+	flush_hash_page(0, va);
 }
 
 /*
  * TLB flushing:
  *
- *  - flush_tlb() flushes the current mm struct TLBs
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  *
  * since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush them too.
+ * tlb as far as the linux tables are concerned, flush it too.
  *    -- Cort
  */
-inline void
-flush_tlb(void)
-{
-  PTE *ptep;
-  int context = current->mm->context;
-  struct vm_area_struct *v;
-  unsigned int i;
-  
-  v = current->mm->mmap;
-
-  /* for every virtual memory address in the current context -- flush
-     the hash table */
-  while ( v != NULL )
-  {
-    for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
-    {
-      MMU_invalidate_page(v->vm_mm,i);
-    }
-    v = v->vm_next;
-  }
 
-  _tlbia();
-}
-
-/* flush all tlb/hash table entries except for kernels
-
-   although the kernel is mapped with the bats, it's dynamic areas
-   obtained via kmalloc are mapped by the seg regs
-                      -- Cort
-   */
-inline void
+/*
+ * Flush all tlb/hash table entries except for the kernel's.
+ * We use the fact that only kernel mappings use VSIDs 0 - 15.
+ */
+void
 flush_tlb_all(void)
 {
-  PTE *ptep;
-
-  /* flush hash table */
-  for ( ptep = Hash ; ptep < (PTE *)((unsigned long)Hash+Hash_size) ; ptep++ )
-  {
-    /* if not kernel vsids 0-7 (vsid greater than that for process 0)*/
-    if ( (ptep->vsid > 7 ) && (ptep->v))
-    {
-      ptep->v = 0;
-    }
-  }
+	struct task_struct *tsk;
 
-  _tlbia();
+	read_lock(&tasklist_lock);
+	for_each_task(tsk) {
+		if (tsk->mm)
+			tsk->mm->context = NO_CONTEXT;
+	}
+	read_unlock(&tasklist_lock);
+	get_mmu_context(current);
+	set_context(current->mm->context);
 }
 
-inline void
+
+/*
+ * Flush all the (user) entries for the address space described
+ * by mm.  We can't rely on mm->mmap describing all the entries
+ * that might be in the hash table.
+ */
+void
 flush_tlb_mm(struct mm_struct *mm)
 {
-  PTE *ptep;
-  int context = mm->context;
-  struct vm_area_struct *v;
-  unsigned int i;
-
-  v = mm->mmap;
-  while ( v != NULL )
-  {
-    for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
-    {
-      MMU_invalidate_page(v->vm_mm,i);
-    }
-    v = v->vm_next;
-  }
-
-  _tlbia();
+	mm->context = NO_CONTEXT;
+	if (mm == current->mm) {
+		get_mmu_context(current);
+		/* done by get_mmu_context() now -- Cort */
+		/*set_context(current->mm->context);*/
+	}
 }
 
 
-inline void
-flush_tlb_page(struct vm_area_struct *vma, long vmaddr)
+void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
-  MMU_invalidate_page(vma->vm_mm,vmaddr);
+	unsigned vsid;
+	
+	if ( vmaddr < TASK_SIZE) {
+		/*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
+		flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
+		/* this is needed on prep at the moment -- don't know why
+		   -- Cort*/
+		MMU_invalidate_page(vma->vm_mm,vmaddr);
+	}
+	else
+	{
+		/*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
+	}
 }
 
 
-/* for each page addr in the range, call mmu_invalidat_page()
+/* for each page addr in the range, call MMU_invalidate_page()
    if the range is very large and the hash table is small it might be faster to
    do a search of the hash table and just invalidate pages that are in the range
    but that's for study later.
         -- Cort
    */
-inline void
-flush_tlb_range(struct mm_struct *mm, long start, long end)
+void
+flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-  long i;
-  for ( i = PAGE_ALIGN(start-PAGE_SIZE) ; i < PAGE_ALIGN(end) ; i += PAGE_SIZE)
-  {
-    MMU_invalidate_page(mm,i);
-  }
+        start &= PAGE_MASK;
+	for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
+	{
+		/*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
+				start );*/
+		flush_hash_page(mm->context, start);
+		/* this is needed on prep at the moment -- don't know why
+		   -- Cort*/
+		MMU_invalidate_page(mm,start);
+	}
+}
+
+/*
+ * The context counter has overflowed.
+ * We set mm->context to NO_CONTEXT for all mm's in the system.
+ * We assume we can get to all mm's by looking as tsk->mm for
+ * all tasks in the system.
+ */
+void
+mmu_context_overflow(void)
+{
+	struct task_struct *tsk;
+	int nr;
+
+	printk(KERN_INFO "mmu_context_overflow\n");
+	for (nr = 0; nr < NR_TASKS; ++nr) {
+		tsk = task[nr];
+		if (tsk && tsk->mm)
+			tsk->mm->context = NO_CONTEXT;
+	}
+	flush_hash_segments(0x10, 0xffffff);
+	_tlbia();
+	next_mmu_context = 0;
+}
+
+#ifdef CONFIG_PREP
+/*
+ * it's not a simple matter to get rid of these and switch to the
+ * ones paul is using. it will take some time and thought  -- Cort
+ */
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
+{
+	int hash, page_index, segment, i, h, _h, api, vsid, perms;
+	PTE *_pte, *slot;
+	int flags = 0;
+	page_index = ((int)va & 0x0FFFF000) >> 12;
+	segment = (unsigned int)va >> 28;
+	api = page_index >> 10;
+	vsid = VSID_FROM_CONTEXT(segment,mm->context);
+	for (_h = 0;  _h < 2;  _h++)
+	{
+		hash = page_index ^ vsid;		
+		if (_h)
+		{
+			hash = ~hash;  /* Secondary hash uses ones-complement */
+		}
+		hash &= 0x3FF | (Hash_mask /*<< 10*/);
+		hash *= 8;  /* Eight entries / hash bucket */
+		_pte = &Hash[hash];
+		for (i = 0;  i < 8;  i++, _pte++)
+		{
+			if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
+			{ /* Found it! */
+				_tlbie(va); /* Clear TLB */
+				if (_pte->r) flags |= _PAGE_ACCESSED;
+				if (_pte->c) flags |= _PAGE_DIRTY;
+				_pte->v = 0;
+				return /*(flags)*/;
+			}
+		}
+	}
+	_tlbie(va);
+	return /*(flags)*/;
 }
+#endif
 
-inline void
-flush_page_to_ram(unsigned long page)
+#include <asm/mmu.h>
+void print_mm_info(void)
 {
+	struct _SEGREG s;
+	long a;
+	struct _BATU bu;
+	struct _BATL bl;
+	unsigned long i;
+
+	for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
+	{
+		a = get_SR(i);
+		memcpy(&s,&a,4);
+		printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x  %x\n",
+		       i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
+	}
+
+	asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
+	printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
+       	       bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
 }
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig
--- v2.1.47/linux/arch/ppc/prep_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/prep_defconfig	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,239 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+# CONFIG_HEARTBEAT is not set
+# CONFIG_POWERSAVING is not set
+CONFIG_MCOMMON=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_NCR53C7xx=y
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI_QLOGIC_PMAC is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_BEXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RNFS_BOOTP is not set
+# CONFIG_RNFS_RARP is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_HFS_FS=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff -u --recursive --new-file v2.1.47/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.47/linux/arch/sparc/defconfig	Thu Jul 17 10:06:03 1997
+++ linux/arch/sparc/defconfig	Thu Jul 31 13:09:17 1997
@@ -42,7 +42,7 @@
 SUN_FB_BWTWO=y
 SUN_FB_LEO=y
 TADPOLE_FB_WEITEK=y
-#SUN_FB_CREATOR is not set
+SUN_FB_CREATOR=y
 
 #
 # Misc Linux/SPARC drivers
@@ -180,15 +180,12 @@
 # Filesystems
 #
 CONFIG_QUOTA=y
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=m
-CONFIG_UMSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
diff -u --recursive --new-file v2.1.47/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.47/linux/arch/sparc/kernel/sys_sunos.c	Thu Jul 17 10:06:03 1997
+++ linux/arch/sparc/kernel/sys_sunos.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
+/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -842,8 +842,9 @@
 	linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
 	linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
 
-	if (getname (sunos_mount->hostname, &the_name))
-		return -EFAULT;
+	the_name = getname(sunos_mount->hostname);
+	if(IS_ERR(the_name))
+		return PTR_ERR(the_name);
 
 	strncpy (linux_nfs_mount.hostname, the_name, 254);
 	linux_nfs_mount.hostname [255] = 0;
diff -u --recursive --new-file v2.1.47/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.47/linux/arch/sparc/mm/srmmu.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc/mm/srmmu.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.148 1997/06/24 15:48:02 jj Exp $
+/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -2214,7 +2214,8 @@
 {
 	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
 		struct vm_area_struct *vmaring;
-		struct inode *inode;
+		struct dentry *dentry;
+		struct inode *inode = NULL;
 		unsigned long flags, offset, vaddr, start;
 		int alias_found = 0;
 		pgd_t *pgdp;
@@ -2223,7 +2224,9 @@
 
 		save_and_cli(flags);
 
-		inode = vma->vm_inode;
+		dentry = vma->vm_dentry;
+		if(dentry)
+			inode = dentry->d_inode;
 		if (!inode)
 			goto done;
 		offset = (address & PAGE_MASK) - vma->vm_start;
diff -u --recursive --new-file v2.1.47/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.1.47/linux/arch/sparc/mm/sun4c.c	Sat May 24 09:10:23 1997
+++ linux/arch/sparc/mm/sun4c.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
+/* $Id: sun4c.c,v 1.149 1997/07/20 05:59:38 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2435,11 +2435,14 @@
  */
 static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-	struct inode *inode;
+	struct dentry *dentry;
+	struct inode *inode = NULL;
 	pgd_t *pgdp;
 	pte_t *ptep;
 
-	inode = vma->vm_inode;
+	dentry = vma->vm_dentry;
+	if(dentry)
+		inode = dentry->d_inode;
 	if(inode) {
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
 		struct vm_area_struct *vmaring = inode->i_mmap; 
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.47/linux/arch/sparc64/defconfig	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/defconfig	Thu Jul 31 13:09:17 1997
@@ -160,14 +160,11 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.1.47/linux/arch/sparc64/kernel/Makefile	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/Makefile	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $
+# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,12 +7,24 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+ifdef SMP
+
+.S.s:
+	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
 .S.s:
 	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 
 .S.o:
 	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
+endif
+
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
@@ -22,6 +34,10 @@
 	    unaligned.o sys_sunos32.o sunos_ioctl32.o
 OX_OBJS  := sparc64_ksyms.o
 
+ifdef SMP
+O_OBJS += smp.o trampoline.o
+endif
+
 ifdef CONFIG_SPARC32_COMPAT
   O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o
 endif
@@ -36,7 +52,7 @@
 
 head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
 	winfixup.S entry.S
-	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
 
 #
 # This is just to get the dependencies...
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/auxio.c linux/arch/sparc64/kernel/auxio.c
--- v2.1.47/linux/arch/sparc64/kernel/auxio.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/auxio.c	Thu Jul 31 13:09:17 1997
@@ -4,6 +4,9 @@
  */
 
 #include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/init.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.1.47/linux/arch/sparc64/kernel/cpu.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/cpu.c	Thu Jul 31 13:09:17 1997
@@ -6,6 +6,8 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 #include <asm/asi.h>
 #include <asm/system.h>
 #include <asm/fpumacro.h>
@@ -56,12 +58,7 @@
 	long ver, fpu_vers;
 	long fprs;
 	
-#ifndef __SMP__
-	cpuid = 0;
-#else
-#error SMP not supported on sparc64 yet
-	/* cpuid = get_cpuid(); */
-#endif
+	cpuid = smp_processor_id();
 
 	fprs = fprs_read ();
 	fprs_write (FPRS_FEF);
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.1.47/linux/arch/sparc64/kernel/devices.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/devices.c	Thu Jul 31 13:09:17 1997
@@ -13,7 +13,7 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 
-struct prom_cpuinfo linux_cpus[NCPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS];
 int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.47/linux/arch/sparc64/kernel/entry.S	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/entry.S	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $
+/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -206,7 +206,7 @@
 	 * flushing very quickly.
 	 */
 	.align	32
-	.globl	do_ivec
+	.globl	do_ivec, do_ivec_return
 do_ivec:
 	ldxa		[%g0] ASI_INTR_RECEIVE, %g1
 	andcc		%g1, 0x20, %g0
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.1.47/linux/arch/sparc64/kernel/ioctl32.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/ioctl32.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
+/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -30,6 +30,7 @@
 #include <asm/kbio.h>
 #include <asm/vuid_event.h>
 #include <asm/rtc.h>
+#include <asm/openpromio.h>
 
 /* As gcc will warn about casting u32 to some ptr, we have to cast it to
  * unsigned long first, and that's what is A() for.
@@ -696,6 +697,22 @@
 	/* Little p (/dev/rtc etc.) */
 	case RTCGET:
 	case RTCSET:
+
+	/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
+	 * embedded pointers in the arg which we'd need to clean up...
+	 */
+	case OPROMGETOPT:
+	case OPROMSETOPT:
+	case OPROMNXTOPT:
+	case OPROMSETOPT2:
+	case OPROMNEXT:
+	case OPROMCHILD:
+	case OPROMGETPROP:
+	case OPROMNXTPROP:
+	case OPROMU2P:
+	case OPROMGETCONS:
+	case OPROMGETFBNAME:
+	case OPROMGETBOOTARGS:
 
 	/* Socket level stuff */
 	case FIOSETOWN:
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/ioport.c linux/arch/sparc64/kernel/ioport.c
--- v2.1.47/linux/arch/sparc64/kernel/ioport.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/ioport.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $
+/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,7 @@
 	unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
 	unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
 	
-	if (virtual >= PAGE_OFFSET + 0x10000000000UL)
+	if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
 		return;
 
 	release_region(vaddr, plen);
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.1.47/linux/arch/sparc64/kernel/irq.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/irq.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
+/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,7 @@
 #include <asm/iommu.h>
 #include <asm/upa.h>
 #include <asm/oplib.h>
+#include <asm/timer.h>
 #include <asm/smp.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
@@ -76,7 +77,7 @@
 }
 
 /* INO number to Sparc PIL level. */
-static unsigned char ino_to_pil[] = {
+unsigned char ino_to_pil[] = {
 	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 0 */
 	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 1 */
 	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 2 */
@@ -391,7 +392,116 @@
 #define irq_exit(cpu, irq)	(local_irq_count[cpu]--)
 
 #else
-#error SMP not supported on sparc64 just yet
+
+atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+static inline void wait_on_irq(int cpu)
+{
+	int local_count = local_irq_count[cpu];
+
+	while(local_count != atomic_read(&global_irq_count)) {
+		atomic_sub(local_count, &global_irq_count);
+		spin_unlock(&global_irq_lock);
+		for(;;) {
+			if (atomic_read(&global_irq_count))
+				continue;
+			if (*((unsigned char *)&global_irq_lock))
+				continue;
+			if (spin_trylock(&global_irq_lock))
+				break;
+		}
+		atomic_add(local_count, &global_irq_count);
+	}
+}
+
+static inline void get_irqlock(int cpu)
+{
+	if (!spin_trylock(&global_irq_lock)) {
+		if ((unsigned char) cpu == global_irq_holder)
+			return;
+		do {
+			barrier();
+		} while (!spin_trylock(&global_irq_lock));
+	}
+	wait_on_irq(cpu);
+	global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+	int cpu = smp_processor_id();
+
+	__cli();
+	get_irqlock(cpu);
+}
+
+void __global_sti(void)
+{
+	release_irqlock(smp_processor_id());
+	__sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+	return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+	if (flags & 1) {
+		__global_cli();
+	} else {
+		if (global_irq_holder == (unsigned char) smp_processor_id()) {
+			global_irq_holder = NO_PROC_ID;
+			spin_unlock(&global_irq_lock);
+		}
+		if (!(flags & 2))
+			__sti();
+	}
+}
+
+void irq_enter(int cpu, int irq)
+{
+	hardirq_enter(cpu);
+	barrier();
+	while (*((unsigned char *)&global_irq_lock)) {
+		if ((unsigned char) cpu == global_irq_holder)
+			printk("irq_enter: Frosted Lucky Charms, "
+			       "they're magically delicious!\n");
+		barrier();
+	}
+}
+
+void irq_exit(int cpu, int irq)
+{
+	hardirq_exit(cpu);
+	release_irqlock(cpu);
+}
+
+void synchronize_irq(void)
+{
+	int cpu = smp_processor_id();
+	int local_count = local_irq_count[cpu];
+	unsigned long flags;
+
+	if (local_count != atomic_read(&global_irq_count)) {
+		save_and_cli(flags);
+		restore_flags(flags);
+	}
+}
+
 #endif /* __SMP__ */
 
 void report_spurious_ivec(struct pt_regs *regs)
@@ -432,9 +542,7 @@
 	struct irqaction *action;
 	int cpu = smp_processor_id();
 
-	/* XXX */
-	if(irq != 14)
-		clear_softint(1 << irq);
+	clear_softint(1 << irq);
 
 	irq_enter(cpu, irq);
 	action = *(irq + irq_action);
@@ -575,53 +683,46 @@
   return 0;
 }
 
-/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
- * XXX with mixed MHZ Ultras in the machine. -DaveM
- */
-static unsigned long cpu_cfreq;
-static unsigned long tick_offset;
+struct sun5_timer *linux_timers = NULL;
 
-/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
-static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+/* This is called from sbus_init() to get the jiffies timer going.
+ * We need to call this after there exists a valid SBus_chain so
+ * that the IMAP/ICLR registers can be accessed.
+ *
+ * XXX That is because the whole startup sequence is broken.  I will
+ * XXX fix it all up very soon.  -DaveM
+ */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
 {
-	if (!(get_softint () & 1)) {
-		/* Just to be sure... */
-		clear_softint(1 << 14);
-		printk("Spurious level14 at %016lx\n", regs->tpc);
-		return;
-	} else {
-		unsigned long compare, tick;
-
-		do {
-			extern void timer_interrupt(int, void *, struct pt_regs *);
-
-			timer_interrupt(irq, dev_id, regs);
-
-			/* Acknowledge INT_TIMER */
-			clear_softint(1 << 0);
+	struct linux_prom64_registers pregs[3];
+	u32 pirqs[2];
+	int node, err;
 
-			/* Set up for next timer tick. */
-			__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-					     "add	%0, %2, %0\n\t"
-					     "wr	%0, 0x0, %%tick_cmpr\n\t"
-					     "rd	%%tick, %1"
-					     : "=&r" (compare), "=r" (tick)
-					     : "r" (tick_offset));
-		} while(tick >= compare);
+	node = prom_finddevice("/counter-timer");
+	if(node == 0) {
+		prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
+		prom_halt();
 	}
-}
+	err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+	if(err == -1) {
+		prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n");
+		prom_halt();
+	}
+	err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs));
+	if(err == -1) {
+		prom_printf("init_timers: Cannot obtain 'interrupts' "
+			    "for counter-timer.\n");
+		prom_halt();
+	}
+	linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
 
-/* This is called from time_init() to get the jiffies timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
-{
-	int node, err;
+	/* Shut it up first. */
+	linux_timers->limit0 = 0;
+
+	/* Register IRQ handler. */
+	err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
+			  cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
 
-	/* XXX FIX this for SMP -JJ */
-	node = linux_cpus [0].prom_node;
-	cpu_cfreq = prom_getint(node, "clock-frequency");
-	tick_offset = cpu_cfreq / HZ;
-	err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
-			  "timer", NULL);
 	if(err) {
 		prom_printf("Serious problem, cannot register timer interrupt\n");
 		prom_halt();
@@ -630,27 +731,33 @@
 
 		save_and_cli(flags);
 
-		__asm__ __volatile__("wr	%0, 0x0, %%tick_cmpr\n\t"
-				     "wrpr	%%g0, 0x0, %%tick"
-				     : /* No outputs */
-				     : "r" (tick_offset));
-				     
-		clear_softint (get_softint ());
+		/* Set things up so user can access tick register for profiling
+		 * purposes.
+		 */
+		__asm__ __volatile__("
+	sethi	%%hi(0x80000000), %%g1
+	sllx	%%g1, 32, %%g1
+	rd	%%tick, %%g2
+	add	%%g2, 6, %%g2
+	andn	%%g2, %%g1, %%g2
+	wrpr	%%g2, 0, %%tick
+"		: /* no outputs */
+		: /* no inputs */
+		: "g1", "g2");
+
+		linux_timers->limit0 =
+			(SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO |
+			 (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK));
 
 		restore_flags(flags);
 	}
+
 	sti();
 }
 
-/* We use this nowhere else, so only define it's layout here. */
-struct sun5_timer {
-	volatile u32 count0, _unused0;
-	volatile u32 limit0, _unused1;
-	volatile u32 count1, _unused2;
-	volatile u32 limit1, _unused3;
-} *prom_timers;
+struct sun5_timer *prom_timers;
 
-static u32 prom_limit0, prom_limit1;
+static u64 prom_limit0, prom_limit1;
 
 static void map_prom_timers(void)
 {
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.47/linux/arch/sparc64/kernel/process.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/process.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
+/*  $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,9 +50,12 @@
 		return -EPERM;
 
 	/* endless idle loop with no priority at all */
+	current->priority = -100;
 	current->counter = -100;
-	for (;;)
+	for (;;) {
+		run_task_queue(&tq_scheduler);
 		schedule();
+	}
 	return 0;
 }
 
@@ -61,42 +64,27 @@
 /*
  * the idle loop on a UltraMultiPenguin...
  */
-asmlinkage int sys_idle(void)
+asmlinkage int cpu_idle(void)
 {
-	if (current->pid != 0)
-		return -EPERM;
-
-	/* endless idle loop with no priority at all */
-	current->counter = -100;
-	schedule();
-	return 0;
+	current->priority = -100;
+	while(1) {
+		if(tq_scheduler) {
+			lock_kernel();
+			run_task_queue(&tq_scheduler);
+			unlock_kernel();
+		}
+		current->counter = -100;
+		schedule();
+	}
 }
 
-/* This is being executed in task 0 'user space'. */
-int cpu_idle(void *unused)
+asmlinkage int sys_idle(void)
 {
-	volatile int *spap = &smp_process_available;
-	volatile int cval;
+	if(current->pid != 0)
+		return -EPERM;
 
-	while(1) {
-		if(0==*spap)
-			continue;
-		cli();
-		/* Acquire exclusive access. */
-		while((cval = smp_swap(spap, -1)) == -1)
-			while(*spap == -1)
-				;
-                if (0==cval) {
-			/* ho hum, release it. */
-			*spap = 0;
-			sti();
-                        continue;
-                }
-		/* Something interesting happened, whee... */
-		*spap = (cval - 1);
-		sti();
-		idle();
-	}
+	cpu_idle();
+	return 0;
 }
 
 #endif
@@ -467,7 +455,11 @@
  *       allocate the task_struct and kernel stack in
  *       do_fork().
  */
+#ifdef __SMP__
+extern void ret_from_smpfork(void);
+#else
 extern void ret_from_syscall(void);
+#endif
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 		struct task_struct *p, struct pt_regs *regs)
@@ -485,7 +477,11 @@
 	child_trap_frame = ((char *)p) + stack_offset;
 	memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
 	p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+#ifdef __SMP__
+	p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8;
+#else
 	p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+#endif
 	p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
 	p->tss.cwp = regs->u_regs[UREG_G0];
 	if(regs->tstate & TSTATE_PRIV) {
@@ -495,6 +491,10 @@
 		p->tss.ctx = 0;
 		p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
 	} else {
+		if(current->tss.flags & SPARC_FLAG_32BIT) {
+			sp &= 0x00000000ffffffff;
+			regs->u_regs[UREG_FP] &= 0x00000000ffffffff;
+		}
 		p->tss.kregs->u_regs[UREG_FP] = sp;
 		p->tss.flags &= ~SPARC_FLAG_KTHREAD;
 		p->tss.current_ds = USER_DS;
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.1.47/linux/arch/sparc64/kernel/setup.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/setup.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $
+/*  $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -405,11 +405,7 @@
 
 int get_cpuinfo(char *buffer)
 {
-#ifndef __SMP__
-	int cpuid=0;
-#else
-#error SMP not supported on sparc64 yet
-#endif
+	int cpuid=smp_processor_id();
 
 	return sprintf(buffer, "cpu\t\t: %s\n"
             "fpu\t\t: %s\n"
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.1.47/linux/arch/sparc64/kernel/smp.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/smp.c	Thu Jul 31 13:09:17 1997
@@ -3,6 +3,26 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
@@ -13,8 +33,9 @@
 unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready = 0;
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 
-struct cpuinfo_sparc64 cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS];
 static unsigned char boot_cpu_id = 0;
 static int smp_activated = 0;
 
@@ -52,11 +73,11 @@
 
 void smp_commence(void)
 {
-	local_flush_cache_all();
-	local_flush_tlb_all();
+	flush_cache_all();
+	flush_tlb_all();
 	smp_commenced = 1;
-	local_flush_cache_all();
-	local_flush_tlb_all();
+	flush_cache_all();
+	flush_tlb_all();
 }
 
 static void smp_setup_percpu_timer(void);
@@ -67,8 +88,8 @@
 {
 	int cpuid = hard_smp_processor_id();
 
-	local_flush_cache_all();
-	local_flush_tlb_all();
+	flush_cache_all();
+	flush_tlb_all();
 
 	smp_setup_percpu_timer();
 
@@ -76,7 +97,7 @@
 	smp_store_cpu_info(cpuid);
 	callin_flag = 1;
 	__asm__ __volatile__("membar #Sync\n\t"
-			     "flush  %g6" : : : "memory");
+			     "flush  %%g6" : : : "memory");
 
 	while(!task[cpuid])
 		barrier();
@@ -103,11 +124,18 @@
 	return cpu_idle(NULL);
 }
 
+void cpu_panic(void)
+{
+	printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
+	panic("SMP bolixed\n");
+}
+
 extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern unsigned long sparc64_cpu_startup;
 
 void smp_boot_cpus(void)
 {
-	int cpucount = 0, i, first, prev;
+	int cpucount = 0, i;
 
 	printk("Entering UltraSMPenguin Mode...\n");
 	__sti();
@@ -133,15 +161,15 @@
 			continue;
 
 		if(cpu_present_map & (1 << i)) {
-			extern unsigned long sparc64_cpu_startup;
-			unsigned long entry = (unsigned long)&sparc_cpu_startup;
 			struct task_struct *p;
 			int timeout;
 
 			kernel_thread(start_secondary, NULL, CLONE_PID);
 			p = task[++cpucount];
 			p->processor = i;
-			prom_startcpu(linux_cpus[i].prom_node, entry, i);
+			prom_startcpu(linux_cpus[i].prom_node,
+				      ((unsigned long)&sparc64_cpu_startup),
+				      ((unsigned long)p));
 			for(timeout = 0; timeout < 5000000; timeout++) {
 				if(cpu_callin_map[i])
 					break;
@@ -190,49 +218,46 @@
 		barrier();
 }
 
-/* XXX Make it fast later. */
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
+{
+	u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
+
+	__asm__ __volatile__("
+	wrpr	%0, %1, %%pstate
+	wr	%%g0, %2, %%asi
+	stxa	%3, [0x40] %%asi
+	stxa	%4, [0x50] %%asi
+	stxa	%5, [0x60] %%asi
+	stxa	%%g0, [%6] %%asi
+	membar	#Sync"
+	: /* No outputs */
+	: "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+	  "r" (data0), "r" (data1), "r" (data2), "r" (target));
+
+	/* NOTE: PSTATE_IE is still clear. */
+	do {
+		__asm__ __volatile__("ldxa [%%g0] %1, %0"
+			: "=r" (result)
+			: "i" (ASI_INTR_DISPATCH_STAT));
+	} while(result & 0x1);
+	__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+			     : : "r" (pstate));
+	if(result & 0x2)
+		panic("Penguin NACK's master!");
+}
+
 void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
 {
 	if(smp_processors_ready) {
-		unsigned long mask;
-		u64 data0 = (((unsigned long)ctx)<<32 |
-			     (((unsigned long)func) & 0xffffffff));
-		u64 pstate;
+		unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+		u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
 		int i, ncpus = smp_num_cpus;
 
 		__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
-		mask = (cpu_present_map & ~(1 << smp_processor_id()));
 		for(i = 0; i < ncpus; i++) {
-			if(mask & (1 << i)) {
-				u64 target = mid<<14 | 0x70;
-				u64 result;
-
-				__asm__ __volatile__("
-				wrpr	%0, %1, %%pstate
-				wrpr	%%g0, %2, %%asi
-				stxa	%3, [0x40] %%asi
-				stxa	%4, [0x50] %%asi
-				stxa	%5, [0x60] %%asi
-				stxa	%%g0, [%6] %7
-				membar	#Sync"
-				: /* No outputs */
-				: "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
-				  "r" (data0), "r" (data1), "r" (data2),
-				  "r" (target), "i" (ASI_UDB_INTR_W));
-
-				/* NOTE: PSTATE_IE is still clear. */
-				do {
-					__asm__ __volatile__("ldxa [%%g0] %1, %0",
-						: "=r" (result)
-						: "i" (ASI_INTR_DISPATCH_STAT));
-				} while(result & 0x1);
-				__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
-						     : : "r" (pstate));
-				if(result & 0x2)
-					panic("Penguin NACK's master!");
-			}
+			if(mask & (1 << i))
+				xcall_deliver(data0, data1, data2, pstate, i);
 		}
-
 		/* NOTE: Caller runs local copy on master. */
 	}
 }
@@ -246,17 +271,19 @@
 void smp_flush_cache_all(void)
 {
 	smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
+	__flush_cache_all();
 }
 
 void smp_flush_tlb_all(void)
 {
 	smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+	__flush_tlb_all();
 }
 
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
 	u32 ctx = mm->context & 0x1fff;
-	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+	if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
 		smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
 	__flush_tlb_mm(ctx);
 }
@@ -265,7 +292,7 @@
 			 unsigned long end)
 {
 	u32 ctx = mm->context & 0x1fff;
-	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+	if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
 		smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
 	__flush_tlb_range(ctx, start, end);
 }
@@ -275,7 +302,7 @@
 	struct mm_struct *mm = vma->vm_mm;
 	u32 ctx = mm->context & 0x1fff;
 
-	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+	if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
 		smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
 	__flush_tlb_page(ctx, page);
 }
@@ -308,12 +335,12 @@
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
+	int user = user_mode(regs);
 
-	clear_profile_irq(cpu);
-	if(!user_mode(regs))
-		sparc_do_profile(regs->pc);
+	/* XXX clear_profile_irq(cpu); */
+	if(!user)
+		sparc64_do_profile(regs->tpc);
 	if(!--prof_counter[cpu]) {
-		int user = user_mode(regs);
 		if(current->pid) {
 			update_one_process(current, 1, user, !user);
 			if(--current->counter < 0) {
@@ -344,4 +371,5 @@
 int setup_profiling_timer(unsigned int multiplier)
 {
 	/* XXX implement me */
+	return 0;
 }
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.1.47/linux/arch/sparc64/kernel/time.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/time.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $
+/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
+#include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -35,11 +36,17 @@
  * NOTE: On SUN5 systems the ticker interrupt comes in using 2
  *       interrupts, one at level14 and one with softint bit 0.
  */
-void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+extern struct sun5_timer *linux_timers;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	/* last time the cmos clock got updated */
 	static long last_rtc_update=0;
 
+	__asm__ __volatile__("ldx	[%0], %%g0"
+			     : /* no outputs */
+			     : "r" (&((linux_timers)->limit0)));
+
 	do_timer(regs);
 
 	/* Determine when to update the Mostek clock. */
@@ -239,14 +246,12 @@
 
 __initfunc(void time_init(void))
 {
-	extern void init_timers(void (*func)(int, void *, struct pt_regs *));
 	unsigned int year, mon, day, hour, min, sec;
 	struct mostek48t02 *mregs;
 
 	do_get_fast_time = do_gettimeofday;
 
 	clock_probe();
-	init_timers(timer_interrupt);
 
 	mregs = mstk48t02_regs;
 	if(!mregs) {
@@ -266,6 +271,13 @@
 	mregs->creg &= ~MSTK_CREG_READ;
 }
 
+extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+
+__initfunc(void sun4u_start_timers(void))
+{
+	init_timers(timer_interrupt);
+}
+
 static __inline__ unsigned long do_gettimeoffset(void)
 {
 	unsigned long offset = 0;
@@ -286,16 +298,39 @@
 
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags;
-
-	save_and_cli(flags);
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
-	if(tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}
-	restore_flags(flags);
+	/* Load doubles must be used on xtime so that what we get
+	 * is guarenteed to be atomic, this is why we can run this
+	 * with interrupts on full blast.  Don't touch this... -DaveM
+	 */
+	__asm__ __volatile__("
+	sethi	%hi(linux_timers), %o1
+	sethi	%hi(xtime), %g2
+	ldx	[%o1 + %lo(linux_timers)], %g3
+1:	ldd	[%g2 + %lo(xtime)], %o4
+	ldx	[%g3], %o1
+	ldd	[%g2 + %lo(xtime)], %o2
+	xor	%o4, %o2, %o2
+	xor	%o5, %o3, %o3
+	orcc	%o2, %o3, %g0
+	bne,pn	%icc, 1b
+	 cmp	%o1, 0
+	bge,pt	%icc, 1f
+	 sethi	%hi(tick), %o3
+	ld	[%o3 + %lo(tick)], %o3
+	sethi	%hi(0x1fffff), %o2
+	or	%o2, %lo(0x1fffff), %o2
+	add	%o5, %o3, %o5
+	and	%o1, %o2, %o1
+1:	add	%o5, %o1, %o5
+	sethi	%hi(1000000), %o2
+	or	%o2, %lo(1000000), %o2
+	cmp	%o5, %o2
+	bl,a,pn	%icc, 1f
+	 st	%o4, [%o0 + 0x0]
+	add	%o4, 0x1, %o4
+	sub	%o5, %o2, %o5
+	st	%o4, [%o0 + 0x0]
+1:	st	%o5, [%o0 + 0x4]");
 }
 
 void do_settimeofday(struct timeval *tv)
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.1.47/linux/arch/sparc64/kernel/trampoline.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/trampoline.S	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,197 @@
+/* $Id: trampoline.S,v 1.1 1997/07/24 14:47:53 davem Exp $
+ * trampoline.S: Jump start slave processors on sparc64.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/lsu.h>
+#include <asm/pstate.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/spitfire.h>
+#include <asm/asm_offsets.h>
+
+	.text
+	.globl		sparc64_cpu_startup
+sparc64_cpu_startup:
+	flushw
+	mov	(LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+	stxa	%g1, [%g0] ASI_LSU_CONTROL
+	wrpr	%g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+	wrpr	%g0, 15, %pil
+
+	mov	%o0, %g6
+
+	sethi	%uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+	sllx	%g5, 32, %g5
+	or	%g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+	sethi	%uhi(_PAGE_PADDR), %g3
+	or	%g3, %ulo(_PAGE_PADDR), %g3
+	sllx	%g3, 32, %g3
+	sethi	%hi(_PAGE_PADDR), %g7
+	or	%g7, %lo(_PAGE_PADDR), %g7
+	or	%g3, %g7, %g7
+
+	/* Find TLB entry we are executing out of. */
+	clr	%l0
+	set	0x1fff, %l2
+	rd	%pc, %l3
+	andn	%l3, %l2, %g2
+1:	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
+	nop
+	nop
+	nop
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g2
+	be,a,pn	%xcc, 2f
+	 ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
+	cmp	%l0, (63 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+2:	nop
+	nop
+	nop
+	and	%g1, %g3, %g1
+	sub	%g1, %g2, %g1
+	or	%g5, %g1, %g5
+	clr	%l0
+	sethi	%hi(KERNBASE), %g3
+	sethi	%hi(KERNBASE<<1), %g7
+	mov	TLB_TAG_ACCESS, %l7
+1:	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
+	nop
+	nop
+	nop
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_IMMU
+	stxa	%g0, [%l0] ASI_ITLB_DATA_ACCESS
+2:	cmp	%l0, (63 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+	nop
+	nop
+	nop
+	clr	%l0
+1:	ldxa	[%l0] ASI_DTLB_TAG_READ, %g1
+	nop
+	nop
+	nop
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	 cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_DMMU
+	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
+2:	cmp	%l0, (63 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+	nop
+	nop
+	nop
+	sethi	%hi(KERNBASE), %g3
+	mov	(63 << 3), %g7
+	stxa	%g3, [%l7] ASI_DMMU
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	stxa	%g3, [%l7] ASI_IMMU
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+	flush	%g6
+	membar	#Sync
+	b,pt	%xcc, 1f
+	 nop
+1:	set	bounce, %g2
+	jmpl	%g2 + %g0, %g0
+	 nop
+
+bounce:
+	mov	PRIMARY_CONTEXT, %g7
+	stxa	%g0, [%g7] ASI_DMMU
+	membar	#Sync
+	mov	SECONDARY_CONTEXT, %g7
+	stxa	%g0, [%g7] ASI_DMMU
+	membar	#Sync
+
+	sethi	%uhi(PAGE_OFFSET), %g4
+	sllx	%g4, 32, %g4
+
+	mov	TLB_TAG_ACCESS, %g2
+	stxa	%g3, [%g2] ASI_IMMU
+	stxa	%g3, [%g2] ASI_DMMU
+
+	mov	(63 << 3), %g7
+	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
+	andn	%g1, (_PAGE_G), %g1
+	stxa	%g1, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+
+	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g1
+	andn	%g1, (_PAGE_G), %g1
+	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+
+	flush	%g6
+	membar	#Sync
+
+	mov	1, %g5
+	sllx	%g5, (PAGE_SHIFT + 1), %g5
+	sub	%g5, (REGWIN_SZ + STACK_BIAS), %g5
+	add	%g6, %g5, %sp
+	mov	0, %fp
+
+	wrpr	%g0, 0, %wstate
+	wrpr	%g0, 0, %tl
+
+	/* Setup the trap globals, then we can resurface. */
+	rdpr	%pstate, %o1
+	mov	%g6, %o2
+	wrpr	%o1, (PSTATE_AG | PSTATE_IE), %pstate
+	sethi	%hi(sparc64_ttable_tl0), %g5
+	wrpr	%g5, %tba
+	mov	%o2, %g6
+
+	wrpr	%o1, (PSTATE_MG | PSTATE_IE), %pstate
+	sethi	%hi(0x1ff8), %g2
+	or	%g2, %lo(0x1ff8), %g2
+	ldx	[%o2 + AOFF_task_mm], %g6
+	ldx	[%g6 + AOFF_mm_pgd], %g6
+	clr	%g7
+
+	wrpr	%o1, (PSTATE_IG | PSTATE_IE), %pstate
+	sethi	%hi(ivector_to_mask), %g5
+	or	%g5, %lo(ivector_to_mask), %g1
+	mov	0x40, %g2
+
+	wrpr	%g0, 0, %wstate
+	wrpr	%o1, PSTATE_IE, %pstate
+
+	mov	TSB_REG, %o4
+	mov	1, %o5
+	stxa	%o5, [%o4] ASI_DMMU
+	stxa	%o5, [%o4] ASI_IMMU
+	membar	#Sync
+
+	wrpr	%g0, 0, %pil
+	or	%o1, PSTATE_IE, %o1
+	wrpr	%o1, 0, %pstate
+
+	call	smp_callin
+	 nop
+	call	cpu_idle
+	 mov	0, %o0
+	call	cpu_panic
+	 nop
+1:	b,a,pt	%xcc, 1b
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/lib/locks.S linux/arch/sparc64/lib/locks.S
--- v2.1.47/linux/arch/sparc64/lib/locks.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/locks.S	Thu Jul 31 13:09:17 1997
@@ -1,77 +1,77 @@
-/* $Id: locks.S,v 1.2 1997/03/10 12:28:02 jj Exp $
+/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
  * locks.S: SMP low-level lock primitives on Sparc64.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <asm/asm_offsets.h>
 #include <asm/ptrace.h>
+#include <asm/smp.h>
 
 	.text
-	.align	4
-
-	.globl	__spinlock_waitfor
-__spinlock_waitfor:
-1:	orcc	%g2, 0x0, %g0
-	bne	1b
-	 ldub	[%g1], %g2
-	ldstub	[%g1], %g2
-	jmpl	%o7 - 12, %g0
-	 mov	%g5, %o7
-
-	.globl	___become_idt
-___become_idt:
-#if 0 /* Don't know how to do this on the Ultra yet... */
-#endif
-	jmpl	%o7 + 8, %g0
-	 mov	%g5, %o7
+	.align		32
 
 ___lk_busy_spin:
-	orcc	%g2, 0, %g0
-	bne	___lk_busy_spin
-	 ldub	[%g1 + 0], %g2
-	b	1f
-	 ldstub	[%g1 + 0], %g2
+	orcc		%g2, 0, %g0
+	bne,pt		%icc, ___lk_busy_spin
+	 ldub		[%g1 + 0], %g2
+	b,pt		%xcc, 1f
+	 ldstub		[%g1 + 0], %g2
 
-	.globl	___lock_kernel
+	.globl		___lock_kernel
 ___lock_kernel:
-	addcc	%g2, -1, %g2
-	rdpr	%pil, %g3
-	bcs,a	9f
-	 st	%g2, [%g6 + AOFF_task_lock_depth]
-	wrpr	15, %pil
-	ldstub	[%g1 + 0], %g2
-1:	orcc	%g2, 0, %g0
-	bne,a	___lk_busy_spin
-	 ldub	[%g1 + 0], %g2
-	ldub	[%g1 + 2], %g2
-	cmp	%g2, %g5
-	be	2f
-	 stb	%g5, [%g1 + 1]
-	stb	%g5, [%g1 + 2]
-#ifdef __SMP__
-	/* XXX Figure out how to become interrupt receiver in SMP system. */
-#endif
-2:	mov	-1, %g2
-	st	%g2, [%g6 + AOFF_task_lock_depth]
-	wrpr	%g3, %pil
-9:	jmpl	%o7 + 0x8, %g0
-	 mov	%g5, %o7
+	addcc		%g2, -1, %g2
+	rdpr		%pil, %g3
+	bcs,a,pn	%icc, 9f
+	 st		%g2, [%g6 + AOFF_task_lock_depth]
+	wrpr		%g0, 15, %pil
+	ldstub		[%g1 + 0], %g2
+1:	brnz,a,pn	%g2, ___lk_busy_spin
+	 ldub		[%g1 + 0], %g2
+	lduw		[%g6 + AOFF_task_processor], %g2
+	membar		#LoadLoad | #LoadStore
+	stb		%g2, [%g1 + 1]
+2:	mov		-1, %g2
+	st		%g2, [%g6 + AOFF_task_lock_depth]
+	wrpr		%g3, 0, %pil
+9:	jmpl		%o7 + 0x8, %g0
+	 mov		%g5, %o7
+
+	.globl		___lock_reacquire_kernel
+___lock_reacquire_kernel:
+	rdpr		%pil, %g3
+	wrpr		%g0, 15, %pil
+	st		%g2, [%g6 + AOFF_task_lock_depth]
+	ldstub		[%g1 + 0], %g2
+1:	brz,pt		%g2, 3f
+	 ldub		[%g1 + 0], %g2
+2:	brnz,a,pt	%g2, 2b
+	 ldub		[%g1 + 0], %g2
+	b,pt		%xcc, 1b
+	 ldstub		[%g1 + 0], %g2
+3:	lduw		[%g6 + AOFF_task_processor], %g2
+	membar		#LoadLoad | #LoadStore
+	stb		%g2, [%g1 + 1]
+	wrpr		%g3, 0, %pil
+	jmpl		%o7 + 0x8, %g0
+	 mov		%g5, %o7
 
 #undef NO_PROC_ID
 #define NO_PROC_ID	0xff
 
-	.globl	___unlock_kernel
+	.globl		___unlock_kernel
 ___unlock_kernel:
-	addcc	%g2, 1, %g2
-	rdpr	%pil, %g3
-	bne,a	1f
-	 st	%g2, [%g6 + AOFF_task_lock_depth]
-	wrpr	15, %pil
-	mov	NO_PROC_ID, %g2
-	stb	%g2, [%g1 + 1]
-	stb	%g0, [%g1 + 0]
-	st	%g0, [%g6 + AOFF_task_lock_depth]
-	wrpr	%g3, %pil
-1:	jmpl	%o7 + 0x8, %g0
-	 mov	%g5, %o7
+	addcc		%g2, 1, %g2
+	rdpr		%pil, %g3
+	bne,a,pn	%icc, 1f
+	 stw		%g2, [%g6 + AOFF_task_lock_depth]
+	wrpr		15, %pil
+	mov		NO_PROC_ID, %g2
+	stb		%g2, [%g1 + 1]
+	membar		#StoreStore | #LoadStore
+	stb		%g0, [%g1 + 0]
+	stw		%g0, [%g6 + AOFF_task_lock_depth]
+	wrpr		%g3, 0, %pil
+1:	jmpl		%o7 + 0x8, %g0
+	 mov		%g5, %o7
 	
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/mm/Makefile linux/arch/sparc64/mm/Makefile
--- v2.1.47/linux/arch/sparc64/mm/Makefile	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/mm/Makefile	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 1997/06/27 14:53:38 jj Exp $
+# $Id: Makefile,v 1.4 1997/07/24 12:15:08 davem Exp $
 # Makefile for the linux Sparc64-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,11 +7,23 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+ifdef SMP
+
+.S.s:
+	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
 .S.s:
 	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 
 .S.o:
 	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+endif
 
 O_TARGET := mm.o
 O_OBJS   := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.47/linux/arch/sparc64/mm/init.c	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/mm/init.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.39 1997/07/07 02:50:57 davem Exp $
+/*  $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -431,8 +431,17 @@
 	membar("#Sync");
 }
 
+void __flush_cache_all(void)
+{
+	unsigned long va;
+
+	flushw_all();
+	for(va =  0; va < (PAGE_SIZE << 1); va += 32)
+		spitfire_put_icache_tag(va, 0x0);
+}
+
 /* If not locked, zap it. */
-void flush_tlb_all(void)
+void __flush_tlb_all(void)
 {
 	unsigned long flags;
 	int i;
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.1.47/linux/arch/sparc64/mm/ultra.S	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/mm/ultra.S	Thu Jul 31 13:09:17 1997
@@ -1,10 +1,11 @@
-/* $Id: ultra.S,v 1.8 1997/07/15 05:35:50 davem Exp $
+/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <asm/asi.h>
+#include <asm/pgtable.h>
 #include <asm/spitfire.h>
 
 	/* All callers check mm->context != NO_CONTEXT for us. */
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/prom/console.c linux/arch/sparc64/prom/console.c
--- v2.1.47/linux/arch/sparc64/prom/console.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/prom/console.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.6 1997/03/18 17:59:59 jj Exp $
+/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -88,6 +88,7 @@
 	if(strncmp(propb, "serial", sizeof("serial")))
 		return PROMDEV_I_UNK;
 	/* FIXME: Is there any better way how to find out? */	
+	memset(propb, 0, sizeof(propb));
 	st_p = prom_finddevice ("/options");
 	prom_getproperty(st_p, "input-device", propb, sizeof(propb));
 	if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
@@ -116,6 +117,7 @@
 	if(strncmp("serial", propb, sizeof("serial")))
 		return PROMDEV_O_UNK;
 	/* FIXME: Is there any better way how to find out? */	
+	memset(propb, 0, sizeof(propb));
 	st_p = prom_finddevice ("/options");
 	prom_getproperty(st_p, "output-device", propb, sizeof(propb));
 	if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.1.47/linux/arch/sparc64/prom/misc.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/prom/misc.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.8 1997/07/14 23:45:28 davem Exp $
+/* $Id: misc.c,v 1.9 1997/07/24 12:15:11 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -135,7 +135,7 @@
 }
 
 #ifdef __SMP__
-void prom_start_cpu(int cpunode, unsigned long pc, unsigned long o0)
+void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
 {
 	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
 }
diff -u --recursive --new-file v2.1.47/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.1.47/linux/arch/sparc64/prom/p1275.c	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/prom/p1275.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.10 1997/06/27 04:18:30 davem Exp $
+/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -6,6 +6,8 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
 #include <linux/string.h>
 
 #include <asm/openprom.h>
diff -u --recursive --new-file v2.1.47/linux/drivers/Makefile linux/drivers/Makefile
--- v2.1.47/linux/drivers/Makefile	Sun Jul 27 12:11:00 1997
+++ linux/drivers/Makefile	Mon Jul 28 13:49:04 1997
@@ -9,7 +9,7 @@
 
 SUB_DIRS     := block char net misc #streams
 MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn misc pnp
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp
 
 ifdef CONFIG_PCI
 SUB_DIRS += pci
diff -u --recursive --new-file v2.1.47/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.1.47/linux/drivers/block/acsi.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/acsi.c	Thu Jul 31 13:09:17 1997
@@ -370,7 +370,7 @@
 static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
                        cmd, unsigned long arg );
 static int acsi_open( struct inode * inode, struct file * filp );
-static void acsi_release( struct inode * inode, struct file * file );
+static int acsi_release( struct inode * inode, struct file * file );
 static void acsi_prevent_removal( int target, int flag );
 static int acsi_change_blk_size( int target, int lun);
 static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
@@ -1200,7 +1200,7 @@
  * be forgotten about...
  */
 
-static void acsi_release( struct inode * inode, struct file * file )
+static int acsi_release( struct inode * inode, struct file * file )
 {
 	int device;
 
@@ -1210,6 +1210,7 @@
 	if (--access_count[device] == 0 && acsi_info[device].removable)
 		acsi_prevent_removal(device, 0);
 	MOD_DEC_USE_COUNT;
+	return( 0 );
 }
 
 /*
@@ -1821,7 +1822,7 @@
 {
 	del_timer( &acsi_timer );
 	blk_dev[MAJOR_NR].request_fn = 0;
-	free_pages( acsi_buffer, ACSI_BUFFER_ORDER );
+	free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER );
 
 	if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
 		printk( KERN_ERR "acsi: cleanup_module failed\n");
diff -u --recursive --new-file v2.1.47/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c
--- v2.1.47/linux/drivers/block/acsi_slm.c	Sun Jan 26 02:07:10 1997
+++ linux/drivers/block/acsi_slm.c	Thu Jul 31 13:09:17 1997
@@ -117,7 +117,9 @@
 static char slmprint_cmd[6]    = { 0x0a, 0, 0, 0, 0, 0 };
 static char slminquiry_cmd[6]  = { 0x12, 0, 0, 0, 0, 0x80 };
 static char slmmsense_cmd[6]   = { 0x1a, 0, 0, 0, 255, 0 };
+#if 0
 static char slmmselect_cmd[6]  = { 0x15, 0, 0, 0, 0, 0 };
+#endif
 
 
 #define	MAX_SLM		2
@@ -262,11 +264,13 @@
 static int slm_ioctl( struct inode *inode, struct file *file, unsigned int
                       cmd, unsigned long arg );
 static int slm_open( struct inode *inode, struct file *file );
-static void slm_release( struct inode *inode, struct file *file );
+static int slm_release( struct inode *inode, struct file *file );
 static int slm_req_sense( int device );
 static int slm_mode_sense( int device, char *buffer, int abs_flag );
+#if 0
 static int slm_mode_select( int device, char *buffer, int len, int
                             default_flag );
+#endif
 static int slm_get_pagesize( int device, int *w, int *h );
 
 /************************* End of Prototypes **************************/
@@ -794,7 +798,7 @@
 }
 
 
-static void slm_release( struct inode *inode, struct file *file )
+static int slm_release( struct inode *inode, struct file *file )
 
 {	int device;
 	struct slm *sip;
@@ -806,6 +810,8 @@
 		sip->wbusy = 0;
 	if (file->f_mode & 1)
 		sip->rbusy = 0;
+	
+	return( 0 );
 }
 
 
@@ -876,6 +882,8 @@
 }
 
 
+#if 0
+/* currently unused */
 static int slm_mode_select( int device, char *buffer, int len,
 							int default_flag )
 
@@ -911,6 +919,7 @@
 	stdma_release();
 	return( rv );
 }
+#endif
 
 
 static int slm_get_pagesize( int device, int *w, int *h )
diff -u --recursive --new-file v2.1.47/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.47/linux/drivers/block/genhd.c	Mon Jun 16 16:35:54 1997
+++ linux/drivers/block/genhd.c	Sun Jul 27 12:17:32 1997
@@ -907,14 +907,14 @@
 __initfunc(void device_setup(void))
 {
 	extern void console_map_init(void);
-#ifdef CONFIG_PNP_PARPORT
-	extern int pnp_parport_init(void);
+#ifdef CONFIG_PARPORT
+	extern int parport_init(void);
 #endif
 	struct gendisk *p;
 	int nr=0;
 
-#ifdef CONFIG_PNP_PARPORT
-	pnp_parport_init();
+#ifdef CONFIG_PARPORT
+	parport_init();
 #endif
 	chr_dev_init();
 	blk_dev_init();
diff -u --recursive --new-file v2.1.47/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.47/linux/drivers/char/Config.in	Sun Jul 27 12:11:00 1997
+++ linux/drivers/char/Config.in	Thu Jul 31 13:09:17 1997
@@ -99,5 +99,6 @@
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'PC joystick support' CONFIG_JOYSTICK
 endmenu
diff -u --recursive --new-file v2.1.47/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.47/linux/drivers/char/Makefile	Sun Jul 27 12:11:00 1997
+++ linux/drivers/char/Makefile	Thu Jul 31 13:09:17 1997
@@ -261,6 +261,16 @@
 L_OBJS += rtc.o
 endif
 
+ifeq ($(CONFIG_NVRAM),y)
+M = y
+L_OBJS += nvram.o
+else
+  ifeq ($(CONFIG_NVRAM),m)
+    MM = m
+    M_OBJS += nvram.o
+  endif
+endif
+
 ifeq ($(CONFIG_QIC02_TAPE),y)
 L_OBJS += tpqic02.o
 else
diff -u --recursive --new-file v2.1.47/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- v2.1.47/linux/drivers/char/fbmem.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/fbmem.c	Thu Jul 31 13:09:17 1997
@@ -221,8 +221,7 @@
 	if (remap_page_range(vma->vm_start, vma->vm_offset,
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+	vma->vm_dentry = dget(file->f_dentry);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.47/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.1.47/linux/drivers/char/keyboard.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/keyboard.c	Thu Jul 31 13:09:17 1997
@@ -37,6 +37,7 @@
 #include <linux/kbd_diacr.h>
 #include <linux/vt_kern.h>
 #include <linux/kbd_ll.h>
+#include <linux/sysrq.h>
 
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
@@ -148,8 +149,6 @@
 struct pt_regs * kbd_pt_regs;
 
 #ifdef CONFIG_MAGIC_SYSRQ
-#define SYSRQ_KEY 0x54
-extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
 static int sysrq_pressed;
 #endif
 
@@ -239,7 +238,7 @@
 		return;
 	} else if (sysrq_pressed) {
 		if (!up_flag)
-			handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+			handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
 		return;
 	}
 #endif
diff -u --recursive --new-file v2.1.47/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.47/linux/drivers/char/lp.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/char/lp.c	Sun Aug  3 00:08:51 1997
@@ -500,7 +500,7 @@
 	unsigned int minor = MINOR(inode->i_rdev);
 	unsigned int irq;
 
-	if ((irq = LP_IRQ(minor))) {
+	if ((irq = LP_IRQ(minor)) != PARPORT_IRQ_NONE) {
 		kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
 		lp_table[minor].lp_buffer = NULL;
 	}
@@ -642,7 +642,7 @@
 		parport[0] = -3;
 	} else {
 		if (ints[0] == 0 || ints[1] == 0) {
-			/* disable driver on "parport=" or "parport=0" */
+			/* disable driver on "lp=" or "lp=0" */
 			parport[0] = -2;
 		} else {
 			printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
@@ -652,19 +652,18 @@
 
 #endif
 
-int lp_wakeup(void *ref)
+void lp_wakeup(void *ref)
 {
 	struct lp_struct *lp_dev = (struct lp_struct *) ref;
 
 	if (!lp_dev->lp_wait_q)
-		return 1;	/* Wake up whom? */
+		return;	/* Wake up whom? */
 
 	/* Claim the Parport */
 	if (parport_claim(lp_dev->dev))
-		return 1;	/* Shouldn't happen */
+		return;	/* Shouldn't happen */
 
 	wake_up(&lp_dev->lp_wait_q);
-	return 0;
 }
 
 static int inline lp_searchfor(int list[], int a)
diff -u --recursive --new-file v2.1.47/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.47/linux/drivers/char/mem.c	Thu Jul 17 10:06:04 1997
+++ linux/drivers/char/mem.c	Thu Jul 31 13:09:17 1997
@@ -133,6 +133,10 @@
 	if (x86 > 3 && offset >= __pa(high_memory))
 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #endif
+#ifdef __powerpc__
+	if (offset >= __pa(high_memory))
+		pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+#endif
 	if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	vma->vm_dentry = dget(file->f_dentry);
diff -u --recursive --new-file v2.1.47/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.47/linux/drivers/char/misc.c	Thu Jul 17 10:06:04 1997
+++ linux/drivers/char/misc.c	Thu Jul 31 13:09:17 1997
@@ -74,6 +74,7 @@
 extern void pcwatchdog_init(void);
 extern int rtc_init(void);
 extern int dsp56k_init(void);
+extern int nvram_init(void);
 
 #ifdef CONFIG_PROC_FS
 static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -241,6 +242,9 @@
 #endif
 #ifdef CONFIG_ATARI_DSP56K
 	dsp56k_init();
+#endif
+#ifdef CONFIG_NVRAM
+	nvram_init();
 #endif
 #endif /* !MODULE */
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
diff -u --recursive --new-file v2.1.47/linux/drivers/char/nvram.c linux/drivers/char/nvram.c
--- v2.1.47/linux/drivers/char/nvram.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/nvram.c	Thu Jul 31 13:09:17 1997
@@ -0,0 +1,696 @@
+/*
+ * CMOS/NV-RAM driver for Linux
+ *
+ * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ * idea by and with help from Richard Jelinek <rj@suse.de>
+ *
+ * This driver allows you to access the contents of the non-volatile memory in
+ * the mc146818rtc.h real-time clock. This chip is built into all PCs and into
+ * many Atari machines. In the former it's called "CMOS-RAM", in the latter
+ * "NVRAM" (NV stands for non-volatile).
+ *
+ * The data are supplied as a (seekable) character device, /dev/nvram. The
+ * size of this file is 50, the number of freely available bytes in the memory
+ * (i.e., not used by the RTC itself).
+ * 
+ * Checksums over the NVRAM contents are managed by this driver. In case of a
+ * bad checksum, reads and writes return -EIO. The checksum can be initialized
+ * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or
+ * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
+ * again; use with care!)
+ *
+ * This file also provides some functions for other parts of the kernel that
+ * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
+ * Obviously this can be used only if this driver is always configured into
+ * the kernel and is not a module. Since the functions are used by some Atari
+ * drivers, this is the case on the Atari.
+ *
+ */
+
+#define NVRAM_VERSION		"1.0"
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define PC		1
+#define ATARI	2
+
+/* select machine configuration */
+#if defined(CONFIG_ATARI)
+#define MACH ATARI
+#elif defined(__i386__) /* and others?? */
+#define MACH PC
+#else
+#error Cannot build nvram driver for this machine configuration.
+#endif
+
+#if MACH == PC
+
+/* RTC in a PC */
+#define CHECK_DRIVER_INIT() 1
+
+/* On PCs, the checksum is built only over bytes 2..31 */
+#define PC_CKS_RANGE_START	2
+#define PC_CKS_RANGE_END	31
+#define PC_CKS_LOC			32
+
+#define	mach_check_checksum	pc_check_checksum
+#define	mach_set_checksum	pc_set_checksum
+#define	mach_proc_infos		pc_proc_infos
+
+#endif
+
+#if MACH == ATARI
+
+/* Special parameters for RTC in Atari machines */
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#define RTC_PORT(x)			(TT_RTC_BAS + 2*(x))
+#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
+
+/* On Ataris, the checksum is over all bytes except the checksum bytes
+ * themselves; these are at the very end */
+#define ATARI_CKS_RANGE_START	0
+#define ATARI_CKS_RANGE_END		47
+#define ATARI_CKS_LOC			48
+
+#define	mach_check_checksum	atari_check_checksum
+#define	mach_set_checksum	atari_set_checksum
+#define	mach_proc_infos		atari_proc_infos
+
+#endif
+
+/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
+ * interrupts disabled. Due to the index-port/data-port design of the RTC, we
+ * don't want two different things trying to get to it at once. (e.g. the
+ * periodic 11 min sync from time.c vs. this driver.)
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/mc146818rtc.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+
+static int nvram_open_cnt = 0;	/* #times opened */
+static int nvram_open_mode;		/* special open modes */
+#define	NVRAM_WRITE		1		/* opened for writing (exclusive) */
+#define	NVRAM_EXCL		2		/* opened with O_EXCL */
+
+#define	RTC_FIRST_BYTE		14	/* RTC register number of first NVRAM byte */
+#define	NVRAM_BYTES			50	/* number of NVRAM bytes */
+
+
+static int mach_check_checksum( void );
+static void mach_set_checksum( void );
+#ifdef CONFIG_PROC_FS
+static int mach_proc_infos( unsigned char *contents, char *buffer, int *len,
+							off_t *begin, off_t offset, int size );
+#endif
+
+
+/*
+ * These are the internal NVRAM access functions, which do NOT disable
+ * interrupts and do not check the checksum. Both tasks are left to higher
+ * level function, so they need to be done only once per syscall.
+ */
+
+static __inline__ unsigned char nvram_read_int( int i )
+{
+	return( CMOS_READ( RTC_FIRST_BYTE+i ) );
+}
+
+static __inline__ void nvram_write_int( unsigned char c, int i )
+{
+	CMOS_WRITE( c, RTC_FIRST_BYTE+i );
+}
+
+static __inline__ int nvram_check_checksum_int( void )
+{
+	return( mach_check_checksum() );
+}
+
+static __inline__ void nvram_set_checksum_int( void )
+{
+	mach_set_checksum();
+}
+
+#if MACH == ATARI
+
+/*
+ * These non-internal functions are provided to be called by other parts of
+ * the kernel. It's up to the caller to ensure correct checksum before reading
+ * or after writing (needs to be done only once).
+ *
+ * They're only built if CONFIG_ATARI is defined, because Atari drivers use
+ * them. For other configurations (PC), the rest of the kernel can't rely on
+ * them being present (this driver couldn't be configured at all, or as a
+ * module), so they access config information themselves.
+ */
+
+unsigned char nvram_read_byte( int i )
+{
+	unsigned long flags;
+	unsigned char c;
+
+	save_flags(flags);
+	cli();
+	c = nvram_read_int( i );
+	restore_flags(flags);
+	return( c );
+}
+
+void nvram_write_byte( unsigned char c, int i )
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	nvram_write_int( c, i );
+	restore_flags(flags);
+}
+
+int nvram_check_checksum( void )
+{
+	unsigned long flags;
+	int rv;
+
+	save_flags(flags);
+	cli();
+	rv = nvram_check_checksum_int();
+	restore_flags(flags);
+	return( rv );
+}
+
+void nvram_set_checksum( void )
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	nvram_set_checksum_int();
+	restore_flags(flags);
+}
+
+#endif /* MACH == ATARI */
+
+
+/*
+ * The are the file operation function for user access to /dev/nvram
+ */
+
+static long long nvram_llseek( struct inode *inode, struct file *file,
+							   loff_t offset, int origin )
+{
+	switch( origin ) {
+	  case 0:
+		/* nothing to do */
+		break;
+	  case 1:
+		offset += file->f_pos;
+		break;
+	  case 2:
+		offset += NVRAM_BYTES;
+		break;
+	}
+	return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
+}
+
+static long nvram_read( struct inode * inode, struct file * file,
+						char * buf, unsigned long count )
+{
+	unsigned long flags;
+	unsigned i = file->f_pos;
+	char *tmp = buf;
+
+	save_flags(flags);
+	cli();
+	
+	if (!nvram_check_checksum_int()) {
+		restore_flags(flags);
+		return( -EIO );
+	}
+
+	for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp )
+		put_user( nvram_read_int(i), tmp );
+	file->f_pos = i;
+
+	restore_flags(flags);
+	return( tmp - buf );
+}
+
+static long nvram_write( struct inode * inode, struct file * file,
+						 const char * buf, unsigned long count )
+{
+	unsigned long flags;
+	unsigned i = file->f_pos;
+	const char *tmp = buf;
+	char c;
+
+	save_flags(flags);
+	cli();
+	
+	if (!nvram_check_checksum_int()) {
+		restore_flags(flags);
+		return( -EIO );
+	}
+
+	for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) {
+		get_user( c, tmp );
+		nvram_write_int( c, i );
+	}
+	nvram_set_checksum_int();
+	file->f_pos = i;
+
+	restore_flags(flags);
+	return( tmp - buf );
+}
+
+static int nvram_ioctl( struct inode *inode, struct file *file,
+						unsigned int cmd, unsigned long arg )
+{
+	unsigned long flags;
+	int i;
+	
+	switch( cmd ) {
+
+	  case NVRAM_INIT:			/* initialize NVRAM contents and checksum */
+		if (!suser())
+			return( -EACCES );
+
+		save_flags(flags);
+		cli();
+
+		for( i = 0; i < NVRAM_BYTES; ++i )
+			nvram_write_int( 0, i );
+		nvram_set_checksum_int();
+		
+		restore_flags(flags);
+		return( 0 );
+	  
+	  case NVRAM_SETCKS:		/* just set checksum, contents unchanged
+								 * (maybe useful after checksum garbaged
+								 * somehow...) */
+		if (!suser())
+			return( -EACCES );
+
+		save_flags(flags);
+		cli();
+		nvram_set_checksum_int();
+		restore_flags(flags);
+		return( 0 );
+
+	  default:
+		return( -EINVAL );
+	}
+}
+
+static int nvram_open( struct inode *inode, struct file *file )
+{
+	if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
+		(nvram_open_mode & NVRAM_EXCL) ||
+		((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE)))
+		return( -EBUSY );
+
+	if (file->f_flags & O_EXCL)
+		nvram_open_mode |= NVRAM_EXCL;
+	if (file->f_mode & 2)
+		nvram_open_mode |= NVRAM_WRITE;
+	nvram_open_cnt++;
+	MOD_INC_USE_COUNT;
+	return( 0 );
+}
+
+static int nvram_release( struct inode *inode, struct file *file )
+{
+	nvram_open_cnt--;
+	if (file->f_flags & O_EXCL)
+		nvram_open_mode &= ~NVRAM_EXCL;
+	if (file->f_mode & 2)
+		nvram_open_mode &= ~NVRAM_WRITE;
+
+	MOD_DEC_USE_COUNT;
+	return( 0 );
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+struct proc_dir_entry *proc_nvram;
+
+static int nvram_read_proc( char *buffer, char **start, off_t offset,
+							int size, int *eof, void *data )
+{
+	unsigned long flags;
+	unsigned char contents[NVRAM_BYTES];
+    int i, len = 0;
+    off_t begin = 0;
+	
+	save_flags(flags);
+	cli();
+	for( i = 0; i < NVRAM_BYTES; ++i )
+		contents[i] = nvram_read_int( i );
+	restore_flags(flags);
+	
+	*eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size );
+
+    if (offset >= begin + len)
+		return( 0 );
+    *start = buffer + (begin - offset);
+    return( size < begin + len - offset ? size : begin + len - offset );
+	
+}
+
+/* This macro frees the machine specific function from bounds checking and
+ * this like that... */
+#define	PRINT_PROC(fmt,args...)							\
+	do {												\
+		*len += sprintf( buffer+*len, fmt, ##args );	\
+		if (*begin + *len > offset + size)				\
+			return( 0 );								\
+		if (*begin + *len < offset) {					\
+			*begin += *len;								\
+			*len = 0;									\
+		}												\
+	} while(0)
+
+#endif
+
+static struct file_operations nvram_fops = {
+	nvram_llseek,
+	nvram_read,
+	nvram_write,
+	NULL,			/* No readdir */
+	NULL,			/* No poll */
+	nvram_ioctl,
+	NULL,			/* No mmap */
+	nvram_open,
+	nvram_release
+};
+
+static struct miscdevice nvram_dev = {
+	NVRAM_MINOR,
+	"nvram",
+	&nvram_fops
+};
+
+
+__initfunc(int nvram_init(void))
+{
+	/* First test whether the driver should init at all */
+	if (!CHECK_DRIVER_INIT())
+	    return( -ENXIO );
+
+	printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+	misc_register( &nvram_dev );
+#ifdef CONFIG_PROC_FS
+	if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
+		proc_nvram->read_proc = nvram_read_proc;
+#endif
+	
+	return( 0 );
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+	return( nvram_init() );
+}
+
+void cleanup_module (void)
+{
+#ifdef CONFIG_PROC_FS
+	if (proc_nvram)
+		remove_proc_entry( "nvram", 0 );
+#endif
+	misc_deregister( &nvram_dev );
+}
+#endif
+
+
+/*
+ * Machine specific functions
+ */
+
+
+#if MACH == PC
+
+static int pc_check_checksum( void )
+{
+	int i;
+	unsigned short sum = 0;
+	
+	for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
+		sum += nvram_read_int( i );
+	return( (sum & 0xffff) ==
+			((nvram_read_int(PC_CKS_LOC) << 8) |
+			 nvram_read_int(PC_CKS_LOC+1)) );
+}
+
+static void pc_set_checksum( void )
+{
+	int i;
+	unsigned short sum = 0;
+	
+	for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
+		sum += nvram_read_int( i );
+	nvram_write_int( sum >> 8, PC_CKS_LOC );
+	nvram_write_int( sum & 0xff, PC_CKS_LOC+1 );
+}
+
+#ifdef CONFIG_PROC_FS
+
+static char *floppy_types[] = {
+	"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M"
+};
+
+static char *gfx_types[] = {
+	"EGA, VGA, ... (with BIOS)",
+	"CGA (40 cols)",
+	"CGA (80 cols)",
+	"monochrome",
+};
+
+static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len,
+						  off_t *begin, off_t offset, int size )
+{
+	unsigned long flags;
+	int checksum;
+	int type;
+
+	save_flags(flags);
+	cli();
+	checksum = nvram_check_checksum_int();
+	restore_flags(flags);
+	
+	PRINT_PROC( "Checksum status: %svalid\n", checksum ? "" : "not " );
+
+	PRINT_PROC( "# floppies     : %d\n",
+				(nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0 );
+	PRINT_PROC( "Floppy 0 type  : " );
+	type = nvram[2] >> 4;
+	if (type < sizeof(floppy_types)/sizeof(*floppy_types))
+		PRINT_PROC( "%s\n", floppy_types[type] );
+	else
+		PRINT_PROC( "%d (unknown)\n", type );
+	PRINT_PROC( "Floppy 1 type  : " );
+	type = nvram[2] & 0x0f;
+	if (type < sizeof(floppy_types)/sizeof(*floppy_types))
+		PRINT_PROC( "%s\n", floppy_types[type] );
+	else
+		PRINT_PROC( "%d (unknown)\n", type );
+
+	PRINT_PROC( "HD 0 type      : " );
+	type = nvram[4] >> 4;
+	if (type)
+		PRINT_PROC( " %02x\n", type == 0x0f ? nvram[11] : type );
+	else
+		PRINT_PROC( "none\n" );
+
+	PRINT_PROC( "HD 1 type      : " );
+	type = nvram[4] & 0x0f;
+	if (type)
+		PRINT_PROC( " %02x\n", type == 0x0f ? nvram[12] : type );
+	else
+		PRINT_PROC( "none\n" );
+
+	PRINT_PROC( "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+				nvram[18] | (nvram[19] << 8),
+				nvram[20], nvram[25],
+				nvram[21] | (nvram[22] << 8),
+				nvram[23] | (nvram[24] << 8) );
+	PRINT_PROC( "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+				nvram[39] | (nvram[40] << 8),
+				nvram[41], nvram[46],
+				nvram[42] | (nvram[43] << 8),
+				nvram[44] | (nvram[45] << 8) );
+
+	PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) );
+	PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n",
+				nvram[9] | (nvram[10] << 8),
+				nvram[34] | (nvram[35] << 8) );
+
+	PRINT_PROC( "Gfx adapter    : %s\n", gfx_types[ (nvram[6] >> 4)&3 ] );
+
+	PRINT_PROC( "FPU            : %sinstalled\n",
+				(nvram[6] & 2) ? "" : "not " );
+	
+	return( 1 );
+}
+#endif
+
+#endif /* MACH == PC */
+
+#if MACH == ATARI
+
+static int atari_check_checksum( void )
+{
+	int i;
+	unsigned char sum = 0;
+	
+	for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
+		sum += nvram_read_int( i );
+	return( nvram_read_int( ATARI_CKS_LOC ) == (~sum & 0xff) &&
+			nvram_read_int( ATARI_CKS_LOC+1 ) == (sum & 0xff) );
+}
+
+static void atari_set_checksum( void )
+{
+	int i;
+	unsigned char sum = 0;
+	
+	for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
+		sum += nvram_read_int( i );
+	nvram_write_int( ~sum, ATARI_CKS_LOC );
+	nvram_write_int( sum, ATARI_CKS_LOC+1 );
+}
+
+#ifdef CONFIG_PROC_FS
+
+static struct {
+	unsigned char val;
+	char *name;
+} boot_prefs[] = {
+	{ 0x80, "TOS" },
+	{ 0x40, "ASV" },
+	{ 0x20, "NetBSD (?)" },
+	{ 0x10, "Linux" },
+	{ 0x00, "unspecified" }
+};
+
+static char *languages[] = {
+	"English (US)",
+	"German",
+	"French",
+	"English (UK)",
+	"Spanish",
+	"Italian",
+	"6 (undefined)",
+	"Swiss (French)",
+	"Swiss (German)"
+};
+
+static char *dateformat[] = {
+	"MM%cDD%cYY",
+	"DD%cMM%cYY",
+	"YY%cMM%cDD",
+	"YY%cDD%cMM",
+	"4 (undefined)",
+	"5 (undefined)",
+	"6 (undefined)",
+	"7 (undefined)"
+};
+
+static char *colors[] = {
+	"2", "4", "16", "256", "65536", "??", "??", "??"
+};
+
+#define fieldsize(a)	(sizeof(a)/sizeof(*a))
+
+static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
+							 off_t *begin, off_t offset, int size )
+{
+	int checksum = nvram_check_checksum();
+	int i;
+	unsigned vmode;
+	
+	PRINT_PROC( "Checksum status  : %svalid\n", checksum ? "" : "not " );
+
+	PRINT_PROC( "Boot preference  : " );
+	for( i = fieldsize(boot_prefs)-1; i >= 0; --i ) {
+		if (nvram[1] == boot_prefs[i].val) {
+			PRINT_PROC( "%s\n", boot_prefs[i].name );
+			break;
+		}
+	}
+	if (i < 0)
+		PRINT_PROC( "0x%02x (undefined)\n", nvram[1] );
+
+	PRINT_PROC( "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off" );
+	PRINT_PROC( "SCSI host ID     : " );
+	if (nvram[16] & 0x80)
+		PRINT_PROC( "%d\n", nvram[16] & 7 );
+	else
+		PRINT_PROC( "n/a\n" );
+
+	/* the following entries are defined only for the Falcon */
+	if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
+		return;
+
+	PRINT_PROC( "OS language      : " );
+	if (nvram[6] < fieldsize(languages))
+		PRINT_PROC( "%s\n", languages[nvram[6]] );
+	else
+		PRINT_PROC( "%u (undefined)\n", nvram[6] );
+	PRINT_PROC( "Keyboard language: " );
+	if (nvram[7] < fieldsize(languages))
+		PRINT_PROC( "%s\n", languages[nvram[7]] );
+	else
+		PRINT_PROC( "%u (undefined)\n", nvram[7] );
+	PRINT_PROC( "Date format      : " );
+	PRINT_PROC( dateformat[nvram[8]&7],
+				nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/' );
+	PRINT_PROC( ", %dh clock\n", nvram[8] & 16 ? 24 : 12 );
+	PRINT_PROC( "Boot delay       : " );
+	if (nvram[10] == 0)
+		PRINT_PROC( "default" );
+	else
+		PRINT_PROC( "%ds%s\n", nvram[10],
+					nvram[10] < 8 ? ", no memory test" : "" );
+
+	vmode = (nvram[14] << 8) || nvram[15];
+	PRINT_PROC( "Video mode       : %s colors, %d columns, %s %s monitor\n",
+				colors[vmode & 7],
+				vmode & 8 ? 80 : 40,
+				vmode & 16 ? "VGA" : "TV",
+				vmode & 32 ? "PAL" : "NTSC" );
+	PRINT_PROC( "                   %soverscan, compat. mode %s%s\n",
+				vmode & 64 ? "" : "no ",
+				vmode & 128 ? "on" : "off",
+				vmode & 256 ?
+				  (vmode & 16 ? ", line doubling" : ", half screen") : "" );
+		
+	return( 1 );
+}
+#endif
+
+#endif /* MACH == ATARI */
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.1.47/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.1.47/linux/drivers/char/pc110pad.c	Thu Jul 17 10:06:04 1997
+++ linux/drivers/char/pc110pad.c	Thu Jul 31 13:09:17 1997
@@ -492,7 +492,7 @@
 {
 	fasync_pad(inode, file, 0);
 	if (--active)
-		return;
+		return 0;
 	outb(0x30, current_params.io+2);	/* switch off digitiser */
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -640,7 +640,7 @@
 };
 
 
-static int pc110pad_init(void)
+int pc110pad_init(void)
 {
 	current_params = default_params;
 
diff -u --recursive --new-file v2.1.47/linux/drivers/char/pc110pad.h linux/drivers/char/pc110pad.h
--- v2.1.47/linux/drivers/char/pc110pad.h	Thu Jul 17 10:06:04 1997
+++ linux/drivers/char/pc110pad.h	Thu Jul 31 13:09:17 1997
@@ -26,6 +26,6 @@
 #define PC110PAD_IOCTL_TYPE		0x9a
 
 #define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
-#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
+#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
  
 #endif /* _PC110PAD_H */
diff -u --recursive --new-file v2.1.47/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.47/linux/drivers/char/pc_keyb.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/pc_keyb.c	Mon Aug  4 12:52:22 1997
@@ -7,6 +7,8 @@
  * Major cleanup by Martin Mares, May 1997
  */
 
+#include <linux/config.h>
+
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
@@ -25,21 +27,38 @@
 
 #include "pc_keyb.h"
 
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char pckbd_sysrq_xlate[128] =
+	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
+	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
+	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
+	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
+	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
+	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+	"\r\000/";					/* 0x60 - 0x6f */
+#endif
+
 /*
  * In case we run on a non-x86 hardware we need to initialize both the keyboard
  * controller and the keyboard. On a x86, the BIOS will already have initialized
  * them.
  */
 
+#ifndef __i386__
+#define INIT_KBD
+#endif
+
 #ifdef INIT_KBD
 
 __initfunc(static int kbd_wait_for_input(void))
 {
-        int     n;
-        int     status, data;
+	int     n;
+	int     status, data;
+	unsigned long start = jiffies;
 
-        n = KBD_TIMEOUT;
-        do {
+	do {
                 status = inb(KBD_STATUS_REG);
                 /*
                  * Wait for input data to become available.  This bit will
@@ -62,7 +81,7 @@
 			continue;
                 }
 		return (data & 0xff);
-        } while (--n);
+        } while (jiffies - start < KBD_INIT_TIMEOUT);
         return -1;	/* timed-out if fell through to here... */
 }
 
@@ -155,12 +174,11 @@
 
 __initfunc(static void initialize_kbd(void))
 {
-	unsigned long flags;
 	char *msg;
 
-	save_flags(flags); cli();
+	disable_irq(KEYBOARD_IRQ);
 	msg = initialize_kbd2();
-	restore_flags(flags);
+	enable_irq(KEYBOARD_IRQ);
 
 	if (msg)
 		printk(KERN_WARNING "initialize_kbd: %s\n", msg);
@@ -181,12 +199,15 @@
 
 static inline void kb_wait(void)
 {
-	int i;
+	unsigned long start = jiffies;
 
-	for (i=0; i<KBD_TIMEOUT; i++)
+	do {
 		if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
 			return;
+	} while (jiffies - start < KBC_TIMEOUT);
+#ifdef KBD_REPORT_TIMEOUTS
 	printk(KERN_WARNING "Keyboard timed out\n");
+#endif
 }
 
 /*
@@ -364,7 +385,7 @@
 	}
 	if (scancode == 0) {
 #ifdef KBD_REPORT_ERR
-		printk(KERN_INFO "keyboard buffer overflow\n");
+		printk(KERN_INFO "Keyboard buffer overflow\n");
 #endif
 		prev_scancode = 0;
 		return 0;
@@ -380,7 +401,7 @@
 #ifndef KBD_IS_FOCUS_9000
 #ifdef KBD_REPORT_ERR
 		if (!raw_mode)
-		  printk(KERN_DEBUG "keyboard error\n");
+		  printk(KERN_DEBUG "Keyboard error\n");
 #endif
 #endif
 		prev_scancode = 0;
@@ -503,7 +524,7 @@
 			handle_scancode(scancode);
 
 		status = inb(KBD_STATUS_REG);
-	} while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
+	} while (status & KBD_STAT_OBF);
 
 	mark_bh(KEYBOARD_BH);
 	enable_keyboard();
@@ -517,7 +538,7 @@
 static int send_data(unsigned char data)
 {
 	int retries = 3;
-	int i;
+	unsigned long start;
 
 	do {
 		kb_wait();
@@ -525,16 +546,21 @@
 		resend = 0;
 		reply_expected = 1;
 		outb_p(data, KBD_DATA_REG);
-		for(i=0; i<0x200000; i++) {
-			inb_p(KBD_STATUS_REG); /* just as a delay */
+		start = jiffies;
+		do {
 			if (acknowledge)
 				return 1;
-			if (resend)
-				break;
-		}
-		if (!resend)
-			return 0;
+			if (jiffies - start >= KBD_TIMEOUT) {
+#ifdef KBD_REPORT_TIMEOUTS
+				printk(KERN_WARNING "Keyboard timeout\n");
+#endif
+				return 0;
+			}
+		} while (!resend);
 	} while (retries-- > 0);
+#ifdef KBD_REPORT_TIMEOUTS
+	printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
+#endif
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.47/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h
--- v2.1.47/linux/drivers/char/pc_keyb.h	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/pc_keyb.h	Thu Jul 31 13:09:17 1997
@@ -12,8 +12,12 @@
 
 #define KBD_REPORT_ERR			/* Report keyboard errors */
 #define KBD_REPORT_UNKN			/* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
 #undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_TIMEOUT 0x100000		/* Timeout for sending of commands */
+
+#define KBD_INIT_TIMEOUT HZ		/* Timeout for initializing the keyboard */
+#define KBC_TIMEOUT (HZ/4)		/* Timeout for sending to keyboard controller */
+#define KBD_TIMEOUT (HZ/4)		/* Timeout for keyboard command acknowledge */
 
 /*
  *	Internal variables of the driver
diff -u --recursive --new-file v2.1.47/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v2.1.47/linux/drivers/char/psaux.c	Thu Jul 17 10:06:04 1997
+++ linux/drivers/char/psaux.c	Thu Jul 31 13:09:17 1997
@@ -53,6 +53,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/semaphore.h>
 
 #include <linux/config.h>
 
@@ -141,19 +142,7 @@
 		schedule();
 		retries++;
 	}
-	return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
-	int retries = 0;
-
-	while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < 1000000) {
- 		if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
-			inb_p(KBD_DATA_REG);
-		retries++;
-	}
-	return !(retries == 1000000);
+	return (retries < MAX_RETRIES);
 }
 
 /*
@@ -173,18 +162,10 @@
  */
 
 #ifdef INITIALIZE_DEVICE
-__initfunc(static void aux_write_dev_nosleep(int val))
-{
-	poll_aux_status_nosleep();
-	outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
-	poll_aux_status_nosleep();
-	outb_p(val, KBD_DATA_REG);
-}
-
 __initfunc(static int aux_write_ack(int val))
 {
-	aux_write_dev_nosleep(val);
-	poll_aux_status_nosleep();
+	aux_write_dev(val);
+	poll_aux_status();
 
 	if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
 	{
@@ -207,6 +188,31 @@
 }
 
 /*
+ * AUX handler critical section start and end.
+ * 
+ * Only one process can be in the critical section and all keyboard sends are
+ * deferred as long as we're inside. This is necessary as we may sleep when
+ * waiting for the keyboard controller and other processes / BH's can
+ * preempt us. Please note that the input buffer must be flushed when
+ * aux_end_atomic() is called and the interrupt is no longer enabled as not
+ * doing so might cause the keyboard driver to ignore all incoming keystrokes.
+ */
+
+static struct semaphore aux_sema4 = MUTEX;
+
+static inline void aux_start_atomic(void)
+{
+	down(&aux_sema4);
+	disable_bh(KEYBOARD_BH);
+}
+
+static inline void aux_end_atomic(void)
+{
+	enable_bh(KEYBOARD_BH);
+	up(&aux_sema4);
+}
+
+/*
  * Interrupt from the auxiliary device: a character
  * is waiting in the keyboard/aux controller.
  */
@@ -236,14 +242,12 @@
 	fasync_aux(inode, file, 0);
 	if (--aux_count)
 		return 0;
-	/* disable kbd bh to avoid mixing of cmd bytes */
-	disable_bh(KEYBOARD_BH);
+	aux_start_atomic();
 	aux_write_cmd(AUX_INTS_OFF);			    /* Disable controller ints */
 	poll_aux_status();
 	outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);	    /* Disable Aux device */
 	poll_aux_status();
-	/* reenable kbd bh */
-	enable_bh(KEYBOARD_BH);
+	aux_end_atomic();
 #ifdef CONFIG_MCA
 	free_irq(AUX_IRQ, inode);
 #else
@@ -262,10 +266,14 @@
 {
 	if (!aux_present)
 		return -ENODEV;
-	if (aux_count++)
+	aux_start_atomic();
+	if (aux_count++) {
+		aux_end_atomic();
 		return 0;
-	if (!poll_aux_status()) {
+	}
+	if (!poll_aux_status()) {		/* FIXME: Race condition */
 		aux_count--;
+		aux_end_atomic();
 		return -EBUSY;
 	}
 	queue->head = queue->tail = 0;		/* Flush input queue */
@@ -275,18 +283,16 @@
 	if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
 #endif
 		aux_count--;
+		aux_end_atomic();
 		return -EBUSY;
 	}
 	MOD_INC_USE_COUNT;
-	/* disable kbd bh to avoid mixing of cmd bytes */
-	disable_bh(KEYBOARD_BH);
 	poll_aux_status();
 	outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG);	    /* Enable Aux */
 	aux_write_dev(AUX_ENABLE_DEV);			    /* Enable aux device */
 	aux_write_cmd(AUX_INTS_ON);			    /* Enable controller ints */
 	poll_aux_status();
-	/* reenable kbd bh */
-	enable_bh(KEYBOARD_BH);
+	aux_end_atomic();
 
 	aux_ready = 0;
 	return 0;
@@ -304,9 +310,7 @@
 	if (count) {
 		int written = 0;
 
-		/* disable kbd bh to avoid mixing of cmd bytes */
-		disable_bh(KEYBOARD_BH);
-
+		aux_start_atomic();
 		do {
 			char c;
 			if (!poll_aux_status())
@@ -318,8 +322,7 @@
 			outb_p(c, KBD_DATA_REG);
 			written++;
 		} while (--count);
-		/* reenable kbd bh */
-		enable_bh(KEYBOARD_BH);
+		aux_end_atomic();
 		retval = -EIO;
 		if (written) {
 			retval = written;
@@ -618,6 +621,7 @@
 	queue->head = queue->tail = 0;
 	queue->proc_list = NULL;
 	if (!qp_found) {
+		aux_start_atomic();
 #ifdef INITIALIZE_DEVICE
 		outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
 		aux_write_ack(AUX_SET_SAMPLE);
@@ -625,13 +629,15 @@
 		aux_write_ack(AUX_SET_RES);
 		aux_write_ack(3);			/* 8 counts per mm */
 		aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
-		poll_aux_status_nosleep();
+		poll_aux_status();
 #endif /* INITIALIZE_DEVICE */
 		outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
-		poll_aux_status_nosleep();
-		outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
-		poll_aux_status_nosleep();
-		outb_p(AUX_INTS_OFF, KBD_DATA_REG);                
+		poll_aux_status();
+		outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);    /* Disable controller interrupts */
+		poll_aux_status();
+		outb_p(AUX_INTS_OFF, KBD_DATA_REG);
+		poll_aux_status();
+		aux_end_atomic();
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.1.47/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.1.47/linux/drivers/char/sysrq.c	Mon Jul  7 08:24:28 1997
+++ linux/drivers/char/sysrq.c	Thu Jul 31 13:09:17 1997
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *	$Id: sysrq.c,v 1.3 1997/06/18 09:42:12 mj Exp $
+ *	$Id: sysrq.c,v 1.4 1997/07/17 11:54:15 mj Exp $
  *
  *	Linux Magic System Request Key Hacks
  *
@@ -63,72 +63,72 @@
 	console_loglevel = 7;
 	printk(KERN_INFO "SysRq: ");
 	switch (key) {
-	case 19:					    /* R -- Reset raw mode */
-		kbd->kbdmode = VC_XLATE;
-		printk("Keyboard mode set to XLATE\n");
+	case 'r':					    /* R -- Reset raw mode */
+		if (kbd) {
+			kbd->kbdmode = VC_XLATE;
+			printk("Keyboard mode set to XLATE\n");
+		}
 		break;
-	case 30:					    /* A -- SAK */
+	case 'a':					    /* A -- SAK */
 		printk("SAK\n");
-		do_SAK(tty);
+		if (tty)
+			do_SAK(tty);
 		reset_vc(fg_console);
 		break;
-	case 48:					    /* B -- boot immediately */
+	case 'b':					    /* B -- boot immediately */
 		printk("Resetting\n");
 		machine_restart(NULL);
 		break;
 #ifdef __sparc__
-	case 35:					    /* H -- halt immediately */
+	case 'h':					    /* H -- halt immediately */
 		printk("Halting\n");
 		halt_now();
 		break;
 #endif
 #ifdef CONFIG_APM
-	case 24:					    /* O -- power off */
+	case 'o':					    /* O -- power off */
 		printk("Power off\n");
 		apm_set_power_state(APM_STATE_OFF);
 		break;
 #endif
-	case 31:					    /* S -- emergency sync */
+	case 's':					    /* S -- emergency sync */
 		printk("Emergency Sync\n");
 		emergency_sync_scheduled = EMERG_SYNC;
 		wakeup_bdflush(0);
 		break;
-	case 22:					    /* U -- emergency remount R/O */
+	case 'u':					    /* U -- emergency remount R/O */
 		printk("Emergency Remount R/O\n");
 		emergency_sync_scheduled = EMERG_REMOUNT;
 		wakeup_bdflush(0);
 		break;
-	case 25:					    /* P -- show PC */
+	case 'p':					    /* P -- show PC */
 		printk("Show Regs\n");
 		if (pt_regs)
 			show_regs(pt_regs);
 		break;
-	case 20:					    /* T -- show task info */
+	case 't':					    /* T -- show task info */
 		printk("Show State\n");
 		show_state();
 		break;
-	case 50:					    /* M -- show memory info */
+	case 'm':					    /* M -- show memory info */
 		printk("Show Memory\n");
 		show_mem();
 		break;
-	case 2 ... 11:					    /* 0-9 -- set console logging level */
-		key--;
-		if (key == 10)
-			key = 0;
-		orig_log_level = key;
-		printk("Log level set to %d\n", key);
+	case '0' ... '9':				    /* 0-9 -- set console logging level */
+		orig_log_level = key - '0';
+		printk("Log level set to %d\n", orig_log_level);
 		break;
-	case 18:					    /* E -- terminate all user processes */
+	case 'e':					    /* E -- terminate all user processes */
 		printk("Terminate All Tasks\n");
 		send_sig_all(SIGTERM, 0);
 		orig_log_level = 8;			    /* We probably have killed syslogd */
 		break;
-	case 37:					    /* K -- kill all user processes */
+	case 'k':					    /* K -- kill all user processes */
 		printk("Kill All Tasks\n");
 		send_sig_all(SIGKILL, 0);
 		orig_log_level = 8;
 		break;
-	case 38:					    /* L -- kill all processes including init */
+	case 'l':					    /* L -- kill all processes including init */
 		printk("Kill ALL Tasks (even init)\n");
 		send_sig_all(SIGKILL, 1);
 		orig_log_level = 8;
@@ -154,7 +154,7 @@
 	struct file *file;
 
 	for (file = inuse_filps; file; file = file->f_next)
-		if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+		if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
 			file->f_mode &= ~2;
 }
 
diff -u --recursive --new-file v2.1.47/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.47/linux/drivers/char/tty_io.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/char/tty_io.c	Sat Aug  2 17:14:06 1997
@@ -688,7 +688,6 @@
 		return -ENODEV;
 
 	idx = MINOR(device) - driver->minor_start;
-	tty = driver->table[idx];
 
 	/* 
 	 * Check whether we need to acquire the tty semaphore to avoid
@@ -697,7 +696,8 @@
 	down_tty_sem(idx);
 
 	/* check whether we're reopening an existing tty */
-	if(tty) goto fast_track;
+	tty = driver->table[idx];
+	if (tty) goto fast_track;
 
 	/*
 	 * First time open is complex, especially for PTY devices.
diff -u --recursive --new-file v2.1.47/linux/drivers/char/vga.c linux/drivers/char/vga.c
--- v2.1.47/linux/drivers/char/vga.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/vga.c	Thu Jul 31 13:09:17 1997
@@ -72,6 +72,12 @@
 #define dac_reg (0x3c8)
 #define dac_val (0x3c9)
 
+#ifdef __powerpc__
+#define VGA_OFFSET 0xC0000000;
+#else
+#define VGA_OFFSET 0x0
+#endif
+
 /*
  * By replacing the four outb_p with two back to back outw, we can reduce
  * the window of opportunity to see text mislocated to the RHS of the
@@ -152,20 +158,20 @@
 {
 	if (ORIG_VIDEO_MODE == 7)	/* Is this a monochrome display? */
 	{
-		video_mem_base = 0xb0000;
+		video_mem_base = 0xb0000 + VGA_OFFSET;
 		video_port_reg = 0x3b4;
 		video_port_val = 0x3b5;
 		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
 		{
 			video_type = VIDEO_TYPE_EGAM;
-			video_mem_term = 0xb8000;
+			video_mem_term = 0xb8000 + VGA_OFFSET;
 			*display_desc = "EGA+";
 			request_region(0x3b0,16,"ega");
 		}
 		else
 		{
 			video_type = VIDEO_TYPE_MDA;
-			video_mem_term = 0xb2000;
+			video_mem_term = 0xb2000 + VGA_OFFSET;
 			*display_desc = "*MDA";
 			request_region(0x3b0,12,"mda");
 			request_region(0x3bf, 1,"mda");
@@ -174,14 +180,14 @@
 	else				/* If not, it is color. */
 	{
 		can_do_color = 1;
-		video_mem_base = 0xb8000;
+		video_mem_base = 0xb8000  + VGA_OFFSET;
 		video_port_reg	= 0x3d4;
 		video_port_val	= 0x3d5;
 		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
 		{
 			int i ;
 
-			video_mem_term = 0xc0000;
+			video_mem_term = 0xc0000 + VGA_OFFSET;
 
 			if (!ORIG_VIDEO_ISVGA) {
 				video_type = VIDEO_TYPE_EGAC;
@@ -199,8 +205,8 @@
 				 * controllers (it seems like setting MM=01
 				 * and COE=1 isn't necessarily a good idea)
 				 */
-				video_mem_base = 0xa0000 ;
-				video_mem_term = 0xb0000 ;
+				video_mem_base = 0xa0000  + VGA_OFFSET;
+				video_mem_term = 0xb0000  + VGA_OFFSET;
 				outb_p (6, 0x3ce) ;
 				outb_p (6, 0x3cf) ;
 #endif
@@ -232,7 +238,7 @@
 		else
 		{
 			video_type = VIDEO_TYPE_CGA;
-			video_mem_term = 0xba000;
+			video_mem_term = 0xba000 + VGA_OFFSET;
 			*display_desc = "*CGA";
 			request_region(0x3d4,2,"cga");
 		}
diff -u --recursive --new-file v2.1.47/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.1.47/linux/drivers/misc/parport_arc.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/parport_arc.c	Mon Jul 28 13:46:29 1997
@@ -10,7 +10,6 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.1.47/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.1.47/linux/drivers/misc/parport_init.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/parport_init.c	Sun Aug  3 00:08:51 1997
@@ -56,6 +56,7 @@
 #ifdef MODULE
 int init_module(void)
 {
+	parport_proc_init();
 	return 0;
 }
 
@@ -79,7 +80,8 @@
 {
 	struct parport *pb;
 
-	if (io[0] == PARPORT_DISABLE) return 1; 
+	if (io[0] == PARPORT_DISABLE) return 1;
+	parport_proc_init();
 #ifdef CONFIG_PARPORT_PC
 	parport_pc_init(io, irq, dma);
 #endif
@@ -92,12 +94,15 @@
 EXPORT_SYMBOL(parport_claim);
 EXPORT_SYMBOL(parport_release);
 EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_unregister_port);
 EXPORT_SYMBOL(parport_quiesce);
 EXPORT_SYMBOL(parport_register_device);
 EXPORT_SYMBOL(parport_unregister_device);
 EXPORT_SYMBOL(parport_enumerate);
 EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
 EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_proc_register);
+EXPORT_SYMBOL(parport_proc_unregister);
 
 void inc_parport_count(void)
 {
diff -u --recursive --new-file v2.1.47/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.47/linux/drivers/misc/parport_pc.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/parport_pc.c	Sun Aug  3 00:08:51 1997
@@ -10,6 +10,7 @@
  *              and Philip Blundell <Philip.Blundell@pobox.com>
  */
 
+#include <linux/stddef.h>
 #include <linux/tasks.h>
 
 #include <asm/ptrace.h>
@@ -140,7 +141,7 @@
 static void pc_release_resources(struct parport *p)
 {
 	if (p->irq != PARPORT_IRQ_NONE)
-		free_irq(p->irq, NULL);
+		free_irq(p->irq, p);
 	release_region(p->base, p->size);
 	if (p->modes & PARPORT_MODE_PCECR)
 		release_region(p->base+0x400, 3);
@@ -439,9 +440,10 @@
  */
 static int parport_ECR_present(struct parport *pb)
 {
-	int r, octr = pc_read_control(pb), oecr = pc_read_econtrol(pb);
+	unsigned int r, octr = pc_read_control(pb), 
+	  oecr = pc_read_econtrol(pb);
 
-	r= pc_read_control(pb);	
+	r = pc_read_control(pb);	
 	if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03)) {
 		pc_write_control(pb, r ^ 0x03 ); /* Toggle bits 0-1 */
 
@@ -820,7 +822,10 @@
 	}
 	if (p->irq != PARPORT_IRQ_NONE)
 		printk(", irq %d", p->irq);
-	if (p->irq != PARPORT_DMA_NONE)
+	if (p->dma == PARPORT_DMA_AUTO)		
+		p->dma = (p->modes & PARPORT_MODE_PCECP)?
+			parport_dma_probe(p):PARPORT_DMA_NONE;
+	if (p->dma != PARPORT_DMA_NONE)
 		printk(", dma %d", p->dma);
 	printk(" [");
 #define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}}
@@ -835,6 +840,7 @@
 	}
 #undef printmode
 	printk("]\n");
+	parport_proc_register(p);
 	return 1;
 }
 
@@ -868,7 +874,7 @@
 
 static int init_module(void)
 {	
-	return (parport_pc_init(NULL, NULL, NULL)?0:1);
+	return (parport_pc_init(io, irq, dma)?0:1);
 }
 
 static void cleanup_module(void)
@@ -878,6 +884,8 @@
 		if (p->modes & PARPORT_MODE_PCSPP) { 
 			if (!(p->flags & PARPORT_FLAG_COMA)) 
 				parport_quiesce(p);
+			parport_proc_unregister(p);
+			parport_unregister_port(p);
 		}
 		p = p->next;
 	}
diff -u --recursive --new-file v2.1.47/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.47/linux/drivers/misc/parport_procfs.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/parport_procfs.c	Sun Aug  3 00:08:51 1997
@@ -8,12 +8,12 @@
  *              and Philip Blundell <Philip.Blundell@pobox.com>
  */
 
+#include <linux/stddef.h>
 #include <linux/tasks.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -131,7 +131,10 @@
 		len += sprintf(page+len, "irq:\tnone\n");
 	else
 		len += sprintf(page+len, "irq:\t%d\n",pp->irq);
-	len += sprintf(page+len, "dma:\t%d\n",pp->dma);
+	if (pp->dma == PARPORT_DMA_NONE)
+		len += sprintf(page+len, "dma:\tnone\n");
+	else
+		len += sprintf(page+len, "dma:\t%d\n",pp->dma);
 
 
 #if 0
diff -u --recursive --new-file v2.1.47/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.1.47/linux/drivers/misc/parport_share.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/misc/parport_share.c	Sun Aug  3 00:08:51 1997
@@ -88,6 +88,23 @@
 	return tmp;
 }
 
+void parport_unregister_port(struct parport *port)
+{
+	struct parport *p;
+	kfree(port->name);
+	if (portlist == port) {
+		portlist = port->next;
+	} else {
+		for (p = portlist; (p != NULL) && (p->next != port); 
+		     p=p->next);
+		if (p) {
+			if ((p->next = port->next) == NULL)
+				portlist_tail = p;
+		}
+	}
+	kfree(port);
+}
+
 void parport_quiesce(struct parport *port)
 {
 	if (port->devices) {
@@ -106,7 +123,7 @@
 }
 
 struct pardevice *parport_register_device(struct parport *port, const char *name,
-			  int (*pf)(void *), int (*kf)(void *),
+			  int (*pf)(void *), void (*kf)(void *),
 			  void (*irq_func)(int, void *, struct pt_regs *), 
 			  int flags, void *handle)
 {
@@ -223,7 +240,6 @@
 	pd1 = dev->port->cad;
 	if (dev->port->cad) {
 		if (dev->port->cad->preempt) {
-			/* Now try to preempt */
 			if (dev->port->cad->preempt(dev->port->cad->private))
 				return -EAGAIN;
 			dev->port->ops->save_state(dev->port, dev->state);
@@ -301,19 +317,10 @@
 	}
 
 	/* Now give the lurker a chance.
-	 * There should be a wakeup callback because we checked for it
+	 * There must be a wakeup callback because we checked for it
 	 * at registration.
 	 */
 	if (dev->port->lurker && (dev->port->lurker != dev)) {
-		if (dev->port->lurker->wakeup) {
-			dev->port->lurker->wakeup(dev->port->lurker->private);
-		} 
-#ifdef PARPORT_PARANOID
-		else {  /* can't happen */
-			printk(KERN_DEBUG
-			  "%s (%s): lurker's wakeup callback went away!\n",
-			       dev->port->name, dev->name);
-		}
-#endif
+		dev->port->lurker->wakeup(dev->port->lurker->private);
 	}
 }
diff -u --recursive --new-file v2.1.47/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.1.47/linux/drivers/net/myri_sbus.c	Tue May 13 22:41:09 1997
+++ linux/drivers/net/myri_sbus.c	Thu Jul 31 13:09:17 1997
@@ -275,7 +275,7 @@
 		mp->rx_skbs[i] = skb;
 		skb->dev = dev;
 		skb_put(skb, RX_ALLOC_SIZE);
-		rxd[i].myri_scatters[0].addr = (unsigned int) skb->data;
+		rxd[i].myri_scatters[0].addr = (unsigned long) skb->data;
 		rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE;
 		rxd[i].ctx = i;
 		rxd[i].num_sg = 1;
@@ -429,7 +429,7 @@
 			drops++;
 			DRX(("DROP "));
 			mp->enet_stats.rx_dropped++;
-			rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+			rxd->myri_scatters[0].addr = (unsigned long) skb->data;
 			rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
 			rxd->ctx = index;
 			rxd->num_sg = 1;
@@ -450,7 +450,7 @@
 			mp->rx_skbs[index] = new_skb;
 			new_skb->dev = dev;
 			skb_put(new_skb, RX_ALLOC_SIZE);
-			rxd->myri_scatters[0].addr = (unsigned int) new_skb->data;
+			rxd->myri_scatters[0].addr = (unsigned long) new_skb->data;
 			rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
 			rxd->ctx = index;
 			rxd->num_sg = 1;
@@ -474,7 +474,7 @@
 
 			/* Reuse original ring buffer. */
 			DRX(("reuse "));
-			rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+			rxd->myri_scatters[0].addr = (unsigned long) skb->data;
 			rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
 			rxd->ctx = index;
 			rxd->num_sg = 1;
@@ -618,7 +618,7 @@
 	txd = &sq->myri_txd[entry];
 	mp->tx_skbs[entry] = skb;
 
-	txd->myri_gathers[0].addr = (unsigned int) skb->data;
+	txd->myri_gathers[0].addr = (unsigned long) skb->data;
 	txd->myri_gathers[0].len = len;
 	txd->num_sg = 1;
 	txd->chan = KERNEL_CHANNEL;
diff -u --recursive --new-file v2.1.47/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.1.47/linux/drivers/net/plip.c	Tue May 13 22:41:09 1997
+++ linux/drivers/net/plip.c	Sun Aug  3 00:08:51 1997
@@ -204,7 +204,7 @@
 	struct tq_struct deferred;
 	struct plip_local snd_data;
 	struct plip_local rcv_data;
-	struct ppd *pardev;
+	struct pardevice *pardev;
 	unsigned long  trigger;
 	unsigned long  nibble;
 	enum plip_connection_state connection;
@@ -228,7 +228,7 @@
 plip_init_dev(struct device *dev, struct parport *pb))
 {
 	struct net_local *nl;
-	struct ppd *pardev;
+	struct pardevice *pardev;
 
 	dev->irq = pb->irq;
 	dev->base_addr = pb->base;
@@ -239,8 +239,8 @@
 	}
 	
 	pardev = parport_register_device(pb, dev->name, plip_preempt,
-					plip_wakeup,
-					plip_interrupt, PARPORT_DEV_LURK, dev);
+					 plip_wakeup, plip_interrupt, 
+					 PARPORT_DEV_LURK, dev);
 
 	printk(version);
 	printk("%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
@@ -1045,7 +1045,7 @@
 	return 0;
 }
 
-static int
+static void
 plip_wakeup(void *handle)
 {
 	struct device *dev = (struct device *)handle;
@@ -1058,12 +1058,12 @@
 			/* bus_owner is already set (but why?) */
 			printk(KERN_DEBUG "%s: I'm broken.\n", dev->name);
 		else
-			return 1;
+			return;
 	}
 	
 	if (!(dev->flags & IFF_UP))
 		/* Don't need the port when the interface is down */
-		return 1;
+		return;
 
 	if (!parport_claim(nl->pardev)) {
 		nl->port_owner = 1;
@@ -1072,7 +1072,7 @@
 		outb (0x00, PAR_DATA(dev));
 	}
 
-	return 0;
+	return;
 }
 
 static struct net_device_stats *
diff -u --recursive --new-file v2.1.47/linux/drivers/net/soundmodem/sm_sbc.c linux/drivers/net/soundmodem/sm_sbc.c
--- v2.1.47/linux/drivers/net/soundmodem/sm_sbc.c	Mon Jun 16 16:35:56 1997
+++ linux/drivers/net/soundmodem/sm_sbc.c	Thu Jul 31 13:09:17 1997
@@ -339,6 +339,7 @@
 	sti();
 	if (sm->dma.ptt_cnt <= 0) {
 		dma_receive(sm, curfrag);
+		hdlcdrv_arbitrate(dev, &sm->hdrv);
 		if (hdlcdrv_ptt(&sm->hdrv)) {
 			/* starting to transmit */
 			disable_dma(dev->dma);
@@ -352,10 +353,8 @@
 		sti();
 		dma_init_receive(sm);
 		setup_dma_dsp(dev, sm, 0);
-        } else {
+        } else
 		dma_transmit(sm);
-		hdlcdrv_arbitrate(dev, &sm->hdrv);
-        }
 	sm_output_status(sm);
 	hdlcdrv_transmitter(dev, &sm->hdrv);
 	hdlcdrv_receiver(dev, &sm->hdrv);
diff -u --recursive --new-file v2.1.47/linux/drivers/net/soundmodem/sm_wss.c linux/drivers/net/soundmodem/sm_wss.c
--- v2.1.47/linux/drivers/net/soundmodem/sm_wss.c	Mon Jun 16 16:35:56 1997
+++ linux/drivers/net/soundmodem/sm_wss.c	Thu Jul 31 13:09:17 1997
@@ -402,6 +402,7 @@
 	sti();
 	if (sm->dma.ptt_cnt <= 0) {
 		dma_receive(sm, curfrag);
+		hdlcdrv_arbitrate(dev, &sm->hdrv);
 		if (hdlcdrv_ptt(&sm->hdrv)) {
 			/* starting to transmit */
 			disable_dma(dev->dma);
@@ -415,10 +416,8 @@
 		sti();
 		dma_init_receive(sm);
 		setup_dma_wss(dev, sm, 0);
-        } else {
+        } else
 		dma_transmit(sm);
-		hdlcdrv_arbitrate(dev, &sm->hdrv);
-        }
 	sm_output_status(sm);
 	hdlcdrv_transmitter(dev, &sm->hdrv);
 	hdlcdrv_receiver(dev, &sm->hdrv);
diff -u --recursive --new-file v2.1.47/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c
--- v2.1.47/linux/drivers/pnp/parport_probe.c	Sun Jul 27 12:11:00 1997
+++ linux/drivers/pnp/parport_probe.c	Sun Aug  3 00:08:52 1997
@@ -86,15 +86,15 @@
 
 static struct wait_queue *wait_q = NULL;
 
-static int wakeup(void *ref)
+static void wakeup(void *ref)
 {
 	struct pardevice **dev = (struct pardevice **)ref;
 	
 	if (!wait_q || parport_claim(*dev))
-		return 1;
+		return;
 
 	wake_up(&wait_q);
-	return 0;
+	return;
 }
 
 int parport_probe(struct parport *port, char *buffer, int len)
diff -u --recursive --new-file v2.1.47/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.1.47/linux/drivers/sbus/char/Makefile	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/Makefile	Thu Jul 31 13:09:17 1997
@@ -32,7 +32,9 @@
  FB_OBJS +=	weitek.o
 endif
 ifdef SUN_FB_CREATOR
+ ifeq ($(ARCH),sparc64)
  FB_OBJS += creator.o
+ endif
 endif
 #ifdef SUN_FB_FAST_ONE
 # FB_OBJS +=	sun_8bit_fast1.o
diff -u --recursive --new-file v2.1.47/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c
--- v2.1.47/linux/drivers/sbus/char/creator.c	Thu Jul 17 10:06:05 1997
+++ linux/drivers/sbus/char/creator.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
+/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
  * creator.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -235,7 +235,6 @@
 	struct fb_wid_item wit[30];
 	char *km = NULL;
 	int i, j;
-	u32 l;
 	int err;
 	
 #ifdef CONFIG_SPARC32_COMPAT
@@ -287,7 +286,6 @@
 	struct fb_wid_item wit[30];
 	char *km = NULL;
 	int i, j;
-	u32 l;
 	
 #ifdef CONFIG_SPARC32_COMPAT
 	if (current->tss.flags & SPARC_FLAG_32BIT) {
@@ -464,8 +462,6 @@
 static int
 ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
 {
-	int i;
-	
 	switch (cmd) {
 	case FBIO_WID_GET:
 		return ffb_wid_get (fb, (struct fb_wid_list *)arg);
diff -u --recursive --new-file v2.1.47/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v2.1.47/linux/drivers/sbus/char/suncons.c	Thu Jul 17 10:06:05 1997
+++ linux/drivers/sbus/char/suncons.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $
+/* $Id: suncons.c,v 1.67 1997/07/20 05:59:42 davem Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -931,7 +931,7 @@
 		leo_setup (&fbinfo [n], n, base, io);
 		break;
 #endif
-#ifdef SUN_FB_CREATOR
+#if defined(SUN_FB_CREATOR) && defined(__sparc_v9__)
 	case FBTYPE_CREATOR:
 		creator_setup (&fbinfo [n], n, con_node, base, io);
 		break;
diff -u --recursive --new-file v2.1.47/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c
--- v2.1.47/linux/drivers/sbus/char/tcx.c	Thu Jul 17 10:06:05 1997
+++ linux/drivers/sbus/char/tcx.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
+/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -309,9 +309,9 @@
 	tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
 		 sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
 	if (!fb->base){
-		fb->base = (uint)
-			sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
-				       fb->type.fb_size, "tcx_ram", fb->space, 0);
+		fb->base = (unsigned long)
+			sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET],
+				       0, fb->type.fb_size, "tcx_ram", fb->space, 0);
 	}
 	
 	if (prom_getbool (node, "hw-cursor")) {
diff -u --recursive --new-file v2.1.47/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c
--- v2.1.47/linux/drivers/sbus/char/weitek.c	Thu Jul 17 10:06:05 1997
+++ linux/drivers/sbus/char/weitek.c	Thu Jul 31 13:09:17 1997
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
+/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -99,8 +99,6 @@
 
 __initfunc(void weitek_setup(fbinfo_t *fb, int slot, u32 addr, int io))
 {
-	extern struct screen_info screen_info;
-	
 	printk ("weitek%d at 0x%8.8x\n", slot, addr);
 	
 	/* Fill in parameters we left out */
diff -u --recursive --new-file v2.1.47/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.1.47/linux/drivers/sbus/sbus.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/sbus.c	Thu Jul 31 13:09:17 1997
@@ -385,5 +385,12 @@
 	if (sparc_cpu_model == sun4u)
 		auxio_probe ();
 #endif
+#ifdef __sparc_v9__
+	if (sparc_cpu_model == sun4u) {
+		extern void sun4u_start_timers(void);
+
+		sun4u_start_timers();
+	}
+#endif
 	return memory_start;
 }
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.1.47/linux/drivers/scsi/53c7,8xx.c	Tue May 13 22:41:12 1997
+++ linux/drivers/scsi/53c7,8xx.c	Thu Jul 31 13:09:17 1997
@@ -560,7 +560,7 @@
      * sure what the relationship between the NCR structures
      * and host structures were going to be.
      */
-	(struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) - 
+	(struct NCR53c7x0_cmd *) ((char *) bus_to_virt (le32_to_cpu(issue[1])) - 
 	    (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
 	    offsetof(struct NCR53c7x0_cmd, dsa)) 
     /* If the IF TRUE bit is not set, it's a NOP */
@@ -795,18 +795,18 @@
     for (i = 0, curr = (u32 *) hostdata->schedule; 
 	i < host->can_queue; ++i, curr += 2) {
 	curr[0] = hostdata->NOP_insn;
-	curr[1] = 0xdeadbeef;
+	curr[1] = le32_to_cpu(0xdeadbeef);
     }
-    curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
-    curr[1] = (u32) virt_to_bus (hostdata->script) +
-	hostdata->E_wait_reselect;
+    curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE);
+    curr[1] = (u32) le32_to_cpu(virt_to_bus (hostdata->script) +
+	hostdata->E_wait_reselect);
     hostdata->reconnect_dsa_head = 0;
     hostdata->addr_reconnect_dsa_head = (u32) 
-	virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+	le32_to_cpu(virt_to_bus((void *) &(hostdata->reconnect_dsa_head)));
     hostdata->expecting_iid = 0;
     hostdata->expecting_sto = 0;
     if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS) 
-	hostdata->initiate_sdtr = 0xffff; 
+	hostdata->initiate_sdtr = le32_to_cpu(0xffff); 
     else
     	hostdata->initiate_sdtr = 0;
     hostdata->talked_to = 0;
@@ -877,7 +877,7 @@
  * Returns : 0 on success, -1 on failure.
  */
 
-static inline int 
+static int 
 NCR53c7x0_init (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     int i, ccf, expected_ccf;
@@ -899,6 +899,7 @@
      * will differ.
      */
     int expected_mapping = OPTION_IO_MAPPED;
+
     NCR53c7x0_local_setup(host);
 
     switch (hostdata->chip) {
@@ -929,10 +930,10 @@
 
     /* Assign constants accessed by NCR */
     hostdata->NCR53c7xx_zero = 0;			
-    hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
-    hostdata->NCR53c7xx_msg_abort = ABORT;
-    hostdata->NCR53c7xx_msg_nop = NOP;
-    hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+    hostdata->NCR53c7xx_msg_reject = le32_to_cpu(MESSAGE_REJECT);
+    hostdata->NCR53c7xx_msg_abort = le32_to_cpu(ABORT);
+    hostdata->NCR53c7xx_msg_nop = le32_to_cpu(NOP);
+    hostdata->NOP_insn = le32_to_cpu((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24);
 
     if (expected_mapping == -1 || 
 	(hostdata->options & (OPTION_MEMORY_MAPPED)) != 
@@ -1131,7 +1132,14 @@
 	search->irq == host->irq && search != host); search=search->next);
 
     if (!search) {
-	if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL)) {
+#ifdef __powerpc__
+	if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
+#else
+	if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+#endif
+	  {
+	  
+	  
 	    printk("scsi%d : IRQ%d not free, detaching\n"
 	           "         You have either a configuration problem, or a\n"
                    "         broken BIOS.  You may wish to manually assign\n"
@@ -1453,6 +1461,21 @@
 	return -1;
     }
 
+#ifdef __powerpc__
+    if ( ! (command & PCI_COMMAND_MASTER)) {
+      printk("SCSI: PCI Master Bit has not been set. Setting...\n");
+      command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+      pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+      if (io_port >= 0x10000000) {
+	      /* Mapping on PowerPC can't handle this! */
+	      unsigned long new_io_port;
+	      new_io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+	      printk("SCSI: I/O moved from %08X to %08x\n", io_port, new_io_port);
+	      io_port = new_io_port;
+	      pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+      }
+    }
+#endif
 
     /* 
      * Bit 0 is the address space indicator and must be one for I/O
@@ -1613,6 +1636,9 @@
     unsigned char tmp;
     int i, ncr_to_memory, memory_to_ncr;
     u32 base;
+#ifdef __powerpc__
+    unsigned long *script_ptr;
+#endif    
     NCR53c7x0_local_setup(host);
 
 
@@ -1801,6 +1827,14 @@
     	printk("scsi%d : NCR dsa_fields start is %d not %d\n",
     	    host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - 
     	    Ent_dsa_zero);
+#ifdef __powerpc__
+/* The PowerPC is Big Endian - adjust script appropriately */
+    script_ptr = hostdata->script;
+    for (i = 0;  i < sizeof(SCRIPT);  i += sizeof(long))
+    {
+        *script_ptr++ = le32_to_cpu(*script_ptr);
+    }
+#endif    	    
 
     printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
 	virt_to_bus(hostdata->script), hostdata->script);
@@ -1884,7 +1918,7 @@
 		    "         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) 
+      else if (hostdata->test_completed != 1) 
 	    printk ("scsi%d : test 1 bad interrupt value (%d)\n", 
 		host->host_no, hostdata->test_completed);
 	else 
@@ -1922,16 +1956,17 @@
     	cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
     	cmd[4] = sizeof(data); 
 
-    	dsa[2] = 1;
-    	dsa[3] = virt_to_bus(&identify);
-    	dsa[4] = 6;
-    	dsa[5] = virt_to_bus(&cmd);
-    	dsa[6] = sizeof(data);
-    	dsa[7] = virt_to_bus(&data);
-    	dsa[8] = 1;
-    	dsa[9] = virt_to_bus(&status);
-    	dsa[10] = 1;
-    	dsa[11] = virt_to_bus(&msg);
+/* Need to adjust for endian-ness */    	
+    	dsa[2] = le32_to_cpu(1);
+    	dsa[3] = le32_to_cpu(virt_to_bus(&identify));
+    	dsa[4] = le32_to_cpu(6);
+    	dsa[5] = le32_to_cpu(virt_to_bus(&cmd));
+    	dsa[6] = le32_to_cpu(sizeof(data));
+    	dsa[7] = le32_to_cpu(virt_to_bus(&data));
+    	dsa[8] = le32_to_cpu(1);
+    	dsa[9] = le32_to_cpu(virt_to_bus(&status));
+    	dsa[10] = le32_to_cpu(1);
+    	dsa[11] = le32_to_cpu(virt_to_bus(&msg));
 
 	for (i = 0; i < 3; ++i) {
 	    cli();
@@ -1942,7 +1977,7 @@
 	    }
 
 	    /*	     SCNTL3         SDID	*/
-	    dsa[0] = (0x33 << 24) | (i << 16)  ;
+	    dsa[0] = le32_to_cpu((0x33 << 24) | (i << 16))  ;
 	    hostdata->idle = 0;
 	    hostdata->test_running = 2;
 	    hostdata->test_completed = -1;
@@ -2004,9 +2039,22 @@
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
     	host->hostdata;
     int i;
+#ifdef __powerpc__
+    int len;
+    unsigned long *dsa_ptr;
+#endif    
 
     memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
     	hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+#ifdef __powerpc__
+    /* Note: the script has already been 'endianized' */
+    dsa_ptr = cmd->dsa;
+    len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+    for (i = 0;  i < len;  i += sizeof(long))
+    {
+       *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+    }
+#endif    	
 
     /* 
      * Note : within the NCR 'C' code, dsa points to the _start_
@@ -2046,6 +2094,14 @@
     /*  XXX - new start stuff */
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
 	dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+#ifdef __powerpc__
+    dsa_ptr = cmd->dsa;    
+    len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+    for (i = 0;  i < len;  i += sizeof(long))
+    {
+       *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+    }
+#endif    	
 
 }
 
@@ -2125,7 +2181,7 @@
 	if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd) 
 	{
 	    curr[0] = hostdata->NOP_insn;
-	    curr[1] = 0xdeadbeef;
+	    curr[1] = le32_to_cpu(0xdeadbeef);
 	    ++found;
 	    break;
 	}
@@ -2140,13 +2196,13 @@
      */
 
     for (left = host->can_queue,
-	    ncr_search = hostdata->reconnect_dsa_head, 
+	    ncr_search = le32_to_cpu(hostdata->reconnect_dsa_head), 
 	    ncr_prev = &hostdata->reconnect_dsa_head;
 	left >= 0 && ncr_search && 
 	    ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start) 
 		!= (char *) cmd->dsa;
 	ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) + 
-	    hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+	    hostdata->dsa_next), ncr_search = le32_to_cpu(*ncr_prev), --left);
 
     if (left < 0) 
 	printk("scsi%d: loop detected in ncr reconnect list\n",
@@ -2491,7 +2547,7 @@
     dsps = NCR53c7x0_read32(DSPS_REG);
     dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
 
-    if (hostdata->options & OPTION_DEBUG_INTR) 
+    if (hostdata->options & OPTION_DEBUG_INTR)
 	printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
 
     switch (dsps) {
@@ -2584,9 +2640,9 @@
 		    hostdata->msg_buf[4] = 0;		/* 0 offset = async */
 		    asynchronous (host, c->target);
 		}
-		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, le32_to_cpu(5));
 		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32) 
-		    virt_to_bus ((void *)&hostdata->msg_buf));
+		    le32_to_cpu(virt_to_bus ((void *)&hostdata->msg_buf)));
 		hostdata->dsp = hostdata->script + 
 		    hostdata->E_respond_message / sizeof(u32);
 		hostdata->dsp_changed = 1;
@@ -2649,14 +2705,14 @@
 	 *	agrees with this being an untagged queue'd command.
 	 */
 
-    	patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+    	patch_dsa_32 (cmd->dsa, dsa_msgout, 0, le32_to_cpu(1));
 
     	/* 
     	 * Modify the table indirect for COMMAND OUT phase, since 
     	 * Request Sense is a six byte command.
     	 */
 
-    	patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+    	patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, le32_to_cpu(6));
 
 	c->cmnd[0] = REQUEST_SENSE;
 	c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
@@ -2672,17 +2728,17 @@
 	 */
 
     	patch_dsa_32 (cmd->dsa, dsa_dataout, 0, 
-	    virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+	    le32_to_cpu(virt_to_bus(hostdata->script) + hostdata->E_other_transfer));
     	patch_dsa_32 (cmd->dsa, dsa_datain, 0, 
-	    virt_to_bus(cmd->data_transfer_start));
-    	cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
-    	    DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
-    	cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
-
-	cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
-    	    << 24) | DBC_TCI_TRUE;
-	cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) + 
-	    hostdata->E_other_transfer;
+	    le32_to_cpu(virt_to_bus(cmd->data_transfer_start)));
+    	cmd->data_transfer_start[0] = le32_to_cpu((((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
+    	    DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer));
+    	cmd->data_transfer_start[1] = (u32) le32_to_cpu(virt_to_bus(c->sense_buffer));
+
+	cmd->data_transfer_start[2] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
+    	    << 24) | DBC_TCI_TRUE);
+	cmd->data_transfer_start[3] = (u32) le32_to_cpu(virt_to_bus(hostdata->script) + 
+	    hostdata->E_other_transfer);
 
     	/*
     	 * Currently, this command is flagged as completed, ie 
@@ -2691,7 +2747,7 @@
 	 * status, etc are used.
     	 */
 
-	cmd->cmd->result = 0xffff;		
+	cmd->cmd->result = le32_to_cpu(0xffff);		
 
 	/* 
 	 * Restart command as a REQUEST SENSE.
@@ -2732,7 +2788,7 @@
 		host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
 	    printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
 		    host->host_no, cmd->saved_data_pointer,
-		    bus_to_virt(cmd->saved_data_pointer));
+		    bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)));
 	    print_insn (host, hostdata->script + Ent_reselected_ok / 
     	    	    sizeof(u32), "", 1);
     	    printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
@@ -2765,7 +2821,7 @@
 	    if (dsa) {
 		printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
 		    host->host_no, cmd->saved_data_pointer,
-		    bus_to_virt (cmd->saved_data_pointer));
+		    bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
 #if 0
 		printk("scsi%d : template code :\n", host->host_no);
 		for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero) 
@@ -2794,7 +2850,7 @@
 		printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
 		       "         (temp was 0x%x (virt 0x%p))\n",
 		    host->host_no, cmd->saved_data_pointer,
-		    bus_to_virt (cmd->saved_data_pointer),
+		    bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)),
 		    NCR53c7x0_read32 (TEMP_REG),
 		    bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
 	}
@@ -2888,7 +2944,7 @@
     	    OPTION_DEBUG_DISCONNECT)) {
     	    printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
     	    	host->host_no, cmd->saved_data_pointer,
-		bus_to_virt (cmd->saved_data_pointer));
+		bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
     	    print_progress (c);
     	}
     	return SPECIFIC_INT_RESTART;
@@ -2901,11 +2957,11 @@
 		int size;
     	    	printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
     	    	    host->host_no, cmd->saved_data_pointer, bus_to_virt (
-		    cmd->saved_data_pointer));
+		    le32_to_cpu(cmd->saved_data_pointer)));
 		size = print_insn (host, (u32 *) 
-		    bus_to_virt(cmd->saved_data_pointer), "", 1);
+		    bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)), "", 1);
 		size = print_insn (host, (u32 *) 
-		    bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+		    bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)) + size, "", 1);
     	    	print_progress (c);
 	    }
 #if 0
@@ -2947,8 +3003,8 @@
 		    (int) NCR53c7x0_read8(SCNTL3_REG_800),
 		    datapath_residual (host)) ;
 		print_insn (host, dsp, "", 1);
-		size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
-		print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+		size = print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])), "", 1);
+		print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])) + size, "", 1);
 	   } 
 	return SPECIFIC_INT_RESTART;
 #endif
@@ -3543,7 +3599,6 @@
     case MODE_SELECT: 
     case WRITE_6:
     case WRITE_10:
-    case START_STOP: /* also SCAN, which may do DATA OUT */
 #if 0
 	printk("scsi%d : command is ", host->host_no);
 	print_command(cmd->cmnd);
@@ -3562,6 +3617,7 @@
      * These commands do no data transfer, we should force an
      * interrupt if a data phase is attempted on them.
      */
+    case START_STOP: /* also SCAN, which may do DATA OUT */
     case TEST_UNIT_READY:
     	datain = dataout = 0;
 	break;
@@ -3612,8 +3668,8 @@
      * will start the data transfer over at the beginning.
      */
 
-    tmp->saved_data_pointer = virt_to_bus (hostdata->script) + 
-	hostdata->E_data_transfer;
+    tmp->saved_data_pointer = le32_to_cpu(virt_to_bus (hostdata->script) + 
+	hostdata->E_data_transfer);
 
     /*
      * Initialize Linux specific fields.
@@ -3622,9 +3678,9 @@
     tmp->cmd = cmd;
     tmp->next = NULL;
     tmp->flags = 0;
-    tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next - 
-	hostdata->dsa_start;
-    tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+    tmp->dsa_next_addr = le32_to_cpu(virt_to_bus(tmp->dsa) + hostdata->dsa_next - 
+	hostdata->dsa_start);
+    tmp->dsa_addr = le32_to_cpu(virt_to_bus(tmp->dsa) - hostdata->dsa_start);
 
     /* 
      * Calculate addresses of dynamic code to fill in DSA
@@ -3650,8 +3706,8 @@
     if (hostdata->dsa_fixup)
     	hostdata->dsa_fixup(tmp);
 
-    patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
-    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+    patch_dsa_32(tmp->dsa, dsa_next, 0, le32_to_cpu(0));
+    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, le32_to_cpu(virt_to_bus(cmd)));
 
     if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) 
 	if (hostdata->sync[cmd->target].select_indirect != 
@@ -3664,8 +3720,8 @@
 
 	}
 
-    patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
-    	select_indirect);
+    patch_dsa_32(tmp->dsa, dsa_select, 0, le32_to_cpu(hostdata->sync[cmd->target].
+    	select_indirect));
     /*
      * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
      * different commands; although it should be trivial to do them
@@ -3674,7 +3730,7 @@
     if (hostdata->initiate_wdtr & (1 << cmd->target)) {
 	memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
 	    sizeof(wdtr_message));
-    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(wdtr_message)));
 	save_flags(flags);
 	cli();
 	hostdata->initiate_wdtr &= ~(1 << cmd->target);
@@ -3682,7 +3738,7 @@
     } else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
 	memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, 
 	    sizeof(sdtr_message));
-    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(sdtr_message)));
 	tmp->flags |= CMD_FLAG_SDTR;
 	save_flags(flags);
 	cli();
@@ -3695,40 +3751,40 @@
 		!(hostdata->options & OPTION_NO_ASYNC)) {
 	memcpy ((void *) (tmp->select + 1), (void *) async_message, 
 	    sizeof(async_message));
-    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(async_message)));
 	tmp->flags |= CMD_FLAG_SDTR;
     } 
 #endif
     else 
-    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1));
     hostdata->talked_to |= (1 << cmd->target);
     tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ? 
 	IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
-    patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
-    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
+    patch_dsa_32(tmp->dsa, dsa_msgout, 1, le32_to_cpu(virt_to_bus(tmp->select)));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 0, le32_to_cpu(cmd->cmd_len));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, le32_to_cpu(virt_to_bus(cmd->cmnd)));
+    patch_dsa_32(tmp->dsa, dsa_dataout, 0, le32_to_cpu(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 (hostdata->script) + hostdata->E_other_transfer));
+    patch_dsa_32(tmp->dsa, dsa_datain, 0, le32_to_cpu(cmd_datain ? 
     	    virt_to_bus (cmd_datain) 
-	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+	: 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, 0, le32_to_cpu(1));
 /* 
  * FIXME : these only works for little endian.  We probably want to 
  * 	provide message and status fields in the NCR53c7x0_cmd 
  *	structure, and assign them to cmd->result when we're done.
  */
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
-    patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, le32_to_cpu(virt_to_bus(&cmd->result) + 1));
+    patch_dsa_32(tmp->dsa, dsa_status, 0, le32_to_cpu(1));
+    patch_dsa_32(tmp->dsa, dsa_status, 1, le32_to_cpu(virt_to_bus(&cmd->result)));
+    patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, le32_to_cpu(1));
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
-	virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+	le32_to_cpu(virt_to_bus(&(hostdata->NCR53c7xx_msg_nop))));
     
     /*
      * Generate code for zero or more of the DATA IN, DATA OUT phases 
@@ -3779,15 +3835,15 @@
 
 	if (datain) {
 	    /* CALL other_in, WHEN NOT DATA_IN */  
-	    cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
+	    cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
 		DCMD_TCI_IO) << 24) | 
-		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
-	    cmd_datain[1] = virt_to_bus (hostdata->script) + 
-		hostdata->E_other_in;
+		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+	    cmd_datain[1] = le32_to_cpu(virt_to_bus (hostdata->script) + 
+		hostdata->E_other_in);
 	    /* MOVE count, buf, WHEN DATA_IN */
-	    cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
-    	    	<< 24) | count;
-	    cmd_datain[3] = buf;
+	    cmd_datain[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
+    	    	<< 24) | count);
+	    cmd_datain[3] = le32_to_cpu(buf);
 #if 0
 	    print_insn (host, cmd_datain, "dynamic ", 1);
 	    print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -3795,14 +3851,14 @@
 	}
 	if (dataout) {
 	    /* CALL other_out, WHEN NOT DATA_OUT */
-	    cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
-		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
-	    cmd_dataout[1] = virt_to_bus(hostdata->script) + 
-    	    	hostdata->E_other_out;
+	    cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
+		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+	    cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) + 
+    	    	hostdata->E_other_out);
 	    /* MOVE count, buf, WHEN DATA+OUT */
-	    cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
-		| count;
-	    cmd_dataout[3] = buf;
+	    cmd_dataout[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
+		| count);
+	    cmd_dataout[3] = le32_to_cpu(buf);
 #if 0
 	    print_insn (host, cmd_dataout, "dynamic ", 1);
 	    print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -3817,10 +3873,10 @@
   
     
     if (datain) {
-	cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
-    	    DBC_TCI_TRUE;
-	cmd_datain[1] = virt_to_bus(hostdata->script) + 
-    	    hostdata->E_other_transfer;
+	cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+    	    DBC_TCI_TRUE);
+	cmd_datain[1] = le32_to_cpu(virt_to_bus(hostdata->script) + 
+    	    hostdata->E_other_transfer);
 #if 0
 	print_insn (host, cmd_datain, "dynamic jump ", 1);
 #endif
@@ -3834,10 +3890,10 @@
     }
 #endif
     if (dataout) {
-	cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
-    	    DBC_TCI_TRUE;
-	cmd_dataout[1] = virt_to_bus(hostdata->script) + 
-    	    hostdata->E_other_transfer;
+	cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+    	    DBC_TCI_TRUE);
+	cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) + 
+    	    hostdata->E_other_transfer);
 #if 0
 	print_insn (host, cmd_dataout, "dynamic jump ", 1);
 #endif
@@ -3894,26 +3950,25 @@
 	|| hostdata->state == STATE_DISABLED) {
 	printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
 	    cmd->target, cmd->lun);
-	cmd->result = (DID_BAD_TARGET << 16);
+	cmd->result = DID_BAD_TARGET << 16;
     } else if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
 	(hostdata->debug_count_limit == 0)) {
 	printk("scsi%d : maximum commands exceeded\n", host->host_no);
-	cmd->result = (DID_BAD_TARGET << 16);
-	cmd->result = (DID_BAD_TARGET << 16);
+	cmd->result = DID_BAD_TARGET << 16;
     } else if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
 	switch (cmd->cmnd[0]) {
 	case WRITE_6:
 	case WRITE_10:
 	    printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
 		host->host_no);
-	    cmd->result = (DID_BAD_TARGET << 16);
+	    cmd->result = DID_BAD_TARGET << 16;
 	}
     } else {
     	if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
 	    hostdata->debug_count_limit != -1) 
 	    --hostdata->debug_count_limit;
 	restore_flags (flags);
-	cmd->result = 0xffff;	/* The NCR will overwrite message
+	cmd->result = le32_to_cpu(0xffff);	/* The NCR will overwrite message
 				       and status with valid data */
 	cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
     }
@@ -3967,7 +4022,7 @@
 
     int i;
     NCR53c7x0_local_setup(host);
-#if 0	
+#if 0
     printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no, 
 	virt_to_bus(dsa), dsa);
 #endif
@@ -3982,7 +4037,7 @@
 
     if (hostdata->state == STATE_DISABLED) {
 	printk("scsi%d : driver disabled\n", host->host_no);
-	tmp->result = (DID_BAD_TARGET << 16);
+	tmp->result = DID_BAD_TARGET << 16;
 	cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
 	hostdata->free = cmd;
 	tmp->scsi_done(tmp);
@@ -4001,18 +4056,18 @@
 
 	/* Restore this instruction to a NOP once the command starts */
 	cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / 
-	    sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
+	    sizeof(u32)] = (u32) le32_to_cpu(virt_to_bus ((void *)curr));
 	/* Replace the current jump operand.  */
 	curr[1] =
-	    virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
-	    hostdata->E_dsa_code_template;
+	    le32_to_cpu(virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+	    hostdata->E_dsa_code_template);
 	/* Replace the NOP instruction with a JUMP */
-	curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
-	    DBC_TCI_TRUE;
+	curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+	    DBC_TCI_TRUE);
     }  else {
 	printk ("scsi%d: no free slot\n", host->host_no);
 	disable(host);
-	tmp->result = (DID_ERROR << 16);
+	tmp->result = DID_ERROR << 16;
 	cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
 	hostdata->free = cmd;
 	tmp->scsi_done(tmp);
@@ -4101,7 +4156,7 @@
 	    	if (hostdata->state == STATE_DISABLED) {
 		    tmp = (Scsi_Cmnd *) hostdata->issue_queue;
 		    hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
-		    tmp->result = (DID_BAD_TARGET << 16);
+		    tmp->result = DID_BAD_TARGET << 16;
 		    if (tmp->host_scribble) {
 			((struct NCR53c7x0_cmd *)tmp->host_scribble)->next = 
 			    hostdata->free;
@@ -4133,6 +4188,7 @@
 				    (struct NCR53c7x0_cmd *)
 				    tmp->host_scribble);
 			    } else {
+			    	tmp->result = le32_to_cpu(tmp->result);
 				if (((tmp->result & 0xff) == 0xff) ||
 			    	    ((tmp->result & 0xff00) == 0xff00)) {
 				    printk ("scsi%d : danger Will Robinson!\n",
@@ -4370,7 +4426,6 @@
     char buf[80];				/* Debugging sprintf buffer */
     size_t buflen;				/* Length of same */
 #endif
-
     do {
 	done = 1;
 	for (host = first_host; host; host = host->next) 
@@ -4449,10 +4504,16 @@
 			printk ("scsi%d : looking at result of 0x%x\n",
 			    host->host_no, cmd->cmd->result);
 #endif
-		
+
+#ifdef __powerpc__
+			if (tmp->result == le32_to_cpu(0xffff))
+			    continue;
+			tmp->result = le32_to_cpu(tmp->result);
+#else			
 			if (((tmp->result & 0xff) == 0xff) ||
 			    ((tmp->result & 0xff00) == 0xff00))
 			    continue;
+#endif			    
 
 			search_found = 1;
 
@@ -4537,7 +4598,6 @@
 			    printk("scsi%d : no active command\n", host->host_no);
 			}
 		    }
-
 		    if (istat & ISTAT_SIP) {
 			if (hostdata->options & OPTION_DEBUG_INTR) 
 			    printk ("scsi%d : ISTAT_SIP\n", host->host_no);
@@ -4872,12 +4932,12 @@
 	     * from normal dynamic code.
 	     */
 	    if (dsp != cmd->residual + 2) {
-		cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+		cmd->residual[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
 			((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) | 
-		    DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
-		cmd->residual[1] = virt_to_bus(hostdata->script)
+		    DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+		cmd->residual[1] = le32_to_cpu(virt_to_bus(hostdata->script)
 		    + ((dcmd & DCMD_BMI_IO)
-		       ? hostdata->E_other_in : hostdata->E_other_out);
+		       ? hostdata->E_other_in : hostdata->E_other_out));
 	    }
 
 	    /*
@@ -4885,17 +4945,17 @@
 	     * move instruction, reflecting the pointer and count at the 
 	     * time of the phase mismatch.
 	     */
-	    cmd->residual[2] = dbc_dcmd + residual;
-	    cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+	    cmd->residual[2] = le32_to_cpu(dbc_dcmd + residual);
+	    cmd->residual[3] = le32_to_cpu(NCR53c7x0_read32(DNAD_REG) - residual);
 
 	    /*
 	     * The third and final instruction is a jump to the instruction
 	     * which follows the instruction which had to be 'split'
 	     */
 	    if (dsp != cmd->residual + 2) {
-		cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) 
-		    << 24) | DBC_TCI_TRUE;
-		cmd->residual[5] = virt_to_bus(dsp_next);
+		cmd->residual[4] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) 
+		    << 24) | DBC_TCI_TRUE);
+		cmd->residual[5] = le32_to_cpu(virt_to_bus(dsp_next));
 	    }
 
 	    /*
@@ -5375,11 +5435,11 @@
  */
 	sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)", 
 	    (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,  
-	    insn[0], insn[1], bus_to_virt (insn[1]));
+	    insn[0], insn[1], bus_to_virt (le32_to_cpu(insn[1])));
 	tmp = buf + strlen(buf);
 	if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
 	    sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2], 
-		bus_to_virt(insn[2]));
+		bus_to_virt(le32_to_cpu(insn[2])));
 	    size = 3;
 	} else {
 	    sprintf (tmp, "\n");
@@ -5439,6 +5499,7 @@
     struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
 	host->hostdata : NULL;
     unsigned long flags;
+    unsigned long result;
     struct NCR53c7x0_cmd *curr, **prev;
     Scsi_Cmnd *me, **last;
 #if 0
@@ -5530,7 +5591,8 @@
          &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
-	if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+	result = le32_to_cpu(cmd->result);
+	if ((result & 0xff) != 0xff && (result & 0xff00) != 0xff00) {
 	    if (prev)
 		*prev = (struct NCR53c7x0_cmd *) curr->next;
 	    curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
@@ -5561,8 +5623,9 @@
 	cmd->host_scribble = NULL;
     }
 
-    if (((cmd->result & 0xff00) == 0xff00) ||
-	((cmd->result & 0xff) == 0xff)) {
+    result = le32_to_cpu(cmd->result);
+    if (((result & 0xff00) == 0xff00) ||
+	((result & 0xff) == 0xff)) {
 	printk ("scsi%d : did this command ever run?\n", host->host_no);
 	cmd->result = DID_ABORT << 16;
     } else {
@@ -5709,7 +5772,7 @@
     	(insn >= ncmd->residual &&
     	    insn < (ncmd->residual + 
     	    	sizeof(ncmd->residual))))) {
-	    ptr = bus_to_virt(insn[3]);
+	    ptr = bus_to_virt(le32_to_cpu(insn[3]));
 
 	    if ((buffers = cmd->use_sg)) {
     	    	for (offset = 0, 
@@ -5764,7 +5827,7 @@
 	    continue;
 	if (!i) {
 	    where = "saved";
-	    ptr = bus_to_virt(ncmd->saved_data_pointer);
+	    ptr = bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer));
 	} else {
 	    where = "active";
 	    ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
@@ -5782,9 +5845,9 @@
 		cmd->host->host_no, where);
 	    if (ncmd) {
 		size = print_insn (cmd->host, 
-		    bus_to_virt(ncmd->saved_data_pointer), "", 1);
+		    bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)), "", 1);
 		print_insn (cmd->host, 
-		    bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+		    bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)) + size * sizeof(u32),
 		    "", 1);
 	    }
 	}
@@ -5809,9 +5872,9 @@
 	    "        + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
     	    prefix ? prefix : "",
     	    host->host_no,  virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
-    	    dsa[hostdata->dsa_msgout / sizeof(u32)],
-	    dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
-	    bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+    	    le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+	    le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]),
+	    bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])));
 
     /* 
      * Only print messages if they're sane in length so we don't
@@ -5819,10 +5882,10 @@
      * anything.
      */
 
-    if (dsa[hostdata->dsa_msgout / sizeof(u32)] < 
+    if (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]) < 
 	    sizeof (hostdata->free->select)) 
-	for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
-	    ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]); 
+	for (i = le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+	    ptr = bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])); 
 	    i > 0 && !check_address ((unsigned long) ptr, 1);
 	    ptr += len, i -= len) {
 	    printk("               ");
@@ -5833,8 +5896,8 @@
 	}
 
     printk("        + %d : select_indirect = 0x%x\n",
-	hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
-    cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+	hostdata->dsa_select, le32_to_cpu(dsa[hostdata->dsa_select / sizeof(u32)]));
+    cmd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_cmnd / sizeof(u32)]));
     printk("        + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
 	   (u32) virt_to_bus(cmd));
     if (cmd) {
@@ -5844,7 +5907,7 @@
     } else
 	printk("\n");
     printk("        + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
-	dsa[hostdata->dsa_next / sizeof(u32)]);
+	le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
     if (cmd) { 
 	printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
 	       "                   script : ",
@@ -5891,8 +5954,7 @@
 		    host->host_no, cmd->pid);
 	    /* print_dsa does sanity check on address, no need to check */
 	    else
-	    	print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
-		    -> dsa, "");
+	    	print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), "");
 	} else 
 	    printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
 		host->host_no, cmd->pid, cmd->target, cmd->lun);
@@ -5917,7 +5979,7 @@
 	    left > 0; curr += 2, --left)
 	if (curr[0] != hostdata->NOP_insn) 
 /* FIXME : convert pointer to dsa_begin to pointer to dsa. */
-	    print_dsa (host, bus_to_virt (curr[1] - 
+	    print_dsa (host, bus_to_virt (le32_to_cpu(curr[1]) - 
 		(hostdata->E_dsa_code_begin - 
 		hostdata->E_dsa_code_template)), "");
     printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -5925,7 +5987,7 @@
     printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
 	    
     for (left = host->can_queue, 
-	dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+	dsa = bus_to_virt (le32_to_cpu(hostdata->reconnect_dsa_head));
 	left >= 0 && dsa; 
 	dsa = next_dsa) {
 	save_flags (flags);
@@ -5937,7 +5999,7 @@
 	}
 	else 
 	{
-	    next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+	    next_dsa = bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
 	    print_dsa (host, dsa, "");
 	}
 	restore_flags(flags);
@@ -6131,7 +6193,7 @@
 	for (i = 0, curr = (u32 *) hostdata->schedule; 
 	    i < host->can_queue; ++i, curr += 2) {
 	    curr[0] = hostdata->NOP_insn;
-	    curr[1] = 0xdeadbeef;
+	    curr[1] = le32_to_cpu(0xdeadbeef);
 	}
 	hostdata->curr = NULL;
     }
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h
--- v2.1.47/linux/drivers/scsi/53c7,8xx.h	Mon Jul  7 16:02:51 1997
+++ linux/drivers/scsi/53c7,8xx.h	Mon Aug  4 14:00:47 1997
@@ -1574,7 +1574,7 @@
 	if (hostdata->options & OPTION_DEBUG_DSA)			\
 	    printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",	\
 		#dsa, #symbol, hostdata->##symbol, 			\
-		(word), (u32) (value));					\
+		(word), (u32) le32_to_cpu(value));			\
 	}
 
 /* Paranoid people could use panic() here. */
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.47/linux/drivers/scsi/Config.in	Tue May 13 22:41:12 1997
+++ linux/drivers/scsi/Config.in	Sun Aug  3 19:39:57 1997
@@ -21,7 +21,14 @@
 dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
-dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
+    bool '   Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
+    int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+    bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
+    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+    int  '   delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.47/linux/drivers/scsi/Makefile	Sat May 24 09:10:24 1997
+++ linux/drivers/scsi/Makefile	Thu Jul 31 12:36:27 1997
@@ -421,12 +421,8 @@
 aha152x.o: aha152x.c
 	$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
-aic7xxx_asm:	aic7xxx_asm.c
-	$(HOSTCC) -o $@ aic7xxx_asm.c
-
-aic7xxx.c: aic7xxx_seq.h
-aic7xxx_seq.h:	aic7xxx_asm aic7xxx.seq
-	./aic7xxx_asm -o $@ aic7xxx.seq
+aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
+	$(CC) $(CFLAGS) -c -o $@ aic7xxx.c
 
 seagate.o: seagate.c
 	$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c 
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.1.47/linux/drivers/scsi/README.aic7xxx	Sat Apr 20 10:59:10 1996
+++ linux/drivers/scsi/README.aic7xxx	Thu Jul 31 12:37:17 1997
@@ -1,5 +1,5 @@
 			    AIC7xxx Driver for Linux
-				 April 15, 1996
+				 July 20, 1997
 
 Introduction
 ------------------------
@@ -31,6 +31,7 @@
     -----------------------
     AIC-777x   
     AIC-785x
+    AIC-786x
     AIC-787x
     AIC-788x
 
@@ -58,6 +59,7 @@
     Dan Eischen     deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
     Dean Gehnert    deang@teleport.com             (Linux FTP/patch maintainer)
     Jess Johnson    jester@frenzy.com              (AIC7xxx FAQ author)
+    Doug Ledford    dledford@dialnet.net           (Stress tester/bug squasher)
 
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
@@ -82,10 +84,17 @@
 
     Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
     
-  Command line options
-  ------------------------
+  Command line options ("aic7xxx=option[,option...]")
+  ---------------------------------------------------
     "aic7xxx=no_reset" -  Eliminate the SCSI reset delay during startup.
         Some SCSI devices need some extra time to reset.
+    "aic7xxx=extended" - Force extended translation.
+    "aic7xxx=ultra" - Force Ultra mode
+    "aic7xxx=irq_trigger:[0,1]" - Edge (0) or Level (1) triggered
+        interrupts.  AFAIK, the driver only works with level triggered
+        interrupts.  This only applies to EISA adapters.
+    "aic7xxx=verbose" - Enable more bootup messages.  PLEASE use this
+        if you have problems with the driver.
 
   /proc support
   ------------------------
@@ -106,10 +115,37 @@
       - US Linux mirror of Teleport site
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
       - European Linux mirror of Teleport site
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Daniel Eischens experimental/development ftp site that is
+        also home of the Linux aic7xxx sequencer assembler source.
+
+  Sequencer assembler
+  ------------------------
+    The sequencer assembler is no longer being distributed with the
+    Linux kernel.  The sequencer assembler (aic7xxx_asm) is now being
+    maintained by Justin Gibbs under a BSD copyright (which pretty
+    much lets you do anything you want with it).  I keep a Linux
+    version of the assembler at my ftp site should you wish to hack
+    the sequencer code (ftp://ftp.pcnet.com/users/eischen/Linux/).
+    Please note that you do NOT need the assembler to build a kernel
+    with aic7xxx support.  The assembler generates the code that is
+    downloaded to the aic7xxx controllers; this code IS part of the
+    Linux kernel (aic7xxx_seq.h and aic7xxx_reg.h).
+
+  Problems compiling the kernel with aic7xxx support
+  --------------------------------------------------
+    This is probably due to having modified the sequencer files in
+    some way.  If you are not modifying the sequencer source (in
+    drivers/scsi/aic7xxx/aic7xxx.seq), then you can just re-extract
+    the necessary files from your kernel tarball.  Otherwise, visit
+    my anonymous ftp site (ftp.pcnet.com) and grab the sequencer
+    assembler source.
 
 
 Dean W. Gehnert
 deang@teleport.com
 
-$Revision: 3.0 $
+(Modified by D. Eischen, 7/20/97)
+
+$Revision: 3.1a $
 
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- v2.1.47/linux/drivers/scsi/aic7xxx/aic7xxx.reg	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Thu Jul 31 12:37:17 1997
@@ -0,0 +1,1120 @@
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
+ */
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+	address			0x000
+	access_mode RW
+	bit	TEMODE		0x80
+	bit	ENSELO		0x40
+	bit	ENSELI		0x20
+	bit	ENRSELI		0x10
+	bit	ENAUTOATNO	0x08
+	bit	ENAUTOATNI	0x04
+	bit	ENAUTOATNP	0x02
+	bit	SCSIRSTO	0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+	address			0x001
+	access_mode RW
+	bit	DFON		0x80
+	bit	DFPEXP		0x40
+	bit	FAST20		0x20
+	bit	CLRSTCNT	0x10
+	bit	SPIOEN		0x08
+	bit	SCAMEN		0x04
+	bit	CLRCHN		0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+	address			0x002
+	access_mode RW
+	bit	BITBUCKET	0x80
+	bit	SWRAPEN		0x40
+	bit	ENSPCHK		0x20
+	mask	STIMESEL	0x18
+	bit	ENSTIMER	0x04
+	bit	ACTNEGEN	0x02
+	bit	STPWEN		0x01	/* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+	address			0x003
+	access_mode RO
+	bit	CDI		0x80
+	bit	IOI		0x40
+	bit	MSGI		0x20
+	bit	ATNI		0x10
+	bit	SELI		0x08
+	bit	BSYI		0x04
+	bit	REQI		0x02
+	bit	ACKI		0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+	address			0x003
+	access_mode WO
+	bit	CDO		0x80
+	bit	IOO		0x40
+	bit	MSGO		0x20
+	bit	ATNO		0x10
+	bit	SELO		0x08
+	bit	BSYO		0x04
+	bit	REQO		0x02
+	bit	ACKO		0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+	address			0x004
+	access_mode RW
+	bit	WIDEXFER	0x80		/* Wide transfer control */
+	mask	SXFR		0x70		/* Sync transfer rate */
+	mask	SOFS		0x0f		/* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID	{
+	address			0x005
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	OID		0x0f		/* Our ID mask */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+	address			0x006
+	access_mode RW
+}
+
+register SCSIDATH {
+	address			0x007
+	access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transferred.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+register STCNT {
+	address			0x008
+	size	3
+	access_mode RW
+}
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+	address			0x00b
+	access_mode WO
+	bit	CLRSELDO	0x40
+	bit	CLRSELDI	0x20
+	bit	CLRSELINGO	0x10
+	bit	CLRSWRAP	0x08
+	bit	CLRSPIORDY	0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+register SSTAT0	{
+	address			0x00b
+	access_mode RO
+	bit	TARGET		0x80		/* Board acting as target */
+	bit	SELDO		0x40		/* Selection Done */
+	bit	SELDI		0x20		/* Board has been selected */
+	bit	SELINGO		0x10		/* Selection In Progress */
+	bit	SWRAP		0x08		/* 24bit counter wrap */
+	bit	SDONE		0x04		/* STCNT = 0x000000 */
+	bit	SPIORDY		0x02		/* SCSI PIO Ready */
+	bit	DMADONE		0x01		/* DMA transfer completed */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+	address			0x00c
+	access_mode WO
+	bit	CLRSELTIMEO	0x80
+	bit	CLRATNO		0x40
+	bit	CLRSCSIRSTI	0x20
+	bit	CLRBUSFREE	0x08
+	bit	CLRSCSIPERR	0x04
+	bit	CLRPHASECHG	0x02
+	bit	CLRREQINIT	0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1	{
+	address			0x00c
+	access_mode RO
+	bit	SELTO		0x80
+	bit	ATNTARG 	0x40
+	bit	SCSIRSTI	0x20
+	bit	PHASEMIS	0x10
+	bit	BUSFREE		0x08
+	bit	SCSIPERR	0x04
+	bit	PHASECHG	0x02
+	bit	REQINIT		0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+	address			0x00d
+	access_mode RO
+	bit	OVERRUN		0x80
+	mask	SFCNT		0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+	address			0x00e
+	access_mode RO
+	mask	SCSICNT		0xf0
+	mask	OFFCNT		0x0f
+}
+
+/*
+ * SCSI Test Control (p. 3-27)
+ */
+register SCSITEST {
+	address			0x00f
+	access_mode RW
+	bit	RQAKCNT		0x04
+	bit	CNTRTEST	0x02
+	bit	CMODE		0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+	address			0x010
+	access_mode RW
+	bit	ENSELDO		0x40
+	bit	ENSELDI		0x20
+	bit	ENSELINGO	0x10
+	bit	ENSWRAP		0x08
+	bit	ENSDONE		0x04
+	bit	ENSPIORDY	0x02
+	bit	ENDMADONE	0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+	address			0x011
+	access_mode RW
+	bit	ENSELTIMO	0x80
+	bit	ENATNTARG	0x40
+	bit	ENSCSIRST	0x20
+	bit	ENPHASEMIS	0x10
+	bit	ENBUSFREE	0x08
+	bit	ENSCSIPERR	0x04
+	bit	ENPHASECHG	0x02
+	bit	ENREQINIT	0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+	address			0x012
+	access_mode RO
+}
+
+register SCSIBUSH {
+	address			0x013
+	access_mode RO
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+	address			0x014
+	size	4
+	access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+	address			0x018
+	access_mode RW
+	bit	STAGE6		0x20
+	bit	STAGE5		0x10
+	bit	STAGE4		0x08
+	bit	STAGE3		0x04
+	bit	STAGE2		0x02
+	bit	STAGE1		0x01
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+	address			0x019
+	access_mode RW
+	mask	SELID_MASK	0xf0
+	bit	ONEBIT		0x08
+}
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection.  In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+	address			0x01f
+	access_mode RW
+	bit	DIAGLEDEN	0x80	/* Aic78X0 only */
+	bit	DIAGLEDON	0x40	/* Aic78X0 only */
+	bit	AUTOFLUSHDIS	0x20
+	bit	SELBUSB		0x08
+	bit	SELWIDE		0x02
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+	address			0x060
+	access_mode RW
+	bit	PERRORDIS	0x80
+	bit	PAUSEDIS	0x40
+	bit	FAILDIS		0x20
+	bit	FASTMODE	0x10
+	bit	BRKADRINTEN	0x08
+	bit	STEP		0x04
+	bit	SEQRESET	0x02
+	bit	LOADRAM		0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in sucessesion.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+	address			0x061
+	access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+	address			0x062
+	access_mode RW
+}
+
+register SEQADDR1 {
+	address			0x063
+	access_mode RW
+	mask	SEQADDR1_MASK	0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+	address			0x064
+	access_mode RW
+	accumulator
+}
+
+register SINDEX	{
+	address			0x065
+	access_mode RW
+	sindex
+}
+
+register DINDEX {
+	address			0x066
+	access_mode RW
+}
+
+register ALLONES {
+	address			0x069
+	access_mode RO
+	allones
+}
+
+register ALLZEROS {
+	address			0x06a
+	access_mode RO
+	allzeros
+}
+
+register NONE {
+	address			0x06a
+	access_mode WO
+	none
+}
+
+register FLAGS {
+	address			0x06b
+	access_mode RO
+	bit	ZERO		0x02
+	bit	CARRY		0x01
+}
+
+register SINDIR	{
+	address			0x06c
+	access_mode RO
+}
+
+register DINDIR	 {
+	address			0x06d
+	access_mode WO
+}
+
+register FUNCTION1 {
+	address			0x06e
+	access_mode RW
+}
+
+register STACK {
+	address			0x06f
+	access_mode RO
+}
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+	address			0x084
+	access_mode RW
+	bit	ACE		0x08
+	bit	ENABLE		0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND {
+	address			0x084
+	access_mode RW
+	bit	CACHETHEN	0x80	/* Cache Threshold enable */
+	bit	DPARCKEN	0x40	/* Data Parity Check Enable */
+	bit	MPARCKEN	0x20	/* Memory Parity Check Enable */
+	bit	EXTREQLCK	0x10	/* External Request Lock */
+}
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+register BUSTIME {
+	address			0x085
+	access_mode RW
+	mask	BOFF		0xf0
+	mask	BON		0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+register BUSSPD {
+	address			0x086
+	access_mode RW
+	mask	DFTHRSH		0xc0
+	mask	STBOFF		0x38
+	mask	STBON		0x07
+	mask	DFTHRSH_100	0xc0
+}
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+	address			0x087
+	access_mode RW
+	bit	POWRDN		0x40
+	bit	SWINT		0x10
+	bit	IRQMS		0x08
+	bit	PAUSE		0x04
+	bit	INTEN		0x02
+	bit	CHIPRST		0x01
+	bit	CHIPRSTACK	0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+	address			0x088
+	size	4
+	access_mode RW
+}
+
+register HCNT {
+	address			0x08c
+	size	3
+	access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+	address			0x090
+	access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+	address			0x091
+	access_mode RW
+	bit	BRKADRINT 0x08
+	bit	SCSIINT	  0x04
+	bit	CMDCMPLT  0x02
+	bit	SEQINT    0x01
+	mask	BAD_PHASE	SEQINT		/* unknown scsi bus phase */
+	mask	SEND_REJECT	0x10|SEQINT	/* sending a message reject */
+	mask	NO_IDENT	0x20|SEQINT	/* no IDENTIFY after reconnect*/
+	mask	NO_MATCH	0x30|SEQINT	/* no cmd match for reconnect */
+	mask	EXTENDED_MSG	0x40|SEQINT	/* Extended message received */
+	mask	NO_MATCH_BUSY	0x50|SEQINT	/* Couldn't find BUSY SCB */
+	mask	REJECT_MSG	0x60|SEQINT	/* Reject message received */
+	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
+	mask	RESIDUAL	0x80|SEQINT	/* Residual byte count != 0 */
+	mask	ABORT_CMDCMPLT	0x91		/*
+						 * Command tagged for abort
+						 * completed successfully.
+						 */
+	mask	AWAITING_MSG	0xa0|SEQINT	/*
+						 * Kernel requested to specify
+                                                 * a message to this target
+                                                 * (command was null), so tell
+                                                 * it that it can fill the
+                                                 * message buffer.
+                                                 */
+	mask	MSG_BUFFER_BUSY	0xc0|SEQINT	/*
+						 * Sequencer wants to use the
+						 * message buffer, but it
+						 * already contains a message
+						 */
+	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
+						 * Target changed phase on us
+						 * when we were expecting
+						 * another msgin byte.
+						 */
+	mask	DATA_OVERRUN	0xe0|SEQINT	/*
+						 * Target attempted to write
+						 * beyond the bounds of its
+						 * command.
+						 */
+
+	mask	SEQINT_MASK	0xf0|SEQINT	/* SEQINT Status Codes */
+	mask	INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+	address			0x092
+	access_mode RO
+	bit	PARERR		0x08
+	bit	ILLOPCODE	0x04
+	bit	ILLSADDR	0x02
+	bit	ILLHADDR	0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+	address			0x092
+	access_mode WO
+	bit	CLRBRKADRINT	0x08
+	bit	CLRSCSIINT      0x04
+	bit	CLRCMDINT 	0x02
+	bit	CLRSEQINT 	0x01
+}
+
+register DFCNTRL {
+	address			0x093
+	access_mode RW
+	bit	WIDEODD		0x40
+	bit	SCSIEN		0x20
+	bit	SDMAEN		0x10
+	bit	SDMAENACK	0x10
+	bit	HDMAEN		0x08
+	bit	HDMAENACK	0x08
+	bit	DIRECTION	0x04
+	bit	FIFOFLUSH	0x02
+	bit	FIFORESET	0x01
+}
+
+register DFSTATUS {
+	address			0x094
+	access_mode RO
+	bit	DWORDEMP	0x20
+	bit	MREQPEND	0x10
+	bit	HDONE		0x08
+	bit	DFTHRESH	0x04
+	bit	FIFOFULL	0x02
+	bit	FIFOEMP		0x01
+}
+
+register DFDAT {
+	address			0x099
+	access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+	address			0x09a
+	access_mode RW
+	bit	SCBAUTO		0x80
+	mask	SCBCNT_MASK	0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+	address			0x09b
+	access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT	{
+	address			0x09c
+	access_mode RO
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+	address			0x09d
+	access_mode WO
+}
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+	address			0x09e
+	access_mode RO
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+	address			0x0a0
+	SCB_CONTROL {
+		size	1
+		bit	MK_MESSAGE      0x80
+		bit	DISCENB         0x40
+		bit	TAG_ENB		0x20
+		bit	MUST_DMAUP_SCB	0x10
+		bit	ABORT_SCB	0x08
+		bit	DISCONNECTED	0x04
+		mask	SCB_TAG_TYPE	0x03
+	}
+	SCB_TCL {
+		size	1
+		bit	SELBUSB		0x08
+		mask	TID		0xf0
+		mask	LID		0x07
+	}
+	SCB_TARGET_STATUS {
+		size	1
+	}
+	SCB_SGCOUNT {
+		size	1
+	}
+	SCB_SGPTR {
+		size	4
+	}
+	SCB_RESID_SGCNT {
+		size	1
+	}
+	SCB_RESID_DCNT	{
+		size	3
+	}
+	SCB_DATAPTR {
+		size	4
+	}
+	SCB_DATACNT {
+		size	3
+	}
+	SCB_LINKED_NEXT {
+		size	1
+	}
+	SCB_CMDPTR {
+		size	4
+	}
+	SCB_CMDLEN {
+		size	1
+	}
+	SCB_TAG {
+		size	1
+	}
+	SCB_NEXT {
+		size	1
+	}
+	SCB_PREV {
+		size	1
+	}
+	SCB_BUSYTARGETS {
+		size	4
+	}
+}
+
+const	SG_SIZEOF	0x08		/* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+	address			0x0c0
+	access_mode RW
+	bit	CS_2840		0x04
+	bit	CK_2840		0x02
+	bit	DO_2840		0x01
+}
+
+register STATUS_2840 {
+	address			0x0c1
+	access_mode RW
+	bit	EEPROM_TF	0x80
+	mask	BIOS_SEL	0x60
+	mask	ADSEL		0x1e
+	bit	DI_2840		0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register DSPCISTATUS {
+	address			0x086
+}
+
+register BRDCTL	{
+	address			0x01d
+	bit	BRDDAT7		0x80
+	bit	BRDDAT6		0x40
+	bit	BRDDAT5		0x20
+	bit	BRDSTB		0x10
+	bit	BRDCS		0x08
+	bit	BRDRW		0x04
+	bit	BRDCTL1		0x02
+	bit	BRDCTL0		0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+register SEECTL {
+	address			0x01e
+	bit	EXTARBACK	0x80
+	bit	EXTARBREQ	0x40
+	bit	SEEMS		0x20
+	bit	SEERDY		0x10
+	bit	SEECS		0x08
+	bit	SEECK		0x04
+	bit	SEEDO		0x02
+	bit	SEEDI		0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, 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).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+	address			0x020
+
+	/*
+	 * 1 byte per target starting at this address for configuration values
+	 */
+	TARG_SCRATCH {
+		size		16
+	}
+	ULTRA_ENB {
+		size		2
+	}
+	/*
+	 * Bit vector of targets that have disconnection disabled.
+	 */
+	DISC_DSB {
+		size		2
+	}
+	/*
+	 * Length of pending message
+	 */
+	MSG_LEN	{
+		size		1
+	}
+	/* We reserve 8bytes to store outgoing messages */
+	MSG_OUT {
+		size		8
+	}
+	/* Parameters for DMA Logic */
+	DMAPARAMS {
+		size		1
+		bit	WIDEODD		0x40
+		bit	SCSIEN		0x20
+		bit	SDMAEN		0x10
+		bit	SDMAENACK	0x10
+		bit	HDMAEN		0x08
+		bit	HDMAENACK	0x08
+		bit	DIRECTION	0x04
+		bit	FIFOFLUSH	0x02
+		bit	FIFORESET	0x01
+	}
+	/*
+	 * Number of SCBs supported by
+	 * this card.
+	 */
+	SCBCOUNT {
+		size		1
+	}
+	/*
+	 * Two's complement of SCBCOUNT
+	 */
+	COMP_SCBCOUNT {
+		size		1
+	}
+	/*
+	 * Mask of bits to test against
+	 * when looking at the Queue Count
+	 * registers.  Works around a bug
+	 * on aic7850 chips. 
+	 */
+	QCNTMASK {
+		size		1
+	}
+	SEQ_FLAGS {
+		size		1
+		bit	RESELECTED	0x80
+		bit	IDENTIFY_SEEN	0x40
+		bit	TAGGED_SCB	0x20
+		bit	DPHASE		0x10
+		bit	PAGESCBS	0x04
+		bit	WIDE_BUS	0x02
+		bit	TWIN_BUS	0x01
+	}
+	/*
+	 * Temporary storage for the
+	 * target/channel/lun of a
+	 * reconnecting target
+	 */
+	SAVED_TCL {
+		size		1
+	}
+	SG_COUNT {
+		size		1
+	}
+	/* working value of SG pointer */
+	SG_NEXT	{
+		size		4
+	}
+	/*
+	 * head of list of SCBs awaiting
+	 * selection
+	 */
+	WAITING_SCBH {
+		size		1
+	}
+	SAVED_LINKPTR {
+		size		1
+	}
+	SAVED_SCBPTR {
+		size		1
+	}
+	/*
+	 * The sequencer will stick the frist byte of any rejected message here
+	 * so we can see what is getting thrown away.
+	 */
+	REJBYTE	{
+		size		1
+	}
+	/*
+	 * The last bus phase as seen by the sequencer. 
+	 */
+	LASTPHASE {
+		size		1
+		bit	CDI		0x80
+		bit	IOI		0x40
+		bit	MSGI		0x20
+		mask	PHASE_MASK	CDI|IOI|MSGI
+		mask	P_DATAOUT	0x00
+		mask	P_DATAIN	IOI
+		mask	P_COMMAND	CDI
+		mask	P_MESGOUT	CDI|MSGI
+		mask	P_STATUS	CDI|IOI
+		mask	P_MESGIN	CDI|IOI|MSGI
+		mask	P_BUSFREE	0x01
+	}
+	MSGIN_EXT_LEN {
+		size		1
+	}
+	MSGIN_EXT_OPCODE {
+		size		1
+	}
+	/*
+	 * location 3, stores the last
+	 * byte of an extended message if
+	 * it passes the two bytes of space
+	 * we allow now.  This byte isn't
+	 * used for anything, it just makes
+	 * the code shorter for tossing
+	 * extra bytes.
+	 */
+	MSGIN_EXT_BYTES	{
+		size		3
+	}
+	/*
+	 * head of list of SCBs that are
+	 * disconnected.  Used for SCB
+	 * paging.
+	 */
+	DISCONNECTED_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * not in use.  Used for SCB paging.
+	 */
+	FREE_SCBH {
+		size		1
+	}
+	HSCB_ADDR {
+		size		4
+	}
+	CUR_SCBID {
+		size		1
+	}
+	ARG_1 {
+		size		1
+		mask	SEND_MSG	0x80
+		mask	SEND_SENSE	0x40
+		mask	SEND_REJ	0x20
+		alias	RETURN_1
+	}
+	/*
+	 * These are reserved registers in the card's scratch ram.  Some of
+	 * the values are specified in the AHA2742 technical reference manual
+	 * and are initialized by the BIOS at boot time.
+	 */
+	SCSICONF {
+		address		0x05a
+		size		1
+		bit	RESET_SCSI	0x40
+	}
+	HOSTCONF {
+		address		0x05d
+		size		1
+	}
+	HA_274_BIOSCTRL	{
+		address		0x05f
+		size		1
+		mask	BIOSMODE		0x30
+		mask	BIOSDISABLED		0x30	
+		bit	CHANNEL_B_PRIMARY	0x08
+	}
+}
+
+const SCB_LIST_NULL	0xff
+
+
+/* WDTR Message values */
+const BUS_8_BIT		0x00
+const BUS_16_BIT		0x01
+const BUS_32_BIT		0x02
+const MAX_OFFSET_8BIT		0x0f
+const MAX_OFFSET_16BIT	0x08
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- v2.1.47/linux/drivers/scsi/aic7xxx/aic7xxx.seq	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Thu Jul 31 12:37:17 1997
@@ -0,0 +1,1147 @@
+/*
+ * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
+ */
+
+#include <aic7xxx.reg>
+#include <scsi_message.h>
+
+/*
+ * A few words on the waiting SCB list:
+ * After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
+ * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
+ * this list everytime a request sense occurs or after completing a non-tagged
+ * command for which a second SCB has been queued.  The sequencer will
+ * automatically consume the entries.
+ */
+
+/*
+ * We assume that the kernel driver may reset us at any time, even in the
+ * middle of a DMA, so clear DFCNTRL too.
+ */
+reset:
+	clr	SCSISIGO;		/* De-assert BSY */
+	/* Always allow reselection */
+	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
+	call	clear_target_state;
+poll_for_work:
+	test	SSTAT0,SELDO	jnz select;
+	test	SSTAT0,SELDI	jnz reselect;
+	test	SCSISEQ, ENSELO	jnz poll_for_work;
+.if ( TWIN_CHANNEL )
+	/*
+	 * Twin channel devices cannot handle things like SELTO
+	 * interrupts on the "background" channel.  So, if we
+	 * are selecting, keep polling the current channel util
+	 * either a selection or reselection occurs.
+	 */
+	xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
+	test	SSTAT0,SELDO	jnz select;
+	test	SSTAT0,SELDI	jnz reselect;
+	test	SCSISEQ, ENSELO	jnz poll_for_work;
+	xor	SBLKCTL,SELBUSB;	/* Toggle back */
+.endif
+	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
+test_queue:
+	/* Has the driver posted any work for us? */
+	mov	A, QCNTMASK;
+	test	QINCNT,A	jz poll_for_work;
+
+/*
+ * We have at least one queued SCB now and we don't have any 
+ * SCBs in the list of SCBs awaiting selection.  If we have
+ * any SCBs available for use, pull the tag from the QINFIFO
+ * and get to work on it.
+ */
+.if ( SCB_PAGING )
+	mov	ALLZEROS	call	get_free_or_disc_scb;
+	cmp	SINDEX, SCB_LIST_NULL	je poll_for_work;
+.endif
+dequeue_scb:
+	mov	CUR_SCBID,QINFIFO;
+.if !( SCB_PAGING )
+	/* In the non-paging case, the SCBID == hardware SCB index */
+	mov	SCBPTR, CUR_SCBID;
+.endif
+dma_queued_scb:
+/*
+ * DMA the SCB from host ram into the current SCB location.
+ */
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	CUR_SCBID	call dma_scb;
+
+/*
+ * See if there is not already an active SCB for this target.  This code
+ * locks out on a per target basis instead of target/lun.  Although this
+ * is not ideal for devices that have multiple luns active at the same
+ * time, it is faster than looping through all SCB's looking for active
+ * commands.  We also don't have enough spare SCB space for us to store the
+ * SCBID of the currently busy transaction for each target/lun making it
+ * impossible to link up the SCBs.
+ */
+test_busy:
+	test	SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
+	mvi	SEQCTL, PAUSEDIS|FASTMODE;
+	mov	SAVED_SCBPTR, SCBPTR;
+	mov	SCB_TCL		call	index_untagged_scb;
+	mov	ARG_1, SINDIR;			/*
+						 * ARG_1 should
+						 * now have the SCB ID of
+						 * any active, non-tagged,
+						 * command for this target.
+						 */
+	cmp	ARG_1, SCB_LIST_NULL je make_busy;
+.if ( SCB_PAGING )
+	/*
+	 * Put this SCB back onto the free list.  It
+	 * may be necessary to satisfy the search for
+	 * the active SCB.
+	 */
+	mov	SCBPTR, SAVED_SCBPTR;
+	call	add_scb_to_free_list;
+	/* Find the active SCB */
+	mov	ALLZEROS	call findSCB;
+	/*
+	 * If we couldn't find it, tell the kernel.  This should
+	 * never happen.
+	 */
+	cmp	SINDEX, SCB_LIST_NULL	jne paged_busy_link;
+	mvi	INTSTAT, NO_MATCH_BUSY;
+paged_busy_link:
+	/* Link us in */
+	mov	SCB_LINKED_NEXT, CUR_SCBID;
+	/* Put it back on the disconnected list */
+	call	add_scb_to_disc_list;
+	mvi	SEQCTL, FASTMODE;
+	jmp	poll_for_work;
+.else
+simple_busy_link:
+	mov	SCBPTR, ARG_1;
+	mov	SCB_LINKED_NEXT, CUR_SCBID;
+	mvi	SEQCTL, FASTMODE;
+	jmp	poll_for_work;
+.endif
+make_busy:
+	mov	DINDIR, CUR_SCBID;
+	mov	SCBPTR, SAVED_SCBPTR;
+	mvi	SEQCTL, FASTMODE;
+
+start_scb:
+	/*
+	 * Place us on the waiting list in case our selection
+	 * doesn't win during bus arbitration.
+	 */
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+start_waiting:
+	/*
+	 * Pull the first entry off of the waiting SCB list
+	 * We don't have to "test_busy" because only transactions that
+	 * have passed that test can be in the WAITING_SCB list.
+	 */
+	mov	SCBPTR, WAITING_SCBH;
+	call	start_selection;
+	jmp	poll_for_work;
+
+start_selection:
+.if ( TWIN_CHANNEL )
+	and	SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
+	and	A,SELBUSB,SCB_TCL;	/* Get new channel bit */
+	or	SINDEX,A;
+	mov	SBLKCTL,SINDEX;		/* select channel */
+.endif
+initialize_scsiid:
+	and	A, TID, SCB_TCL;	/* Get target ID */
+	and	SCSIID, OID;		/* Clear old target */
+	or	SCSIID, A;
+	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
+ */
+reselect:
+	clr	MSG_LEN;	/* Don't have anything in the mesg buffer */
+	mvi	CLRSINT0, CLRSELDI;
+	/* XXX test for and handle ONE BIT condition */
+	and	SAVED_TCL, SELID_MASK, SELID;
+	or	SEQ_FLAGS,RESELECTED;
+	jmp	select2;
+
+/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH.  Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select:
+	/* Turn off the selection hardware */
+	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
+						 * ATN on parity errors
+						 * for "in" phases
+						 */
+	mvi	CLRSINT0, CLRSELDO;
+	mov	SCBPTR, WAITING_SCBH;
+	mov	WAITING_SCBH,SCB_NEXT;
+	mov	SAVED_TCL, SCB_TCL;
+/*
+ * 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.
+ *
+ * Messages are stored in scratch RAM starting with a length byte
+ * followed by the message itself.
+ */
+
+mk_identify:
+	and	MSG_OUT,0x7,SCB_TCL;	/* lun */
+	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
+	or	MSG_OUT,A;		/* or in disconnect privledge */
+	or	MSG_OUT,MSG_IDENTIFYFLAG;
+	mvi	MSG_LEN, 1;
+
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
+ */
+mk_tag:
+	test	SCB_CONTROL,TAG_ENB jz  mk_message;
+	and	MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	mov	MSG_OUT[2],SCB_TAG;
+	add	MSG_LEN,2;	/* update message length */
+
+/*
+ * Interrupt the driver, and allow it to tweak the message buffer
+ * if it asks.
+ */
+mk_message:
+	test	SCB_CONTROL,MK_MESSAGE  jz select2;
+	mvi     INTSTAT,AWAITING_MSG;
+
+select2:
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ */
+	or	SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
+.if ( ULTRA )
+ultra:
+	mvi	SINDEX, ULTRA_ENB+1;
+	test	SAVED_TCL, 0x80		jnz ultra_2;	/* Target ID > 7 */
+	dec	SINDEX;
+ultra_2:
+	mov     FUNCTION1,SAVED_TCL;
+	mov     A,FUNCTION1;
+	test	SINDIR, A	jz ndx_dtr;
+	or	SXFRCTL0, FAST20;
+.endif
+ 
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCRATCH.
+ */
+ndx_dtr:
+	shr	A,4,SAVED_TCL;
+	test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
+	or	SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+	or	A,0x08;			/* Channel B entries add 8 */
+ndx_dtr_2:
+	add	SINDEX,TARG_SCRATCH,A;
+	mov	SCSIRATE,SINDIR;
+
+
+/*
+ * 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.
+ *
+ */
+ITloop:
+	test	SSTAT1,REQINIT		jz ITloop;
+	test	SSTAT1, SCSIPERR	jnz ITloop;
+
+	and	A,PHASE_MASK,SCSISIGI;
+	mov	LASTPHASE,A;
+	mov	SCSISIGO,A;
+
+	cmp	ALLZEROS,A	je p_dataout;
+	cmp	A,P_DATAIN	je p_datain;
+	cmp	A,P_COMMAND	je p_command;
+	cmp	A,P_MESGOUT	je p_mesgout;
+	cmp	A,P_STATUS	je p_status;
+	cmp	A,P_MESGIN	je p_mesgin;
+
+	mvi	INTSTAT,BAD_PHASE;	/* unknown phase - signal driver */
+	jmp	ITloop;			/* Try reading the bus again. */
+
+await_busfree:
+	and	SIMODE1, ~ENBUSFREE;
+	call	clear_target_state;
+	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	test	SSTAT1,REQINIT|BUSFREE	jz .;
+	test	SSTAT1, BUSFREE jnz poll_for_work;
+	mvi	INTSTAT, BAD_PHASE;
+	
+clear_target_state:
+	clr	DFCNTRL;
+	clr	SCSIRATE;		/*
+					 * We don't know the target we will
+					 * connect to, so default to narrow
+					 * transfers to avoid parity problems.
+					 */
+	and	SXFRCTL0, ~FAST20;	
+	mvi	LASTPHASE, P_BUSFREE;
+	/* clear target specific flags */
+	and	SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
+
+p_dataout:
+	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
+	jmp	data_phase_init;
+
+/*
+ * If we re-enter the data phase after going through another phase, the
+ * STCNT may have been cleared, so restore it from the residual field.
+ */
+data_phase_reinit:
+	mvi	DINDEX, STCNT;
+	mvi	SCB_RESID_DCNT	call bcopy_3;
+	jmp	data_phase_loop;
+
+p_datain:
+	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+data_phase_init:
+	call	assert;			/*
+					 * Ensure entering a data
+					 * phase is okay - seen identify, etc.
+					 */
+
+	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+
+	/*
+	 * Initialize the DMA address and counter from the SCB.
+	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
+	 * modify the values in the SCB itself until we see a
+	 * save data pointers message.
+	 */
+	mvi	DINDEX, HADDR;
+	mvi	SCB_DATAPTR	call bcopy_7;
+
+	call	set_stcnt_from_hcnt;
+
+	mov	SG_COUNT,SCB_SGCOUNT;
+
+	mvi	DINDEX, SG_NEXT;
+	mvi	SCB_SGPTR	call bcopy_4;
+
+data_phase_loop:
+/* Guard against overruns */
+	test	SG_COUNT, 0xff jnz data_phase_inbounds;
+/*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
+	or	SXFRCTL1,BITBUCKET;
+	mvi	HCNT[0], 0xff;
+	mvi	HCNT[1], 0xff;
+	mvi	HCNT[2], 0xff;
+	call	set_stcnt_from_hcnt;
+
+data_phase_inbounds:
+/* If we are the last SG block, ensure wideodd is off. */
+	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+	and	DMAPARAMS, ~WIDEODD;
+data_phase_wideodd:
+	mov	DMAPARAMS  call dma;
+
+/* Go tell the host about any overruns */
+	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+
+/* Exit if we had an underrun.  dma clears SINDEX in this case. */
+	test	SINDEX,0xff	jz data_phase_finish;
+
+/*
+ * Advance the scatter-gather pointers if needed 
+ */
+sg_advance:
+	dec	SG_COUNT;	/* one less segment to go */
+
+	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
+
+	clr	A;			/* add sizeof(struct scatter) */
+	add	SG_NEXT[0],SG_SIZEOF;
+	adc	SG_NEXT[1],A;
+
+/*
+ * Load a struct scatter 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 all DMA's, assumes little-endian host data storage.
+ */
+sg_load:
+	mvi	DINDEX, HADDR;
+	mvi	SG_NEXT	call bcopy_4;
+
+	mvi	HCNT[0],SG_SIZEOF;
+	clr	HCNT[1];
+	clr	HCNT[2];
+
+	or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+	call	dma_finish;
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count.  This assumes
+ * that the SG segments are of the form:
+ *
+ * struct ahc_dma_seg {
+ *	u_int32_t	addr;		four bytes, little-endian order
+ *	u_int32_t	len;		four bytes, little endian order
+ * };
+ */
+	mvi	HADDR	call dfdat_in_7;
+
+/* Load STCNT as well.  It is a mirror of HCNT */
+	call	set_stcnt_from_hcnt;
+	test	SSTAT1,PHASEMIS	jz data_phase_loop;
+
+data_phase_finish:
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+	mov	SCB_RESID_DCNT[0],STCNT[0];
+	mov	SCB_RESID_DCNT[1],STCNT[1];
+	mov	SCB_RESID_DCNT[2],STCNT[2];
+	mov	SCB_RESID_SGCNT, SG_COUNT;
+
+	/* We have seen a data phase */
+	or	SEQ_FLAGS, DPHASE;
+
+	jmp	ITloop;
+
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+	and	SXFRCTL1, ~BITBUCKET;
+	mvi	INTSTAT,DATA_OVERRUN;
+	jmp	ITloop;
+
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+	call	assert;
+
+/*
+ * Load HADDR and HCNT.
+ */
+	mvi	DINDEX, HADDR;
+	mvi	SCB_CMDPTR	call bcopy_5;
+	clr	HCNT[1];
+	clr	HCNT[2];
+
+	call	set_stcnt_from_hcnt;
+
+	mvi	(SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+	jmp	ITloop;
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+	call	assert;
+
+	mov	SCB_TARGET_STATUS, SCSIDATL;
+	jmp	ITloop;
+
+/*
+ * Message out phase.  If there is not an active message, but the target
+ * took us into this phase anyway, build a no-op message and send it.
+ */
+p_mesgout:
+	test	MSG_LEN, 0xff	jnz  p_mesgout_start;
+	mvi	MSG_NOOP	call mk_mesg;	/* build NOP message */
+p_mesgout_start:
+/*
+ * Set up automatic PIO transfer from MSG_OUT.  Bit 3 in
+ * SXFRCTL0 (SPIOEN) is already on.
+ */
+	mvi	SINDEX,MSG_OUT;
+	mov	DINDEX,MSG_LEN;
+
+/*
+ * 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.
+ * ATN must be dropped *at least* 90ns before we ack the last byte, so
+ * the code is aranged to execute two instructions before the byte is
+ * transferred to give a good margin of safety
+ *
+ * Keep an eye out for a phase change, in case the target issues
+ * a MESSAGE REJECT.
+ */
+p_mesgout_loop:
+	test	SSTAT1, REQINIT		jz p_mesgout_loop;
+	test	SSTAT1, SCSIPERR	jnz p_mesgout_loop;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGOUT jne p_mesgout_done;
+p_mesgout_testretry:
+	test	DINDEX,0xff	jnz p_mesgout_dropatn;
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+	jmp	p_mesgout_start;
+/*
+ * 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_mesgout_dropatn:
+	cmp	DINDEX,1	jne p_mesgout_outb;	/* last byte? */
+	mvi	CLRSINT1,CLRATNO;			/* drop ATN */
+p_mesgout_outb:
+	dec	DINDEX;
+	mov	SCSIDATL,SINDIR;
+	jmp	p_mesgout_loop;
+
+p_mesgout_done:
+	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
+	clr	MSG_LEN;		/* no active msg */
+	jmp	ITloop;
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
+	mov	REJBYTE,A;			/* save it for the driver */
+
+	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
+	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
+	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
+	cmp	ALLZEROS,A		je mesgin_complete;
+	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
+	cmp	A,MSG_EXTENDED		je mesgin_extended;
+	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject;
+	cmp	A,MSG_NOOP		je mesgin_done;
+
+rej_mesgin:
+/*
+ * We have no idea what this message in is, so we issue a message reject
+ * and hope for the best.  In any case, rejection should be a rare
+ * occurrence - signal the driver when it happens.
+ */
+	mvi	INTSTAT,SEND_REJECT;		/* let driver know */
+
+	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
+
+mesgin_done:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+	jmp	ITloop;
+
+
+mesgin_complete:
+/*
+ * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * and trigger a completion interrupt.  Before doing so, check to see if there
+ * is a residual or the status byte is something other than NO_ERROR (0).  In
+ * either of these conditions, we upload the SCB back to the host so it can
+ * process this information.  In the case of a non zero status byte, we 
+ * additionally interrupt the kernel driver synchronously, allowing it to
+ * decide if sense should be retrieved.  If the kernel driver wishes to request
+ * sense, it will fill the kernel SCB with a request sense command and set
+ * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
+ * the SCB, and process it as the next command by adding it to the waiting list.
+ * If the kernel driver does not wish to request sense, it need only clear
+ * RETURN_1, and the command is allowed to complete normally.  We don't bother
+ * to post to the QOUTFIFO in the error cases since it would require extra
+ * work in the kernel driver to ensure that the entry was removed before the
+ * command complete code tried processing it.
+ */
+
+/*
+ * First check for residuals
+ */
+	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
+	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Good Status? */
+upload_scb:
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+check_status:
+	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Just a residual? */
+	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
+	cmp	RETURN_1, SEND_SENSE	jne status_ok;
+	/* This SCB becomes the next to execute as it will retrieve sense */
+	mov	SCB_LINKED_NEXT, SCB_TAG;
+	jmp	dma_next_scb;
+
+status_ok:
+/* First, mark this target as free. */
+	test	SCB_CONTROL,TAG_ENB jnz complete;	/*
+							 * Tagged commands
+							 * don't busy the
+							 * target.
+							 */
+	mov	SAVED_SCBPTR, SCBPTR;
+	mov	SAVED_LINKPTR, SCB_LINKED_NEXT;
+	mov	SCB_TCL	call index_untagged_scb;
+	mov	DINDIR, SAVED_LINKPTR;
+	mov	SCBPTR, SAVED_SCBPTR;
+
+complete:
+	/* Post the SCB and issue an interrupt */
+	mov	QOUTFIFO,SCB_TAG;
+	mvi	INTSTAT,CMDCMPLT;
+	test	SCB_CONTROL, ABORT_SCB jz dma_next_scb;
+	mvi	INTSTAT, ABORT_CMDCMPLT;
+
+dma_next_scb:
+	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL	je add_to_free_list;
+.if !( SCB_PAGING )
+	/* Only DMA on top of ourselves if we are the SCB to download */
+	mov	A, SCB_LINKED_NEXT;
+	cmp	SCB_TAG, A	je dma_next_scb2;
+	call	add_scb_to_free_list;
+	mov	SCBPTR, A;
+	jmp	add_to_waiting_list;
+.endif
+dma_next_scb2:
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	SCB_LINKED_NEXT		call dma_scb;
+add_to_waiting_list:
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+	/*
+	 * Prepare our selection hardware before the busfree so we have a
+	 * high probability of winning arbitration.
+	 */
+	call	start_selection;
+	jmp	await_busfree;
+add_to_free_list:
+	call	add_scb_to_free_list;
+	jmp	await_busfree;
+
+/*
+ * Is it an extended message?  Copy the message to our message buffer and
+ * notify the host.  The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * or simply to do nothing.
+ */
+mesgin_extended:
+	mvi	MSGIN_EXT_LEN	 call inb_next;
+	mov	A, MSGIN_EXT_LEN;
+mesgin_extended_loop:
+	mov	DINDEX	call	inb_next;
+	dec	A;
+	cmp	DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
+	dec	DINDEX;		/* dump by repeatedly filling the last byte */
+mesgin_extended_loop_test:
+	test	A, 0xFF		jnz mesgin_extended_loop;
+mesgin_extended_intr:
+	mvi	INTSTAT,EXTENDED_MSG;		/* let driver know */
+	cmp	RETURN_1,SEND_REJ je rej_mesgin;
+	cmp	RETURN_1,SEND_MSG jne mesgin_done;
+/* The kernel has setup a message to be sent */
+	or	SCSISIGO,ATNO,LASTPHASE;	/* turn on ATNO */
+	jmp	mesgin_done;
+
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
+mesgin_disconnect:
+	or	SCB_CONTROL,DISCONNECTED;
+.if ( SCB_PAGING )
+	call	add_scb_to_disc_list;
+.endif
+	jmp	await_busfree;
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
+mesgin_sdptrs:
+	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
+	mov	SCB_SGCOUNT,SG_COUNT;
+
+	/* The SCB SGPTR becomes the next one we'll download */
+	mvi	DINDEX, SCB_SGPTR;
+	mvi	SG_NEXT	call bcopy_4;
+	
+	/* The SCB DATAPTR0 becomes the current SHADDR */
+	mvi	DINDEX, SCB_DATAPTR;
+	mvi	SHADDR		call bcopy_4;
+
+/*
+ * Use the residual number since STCNT is corrupted by any message transfer.
+ */
+	mvi	SCB_RESID_DCNT	call	bcopy_3;
+
+	jmp	mesgin_done;
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
+mesgin_rdptrs:
+	and	SEQ_FLAGS, ~DPHASE;		/*
+						 * We'll reload them
+						 * the next time through
+						 * the dataphase.
+						 */
+	jmp	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.
+ */
+mesgin_identify:
+	test	A,0x78	jnz rej_mesgin;	/*!DiscPriv|!LUNTAR|!Reserved*/
+	and	A,0x07;			/* lun in lower three bits */
+	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
+	mov	SAVED_TCL call index_untagged_scb;
+	mov	ARG_1, SINDIR;
+.if ( SCB_PAGING )
+	cmp	ARG_1,SCB_LIST_NULL	jne use_findSCB;
+.else
+	cmp	ARG_1,SCB_LIST_NULL	je snoop_tag;
+	/* Directly index the SCB */
+	mov	SCBPTR,ARG_1;
+	test	SCB_CONTROL,DISCONNECTED jz not_found;
+	jmp	setup_SCB;
+.endif
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to find the proper
+ * SCB.  With SCB paging, this requires using findSCB for both tagged
+ * and non-tagged transactions since the SCB may exist in any slot.
+ * If we're not using SCB paging, we can use the tag as the direct
+ * index to the SCB.
+ */
+snoop_tag:
+	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
+snoop_tag_loop:
+	test	SSTAT1,REQINIT		jz snoop_tag_loop;
+	test	SSTAT1, SCSIPERR	jnz snoop_tag_loop;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGIN	jne not_found;
+	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
+get_tag:
+	or	SEQ_FLAGS, TAGGED_SCB;
+	mvi	ARG_1	call inb_next;	/* tag value */
+/*
+ * See if the tag is in range.  The tag is < SCBCOUNT if we add
+ * the complement of SCBCOUNT to the incomming tag and there is
+ * no carry.
+ */
+	mov	A,COMP_SCBCOUNT;
+	add	SINDEX,A,ARG_1;
+	jc	not_found;
+
+.if ! ( SCB_PAGING )
+index_by_tag:
+	mov	SCBPTR,ARG_1;
+	mov	A, SAVED_TCL;
+	cmp	SCB_TCL,A		jne not_found;
+	test	SCB_CONTROL,TAG_ENB	jz  not_found;
+	test	SCB_CONTROL,DISCONNECTED jz not_found;
+.else
+/*
+ * Ensure that the SCB the tag points to is for an SCB transaction
+ * to the reconnecting target.
+ */
+use_findSCB:
+	mov	ALLZEROS	call findSCB;	  /* Have to search */
+	cmp	SINDEX, SCB_LIST_NULL	je not_found;
+.endif
+setup_SCB:
+	and	SCB_CONTROL,~DISCONNECTED;
+	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
+	jmp	mesgin_done;
+
+not_found:
+	mvi	INTSTAT, NO_MATCH;
+	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
+	jmp	mesgin_done;
+
+/*
+ * Message reject?  Let the kernel driver handle this.  If we have an 
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from 
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+	mvi	INTSTAT, REJECT_MSG;
+	jmp	mesgin_done;
+
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * 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, PAUSEDIS|FASTMODE;
+	test	MSG_LEN,0xff	jz mk_mesg1;	/* Should always succeed */
+	
+	/*
+	 * Hmmm.  For some reason the mesg buffer is in use.
+	 * Tell the driver.  It should look at SINDEX to find
+	 * out what we wanted to use the buffer for and resolve
+	 * the conflict.
+	 */
+	mvi	SEQCTL,FASTMODE;
+	mvi	INTSTAT,MSG_BUFFER_BUSY;
+
+mk_mesg1:
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
+	mvi	MSG_LEN,1;		/* length = 1 */
+	mov	MSG_OUT,SINDEX;		/* 1-byte message */
+	mvi	SEQCTL,FASTMODE	ret;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * 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_next:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+inb_next_wait:
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
+	test	SSTAT1, REQINIT	jz inb_next_wait;
+	test	SSTAT1, SCSIPERR jnz inb_next_wait;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+	mov	DINDEX,SINDEX;
+	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
+inb_last:
+	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
+
+mesgin_phasemis:
+/*
+ * We expected to receive another byte, but the target changed phase
+ */
+	mvi	INTSTAT, MSGIN_PHASEMIS;
+	jmp	ITloop;
+
+/*
+ * 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;
+dma_loop:
+	test	SSTAT0,DMADONE	jnz dma_dmadone;
+	test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
+dma_phasemis:
+	test	SSTAT0,SDONE	jnz dma_checkfifo;
+	mov	SINDEX,ALLZEROS;		/* Notify caller of phasemiss */
+
+/*
+ * 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.
+ */
+dma_checkfifo:
+	test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
+dma_fifoflush:
+	test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
+
+dma_fifoempty:
+	/* Don't clobber an inprogress host data transfer */
+	test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are 
+ * actually off first lest we get an ILLSADDR.
+ */
+dma_dmadone:
+	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN)	jnz dma_halt; 
+return:
+	ret;
+
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * message.
+ */
+assert:
+	test	SEQ_FLAGS,RESELECTED	jz return;	/* reselected? */
+	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
+
+	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
+
+.if ( SCB_PAGING )
+/*
+ * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
+ * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
+ * otherwise, SCBPTR is set to the proper SCB.
+ */
+findSCB:
+	mov	SCBPTR,SINDEX;			/* switch to next SCB */
+	mov	A, ARG_1;			/* Tag passed in ARG_1 */
+	cmp	SCB_TAG,A	jne findSCB_loop;
+	test	SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
+findSCB_loop:
+	inc	SINDEX;
+	mov	A,SCBCOUNT;
+	cmp	SINDEX,A	jne findSCB;
+/*
+ * We didn't find it.  If we're paging, pull an SCB and DMA down the
+ * one we want.  If we aren't paging or the SCB we dma down has the
+ * abort flag set, return not found.
+ */
+	mov	ALLZEROS	call	get_free_or_disc_scb;
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	ARG_1	call dma_scb;
+	test	SCB_RESID_SGCNT, 0xff jz . + 2;
+	or	SCB_CONTROL, MUST_DMAUP_SCB;
+	test	SCB_CONTROL, ABORT_SCB jz return;
+find_error:
+	mvi	SINDEX, SCB_LIST_NULL ret;
+foundSCB:
+	test	SCB_CONTROL, ABORT_SCB jnz find_error;
+rem_scb_from_disc_list:
+/* Remove this SCB from the disconnection list */
+	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev;
+	mov	SAVED_LINKPTR, SCB_PREV;
+	mov	SCBPTR, SCB_NEXT;
+	mov	SCB_PREV, SAVED_LINKPTR;
+	mov	SCBPTR, SINDEX;
+unlink_prev:
+	cmp	SCB_PREV,SCB_LIST_NULL	je rHead;/* At the head of the list */
+	mov	SAVED_LINKPTR, SCB_NEXT;
+	mov	SCBPTR, SCB_PREV;
+	mov	SCB_NEXT, SAVED_LINKPTR;
+	mov	SCBPTR, SINDEX ret;
+rHead:
+	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
+.else
+	ret;
+.endif
+
+set_stcnt_from_hcnt:
+	mov	STCNT[0], HCNT[0];
+	mov	STCNT[1], HCNT[1];
+	mov	STCNT[2], HCNT[2] ret;
+
+bcopy_7:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+bcopy_5:
+	mov	DINDIR, SINDIR;
+bcopy_4:
+	mov	DINDIR, SINDIR;
+bcopy_3:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR ret;
+
+dma_scb:
+	/*
+	 * SCB index is in SINDEX.  Determine the physical address in
+	 * the host where this SCB is located and load HADDR with it.
+	 */
+	shr	DINDEX, 3, SINDEX;
+	shl	A, 5, SINDEX;
+	add	HADDR[0], A, HSCB_ADDR[0];
+	mov	A, DINDEX;
+	adc	HADDR[1], A, HSCB_ADDR[1];
+	clr	A;
+	adc	HADDR[2], A, HSCB_ADDR[2];
+	adc	HADDR[3], A, HSCB_ADDR[3];
+	/* Setup Count */
+	mvi	HCNT[0], 28;
+	clr	HCNT[1];
+	clr	HCNT[2];
+	mov	DFCNTRL, DMAPARAMS;
+	test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
+	/* Fill it with the SCB data */
+copy_scb_tofifo:
+	mvi	SINDEX, SCB_CONTROL;
+	add	A, 28, SINDEX;
+copy_scb_tofifo_loop:
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	cmp	SINDEX, A jne copy_scb_tofifo_loop;
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+dma_scb_fromhost:
+	call	dma_finish;
+	/* If we were putting the SCB, we are done */
+	test	DMAPARAMS, DIRECTION	jz	return;
+	mvi	SCB_CONTROL  call dfdat_in_7;
+	call	dfdat_in_7_continued;
+	call	dfdat_in_7_continued;
+	jmp	dfdat_in_7_continued;
+dfdat_in_7:
+	mov     DINDEX,SINDEX;
+dfdat_in_7_continued:
+	mov	DINDIR,DFDAT;
+	mov	DINDIR,DFDAT;
+	mov	DINDIR,DFDAT;
+	mov	DINDIR,DFDAT;
+	mov	DINDIR,DFDAT;
+	mov	DINDIR,DFDAT;
+	mov	DINDIR,DFDAT ret;
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+dma_finish:
+	test	DFSTATUS,HDONE	jz dma_finish;
+	/* Turn off DMA */
+	and	DFCNTRL, ~HDMAEN;
+	test	DFCNTRL, HDMAEN jnz .;
+	ret;
+
+index_untagged_scb:
+	mov	DINDEX, SINDEX;
+	shr	DINDEX, 4;
+	and	DINDEX, 0x03;			/* Bottom two bits of tid */
+	add	DINDEX, SCB_BUSYTARGETS;
+	shr	A, 6, SINDEX;			/* Target ID divided by 4 */
+	test	SINDEX, SELBUSB jz index_untagged_scb2;
+	add	A, 2;				/* Add 2 positions */
+index_untagged_scb2:
+	mov	SCBPTR, A;			/*
+						 * Select the SCB with this 
+						 * target's information.
+						 */
+	mov	SINDEX, DINDEX	ret;
+
+add_scb_to_free_list:
+	mov	SCB_NEXT, FREE_SCBH;
+	mvi	SCB_TAG, SCB_LIST_NULL;
+	mov	FREE_SCBH, SCBPTR ret;
+
+.if ( SCB_PAGING )
+get_free_or_disc_scb:
+	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
+return_error:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+dequeue_disc_scb:
+	mov	SCBPTR, DISCONNECTED_SCBH;
+/*
+ * If we have a residual, then we are in the middle of some I/O
+ * and we have to send this SCB back up to the kernel so that the
+ * saved data pointers and residual information isn't lost.
+ */
+	test	SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
+	and	SCB_CONTROL, ~MUST_DMAUP_SCB;
+	jmp	dma_up_scb;
+	test	SCB_RESID_SGCNT,0xff	jnz dma_up_scb;
+	cmp	SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
+dma_up_scb:
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+unlink_disc_scb:
+	/* jmp instead of call since we want to return anyway */
+	mov	SCBPTR	jmp rem_scb_from_disc_list;
+dequeue_free_scb:
+	mov	SCBPTR, FREE_SCBH;
+	mov	FREE_SCBH, SCB_NEXT ret;
+
+add_scb_to_disc_list:
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+	mvi	SCB_PREV, SCB_LIST_NULL;
+	mov	SCB_NEXT, DISCONNECTED_SCBH;
+	mov	DISCONNECTED_SCBH, SCBPTR;
+	cmp	SCB_NEXT,SCB_LIST_NULL je return;
+	mov	SCBPTR,SCB_NEXT;
+	mov	SCB_PREV,DISCONNECTED_SCBH;
+	mov	SCBPTR,DISCONNECTED_SCBH ret;
+.endif
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h
--- v2.1.47/linux/drivers/scsi/aic7xxx/scsi_message.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/scsi_message.h	Thu Jul 31 12:37:17 1997
@@ -0,0 +1,41 @@
+/*
+ * SCSI messages definitions.
+ */
+
+/* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
+#define MSG_CMDCOMPLETE		0x00 /* M/M */
+#define MSG_EXTENDED		0x01 /* O/O */
+#define MSG_SAVEDATAPOINTER	0x02 /* O/O */
+#define MSG_RESTOREPOINTERS	0x03 /* O/O */
+#define MSG_DISCONNECT		0x04 /* O/O */
+#define MSG_INITIATOR_DET_ERR	0x05 /* M/M */
+#define MSG_ABORT		0x06 /* O/M */
+#define MSG_MESSAGE_REJECT	0x07 /* M/M */
+#define MSG_NOOP		0x08 /* M/M */
+#define MSG_PARITY_ERROR	0x09 /* M/M */
+#define MSG_LINK_CMD_COMPLETE	0x0a /* O/O */
+#define MSG_LINK_CMD_COMPLETEF	0x0b /* O/O */
+#define MSG_BUS_DEV_RESET	0x0c /* O/M */
+#define MSG_ABORT_TAG		0x0d /* O/O */
+#define MSG_CLEAR_QUEUE		0x0e /* O/O */
+#define MSG_INIT_RECOVERY	0x0f /* O/O */
+#define MSG_REL_RECOVERY	0x10 /* O/O */
+#define MSG_TERM_IO_PROC	0x11 /* O/O */
+
+/* Messages (2 byte) */
+#define MSG_SIMPLE_Q_TAG	0x20 /* O/O */
+#define MSG_HEAD_OF_Q_TAG	0x21 /* O/O */
+#define MSG_ORDERED_Q_TAG	0x22 /* O/O */
+#define MSG_IGN_WIDE_RESIDUE	0x23 /* O/O */
+
+/* Identify message */		     /* M/M */	
+#define MSG_IDENTIFYFLAG	0x80 
+#define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
+#define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
+
+/* Extended messages (opcode and length) */
+#define MSG_EXT_SDTR		0x01
+#define MSG_EXT_SDTR_LEN	0x03
+
+#define MSG_EXT_WDTR		0x03
+#define MSG_EXT_WDTR_LEN	0x02
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h
--- v2.1.47/linux/drivers/scsi/aic7xxx/sequencer.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/sequencer.h	Thu Jul 31 12:37:17 1997
@@ -0,0 +1,102 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      $Id: sequencer.h,v 1.2 1997/06/27 19:38:52 gibbs Exp $
+ */
+
+#if defined(__KERNEL__)
+typedef unsigned char u_int8_t;
+#endif
+
+struct ins_format1 {
+	u_int8_t immediate;
+	u_int8_t source;
+	u_int8_t destination;
+	u_int8_t opcode_ret;
+};
+
+struct ins_format2 {
+	u_int8_t shift_control;
+	u_int8_t source;
+	u_int8_t destination;
+	u_int8_t opcode_ret;
+#define RETURN_BIT 0x01
+};
+
+struct ins_format3 {
+	u_int8_t immediate;
+	u_int8_t source;
+	u_int8_t address;
+	u_int8_t opcode_addr;
+#define ADDR_HIGH_BIT 0x01
+};
+
+struct instruction {
+	union {
+		struct ins_format1 format1;
+		struct ins_format2 format2;
+		struct ins_format3 format3;
+		u_int8_t	   bytes[4];
+	} format;
+	u_int	srcline;
+	struct symbol *patch_label;
+	struct {
+		struct instruction *stqe_next; /* next element */
+	} links;
+};
+
+#define	AIC_OP_OR	0x0
+#define	AIC_OP_AND	0x1
+#define AIC_OP_XOR	0x2
+#define	AIC_OP_ADD	0x3
+#define	AIC_OP_ADC	0x4
+#define	AIC_OP_ROL	0x5
+
+#define	AIC_OP_JMP	0x8
+#define AIC_OP_JC	0x9
+#define AIC_OP_JNC	0xa
+#define AIC_OP_CALL	0xb
+#define	AIC_OP_JNE	0xc
+#define	AIC_OP_JNZ	0xd
+#define	AIC_OP_JE	0xe
+#define	AIC_OP_JZ	0xf
+
+/* Pseudo Ops */
+#define	AIC_OP_SHL	0x10
+#define	AIC_OP_SHR	0x20
+#define	AIC_OP_ROR	0x30
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.1.47/linux/drivers/scsi/aic7xxx.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/aic7xxx.c	Thu Jul 31 12:37:17 1997
@@ -1,5 +1,3 @@
-#define EXPERIMENTAL_FLAGS 0
-
 /*+M*************************************************************************
  * Adaptec AIC7xxx device driver for Linux.
  *
@@ -29,21 +27,73 @@
  * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
  * ANSI SCSI-2 specification (draft 10c), ...
  *
- * ----------------------------------------------------------------
- *  Modified to include support for wide and twin bus adapters,
- *  DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ * --------------------------------------------------------------------------
+ *
+ *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ *  Substantially modified to include support for wide and twin bus
+ *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
  *  SCB paging, and other rework of the code.
  *
- *  Parts of this driver are based on the FreeBSD driver by Justin
- *  T. Gibbs.
+ *  Parts of this driver were also based on the FreeBSD driver by
+ *  Justin T. Gibbs.  His copyright follows:
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ *  Thanks also go to (in alphabetical order) the following:
+ *
+ *    Rory Bolt     - Sequencer bug fixes
+ *    Jay Estabrook - Initial DEC Alpha support
+ *    Doug Ledford  - Much needed abort/reset bug fixes
+ *    Kai Makisara  - DMAing of SCBs
  *
  *  A Boot time option was also added for not resetting the scsi bus.
  *
- *    Form:  aic7xxx=extended,no_reset
+ *    Form:  aic7xxx=extended
+ *           aic7xxx=no_reset
+ *           aic7xxx=ultra
+ *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
+ *           aic7xxx=verbose
  *
- *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
  *
- *  $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
  *-M*************************************************************************/
 
 #ifdef MODULE
@@ -67,7 +117,11 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx.h"
+
+#include "aic7xxx/sequencer.h"
+#include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
+#include "aic7xxx_seq.h"
 #include <linux/stat.h>
 #include <linux/malloc.h>	/* for kmalloc() */
 
@@ -79,16 +133,20 @@
  */
 #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
 
-static struct proc_dir_entry proc_scsi_aic7xxx = {
+struct proc_dir_entry proc_scsi_aic7xxx = {
     PROC_SCSI_AIC7XXX, 7, "aic7xxx",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
+    S_IFDIR | S_IRUGO | S_IXUGO, 2,
+    0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.0 $"
+#define AIC7XXX_C_VERSION  "$Revision: 4.1 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b)        ((a < b) ? a : b)
+#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
+#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
 #define ALL_TARGETS -1
+#define ALL_CHANNELS '\0'
+#define ALL_LUNS -1
 #ifndef TRUE
 #  define TRUE 1
 #endif
@@ -107,11 +165,8 @@
  *     support because all PCI dependent code is bracketed with
  *     "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
  *
- *   o Twin bus support - this has been tested and does work.
- *
- *   o DMAing of SCBs - thanks to Kai Makisara, this now works.
- *     This define is now taken out and DMAing of SCBs is always
- *     performed (8/12/95 - DE).
+ *   o Twin bus support - this has been tested and does work.  It is
+ *     not an option anymore.
  *
  *   o Tagged queueing - this driver is capable of tagged queueing
  *     but I am unsure as to how well the higher level driver implements
@@ -140,16 +195,16 @@
  *     LUN using its own heuristic based on the number of available
  *     SCBs.
  *
- *   o 3985 support - The 3985 adapter is much like the 3940, but
- *     has three 7870 controllers as opposed to two for the 3940.
- *     It will get probed and recognized as three different adapters,
- *     but all three controllers can share the same external bank of
- *     255 SCBs.  If you enable AIC7XXX_SHARE_SCBS, then the driver
- *     will attempt to share the common bank of SCBs between the three
- *     controllers of the 3985.  This is experimental and hasn't
- *     been tested.  By default, we do not share the bank of SCBs,
- *     and force the controllers to use their own internal bank of
- *     16 SCBs.  Please let us know if sharing the SCB array works.
+ *   o 3985 support - The 3985 adapter is much like the 3940, but has
+ *     three 7870 controllers as opposed to two for the 3940.  It will
+ *     be probed and recognized as three different adapters, but all
+ *     three controllers can share the same external bank of 255 SCBs.
+ *     If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
+ *     to use and share the common bank of SCBs between the three
+ *     controllers of the 3985.  This is experimental and hasn't been
+ *     been tested.  By default, we do not use external SCB RAM, and
+ *     force the controllers to use their own internal bank of 16 SCBs.
+ *     Please let us know if using the external SCB array works.
  *
  *   o SCB paging support - SCB paging is enabled by defining
  *     AIC7XXX_PAGE_ENABLE.  Support for this was taken from the
@@ -162,43 +217,54 @@
  *  Note that sharing of IRQs is not an option any longer.  Linux supports
  *  it so we support it.
  *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 06/30/96
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
  */
 
-/* Uncomment this for testing twin bus support. */
-#define AIC7XXX_TWIN_SUPPORT
-
 /* Uncomment this for tagged queueing. */
-/* #define AIC7XXX_TAGGED_QUEUEING */
+#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
+#define AIC7XXX_TAGGED_QUEUEING
+#endif
 
 /*
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-/* #define AIC7XXX_CMDS_PER_LUN 8 */
+#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
+#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#endif
 
 /* Set this to the delay in seconds after SCSI bus reset. */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#else
 #define AIC7XXX_RESET_DELAY 15
+#endif
 
 /*
- * Uncomment the following define for collection of SCSI transfer statistics
- * for the /proc filesystem.
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
  *
  * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
  * NOTE: This does affect performance since it has to maintain statistics.
  */
-/* #define AIC7XXX_PROC_STATS */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
 
 /*
- * Uncomment the following to enable SCB paging.
+ * Enable SCB paging.
  */
-/* #define AIC7XXX_PAGE_ENABLE */
+#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
+#define AIC7XXX_PAGE_ENABLE
+#endif
 
 /*
- * Uncomment the following to enable sharing of the external bank
- * of 255 SCBs for the 3985.
+ * Uncomment the following to enable use of the external bank
+ * of 255 SCBs.  For 3985 adapters, this will also enable sharing
+ * of the SCB array across all three controllers.
  */
-#define AIC7XXX_SHARE_SCBS
+#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
+#define AIC7XXX_USE_EXT_SCBRAM
+#endif
 
 /*
  * For debugging the abort/reset code.
@@ -211,6 +277,87 @@
 #define AIC7XXX_DEBUG
 
 /*
+ * Set this for defining the number of tagged commands on a device
+ * by device, and controller by controller basis.  The first set
+ * of tagged commands will be used for the first detected aic7xxx
+ * controller, the second set will be used for the second detected
+ * aic7xxx controller, and so on.  These values will *only* be used
+ * for targets that are tagged queueing capable; these values will
+ * be ignored in all other cases.  The tag_commands is an array of
+ * 16 to allow for wide and twin adapters.  Twin adapters will use
+ * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
+ *
+ * *** Determining commands per LUN ***
+ * 
+ * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * own algorithm to determine the commands/LUN.  If SCB paging is
+ * enabled, the commands/LUN is 8.  When SCB paging is not enabled,
+ * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
+ * and 4 commands/LUN for adapters with 3 or 4 SCBs.
+ *
+ */
+/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
+
+#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+typedef struct
+{
+  char tag_commands[16];   /* Allow for wide/twin channel adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Make a define that will tell the driver to use it's own algorithm
+ * for determining commands/LUN (see Determining commands per LUN
+ * above).
+ */
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+/*
+ * Modify this as you see fit for your system.  By setting tag_commands
+ * to 0, the driver will use it's own algorithm for determining the
+ * number of commands to use (see above).  When -1, the driver will
+ * not enable tagged queueing for that particular device.  When positive
+ * (> 0) the values in the array are used for the queue_depth.  Note
+ * that the maximum value for an entry is 127.
+ *
+ * In this example, the first line will enable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter and tells the driver
+ * to use it's own algorithm for determining commands/LUN.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+  {DEFAULT_TAG_COMMANDS},
+  {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+#endif
+
+/*
+ * Don't define this unless you have problems with the driver
+ * interrupt handler.  The old method would register the drivers
+ * interrupt handler as a "fast" type interrupt handler that would
+ * lock out other interrupts.  Since this driver can spend a lot
+ * of time in the interrupt handler, this is _not_ a good idea.
+ * It also conflicts with some of the more common ethernet drivers
+ * that don't use fast interrupts.  Currently, Linux does not allow
+ * IRQ sharing unless both drivers can agree on the type of interrupt
+ * handler.
+ */
+/* #define AIC7XXX_OLD_ISR_TYPE */
+
+
+/*
  * Controller type and options
  */
 typedef enum {
@@ -232,14 +379,15 @@
   AIC_7882,	/* PCI  aic7882 on 3940 Ultra */
   AIC_7883,	/* PCI  aic7883 on 3985 Ultra */
   AIC_7884	/* PCI  aic7884 on 294x Ultra Differential */
-} aha_type;
+} aha_chip_type;
 
 typedef enum {
   AIC_777x,	/* AIC-7770 based */
-  AIC_785x,	/* AIC-7850 based */
+  AIC_785x,	/* AIC-7850 based (3 SCBs)*/
+  AIC_786x,	/* AIC-7860 based (7850 ultra) */
   AIC_787x,	/* AIC-7870 based */
-  AIC_788x	/* AIC-7880 based */
-} aha_chip_type;
+  AIC_788x	/* AIC-7880 based (ultra) */
+} aha_chip_class_type;
 
 typedef enum {
   AIC_SINGLE,  /* Single Channel */
@@ -269,24 +417,24 @@
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "<AIC-7xxx Unknown>",		/* AIC_NONE */
-  "AIC-7770",			/* AIC_7770 */
-  "AHA-2740",			/* AIC_7771 */
-  "AHA-2840",			/* AIC_284x */
-  "AIC-7850",			/* AIC_7850 */
-  "AIC-7855",			/* AIC_7855 */
-  "AIC-7850 Ultra",		/* AIC_7860 */
-  "AHA-2940A Ultra",		/* AIC_7861 */
-  "AIC-7870",			/* AIC_7870 */
-  "AHA-2940",			/* AIC_7871 */
-  "AHA-3940",			/* AIC_7872 */
-  "AHA-3985",			/* AIC_7873 */
-  "AHA-2940 Differential",	/* AIC_7874 */
-  "AIC-7880 Ultra",		/* AIC_7880 */
-  "AHA-2940 Ultra",		/* AIC_7881 */
-  "AHA-3940 Ultra",		/* AIC_7882 */
-  "AHA-3985 Ultra",		/* AIC_7883 */
-  "AHA-2940 Ultra Differential"	/* AIC_7884 */
+  "AIC-7xxx Unknown",		                        /* AIC_NONE */
+  "Adaptec AIC-7770 SCSI host adapter",			/* AIC_7770 */
+  "Adaptec AHA-274X SCSI host adapter",			/* AIC_7771 */
+  "Adaptec AHA-284X SCSI host adapter",			/* AIC_284x */
+  "Adaptec AIC-7850 SCSI host adapter",			/* AIC_7850 */
+  "Adaptec AIC-7855 SCSI host adapter",			/* AIC_7855 */
+  "Adaptec AIC-7860 Ultra SCSI host adapter",		/* AIC_7860 */
+  "Adaptec AHA-2940A Ultra SCSI host adapter",		/* AIC_7861 */
+  "Adaptec AIC-7870 SCSI host adapter",			/* AIC_7870 */
+  "Adaptec AHA-294X SCSI host adapter",			/* AIC_7871 */
+  "Adaptec AHA-394X SCSI host adapter",			/* AIC_7872 */
+  "Adaptec AHA-398X SCSI host adapter",			/* AIC_7873 */
+  "Adaptec AHA-2944 SCSI host adapter",	                /* AIC_7874 */
+  "Adaptec AIC-7880 Ultra SCSI host adapter",		/* AIC_7880 */
+  "Adaptec AHA-294X Ultra SCSI host adapter",		/* AIC_7881 */
+  "Adaptec AHA-394X Ultra SCSI host adapter",		/* AIC_7882 */
+  "Adaptec AHA-398X Ultra SCSI host adapter",		/* AIC_7883 */
+  "Adaptec AHA-2944 Ultra SCSI host adapter"	        /* AIC_7884 */
 };
 
 /*
@@ -310,12 +458,17 @@
  */
 #define DID_RETRY_COMMAND DID_ERROR
 
+#define HSCSIID        0x07
+#define HWSCSIID       0x0F
+#define SCSI_RESET     0x040
+
 /*
  * EISA/VL-bus stuff
  */
 #define MINSLOT		1
 #define MAXSLOT		15
 #define SLOTBASE(x)	((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
 
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
@@ -334,14 +487,6 @@
 #define INTDEF		0x5C		/* Interrupt Definition Register */
 
 /*
- * Some defines for the HCNTRL register.
- */
-#define	REQ_PAUSE	IRQMS | INTEN | PAUSE
-#define	UNPAUSE_274X	IRQMS | INTEN
-#define	UNPAUSE_284X	INTEN
-#define	UNPAUSE_294X	IRQMS | INTEN
-
-/*
  * AIC-78X0 PCI registers
  */
 #define	CLASS_PROGIF_REVID	0x08
@@ -377,7 +522,7 @@
  * each word, while the C56 and C66 (4096 bits) use 8 bits to
  * address each word.
  */
-typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
 
 /*
  *
@@ -417,15 +562,15 @@
 /*
  * Host Adapter Control Bits
  */
-/* UNUSED               0x0001 */
+#define CFAUTOTERM      0x0001          /* Perform Auto termination */
 #define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
 #define CF284XSELTO     0x0003          /* Selection timeout (284x cards) */
 #define CF284XFIFO      0x000C          /* FIFO Threshold (284x cards) */
-#define CFSTERM         0x0004          /* SCSI low byte termination (non-wide cards) */
+#define CFSTERM         0x0004          /* SCSI low byte termination */
 #define CFWSTERM        0x0008          /* SCSI high byte termination (wide card) */
 #define CFSPARITY	0x0010		/* SCSI parity */
 #define CF284XSTERM	0x0020		/* SCSI low byte termination (284x cards) */
-#define CFRESETB	0x0040		/* reset SCSI bus at IC initialization */
+#define CFRESETB	0x0040		/* reset SCSI bus at boot */
 /* UNUSED		0xFF80 */
   unsigned short adapter_control;	/* word 17 */
 
@@ -448,36 +593,17 @@
   unsigned short checksum;		/* word 31 */
 };
 
-
-#define SCSI_RESET 0x040
-
-/*
- * 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) \
-  synchronize_irq();					\
-  outb(p->pause, HCNTRL + p->base);			\
-  while ((inb(HCNTRL + p->base) & PAUSE) == 0)		\
-    ;							\
-
-/*
- * Unpause the sequencer. Unremarkable, yet done often enough to
- * warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p) \
-  outb(p->unpause, HCNTRL + p->base)
-
-/*
- * Restart the sequencer program from address zero
- */
-#define RESTART_SEQUENCER(p) \
-  do {							\
-    outb(SEQRESET | FASTMODE, SEQCTL + p->base);	\
-  } while (inb(SEQADDR0 + p->base) != 0 &&		\
-	   inb(SEQADDR1 + p->base) != 0);		\
-  UNPAUSE_SEQUENCER(p);
+#define SELBUS_MASK		0x0a
+#define 	SELNARROW	0x00
+#define 	SELBUSB		0x08
+#define SINGLE_BUS		0x00
+
+#define SCB_TARGET(scb)         \
+       (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb)            \
+       ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb)   \
+       (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
 
 /*
  * If an error occurs during a data transfer phase, run the command
@@ -541,12 +667,6 @@
 static int aic7xxx_spurious_count;
 
 /*
- * The driver keeps up to four scb structures per card in memory. Only the
- * first 25 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookkeeping.
- */
-
-/*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
  * in the scatter-gather lists.  We need to convert the virtual
  * addresses to physical addresses.
@@ -559,20 +679,28 @@
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define	MAX_SG 256
+#define	AIC7XXX_MAX_SG 27
 
-struct aic7xxx_scb {
+/*
+ * 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	255
+
+
+struct aic7xxx_hwscb {
 /* ------------    Begin hardware supported fields    ---------------- */
 /* 0*/  unsigned char control;
 /* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
 /* 2*/  unsigned char target_status;
 /* 3*/  unsigned char SG_segment_count;
-/* 4*/  unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/* 4*/  unsigned int  SG_list_pointer;
 /* 8*/  unsigned char residual_SG_segment_count;
-/* 9*/  unsigned char residual_data_count[3] __attribute__ ((packed));
-/*12*/  unsigned char data_pointer[4] __attribute__ ((packed));
-/*16*/  unsigned int  data_count __attribute__ ((packed)); /* must be 32 bits */
-/*20*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/* 9*/  unsigned char residual_data_count[3];
+/*12*/  unsigned int  data_pointer;
+/*16*/  unsigned int  data_count;
+/*20*/  unsigned int  SCSI_cmd_pointer;
 /*24*/  unsigned char SCSI_cmd_length;
 /*25*/	u_char tag;			/* Index into our kernel SCB array.
 					 * Also used as the tag for tagged I/O
@@ -580,29 +708,47 @@
 #define SCB_PIO_TRANSFER_SIZE	26 	/* amount we need to upload/download
 					 * via PIO to initialize a transaction.
 					 */
-/*26*/  u_char next;                    /* Used to thread SCBs awaiting selection
+/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
                                          * or disconnected down in the sequencer.
                                          */
-	/*-----------------end of hardware supported fields----------------*/
-	Scsi_Cmnd          *cmd;	/* Scsi_Cmnd for this scb */
-        struct aic7xxx_scb *q_next;     /* next scb in queue */
-#define SCB_FREE               0x00
-#define SCB_ACTIVE             0x01
-#define SCB_ABORTED            0x02
-#define SCB_DEVICE_RESET       0x04
-#define SCB_IMMED              0x08
-#define SCB_SENSE              0x10
-#define SCB_QUEUED_FOR_DONE    0x40
-#define SCB_PAGED_OUT          0x80
-#define SCB_WAITINGQ           0x100
-#define SCB_ASSIGNEDQ          0x200
-#define SCB_SENTORDEREDTAG     0x400
-#define SCB_IN_PROGRESS        (SCB_ACTIVE | SCB_PAGED_OUT | \
-                                SCB_WAITINGQ | SCB_ASSIGNEDQ)
-	int                 state;          /* current state of scb */
-	unsigned int        position;       /* Position in scb array */
-	struct hw_scatterlist  sg_list[MAX_SG]; /* SG list in adapter format */
-	unsigned char       sense_cmd[6];   /* Allocate 6 characters for sense command */
+/*27*/  unsigned char prev;
+/*28*/  unsigned int pad;               /*
+                                         * Unused by the kernel, but we require
+                                         * the padding so that the array of
+                                         * hardware SCBs is alligned on 32 byte
+                                         * boundaries so the sequencer can index
+                                         */
+};
+
+typedef enum {
+	SCB_FREE		= 0x0000,
+	SCB_ACTIVE		= 0x0001,
+	SCB_ABORTED		= 0x0002,
+	SCB_DEVICE_RESET	= 0x0004,
+	SCB_SENSE		= 0x0008,
+	SCB_TIMEDOUT		= 0x0010,
+	SCB_QUEUED_FOR_DONE	= 0x0020,
+	SCB_RECOVERY_SCB	= 0x0040,
+	SCB_WAITINGQ		= 0x0080,
+	SCB_ASSIGNEDQ		= 0x0100,
+	SCB_SENTORDEREDTAG	= 0x0200,
+	SCB_MSGOUT_SDTR		= 0x0400,
+	SCB_MSGOUT_WDTR		= 0x0800,
+	SCB_ABORT		= 0x1000,
+	SCB_QUEUED_ABORT	= 0x2000
+} scb_flag_type;
+
+struct aic7xxx_scb {
+        struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
+	Scsi_Cmnd             *cmd;	      /* Scsi_Cmnd for this scb */
+        struct aic7xxx_scb    *q_next;        /* next scb in queue */
+	scb_flag_type          flags;         /* current state of scb */
+	struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          sg_count;
+	unsigned char          sense_cmd[6];  /*
+                                               * Allocate 6 characters for
+                                               * sense command.
+                                               */
 };
 
 /*
@@ -627,20 +773,17 @@
 generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
 
 typedef struct {
+  struct aic7xxx_hwscb *hscbs;
   scb_queue_type free_scbs;        /*
                                     * SCBs assigned to free slot on
                                     * card (no paging required)
                                     */
-  int            numscbs;          /* current number of scbs */
-  int            activescbs;       /* active scbs */
-} scb_usage_type;
-
-/*
- * 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	255
+  unsigned char  numscbs;          /* current number of scbs */
+  unsigned char  maxhscbs;         /* hardware scbs */
+  unsigned char  maxscbs;          /* max scbs including pageable scbs */
+  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
+  unsigned int   reserve[100];
+} scb_data_type;
 
 /*
  * Define a structure used for each host adapter, only one per IRQ.
@@ -648,17 +791,26 @@
 struct aic7xxx_host {
   struct Scsi_Host        *host;             /* pointer to scsi host */
   int                      host_no;          /* SCSI host number */
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /*   channel B for twin adapters */
+  int                      irq;              /* IRQ for this adapter */
   int                      base;             /* card base address */
-  int                      maxhscbs;         /* hardware SCBs */
-  int                      maxscbs;          /* max SCBs (including pageable) */
-#define A_SCANNED              0x0001
-#define B_SCANNED              0x0002
-#define EXTENDED_TRANSLATION   0x0004
-#define HAVE_SEEPROM           0x0008
-#define ULTRA_ENABLED          0x0010
-#define PAGE_ENABLED           0x0020
-#define IN_ISR                 0x0040
-#define USE_DEFAULTS           0x0080
+  unsigned int             mbase;            /* I/O memory address */
+  volatile unsigned char  *maddr;            /* memory mapped address */
+#define A_SCANNED               0x0001
+#define B_SCANNED               0x0002
+#define EXTENDED_TRANSLATION    0x0004
+#define FLAGS_CHANNEL_B_PRIMARY 0x0008
+#define MULTI_CHANNEL           0x0010
+#define ULTRA_ENABLED           0x0020
+#define PAGE_ENABLED            0x0040
+#define USE_DEFAULTS            0x0080
+#define BIOS_ENABLED            0x0100
+#define IN_ISR                  0x0200
+#define IN_TIMEOUT              0x0400
+#define SHARED_SCBDATA          0x0800
+#define HAVE_SEEPROM            0x1000
   unsigned int             flags;
   unsigned int             isr_count;        /* Interrupt count */
   unsigned short           needsdtr_copy;    /* default config */
@@ -669,36 +821,22 @@
   unsigned short           wdtr_pending;
   unsigned short           orderedtag;
   unsigned short           discenable;	     /* Targets allowed to disconnect */
-  aha_type                 type;             /* card type */
-  aha_chip_type            chip_type;        /* chip base type */
+  aha_chip_type            chip_type;        /* card type */
+  aha_chip_class_type      chip_class;
   aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  char *                   mbase;            /* I/O memory address */
-  unsigned char            chan_num;         /* for 3940/3985, channel number */
+  unsigned char            chan_num;         /* for 39xx, channel number */
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   unsigned char            qcntmask;
-  struct seeprom_config    seeprom;
+  unsigned char            qfullcount;
+  unsigned char            curqincnt;
   struct Scsi_Host        *next;             /* allow for multiple IRQs */
-  struct aic7xxx_scb      *scb_array[AIC7XXX_MAXSCB];  /* active commands */
-  struct aic7xxx_scb      *pagedout_ntscbs[16];  /*
-                                                  * paged-out, non-tagged scbs
-                                                  * indexed by target.
-                                                  */
-  scb_queue_type           page_scbs;        /*
-                                              * SCBs that will require paging
-                                              * before use (no assigned slot)
-                                              */
+  unsigned char            activescbs;       /* active scbs */
   scb_queue_type           waiting_scbs;     /*
-                                              * SCBs waiting to be paged and
-                                              * started.
-                                              */
-  scb_queue_type           assigned_scbs;    /*
-                                              * SCBs that were waiting but have
-                                              * have now been assigned a slot
-                                              * by aic7xxx_free_scb
+                                              * SCBs waiting for space in
+                                              * the QINFIFO.
                                               */
-  scb_usage_type           scb_usage;
-  scb_usage_type          *scb_link;
+  scb_data_type           *scb_data;
 
   struct aic7xxx_cmd_queue {
     Scsi_Cmnd *head;
@@ -710,6 +848,7 @@
 #define  BUS_DEVICE_RESET_PENDING       0x02
     int  flags;
     int  commands_sent;
+    int  active_cmds;
   } device_status[16];
 #ifdef AIC7XXX_PROC_STATS
   /*
@@ -735,34 +874,10 @@
 #endif /* AIC7XXX_PROC_STATS */
 };
 
-struct aic7xxx_host_config {
-  int              irq;        /* IRQ number */
-  int              mbase;      /* memory base address*/
-  int              base;       /* I/O base address*/
-  int              maxhscbs;   /* hardware SCBs */
-  int              maxscbs;    /* max SCBs (including pageable) */
-  int              unpause;    /* unpause value for HCNTRL */
-  int              pause;      /* pause value for HCNTRL */
-  int              scsi_id;    /* host SCSI ID */
-  int              scsi_id_b;  /* host SCSI ID B channel for twin cards */
-  unsigned int     flags;      /* used the same as struct aic7xxx_host flags */
-  int              chan_num;   /* for 3940/3985, channel number */
-  unsigned char    busrtime;   /* bus release time */
-  unsigned char    bus_speed;  /* bus speed */
-  unsigned char    qcntmask;
-  aha_type         type;       /* card type */
-  aha_chip_type    chip_type;  /* chip base type */
-  aha_bus_type     bus_type;   /* normal/twin/wide bus */
-  aha_status_type  bios;       /* BIOS is enabled/disabled */
-  aha_status_type  parity;     /* bus parity enabled/disabled */
-  aha_status_type  low_term;   /* bus termination low byte */
-  aha_status_type  high_term;  /* bus termination high byte (wide cards only) */
-};
-
 /*
  * Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns to the proper value to
- * stick in the scsiscfr reg to use that transfer rate.
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
  */
 static struct {
   short period;
@@ -771,17 +886,17 @@
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
-  {  50,  0x100,  "20.0"  },
-  {  62,  0x110,  "16.0"  },
-  {  75,  0x120,  "13.4"  },
-  { 100,  0x000,  "10.0"  },
-  { 125,  0x010,   "8.0"  },
-  { 150,  0x020,   "6.67" },
-  { 175,  0x030,   "5.7"  },
-  { 200,  0x040,   "5.0"  },
-  { 225,  0x050,   "4.4"  },
-  { 250,  0x060,   "4.0"  },
-  { 275,  0x070,   "3.6"  }
+  { 12,  0x100,  "20.0"  },
+  { 15,  0x110,  "16.0"  },
+  { 18,  0x120,  "13.4"  },
+  { 25,  0x000,  "10.0"  },
+  { 31,  0x010,   "8.0"  },
+  { 37,  0x020,   "6.67" },
+  { 43,  0x030,   "5.7"  },
+  { 50,  0x040,   "5.0"  },
+  { 56,  0x050,   "4.4"  },
+  { 62,  0x060,   "4.0"  },
+  { 68,  0x070,   "3.6"  }
 };
 
 static int num_aic7xxx_syncrates =
@@ -790,166 +905,51 @@
 #ifdef CONFIG_PCI
 static int number_of_3940s = 0;
 static int number_of_3985s = 0;
-#ifdef AIC7XXX_SHARE_SCBS
-static scb_usage_type *shared_3985_scbs = NULL;
-#endif
-#endif CONFIG_PCI
+#endif /* CONFIG_PCI */
 
 #ifdef AIC7XXX_DEBUG
 
-static void
-debug_config(struct aic7xxx_host_config *p)
-{
-  int scsi_conf;
-  unsigned char brelease;
-  unsigned char dfthresh;
-
-  static int DFT[] = { 0, 50, 75, 100 };
-  static int SST[] = { 256, 128, 64, 32 };
-  static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
-
-  scsi_conf = inb(SCSICONF + p->base);
-
-  /*
-   * Scale the Data FIFO Threshhold and the Bus Release Time; they are
-   * stored in formats compatible for writing to sequencer registers.
-   */
-  dfthresh = p->bus_speed  >> 6;
-
-  if (p->chip_type == AIC_777x)
-  {
-    brelease = p->busrtime >> 2;
-  }
-  else
-  {
-    brelease = p->busrtime;
-  }
-  if (brelease == 0)
-  {
-    brelease = 2;
-  }
-
-  switch (p->type)
-  {
-    case AIC_7770:
-    case AIC_7771:
-      printk("%s%s AT EISA SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
-             p->base >> 12);
-      break;
-
-    case AIC_284x:
-      printk("%s%s AT VLB SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
-             p->base >> 12);
-      break;
-
-    case AIC_7850:
-    case AIC_7855:
-    case AIC_7860:
-    case AIC_7861:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7873:
-    case AIC_7874:
-    case AIC_7880:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7883:
-    case AIC_7884:
-      printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type],
-             BUSW[p->bus_type], p->base, p->mbase);
-      break;
-
-    default:
-      panic("aic7xxx: (debug_config) internal error.\n");
-  }
-
-  printk("    irq %d\n"
-	 "    bus release time %d bclks\n"
-	 "    data fifo threshold %d%%\n",
-	 p->irq,
-	 brelease,
-	 DFT[dfthresh]);
-
-  printk("    SCSI CHANNEL A:\n"
-	 "        scsi id %d\n"
-	 "        scsi selection timeout %d ms\n"
-	 "        scsi bus reset at power-on %sabled\n",
-	 scsi_conf & 0x07,
-	 SST[(scsi_conf >> 3) & 0x03],
-	 (scsi_conf & 0x40) ? "en" : "dis");
-
-  if ((p->chip_type == AIC_777x) && (p->parity == AIC_UNKNOWN))
-  {
-    /*
-     * Set the parity for 7770 based cards.
-     */
-    p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
-  }
-  if (p->parity != AIC_UNKNOWN)
-  {
-    printk("        scsi bus parity %sabled\n",
-	   (p->parity == AIC_ENABLED) ? "en" : "dis");
-  }
-
-  if ((p->type == AIC_7770) || (p->type == AIC_7771))
-  {
-    p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
-  }
-  if (p->low_term != AIC_UNKNOWN)
-  {
-    printk("        scsi bus termination (low byte) %sabled\n",
-	  (p->low_term == AIC_ENABLED) ? "en" : "dis");
-  }
-  if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
-  {
-    printk("        scsi bus termination (high byte) %sabled\n",
-	  (p->high_term == AIC_ENABLED) ? "en" : "dis");
-  }
-}
-
 #if 0
 static void
 debug_scb(struct aic7xxx_scb *scb)
 {
-  printk("control 0x%x, tcl 0x%x, sg_count %d, sg_ptr 0x%x, cmdp 0x%x, cmdlen %d\n",
-         scb->control, scb->target_channel_lun, scb->SG_segment_count,
-         (scb->SG_list_pointer[3] << 24) | (scb->SG_list_pointer[2] << 16) |
-         (scb->SG_list_pointer[1] << 8) | scb->SG_list_pointer[0],
-         (scb->SCSI_cmd_pointer[3] << 24) | (scb->SCSI_cmd_pointer[2] << 16) |
-         (scb->SCSI_cmd_pointer[1] << 8) | scb->SCSI_cmd_pointer[0],
-         scb->SCSI_cmd_length);
-  printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
-         (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
-         scb->residual_SG_segment_count,
-         ((scb->residual_data_count[2] << 16) |
-          (scb->residual_data_count[1] <<  8) |
-          (scb->residual_data_count[0]));
-  printk("data ptr 0x%x, data count %d, next waiting %d\n",
-         (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
-         (scb->data_pointer[1] << 8) | scb->data_pointer[0],
-         scb->data_count, scb->next_waiting);
-  printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
-         (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
-         scb->position);
+  struct aic7xxx_hwscb *hscb = scb->hscb;
+
+  printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
+    scb,
+    hscb->control,
+    hscb->target_channel_lun,
+    hscb->SCSI_cmd_length,
+    hscb->SCSI_cmd_pointer );
+  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
+    hscb->data_count,
+    hscb->data_pointer,
+    hscb->SG_segment_count,
+    hscb->SG_list_pointer);
+  printk("        sg_addr:%lx sg_len:%ld\n",
+    hscb->sg_list[0].address,
+    hscb->sg_list[0].length);
 }
 #endif
 
 #else
-#  define debug_config(x)
 #  define debug_scb(x)
 #endif AIC7XXX_DEBUG
 
-#define TCL_OF_SCB(x)  (((x)->target_channel_lun >> 4) & 0xf),  \
-                       (((x)->target_channel_lun >> 3) & 0x01), \
-                       ((x)->target_channel_lun & 0x07)
+#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
+                        (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+                        ((scb->hscb)->target_channel_lun & 0x07)
 
-#define TARGET_INDEX(x)  ((x)->target | ((x)->channel << 3))
+#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
+                       (((scb->hscb)->target_channel_lun >> 3) & 0x01)
+
+#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+
+#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
 /*
  * 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?
+ *       cards in the system.  This should be fixed.
  */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
@@ -959,6 +959,53 @@
                                               *  1 use level triggered
                                               */
 static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
+static int aic7xxx_verbose = 0;	             /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * These functions are not used yet, but when we do memory mapped
+ * IO, we'll use them then.
+ *
+ ***************************************************************************/
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+  if (p->maddr != NULL)
+    return (p->maddr[port]);
+  else
+    return (inb(p->base + port));
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+  if (p->maddr != NULL)
+    p->maddr[port] = val;
+  else
+    outb(val, p->base + port);
+}
+
+static inline void
+aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
+{
+  if (p->maddr != NULL)
+  {
+    __asm __volatile("
+      cld;
+    1:  lodsb;
+      movb %%al,(%0);
+      loop 1b"      :
+              :
+      "r" ((p)->maddr + (port)),
+      "S" ((valp)), "c" ((size))  :
+      "%esi", "%ecx", "%eax");
+  }
+  else
+  {
+    outsb(p->base + port, valp, size);
+  }
+}
 
 /*+F*************************************************************************
  * Function:
@@ -983,6 +1030,7 @@
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
     { "ultra",       &aic7xxx_enable_ultra },
+    { "verbose",     &aic7xxx_verbose },
     { NULL,          NULL }
   };
 
@@ -1008,141 +1056,317 @@
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_loadseq
+ *   pause_sequencer
  *
  * Description:
- *   Load the sequencer code into the controller memory.
+ *   Pause the sequencer and wait for it to actually stop - this
+ *   is important since the sequencer can disable pausing for critical
+ *   sections.
  *-F*************************************************************************/
-static void
-aic7xxx_loadseq(int base)
+static inline void
+pause_sequencer(struct aic7xxx_host *p)
 {
-  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(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
-
-  outsb(SEQRAM + base, seqprog, sizeof(seqprog));
-
-  /*
-   * 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?)
-   */
-  do {
-    /*
-     * Actually, reset it until
-     * the address shows up as
-     * zero just to be safe..
-     */
-    outb(SEQRESET | FASTMODE, SEQCTL + base);
-  } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
+  outb(p->pause, p->base + HCNTRL);
+  while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+  {
+    ;
+  }
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_delay
+ *   unpause_sequencer
  *
  * Description:
- *   Delay for specified amount of time.
+ *   Unpause the sequencer. Unremarkable, yet done often enough to
+ *   warrant an easy way to do it.
  *-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
+static inline void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 {
-  unsigned long i;
-
-  i = jiffies + (seconds * HZ);  /* compute time to stop */
-
-  while (jiffies < i)
+  if (unpause_always ||
+      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
   {
-    ;  /* Do nothing! */
+    outb(p->unpause, p->base + HCNTRL);
   }
 }
 
 /*+F*************************************************************************
  * Function:
- *   rcs_version
+ *   restart_sequencer
  *
  * Description:
- *   Return a string containing just the RCS version number from either
- *   an Id or Revision RCS clause.
+ *   Restart the sequencer program from address zero.  This assumes
+ *   that the sequencer is already paused.
  *-F*************************************************************************/
-static const char *
-rcs_version(const char *version_info)
+static inline void
+restart_sequencer(struct aic7xxx_host *p)
 {
-  static char buf[10];
-  char *bp, *ep;
+  /* Set the sequencer address to 0. */
+  outb(0, p->base + SEQADDR0);
+  outb(0, p->base + SEQADDR1);
 
-  bp = NULL;
-  strcpy(buf, "????");
-  if (!strncmp(version_info, "$Id: ", 5))
+  /*
+   * Reset and unpause the sequencer.  The reset is suppose to
+   * start the sequencer running, but we do an unpause to make
+   * sure.
+   */
+  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
+
+  unpause_sequencer(p, /*unpause_always*/ TRUE);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_next_patch
+ *
+ * Description:
+ *   Find the next patch to download.
+ *-F*************************************************************************/
+static struct patch *
+aic7xxx_next_patch(struct patch *cur_patch, int options, int instrptr)
+{
+  while (cur_patch != NULL)
   {
-    if ((bp = strchr(version_info, ' ')) != NULL)
+    if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
+      || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
+      || (instrptr >= cur_patch->end))
     {
-      bp++;
-      if ((bp = strchr(bp, ' ')) != NULL)
+      /*
+       * Either we want to keep this section of code, or we have consumed
+       * this patch.  Skip to the next patch.
+       */
+      cur_patch++;
+      if (cur_patch->options == 0)
       {
-	bp++;
+        /* Out of patches. */
+        cur_patch = NULL;
       }
     }
-  }
-  else
-  {
-    if (!strncmp(version_info, "$Revision: ", 11))
+    else
     {
-      if ((bp = strchr(version_info, ' ')) != NULL)
-      {
-	bp++;
-      }
+      /* Found an OK patch. */
+      break;
     }
   }
+  return (cur_patch);
+}
 
-  if (bp != NULL)
-  {
-    if ((ep = strchr(bp, ' ')) != NULL)
-    {
-      register int len = ep - bp;
 
-      strncpy(buf, bp, len);
-      buf[len] = '\0';
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_download_instr
+ *
+ * Description:
+ *   Find the next patch to download.
+ *-F*************************************************************************/
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
+{
+  unsigned char opcode;
+  struct ins_format3 *instr;
+
+  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+  /* Pull the opcode */
+  opcode = instr->opcode_addr >> 1;
+  switch (opcode)
+  {
+    case AIC_OP_JMP:
+    case AIC_OP_JC:
+    case AIC_OP_JNC:
+    case AIC_OP_CALL:
+    case AIC_OP_JNE:
+    case AIC_OP_JNZ:
+    case AIC_OP_JE:
+    case AIC_OP_JZ:
+    {
+      int address_offset;
+      struct ins_format3 new_instr;
+      unsigned int address;
+      struct patch *patch;
+      int i;
+
+      address_offset = 0;
+      new_instr = *instr;  /* Strucure copy */
+      address = new_instr.address;
+      address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+      for (i = 0; i < NUMBER(patches); i++)
+      {
+        patch = &patches[i];
+        if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
+            (((patch->options & options) != 0) && (patch->negative == TRUE)))
+        {
+          if (address >= patch->end)
+          {
+            address_offset += patch->end - patch->begin;
+          }
+        }
+      }
+      address -= address_offset;
+      new_instr.address = address &0xFF;
+      new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
+      new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+      outsb(p->base + SEQRAM, &new_instr.immediate, 4);
+      break;
     }
-  }
 
-  return buf;
+    case AIC_OP_OR:
+    case AIC_OP_AND:
+    case AIC_OP_XOR:
+    case AIC_OP_ADD:
+    case AIC_OP_ADC:
+    case AIC_OP_ROL:
+      outsb(p->base + SEQRAM, &instr->immediate, 4);
+      break;
+
+    default:
+      panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+      break;
+  }
 }
 
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_info
+ *   aic7xxx_loadseq
  *
  * Description:
- *   Return a string describing the driver.
+ *   Load the sequencer code into the controller memory.
  *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
+static void
+aic7xxx_loadseq(struct aic7xxx_host *p)
+{
+  int options;
+  struct patch *cur_patch;
+  int i;
+  int downloaded;
+
+  if (aic7xxx_verbose)
+  {
+    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+  }
+  options = 1;  /* Code for all options. */
+  downloaded = 0;
+  if ((p->flags & ULTRA_ENABLED) != 0)
+    options |= ULTRA;
+  if (p->bus_type == AIC_TWIN)
+    options |= TWIN_CHANNEL;
+  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+    options |= SCB_PAGING;
+
+  cur_patch = patches;
+  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
+  outb(0, p->base + SEQADDR0);
+  outb(0, p->base + SEQADDR1);
+
+  for (i = 0; i < sizeof(seqprog) / 4;  i++)
+  {
+    cur_patch = aic7xxx_next_patch(cur_patch, options, i);
+    if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
+    {
+      /* Skip this instruction for this configuration. */
+      continue;
+    }
+    aic7xxx_download_instr(p, options, i);
+    downloaded++;
+  }
+
+  outb(FASTMODE, p->base + SEQCTL);
+  outb(0, p->base + SEQADDR0);
+  outb(0, p->base + SEQADDR1);
+
+  if (aic7xxx_verbose)
+  {
+     printk(" %d instructions downloaded\n", downloaded);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_delay
+ *
+ * Description:
+ *   Delay for specified amount of time.  We use udelay because the timer
+ *   interrupt is not guaranteed to be enabled.  This will cause an
+ *   infinite loop since jiffies (clock ticks) is not updated.
+ *-F*************************************************************************/
+static void
+aic7xxx_delay(int seconds)
+{
+  int i;
+
+  /*                        
+   * Call udelay() for 1 millisecond inside a loop for  
+   * the requested amount of seconds.
+   */
+  for (i=0; i < seconds*1000; i++)
+  {
+    udelay(1000);  /* Delay for 1 millisecond. */
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   rcs_version
+ *
+ * Description:
+ *   Return a string containing just the RCS version number from either
+ *   an Id or Revision RCS clause.
+ *-F*************************************************************************/
+const char *
+rcs_version(const char *version_info)
+{
+  static char buf[10];
+  char *bp, *ep;
+
+  bp = NULL;
+  strcpy(buf, "????");
+  if (!strncmp(version_info, "$Id: ", 5))
+  {
+    if ((bp = strchr(version_info, ' ')) != NULL)
+    {
+      bp++;
+      if ((bp = strchr(bp, ' ')) != NULL)
+      {
+	bp++;
+      }
+    }
+  }
+  else
+  {
+    if (!strncmp(version_info, "$Revision: ", 11))
+    {
+      if ((bp = strchr(version_info, ' ')) != NULL)
+      {
+	bp++;
+      }
+    }
+  }
+
+  if (bp != NULL)
+  {
+    if ((ep = strchr(bp, ' ')) != NULL)
+    {
+      register int len = ep - bp;
+
+      strncpy(buf, bp, len);
+      buf[len] = '\0';
+    }
+  }
+
+  return buf;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_info
+ *
+ * Description:
+ *   Return a string describing the driver.
+ *-F*************************************************************************/
+const char *
+aic7xxx_info(struct Scsi_Host *notused)
 {
   static char buffer[128];
 
@@ -1150,8 +1374,10 @@
   strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
   strcat(buffer, "/");
   strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
+#if 0
   strcat(buffer, "/");
   strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
+#endif
 
   return buffer;
 }
@@ -1161,9 +1387,12 @@
  *   aic7xxx_length
  *
  * Description:
- *   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.
+ *   How much data should be transferred for this SCSI command?  Assume
+ *   all segments are to be transferred except for the last sg_last
+ *   segments.  This will allow us to compute underflow easily.  To
+ *   calculate the total length of the command, use sg_last = 0.  To
+ *   calculate the length of all but the last 2 SG segments, use
+ *   sg_last = 2.
  *-F*************************************************************************/
 static unsigned
 aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
@@ -1177,7 +1406,7 @@
 
   if (cmd->use_sg)
   {
-    for (i = length = 0; (i < cmd->use_sg) && (i < segments); i++)
+    for (i = length = 0; i < segments; i++)
     {
       length += sg[i].length;
     }
@@ -1199,9 +1428,9 @@
  *-F*************************************************************************/
 static void
 aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    short period, unsigned char offset, int target, char channel)
+    unsigned char *period, unsigned char *offset, int target, char channel)
 {
-  int i;
+  int i = num_aic7xxx_syncrates;
   unsigned long ultra_enb_addr;
   unsigned char ultra_enb, sxfrctl0;
 
@@ -1209,11 +1438,11 @@
    * If the offset is 0, then the device is requesting asynchronous
    * transfers.
    */
-  if (offset != 0)
+  if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
   {
     for (i = 0; i < num_aic7xxx_syncrates; i++)
     {
-      if ((aic7xxx_syncrates[i].period - period) >= 0)
+      if (*period <= aic7xxx_syncrates[i].period)
       {
         /*
          * Watch out for Ultra speeds when ultra is not enabled and
@@ -1229,99 +1458,57 @@
            */
           continue;
         }
-        *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+        *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
+        *period = aic7xxx_syncrates[i].period;
 
-        /*
-         * Ensure Ultra mode is set properly for this target.
-         */
-        ultra_enb_addr = ULTRA_ENB;
-        if ((channel == 'B') || (target > 7))
-        {
-          ultra_enb_addr++;
-        }
-        ultra_enb = inb(p->base + ultra_enb_addr);
-        sxfrctl0 = inb(p->base + SXFRCTL0);
-        if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
-        {
-          ultra_enb |= 0x01 << (target & 0x07);
-          sxfrctl0 |= ULTRAEN;
-        }
-        else
+        if (aic7xxx_verbose)
         {
-          ultra_enb &= ~(0x01 << (target & 0x07));
-          sxfrctl0 &= ~ULTRAEN;
+          printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, target, channel,
+                 aic7xxx_syncrates[i].english, *offset);
         }
-        outb(ultra_enb, p->base + ultra_enb_addr);
-        outb(sxfrctl0, p->base + SXFRCTL0);
-
-        printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
-               "offset %d.\n", p->host_no, target, channel,
-               aic7xxx_syncrates[i].english, offset);
-        return;
+        break;
       }
     }
   }
 
-  /*
-   * Default to asynchronous transfer
-   */
-  *scsirate = 0;
-  printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
-         p->host_no, target, channel);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_putscb
- *
- * Description:
- *   Transfer a SCB to the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int base = p->base;
-
-  outb(SCBAUTO, SCBCNT + base);
+  if (i >= num_aic7xxx_syncrates)
+  {
+    /*
+     * Use asynchronous transfers.
+     */
+    *scsirate = 0;
+    *period = 0;
+    *offset = 0;
+    if (aic7xxx_verbose)
+    {
+      printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
+             p->host_no, target, channel);
+    }
+  }
 
   /*
-   * 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.
-   *
-   * We can do 16bit transfers on all but 284x.
+   * Ensure Ultra mode is set properly for this target.
    */
-  if (p->type == AIC_284x)
+  ultra_enb_addr = ULTRA_ENB;
+  if ((channel == 'B') || (target > 7))
+  {
+    ultra_enb_addr++;
+  }
+  ultra_enb = inb(p->base + ultra_enb_addr);
+  sxfrctl0 = inb(p->base + SXFRCTL0);
+  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
   {
-    outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+    ultra_enb |= 0x01 << (target & 0x07);
+    sxfrctl0 |= FAST20;
   }
   else
   {
-    outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
+    ultra_enb &= ~(0x01 << (target & 0x07));
+    sxfrctl0 &= ~FAST20;
   }
-
-  outb(0, SCBCNT + base);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_getscb
- *
- * Description:
- *   Get a SCB from the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int base = p->base;
-
-  /*
-   * This is almost identical to aic7xxx_putscb().
-   */
-  outb(SCBAUTO, SCBCNT + base);
-  insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
-  outb(0, SCBCNT + base);
+  outb(ultra_enb, p->base + ultra_enb_addr);
+  outb(sxfrctl0, p->base + SXFRCTL0);
 }
 
 /*+F*************************************************************************
@@ -1375,6 +1562,47 @@
 
 /*+F*************************************************************************
  * Function:
+ *   scbq_remove
+ *
+ * Description:
+ *   Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  if (queue->head == scb)
+  {
+    /* At beginning of queue, remove from head. */
+    scbq_remove_head(queue);
+  }
+  else
+  {
+    struct aic7xxx_scb *curscb = queue->head;
+
+    /*
+     * Search until the next scb is the one we're looking for, or
+     * we run out of queue.
+     */
+    while ((curscb != NULL) && (curscb->q_next != scb))
+    {
+      curscb = curscb->q_next;
+    }
+    if (curscb != NULL)
+    {
+      /* Found it. */
+      curscb->q_next = scb->q_next;
+      if (scb->q_next == NULL)
+      {
+        /* Update the tail when removing the tail. */
+        queue->tail = curscb;
+      }
+    }
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
  *   scbq_insert_tail
  *
  * Description:
@@ -1404,23 +1632,87 @@
  *   to be reset and all devices on that channel must be aborted.
  *-F*************************************************************************/
 static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
+aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
+    int lun, unsigned char tag)
 {
-  int targ = (scb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int slun = scb->hscb->target_channel_lun & 0x07;
+  int match;
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
-         target, channel, targ, chan);
+  printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
+         scb->cmd->device->host->host_no, target, channel, targ, chan);
 #endif
-  if (target == ALL_TARGETS)
+  match = ((chan == channel) || (channel == ALL_CHANNELS));
+  if (match != 0)
+    match = ((targ == target) || (target == ALL_TARGETS));
+  if (match != 0)
+    match = ((lun == slun) || (lun == ALL_LUNS));
+  if (match != 0)
+    match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+  return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ *   Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+  /*
+   * Invalidate the tag so that aic7xxx_find_scb doesn't think
+   * it's active
+   */
+  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+
+  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
+  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ *   Removes the current SCB from the disconnected list and adds it
+ *   to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+{
+  unsigned char next;
+  unsigned char prev;
+
+  outb(scbptr, p->base + SCBPTR);
+  next = inb(p->base + SCB_NEXT);
+  prev = inb(p->base + SCB_PREV);
+
+  outb(0, p->base + SCB_CONTROL);
+
+  aic7xxx_add_curscb_to_free_list(p);
+
+  if (prev != SCB_LIST_NULL)
   {
-    return (chan == channel);
+    outb(prev, p->base + SCBPTR);
+    outb(next, p->base + SCB_NEXT);
   }
   else
   {
-    return ((chan == channel) && (targ == target));
+    outb(next, p->base + DISCONNECTED_SCBH);
+  }
+
+  if (next != SCB_LIST_NULL)
+  {
+    outb(next, p->base + SCBPTR);
+    outb(prev, p->base + SCB_PREV);
   }
+  return next;
 }
 
 /*+F*************************************************************************
@@ -1428,51 +1720,93 @@
  *   aic7xxx_busy_target
  *
  * Description:
- *   Set the specified target active.
+ *   Set the specified target busy.
  *-F*************************************************************************/
 static void
-aic7xxx_busy_target(unsigned char target, char channel, int base)
+aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
+    char channel, unsigned char scbid)
+{
+  unsigned char active_scb;
+  unsigned char info_scb;
+  unsigned int  scb_offset;
+
+  info_scb = target / 4;
+  if (channel == 'B')
+    info_scb = info_scb + 2;
+
+  active_scb = inb(p->base + SCBPTR);
+  outb(info_scb, p->base + SCBPTR);
+  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+  outb(scbid, p->base + scb_offset);
+  outb(active_scb, p->base + SCBPTR);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_index_busy_target
+ *
+ * Description:
+ *   Returns the index of the busy target, and optionally sets the
+ *   target inactive.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
+    char channel, int unbusy)
 {
-  unsigned char active;
-  unsigned long active_port = ACTIVE_A + base;
+  unsigned char active_scb;
+  unsigned char info_scb;
+  unsigned char busy_scbid;
+  unsigned int  scb_offset;
+
+  info_scb = target / 4;
+  if (channel == 'B')
+    info_scb = info_scb + 2;
 
-  if ((target > 0x07) || (channel == 'B'))
+  active_scb = inb(p->base + SCBPTR);
+  outb(info_scb, p->base + SCBPTR);
+  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+  busy_scbid = inb(p->base + scb_offset);
+  if (unbusy)
   {
-    /*
-     * targets on the Second channel or above id 7 store info in byte two
-     * of ACTIVE
-     */
-    active_port++;
+    outb(SCB_LIST_NULL, p->base + scb_offset);
   }
-  active = inb(active_port);
-  active |= (0x01 << (target & 0x07));
-  outb(active, active_port);
+  outb(active_scb, p->base + SCBPTR);
+  return (busy_scbid);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_unbusy_target
+ *   aic7xxx_find_scb
  *
  * Description:
- *   Set the specified target inactive.
+ *   Look through the SCB array of the card and attempt to find the
+ *   hardware SCB that corresponds to the passed in SCB.  Return
+ *   SCB_LIST_NULL if unsuccessful.  This routine assumes that the
+ *   card is already paused.
  *-F*************************************************************************/
-static void
-aic7xxx_unbusy_target(unsigned char target, char channel, int base)
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char active;
-  unsigned long active_port = ACTIVE_A + base;
+  unsigned char saved_scbptr;
+  unsigned char curindex;
 
-  if ((target > 0x07) || (channel == 'B'))
+  saved_scbptr = inb(p->base + SCBPTR);
+  curindex = 0;
+  for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
   {
-    /*
-     * targets on the Second channel or above id 7 store info in byte two
-     * of ACTIVE
-     */
-    active_port++;
+    outb(curindex, p->base + SCBPTR);
+    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+    {
+      break;
+    }
+  }
+  outb(saved_scbptr, p->base + SCBPTR);
+  if (curindex >= p->scb_data->maxhscbs)
+  {
+    curindex = SCB_LIST_NULL;
   }
-  active = inb(active_port);
-  active &= ~(0x01 << (target & 0x07));
-  outb(active, active_port);
+
+  return (curindex);
 }
 
 /*+F*************************************************************************
@@ -1480,68 +1814,60 @@
  *   aic7xxx_allocate_scb
  *
  * Description:
- *   Get a free SCB either from one already assigned to a hardware
- *   slot, or one that will require an SCB to be paged out before
- *   use.  If there are none, attempt to allocate a new one.
+ *   Get an SCB from the free list or by allocating a new one.
  *-F*************************************************************************/
 static struct aic7xxx_scb *
 aic7xxx_allocate_scb(struct aic7xxx_host *p)
 {
-  struct aic7xxx_scb *scbp = NULL;
-  int maxscbs;
+  struct aic7xxx_scb   *scbp = NULL;
+  struct aic7xxx_hwscb *hscbp = NULL;
+#ifdef AGRESSIVE
+  long processor_flags;
+
+  save_flags(processor_flags);
+  cli();
+#endif
 
-  scbp = p->scb_link->free_scbs.head;
+  scbp = p->scb_data->free_scbs.head;
   if (scbp != NULL)
   {
-    scbq_remove_head(&p->scb_link->free_scbs);
+    scbq_remove_head(&p->scb_data->free_scbs);
   }
   else
   {
-    /*
-     * This should always be NULL if paging is not enabled.
-     */
-    scbp = p->page_scbs.head;
-    if (scbp != NULL)
-    {
-      scbq_remove_head(&p->page_scbs);
-    }
-    else
+    if (p->scb_data->numscbs < p->scb_data->maxscbs)
     {
-      /*
-       * Set limit the SCB allocation to the maximum number of
-       * hardware SCBs if paging is not enabled; otherwise use
-       * the maximum (255).
-       */
-      if (p->flags & PAGE_ENABLED)
-        maxscbs = p->maxscbs;
-      else
-        maxscbs = p->maxhscbs;
-      if (p->scb_link->numscbs < maxscbs)
-      {
-        int scb_index = p->scb_link->numscbs;
-        int scb_size = sizeof(struct aic7xxx_scb);
-
-        p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
-        scbp = (p->scb_array[scb_index]);
-        if (scbp != NULL)
-        {
-          memset(scbp, 0, sizeof(*scbp));
-          scbp->tag = scb_index;
-          if (scb_index < p->maxhscbs)
-            scbp->position = scb_index;
-          else
-	    scbp->position = SCB_LIST_NULL;
-          p->scb_link->numscbs++;
-        }
+      int scb_index = p->scb_data->numscbs;
+      int scb_size = sizeof(struct aic7xxx_scb) +
+                     sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+
+      scbp = kmalloc(scb_size, GFP_ATOMIC);
+      if (scbp != NULL)
+      {
+        memset(scbp, 0, sizeof(struct aic7xxx_scb));
+        hscbp = &p->scb_data->hscbs[scb_index];
+        scbp->hscb = hscbp;
+        scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
+        memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
+        hscbp->tag = scb_index;
+        p->scb_data->numscbs++;
+        /*
+         * Place in the scb array; never is removed
+         */
+        p->scb_data->scb_array[scb_index] = scbp;
       }
     }
   }
+#ifdef AIC7XXX_DEBUG
   if (scbp != NULL)
   {
-#ifdef AIC7XXX_DEBUG
-    p->scb_link->activescbs++;
-#endif
+    p->activescbs++;
   }
+#endif
+
+#ifdef AGRESSIVE
+  restore_flags(processor_flags);
+#endif
   return (scbp);
 }
 
@@ -1581,6 +1907,7 @@
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
+    p->device_status[TARGET_INDEX(cmd)].active_cmds--;
     cmd->scsi_done(cmd);
   }
   p->completeq.tail = NULL;
@@ -1591,53 +1918,29 @@
  *   aic7xxx_free_scb
  *
  * Description:
- *   Free the scb and update the page, waiting, free scb lists.
+ *   Free the scb and insert into the free scb list.
  *-F*************************************************************************/
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_scb *wscb;
+  struct aic7xxx_hwscb *hscb;
+  long flags;
+
+  hscb = scb->hscb;
+  save_flags(flags);
+  cli();
 
-  scb->state = SCB_FREE;
+  scb->flags = SCB_FREE;
   scb->cmd = NULL;
-  scb->control = 0;
-  scb->state = 0;
+  hscb->control = 0;
+  hscb->target_status = 0;
 
-  if (scb->position == SCB_LIST_NULL)
-  {
-    scbq_insert_head(&p->page_scbs, scb);
-  }
-  else
-  {
-    /*
-     * If there are any SCBS on the waiting queue, assign the slot of this
-     * "freed" SCB to the first one.  We'll run the waiting queues after
-     * all command completes for a particular interrupt are completed or
-     * when we start another command.
-     */
-    wscb = p->waiting_scbs.head;
-    if (wscb != NULL)
-    {
-      scbq_remove_head(&p->waiting_scbs);
-      wscb->position = scb->position;
-      scbq_insert_tail(&p->assigned_scbs, wscb);
-      wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ;
-
-      /* 
-       * The "freed" SCB will need to be assigned a slot before being
-       * used, so put it in the page_scbs queue.
-       */
-      scb->position = SCB_LIST_NULL;
-      scbq_insert_head(&p->page_scbs, scb);
-    }
-    else
-    {
-      scbq_insert_head(&p->scb_link->free_scbs, scb);
-    }
+  scbq_insert_head(&p->scb_data->free_scbs, scb);
 #ifdef AIC7XXX_DEBUG
-    p->scb_link->activescbs--;  /* For debugging purposes. */
+  p->activescbs--;  /* For debugging purposes. */
 #endif
-  }
+
+  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1652,68 +1955,113 @@
 {
   Scsi_Cmnd *cmd = scb->cmd;
 
+  if (scb->flags & SCB_RECOVERY_SCB)
+  {
+    p->flags &= ~IN_TIMEOUT;
+  }
+  if (cmd->result == DID_OK)
+  {
+    if (scb->flags & SCB_ABORTED)
+    {
+      cmd->result = (DID_RESET << 16);
+    }
+  }
+  if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+  {
+    unsigned short mask;
+
+    mask = 0x01 << TARGET_INDEX(scb->cmd);
+    if (scb->flags & SCB_MSGOUT_WDTR)
+    {
+      p->wdtr_pending &= ~mask;
+    }
+    if (scb->flags & SCB_MSGOUT_SDTR)
+    {
+      p->sdtr_pending &= ~mask;
+    }
+  }
   aic7xxx_free_scb(p, scb);
   aic7xxx_queue_cmd_complete(p, cmd);
 
+#ifdef AIC7XXX_PROC_STATS
+  {
+    int actual;
+
+    /*
+     * XXX: we should actually know how much actually transferred
+     * XXX: for each command, but apparently that's too difficult.
+     */
+    actual = aic7xxx_length(cmd, 0);
+    if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
+        && (aic7xxx_error(cmd) == 0))
+    {
+      struct aic7xxx_xferstats *sp;
+      long *ptr;
+      int x;
+
+      sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+      sp->xfers++;
+
+      if (cmd->request.cmd == WRITE)
+      {
+        sp->w_total++;
+        sp->w_total512 += (actual >> 9);
+        ptr = sp->w_bins;
+      }
+      else
+      {
+        sp->r_total++;
+        sp->r_total512 += (actual >> 9);
+        ptr = sp->r_bins;
+      }
+      for (x = 9; x <= 17; x++)
+      {
+        if (actual < (1 << x))
+        {
+          ptr[x - 9]++;
+          break;
+        }
+      }
+      if (x > 17)
+      {
+        ptr[x - 9]++;
+      }
+    }
+  }
+#endif /* AIC7XXX_PROC_STATS */
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_done_aborted_scbs
+ *   aic7xxx_run_done_queue
  *
  * Description:
- *   Calls the scsi_done() for the Scsi_Cmnd of each scb in the
- *   aborted list, and adds each scb to the free list.
+ *   Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ *   aborted list, and adds each scb to the free list.  If complete
+ *   is TRUE, we also process the commands complete list.
  *-F*************************************************************************/
 static void
-aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
 {
-  Scsi_Cmnd *cmd;
   struct aic7xxx_scb *scb;
   int i;
 
-  for (i = 0; i < p->scb_link->numscbs; i++)
+  for (i = 0; i < p->scb_data->numscbs; i++)
   {
-    scb = (p->scb_array[i]);
-    if (scb->state & SCB_QUEUED_FOR_DONE)
+    scb = p->scb_data->scb_array[i];
+    if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
 #ifdef AIC7XXX_DEBUG_ABORT
-      printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
-      scb->position, TCL_OF_SCB(scb));
+      printk("(scsi%d:%d:%d) Aborting scb %d\n",
+             p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
 #endif
-      /*
-       * Process the command after marking the scb as free
-       * and adding it to the free list.
-       */
-      cmd = scb->cmd;
-      p->device_status[TARGET_INDEX(cmd)].flags = 0;
-      aic7xxx_free_scb(p, scb);
-      cmd->scsi_done(cmd);  /* call the done function */
+      aic7xxx_done(p, scb);
     }
   }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_add_waiting_scb
- *
- * Description:
- *   Add this SCB to the head of the "waiting for selection" list.
- *-F*************************************************************************/
-static void
-aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
-{
-  unsigned char next;
-  unsigned char curscb;
-
-  curscb = inb(SCBPTR + base);
-  next = inb(WAITING_SCBH + base);
-
-  outb(scb->position, SCBPTR + base);
-  outb(next, SCB_NEXT + base);
-  outb(scb->position, WAITING_SCBH + base);
-
-  outb(curscb, SCBPTR + base);
+  if (complete)
+  {
+    aic7xxx_done_cmds_complete(p);
+  }
 }
 
 /*+F*************************************************************************
@@ -1726,26 +2074,23 @@
  *-F*************************************************************************/
 static unsigned char
 aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
-    unsigned char prev)
+    unsigned char scbpos, unsigned char prev)
 {
   unsigned char curscb, next;
-  int target = (scb->target_channel_lun >> 4) & 0x0F;
-  char channel = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
-  int base = p->base;
 
   /*
    * Select the SCB we want to abort and pull the next pointer out of it.
    */
-  curscb = inb(SCBPTR + base);
-  outb(scb->position, SCBPTR + base);
-  next = inb(SCB_NEXT + base);
+  curscb = inb(p->base + SCBPTR);
+  outb(scbpos, p->base + SCBPTR);
+  next = inb(p->base + SCB_NEXT);
 
   /*
    * Clear the necessary fields
    */
-  outb(0, SCB_CONTROL + base);
-  outb(SCB_LIST_NULL, SCB_NEXT + base);
-  aic7xxx_unbusy_target(target, channel, base);
+  outb(0, p->base + SCB_CONTROL);
+
+  aic7xxx_add_curscb_to_free_list(p);
 
   /*
    * Update the waiting list
@@ -1755,22 +2100,23 @@
     /*
      * First in the list
      */
-    outb(next, WAITING_SCBH + base);
+    outb(next, p->base + WAITING_SCBH);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, SCBPTR + base);
-    outb(next, SCB_NEXT + base);
+    outb(prev, p->base + SCBPTR);
+    outb(next, p->base + SCB_NEXT);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, SCBPTR + base);
-  scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+  outb(curscb, p->base + SCBPTR);
+  scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+  scb->flags &= ~SCB_ACTIVE;
   scb->cmd->result = (DID_RESET << 16);
 
   return (next);
@@ -1778,6 +2124,75 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_search_qinfifo
+ *
+ * Description:
+ *   Search the queue-in FIFO for matching SCBs and conditionally
+ *   requeue.  Returns the number of matching SCBs.
+ *-F*************************************************************************/
+static int
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
+    int lun, unsigned char tag, int flags, int requeue)
+{
+  unsigned char saved_queue[AIC7XXX_MAXSCB];
+  int      queued = inb(p->base + QINCNT) & p->qcntmask;
+  int      i;
+  int      found;
+  struct aic7xxx_scb *scbp;
+  scb_queue_type removed_scbs;
+
+  found = 0;
+  scbq_init (&removed_scbs);
+  for (i = 0; i < (queued - found); i++)
+  {
+    saved_queue[i] = inb(p->base + QINFIFO);
+    scbp = p->scb_data->scb_array[saved_queue[i]];
+    if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    {
+       /*
+        * We found an scb that needs to be removed.
+        */
+       if (requeue)
+       {
+         scbq_insert_head(&removed_scbs, scbp);
+       }
+       else
+       {
+         scbp->flags = flags;
+         scbp->flags &= ~SCB_ACTIVE;
+         /*
+          * XXX - Don't know what error to use here.
+          */
+         aic7xxx_error(scbp->cmd) = DID_RESET;
+       }
+       i--;
+       found++;
+    }
+  }
+  /* Now put the saved scbs back. */
+  for (queued = 0; queued < i; queued++)
+    outb(saved_queue[queued], p->base + QINFIFO);
+
+  if (requeue)
+  {
+    scbp = removed_scbs.head;
+    while (scbp != NULL)
+    {
+      scbq_remove_head(&removed_scbs);
+      /*
+       * XXX - Shouldn't we be adding this to the free list?
+       */
+      scbq_insert_head(&p->waiting_scbs, scbp);
+      scbp->flags |= SCB_WAITINGQ;
+      scbp = removed_scbs.head;
+    }
+  }
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_reset_device
  *
  * Description:
@@ -1785,131 +2200,280 @@
  *   all active and queued scbs for that target/channel.
  *-F*************************************************************************/
 static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+                     int lun, unsigned char tag)
 {
-  int base = p->base;
-  struct aic7xxx_scb *scb;
+  struct aic7xxx_scb *scbp;
   unsigned char active_scb;
   int i = 0;
-  int found = 0;
+  int found;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(SCBPTR + base);
+  active_scb = inb(p->base + SCBPTR);
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
-         target, channel, active_scb);
+  printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
+         p->host_no, target, CHAN_TO_INT(channel), active_scb);
 #endif
+
   /*
-   * Search the QINFIFO.
+   * Deal with the busy target and linked next issues.
    */
   {
-    int saved_queue[AIC7XXX_MAXSCB];
-    int queued = inb(QINCNT + base) & p->qcntmask;
+    int min_target, max_target;
+    unsigned char busy_scbid;
 
-    for (i = 0; i < (queued - found); i++)
+    /* Make all targets 'relative' to bus A. */
+    if (target == ALL_TARGETS)
     {
-      saved_queue[i] = inb(QINFIFO + base);
-      outb(saved_queue[i], SCBPTR + base);
-      scb = (p->scb_array[inb(SCB_TAG + base)]);
-      if (aic7xxx_match_scb(scb, target, channel))
+      switch (channel)
       {
-        /*
-         * We found an scb that needs to be aborted.
-         */
-#ifdef AIC7XXX_DEBUG_ABORT
-        printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n",
-               saved_queue[i], TCL_OF_SCB(scb));
-#endif
-        scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-        scb->cmd->result = (DID_RESET << 16);
-        outb(0, SCB_CONTROL + base);
-        i--;
-        found++;
+        case 'A':
+  	  min_target = 0;
+  	  max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+  	  break;
+        case 'B':
+  	  min_target = 8;
+  	  max_target = 15;
+  	  break;
+        case ALL_CHANNELS:
+        default:
+  	  min_target = 0;
+  	  max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+  	  break;
       }
     }
-    /*
-     * Now put the saved scbs back.
-     */
-    for (queued = 0; queued < i; queued++)
+    else
+    { 
+      min_target = target + channel == 'B' ? 8 : 0;
+      max_target = min_target;
+    }
+
+    for (i = min_target; i <= max_target; i++)
     {
-      outb(saved_queue[queued], QINFIFO + base);
+      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
+      if (busy_scbid < p->scb_data->numscbs)
+      {
+  	struct aic7xxx_scb *busy_scb;
+  	struct aic7xxx_scb *next_scb;
+  	unsigned char next_scbid;
+
+  	busy_scb = p->scb_data->scb_array[busy_scbid];
+  
+  	next_scbid = busy_scb->hscb->data_count >> 24;
+
+  	if (next_scbid == SCB_LIST_NULL)
+        {
+  	  busy_scbid = aic7xxx_find_scb(p, busy_scb);
+
+  	  if (busy_scbid != SCB_LIST_NULL)
+          {
+  	    outb(busy_scbid, p->base + SCBPTR);
+  	    next_scbid = inb(p->base + SCB_LINKED_NEXT);
+  	  }
+  	}
+
+  	if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+        {
+  	  aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
+  	}
+
+  	if (next_scbid != SCB_LIST_NULL)
+        {
+  	  next_scb = p->scb_data->scb_array[next_scbid];
+  	  if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+          {
+  	    continue;
+          }
+  	  /* Requeue for later processing */
+  	  scbq_insert_head(&p->waiting_scbs, next_scb);
+  	  next_scb->flags |= SCB_WAITINGQ;
+  	}
+      }
     }
   }
 
+  found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
+
   /*
    * Search waiting for selection list.
    */
   {
-    unsigned char next, prev;
+    unsigned char next, prev, scb_index;
 
-    next = inb(WAITING_SCBH + base);  /* Start at head of list. */
+    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
 
     while (next != SCB_LIST_NULL)
     {
-      outb(next, SCBPTR + base);
-      scb = (p->scb_array[inb(SCB_TAG + base)]);
-      /*
-       * Select the SCB.
-       */
-      if (aic7xxx_match_scb(scb, target, channel))
+      outb(next, p->base + SCBPTR);
+      scb_index = inb(p->base + SCB_TAG);
+      if (scb_index >= p->scb_data->numscbs)
       {
-        next = aic7xxx_abort_waiting_scb(p, scb, prev);
+        panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
+              scb_index, p->scb_data->numscbs);
+      }
+      scbp = p->scb_data->scb_array[scb_index];
+      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      {
+        unsigned char linked_next;
+
+        next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+        linked_next = inb(p->base + SCB_LINKED_NEXT);
+        if (linked_next != SCB_LIST_NULL)
+        {
+          struct aic7xxx_scb *next_scb;
+          /*
+           * Requeue the waiting SCB via the waiting list.
+           */
+          next_scb = p->scb_data->scb_array[linked_next];
+          if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+          {
+            scbq_insert_head(&p->waiting_scbs, next_scb);
+            next_scb->flags |= SCB_WAITINGQ;
+          }
+        }
         found++;
       }
       else
       {
         prev = next;
-        next = inb(SCB_NEXT + base);
+        next = inb(p->base + SCB_NEXT);
       }
     }
   }
 
   /*
-   * Go through the entire SCB array now and look for commands for
-   * for this target that are active.  These are other (most likely
-   * tagged) commands that were disconnected when the reset occurred.
+   * Go through disconnected list and remove any entries we have queued
+   * for completion, zeroing their control byte too.
+   */
+  {
+    unsigned char next, prev, scb_index;
+
+    next = inb(p->base + DISCONNECTED_SCBH);
+    prev = SCB_LIST_NULL;
+
+    while (next != SCB_LIST_NULL)
+    {
+      outb(next, p->base + SCBPTR);
+      scb_index = inb(p->base + SCB_TAG);
+      if (scb_index > p->scb_data->numscbs)
+      {
+        panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
+              "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
+      }
+      scbp = p->scb_data->scb_array[scb_index];
+      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      {
+        next = aic7xxx_rem_scb_from_disc_list(p, next);
+      }
+      else
+      {
+        prev = next;
+        next = inb(p->base + SCB_NEXT);
+      }
+    }
+  }
+
+  /*
+   * Go through the hardware SCB array looking for commands that
+   * were active but not on any list.
    */
-  for (i = 0; i < p->scb_link->numscbs; i++)
+  for (i = 0; i < p->scb_data->maxhscbs; i++)
   {
-    scb = (p->scb_array[i]);
-    if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
+    unsigned char scbid;
+
+    outb(i, p->base + SCBPTR);
+    scbid = inb(p->base + SCB_TAG);
+    if (scbid < p->scb_data->numscbs)
     {
-      /*
-       * Ensure the target is "free"
-       */
-      aic7xxx_unbusy_target(target, channel, base);
-      if (! (scb->state & SCB_PAGED_OUT))
+      scbp = p->scb_data->scb_array[scbid];
+      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
       {
-        outb(scb->position, SCBPTR + base);
-        outb(0, SCB_CONTROL + base);
+        aic7xxx_add_curscb_to_free_list(p);
       }
-      scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-      scb->cmd->result = (DID_RESET << 16);
+    }
+  }
+
+  /*
+   * Go through the entire SCB array now and look for commands for
+   * for this target that are stillactive.  These are other (most likely
+   * tagged) commands that were disconnected when the reset occurred.
+   */
+  for (i = 0; i < p->scb_data->numscbs; i++)
+  {
+    scbp = p->scb_data->scb_array[i];
+    if (((scbp->flags & SCB_ACTIVE) != 0) &&
+        aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    {
+      scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+      scbp->flags &= ~SCB_ACTIVE;
+      aic7xxx_error(scbp->cmd) = DID_RESET;
+
       found++;
+
+      if ((scbp->flags & SCB_WAITINGQ) != 0)
+      {
+        scbq_remove(&p->waiting_scbs, scbp);
+        scbp->flags &= ~SCB_WAITINGQ;
+      }
     }
   }
 
-  outb(active_scb, SCBPTR + base);
+  outb(active_scb, p->base + SCBPTR);
   return (found);
 }
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_clear_intstat
+ *
+ * Description:
+ *   Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+  /* Clear any interrupt conditions this may have caused. */
+  outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
+  outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
+  outb(CLRSCSIINT, p->base + CLRINT);
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_reset_current_bus
  *
  * Description:
  *   Reset the current SCSI bus.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_current_bus(int base)
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 {
-  outb(SCSIRSTO, SCSISEQ + base);
+  unsigned char scsiseq;
+
+  /* Disable reset interrupts. */
+  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+
+  /* Turn on the bus reset. */
+  scsiseq = inb(p->base + SCSISEQ);
+  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+
+  udelay(1000);
+
+  /* Turn off the bus reset. */
+  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+
+  aic7xxx_clear_intstat(p);
+
+  /* Re-enable reset interrupts. */
+  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+
   udelay(1000);
-  outb(0, SCSISEQ + base);
 }
 
 /*+F*************************************************************************
@@ -1922,25 +2486,24 @@
 static int
 aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
 {
-  int base = p->base;
-  unsigned char sblkctl;
-  char cur_channel;
   unsigned long offset, offset_max;
   int found;
+  unsigned char sblkctl;
+  char cur_channel;
 
+  pause_sequencer(p);
   /*
-   * Clean up all the state information for the
-   * pending transactions on this bus.
+   * Clean up all the state information for the pending transactions
+   * on this bus.
    */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
+  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
   if (channel == 'B')
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
-    outb(0, ACTIVE_B + base);
-    offset = TARG_SCRATCH + base + 8;
-    offset_max = TARG_SCRATCH + base + 16;
+    offset = TARG_SCRATCH + 8;
+    offset_max = TARG_SCRATCH + 16;
   }
   else
   {
@@ -1950,132 +2513,100 @@
       p->needwdtr = p->needwdtr_copy;
       p->sdtr_pending = 0x0;
       p->wdtr_pending = 0x0;
-      outb(0, ACTIVE_A + base);
-      outb(0, ACTIVE_B + base);
-      offset = TARG_SCRATCH + base;
-      offset_max = TARG_SCRATCH + base + 16;
+      offset = TARG_SCRATCH;
+      offset_max = TARG_SCRATCH + 16;
     }
     else
     {
+      /* Channel A */
       p->needsdtr |= (p->needsdtr_copy & 0x00FF);
       p->sdtr_pending &= 0xFF00;
-      outb(0, ACTIVE_A + base);
-      offset = TARG_SCRATCH + base;
-      offset_max = TARG_SCRATCH + base + 8;
+      offset = TARG_SCRATCH;
+      offset_max = TARG_SCRATCH + 8;
     }
   }
+
   while (offset < offset_max)
   {
     /*
-     * Revert to async/narrow transfers
-     * until we renegotiate.
+     * Revert to async/narrow transfers until we renegotiate.
      */
     u_char targ_scratch;
-    targ_scratch = inb(offset);
+
+    targ_scratch = inb(p->base + offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, offset);
+    outb(targ_scratch, p->base + offset);
     offset++;
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-
-  /*
-   * Case 1: Command for another bus is active
-   */
-  sblkctl = inb(SBLKCTL + base);
+  sblkctl = inb(p->base + SBLKCTL);
   cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
   if (cur_channel != channel)
   {
+    /*
+     * Case 1: Command for another bus is active
+     */
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
-           channel);
+    printk("scsi%d: Stealthily resetting channel %c\n",
+           p->host_no, channel);
 #endif
     /*
-     * Stealthily reset the other bus without upsetting the current bus
+     * Stealthily reset the other bus without upsetting the current bus.
      */
-    outb(sblkctl ^ SELBUSB, SBLKCTL + base);
+    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
+    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     if (initiate_reset)
     {
-      aic7xxx_reset_current_bus(base);
+      aic7xxx_reset_current_bus(p);
+      /*
+       * Cause the mid-level SCSI code to delay any further 
+       * queueing by the bus settle time for us.
+       */
+      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
     }
-    outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
-    outb(CLRSCSIINT, CLRINT + base);
-    outb(sblkctl, SBLKCTL + base);
-
-    UNPAUSE_SEQUENCER(p);
+    outb(0, p->base + SCSISEQ);
+    aic7xxx_clear_intstat(p);
+    outb(sblkctl, p->base + SBLKCTL);
+    unpause_sequencer(p, /* unpause_always */ FALSE);
   }
-  /*
-   * Case 2: A command from this bus is active or we're idle
-   */
   else
   {
+    /*
+     * Case 2: A command from this bus is active or we're idle.
+     */
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
-           channel);
+    printk("scsi%d: Resetting current channel %c\n",
+           p->host_no, channel);
 #endif
+    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     if (initiate_reset)
     {
-      aic7xxx_reset_current_bus(base);
+      aic7xxx_reset_current_bus(p);
+      /*
+       * Cause the mid-level SCSI code to delay any further 
+       * queueing by the bus settle time for us.
+       */
+#if 0
+      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
+#endif
     }
-    outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
-    outb(CLRSCSIINT, CLRINT + base);
-    RESTART_SEQUENCER(p);
+    outb(0, p->base + SCSISEQ);
+    aic7xxx_clear_intstat(p);
+    restart_sequencer(p);
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
+    printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
 #endif
   }
 
   /*
-   * Cause the mid-level SCSI code to delay any further 
-   * queueing by the bus settle time for us.
-   */
-  p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-
-  /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
-  aic7xxx_done_aborted_scbs(p);
-  return found;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_page_scb
- *
- * Description:
- *   Swap in_scbp for out_scbp down in the cards SCB array.
- *   We assume that the SCB for out_scbp is already selected in SCBPTR.
- *
- *-F*************************************************************************/
-static inline void
-aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp,
-    struct aic7xxx_scb *in_scbp)
-{
-  int index;
-
-  /* Page-out */
-#if 0
-printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
-       out_scbp->cmd->target, in_scbp->cmd->target);
-#endif
-  aic7xxx_getscb(p, out_scbp);
-  out_scbp->state |= SCB_PAGED_OUT;
-  if (!(out_scbp->control & TAG_ENB))
-  {
-    /* Stick in non-tagged array */
-    index = (out_scbp->target_channel_lun >> 4) | 
-            (out_scbp->target_channel_lun & SELBUSB);
-    p->pagedout_ntscbs[index] = out_scbp;
-  }
-
-  /* Page-in */
-  in_scbp->position = out_scbp->position;
-  out_scbp->position = SCB_LIST_NULL;
-  aic7xxx_putscb(p, in_scbp);
-  in_scbp->state &= ~SCB_PAGED_OUT;
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  return (found);
 }
 
 /*+F*************************************************************************
@@ -2083,1159 +2614,1326 @@
  *   aic7xxx_run_waiting_queues
  *
  * Description:
- *   Scan the assigned_scbs and waiting_scbs queues.  For scbs in the
- *   assigned_scbs queue, we download and start them.  For scbs in the
- *   waiting_scbs queue, we page in as many as we can being careful
- *   not to cause a deadlock for a reconnecting target.
- *
+ *   Scan the awaiting_scbs queue downloading and starting as many
+ *   scbs as we can.
  *-F*************************************************************************/
 static inline void
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
-  u_char cur_scb, intstat;
-  u_long base = p->base;
-  long flags;
 
-  if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
+  if (p->waiting_scbs.head == NULL)
     return;
 
-  save_flags(flags);
-  cli();
-
-  PAUSE_SEQUENCER(p);
-  cur_scb = inb(SCBPTR + base);
-  intstat = inb(INTSTAT + base);
-
+  pause_sequencer(p);
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  scb = p->assigned_scbs.head;
-  while (scb != NULL)
-  {
-    scbq_remove_head(&(p->assigned_scbs));
-    outb(scb->position, SCBPTR + base);
-    aic7xxx_putscb(p, scb);
-    /* Mark this as an active command. */
-    scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE;
-    outb(scb->position, QINFIFO + base);
-    scb = p->assigned_scbs.head;
-  }
-
-  /* Now deal with SCBs that require paging. */
   scb = p->waiting_scbs.head;
-  if (scb != NULL)
+  while (scb != NULL)
   {
-    u_char disc_scb = inb(DISCONNECTED_SCBH + base);
-    u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN);
-    int count = 0;
-    u_char next_scb;
-
-    while (scb != NULL)
+    if (p->curqincnt >= p->qfullcount)
     {
-      /* Attempt to page this SCB in */
-      if (disc_scb == SCB_LIST_NULL)
-        break;
-
-      /*
-       * Advance disc_scb to the next one in the list.
-       */
-      outb(disc_scb, SCBPTR + base);
-      next_scb = inb(SCB_NEXT + base); 
-
-      /*
-       * We have to be careful about when we allow an SCB to be paged out. 
-       * There must always be at least one slot availible for a reconnecting
-       * target in case it references an SCB that has been paged out.  Our
-       * heuristic is that either the disconnected list has at least two
-       * entries in it or there is one entry and the sequencer is activily
-       * working on an SCB which implies that it will either complete or
-       * disconnect before another reconnection can occur.
-       */
-      if ((next_scb != SCB_LIST_NULL) || active)
+      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
+      if (p->curqincnt >= p->qfullcount)
       {
-        u_char out_scbi;
-        struct aic7xxx_scb *out_scbp;
-
-        scbq_remove_head(&(p->waiting_scbs));
-
-        /*
-         * Find the in-core SCB for the one we're paging out.
-         */
-        out_scbi = inb(SCB_TAG + base); 
-        out_scbp = (p->scb_array[out_scbi]);
-
-        /* Do the page out and mark the paged in SCB as active. */
-        aic7xxx_page_scb(p, out_scbp, scb);
-
-        /* Mark this as an active command. */
-        scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE;
-
-        /* Queue the command */
-        outb(scb->position, QINFIFO + base);
-        count++;
-
-        /* Advance to the next disconnected SCB */
-        disc_scb = next_scb;
-        scb = p->waiting_scbs.head;
+        break;
       }
-      else
-        scb = NULL;
     }
 
-    if (count)
+    /*
+     * We have some space.
+     */
+    scbq_remove_head(&(p->waiting_scbs));
+    scb->flags &= ~SCB_WAITINGQ;
+
+    outb(scb->hscb->tag, p->base + QINFIFO);
+
+    if ((p->flags & PAGE_ENABLED) != 0)
     {
-      /* 
-       * Update the head of the disconnected list.
+      /*
+       * We only care about this statistic when paging
+       * since it's impossible to overflow the qinfifo
+       * in the non-paging case.
        */
-      outb(disc_scb, DISCONNECTED_SCBH + base);
-      if (disc_scb != SCB_LIST_NULL)
-      {
-        outb(disc_scb, SCBPTR + base);
-        outb(SCB_LIST_NULL, SCB_PREV + base);
-      }
+      p->curqincnt++;
     }
+    scb = p->waiting_scbs.head;
   }
-  /* Restore old position */
-  outb(cur_scb, SCBPTR + base);
 
-  /*
-   * Guard against unpausing the sequencer if there is an interrupt
-   * waiting to happen.
-   */
-  if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
-  {
-    UNPAUSE_SEQUENCER(p);
-  }
+  unpause_sequencer(p, FALSE);
+}
 
-  restore_flags(flags);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_sdtr
+ *
+ * Description:
+ *   Constucts a synchronous data transfer message in the message
+ *   buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
+    unsigned char period, unsigned char offset)
+{
+  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
+  outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+  outb(MSG_EXT_SDTR,     p->base + MSG_OUT + 2 + start_byte);
+  outb(period,           p->base + MSG_OUT + 3 + start_byte);
+  outb(offset,           p->base + MSG_OUT + 4 + start_byte);
+  outb(start_byte + 5,   p->base + MSG_LEN);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_isr
+ *   aic7xxx_construct_wdtr
  *
  * Description:
- *   SCSI controller interrupt handler.
+ *   Constucts a wide data transfer message in the message buffer
+ *   on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
+    unsigned char bus_width)
+{
+  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
+  outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+  outb(MSG_EXT_WDTR,     p->base + MSG_OUT + 2 + start_byte);
+  outb(bus_width,        p->base + MSG_OUT + 3 + start_byte);
+  outb(start_byte + 4,   p->base + MSG_LEN);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_calc_residual
  *
- *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- *         be disabled all through this function unless we say otherwise.
+ * Description:
+ *   Calculate the residual data not yet transferred.
  *-F*************************************************************************/
 static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  int base, intstat, actual, scb_index, run_aborted_queue = FALSE;
-  struct aic7xxx_host *p;
-  struct aic7xxx_scb *scb = NULL;
-  short         transfer;
-  unsigned char ha_flags, scsi_id, bus_width;
-  unsigned char offset, rate, scratch, scratch_offset;
-  unsigned char max_offset, rej_byte;
-  unsigned short target_mask;
-  char channel;
-  unsigned int addr; /* must be 32 bits */
+  struct aic7xxx_hwscb *hscb;
   Scsi_Cmnd *cmd;
+  int actual;
 
-  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+  cmd = scb->cmd;
+  hscb = scb->hscb;
 
   /*
-   * Search for the host with a pending interrupt.  If we can't find
-   * one, then we've encountered a spurious interrupt.
+   *  Don't destroy valid residual information with
+   *  residual coming from a check sense operation.
    */
-  while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
+  if (((scb->hscb->control & DISCONNECTED) == 0) &&
+      (scb->flags & SCB_SENSE) == 0)
   {
-    if (p->next == NULL)
-    {
-      p = NULL;
-    }
-    else
+    /*
+     *  We had an 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, hscb->residual_SG_segment_count);
+
+    actual -= (hscb->residual_data_count[2] << 16) |
+              (hscb->residual_data_count[1] <<  8) |
+              hscb->residual_data_count[0];
+
+    if (actual < cmd->underflow)
     {
-      p = (struct aic7xxx_host *) p->next->hostdata;
+      printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
+             "Wanted at least %u, got %u, residual SG count %d.\n",
+             p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
+             hscb->residual_SG_segment_count);
+      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+      aic7xxx_status(cmd) = hscb->target_status;
     }
   }
 
-  if (p == NULL)
-    return;
-
   /*
-   * Keep track of interrupts for /proc/scsi
+   * Clean out the residual information in the SCB for the
+   * next consumer.
    */
-  p->isr_count++;
+  hscb->residual_data_count[2] = 0;
+  hscb->residual_data_count[1] = 0;
+  hscb->residual_data_count[0] = 0;
+  hscb->residual_SG_segment_count = 0;
+}
 
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_device_reset
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+{
+  unsigned short targ_mask;
+  unsigned char  targ_scratch;
+  int scratch_offset = target;
+  int found;
+
+  if (channel == 'B')
   {
-    /*
-     * We must only have one card at this IRQ and it must have been
-     * added to the board data before the spurious interrupt occurred.
-     * It is sufficient that we check isr_count and not the spurious
-     * interrupt count.
-     */
-    printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
-    return;
+    scratch_offset += 8;
   }
-
-  base = p->base;
+  targ_mask = (0x01 << scratch_offset);
   /*
-   * Handle all the interrupt sources - especially for SCSI
-   * interrupts, we won't get a second chance at them.
+   * Go back to async/narrow transfers and renegotiate.
    */
-  intstat = inb(INTSTAT + base);
+  p->needsdtr |= p->needsdtr_copy & targ_mask;
+  p->needwdtr |= p->needwdtr_copy & targ_mask;
+  p->sdtr_pending &= ~targ_mask;
+  p->wdtr_pending &= ~targ_mask;
+  targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+  targ_scratch &= SXFR;
+  outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+  found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+  printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
+         "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
 
-  /*
-   * Indicate that we're in the interrupt handler.
-   */
-  p->flags |= IN_ISR;
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_seqint
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  struct aic7xxx_scb *scb;
+  unsigned short target_mask;
+  unsigned char target, scratch_offset;
+  char channel;
 
-  if (intstat & BRKADRINT)
+  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
   {
-    int i;
-    unsigned char errno = inb(ERROR + base);
-
-    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
-    for (i = 0; i < NUMBER(hard_error); i++)
-    {
-      if (errno & hard_error[i].errno)
-      {
-        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
-      }
-    }
-    panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
-          inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
+    target = (inb(p->base + SELID) >> 4) & 0x0F;
   }
-
-  if (intstat & SEQINT)
+  else
   {
-    /*
-     * Although the sequencer is paused immediately on
-     * a SEQINT, an interrupt for a SCSIINT condition will
-     * unpaused the sequencer before this point.
-     */
-    PAUSE_SEQUENCER(p);
+    target = (inb(p->base + SCSIID) >> 4) & 0x0F;
+  }
+  scratch_offset = target;
+  channel = 'A';
+  if (inb(p->base + SBLKCTL) & SELBUSB)
+  {
+    channel = 'B';
+    scratch_offset += 8;
+  }
+  target_mask = (0x01 << scratch_offset);
 
-    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
-    scratch_offset = scsi_id;
-    channel = 'A';
-    if (inb(SBLKCTL + base) & SELBUSB)
-    {
-      channel = 'B';
-      scratch_offset += 8;
-    }
-    target_mask = (0x01 << scratch_offset);
+  switch (intstat & SEQINT_MASK)
+  {
+    case NO_MATCH:
+      {
+        /*
+         * This could be for a normal abort request.  Figure out
+         * which SCB we were trying to find and only give an error
+         * if we didn't ask for this to happen.
+         */
+        unsigned char scb_index;
+        unsigned char busy_scbid;
+        unsigned char arg1;
+
+        busy_scbid = aic7xxx_index_busy_target(p, target, channel,
+            /*unbusy*/ FALSE);
+        arg1 = inb(p->base + ARG_1);
 
-    switch (intstat & SEQINT_MASK)
-    {
-      case NO_MATCH:
-    	if (p->flags & PAGE_ENABLED)
+        if (arg1 == SCB_LIST_NULL)
         {
-    	  /* SCB Page-in request */
-    	  struct aic7xxx_scb *outscb;
-    	  u_char arg_1 = inb(ARG_1 + base);
-          int use_disconnected = FALSE;
-
-          /*
-           * The sequencer expects this value upon return.  Assume
-           * we will find the paged out SCB and set the value now.
-           * If we don't, and one of the methods used to acquire an
-           * SCB calls aic7xxx_done(), we will end up in our queue
-           * routine and unpause the sequencer without giving it the
-           * correct return value, which causes a hang.
-           */
-    	  outb(SCB_PAGEDIN, RETURN_1 + base);
-    	  if (arg_1 == SCB_LIST_NULL)
-          {
-    	    /* Non-tagged command */
-    	    int index = scsi_id;
-            if (channel == 'B')
-            {
-              index |= SELBUSB;
-            }
-    	    scb = p->pagedout_ntscbs[index];
-    	  }
-    	  else
-    	    scb = (p->scb_array[arg_1]);
+          /* untagged request */
+          scb_index = busy_scbid;
+        }
+        else
+        {
+          scb_index = arg1;
+        }
 
-          if (!(scb->state & SCB_PAGED_OUT))
+        if (scb_index < p->scb_data->numscbs)
+        {
+          scb = p->scb_data->scb_array[scb_index];
+          if (scb->hscb->control & ABORT_SCB)
           {
-  	    printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting "
-  	  	  "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-    		  p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-    	    aic7xxx_unbusy_target(scsi_id, channel, base);
-  	    outb(CLRSELTIMEO, CLRSINT1 + base);
-            outb(0, RETURN_1 + base);
+            /*
+             * We expected this.  Let the busfree handler take care
+             * of this when we the abort is finially sent.  Set
+             * IDENTIFY_SEEN so that the busfree handler knows that
+             * there is an SCB to cleanup.
+             */
+            outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
+            printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
+                   p->host_no, TC_OF_SCB(scb));
             break;
           }
+        }
+        printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
+               "target - Issuing BUS DEVICE RESET.\n",
+               p->host_no, target, CHAN_TO_INT(channel));
+
+        printk(KERN_WARNING "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               inb(p->base + SAVED_TCL), arg1,
+               (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+        aic7xxx_handle_device_reset(p, target, channel);
+      }
+      break;
 
-    	  /*
-    	   * Now to pick the SCB to page out.  Either take a free SCB, an
-           * assigned SCB, an SCB that just completed, or the first one
-           * on the disconnected SCB list.
-    	   */
-    	  if (p->scb_link->free_scbs.head != NULL)
-          {
-    	    outscb = p->scb_link->free_scbs.head;
-    	    scbq_remove_head(&p->scb_link->free_scbs);
-    	    scb->position = outscb->position;
-    	    outscb->position = SCB_LIST_NULL;
-    	    scbq_insert_head(&p->page_scbs, outscb);
-    	    outb(scb->position, SCBPTR + base);
-    	    aic7xxx_putscb(p, scb);
-    	    scb->state &= ~SCB_PAGED_OUT;
-    	  }
-    	  else if (p->assigned_scbs.head != NULL)
-          {
-            outscb = p->assigned_scbs.head;
-            scbq_remove_head(&p->assigned_scbs);
-            scb->position = outscb->position;
-            outscb->position = SCB_LIST_NULL;
-            scbq_insert_head(&p->waiting_scbs, outscb);
-            outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ;
-            outb(scb->position, SCBPTR + base);
-    	    aic7xxx_putscb(p, scb);
-            scb->state &= ~SCB_PAGED_OUT;
-          }
-          else if (intstat & CMDCMPLT)
+    case NO_MATCH_BUSY:
+      {
+        /*
+         * XXX - Leave this as a panic for the time being since it
+         * indicates a bug in the timeout code for this to happen.
+         */
+        unsigned char scb_index;
+
+        scb_index = inb(p->base + CUR_SCBID);
+        scb = p->scb_data->scb_array[scb_index];
+
+        panic("scsi%d:  Target %d, channel %c, Target busy link failure, "
+              "but busy SCB exists!\n",
+              p->host_no, target, channel);
+      }
+      break;
+
+    case SEND_REJECT:
+      {
+        unsigned char rej_byte;
+
+        rej_byte = inb(p->base + REJBYTE);
+        printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
+               "received from target, SEQ_FLAGS=0x%x\n",
+               p->host_no, target, CHAN_TO_INT(channel), rej_byte,
+               inb(p->base + SEQ_FLAGS));
+      }
+      break;
+
+    case NO_IDENT:
+      {
+        /*
+         * The reconnecting target either did not send an identify
+         * message, or did, but we didn't find and SCB to match and
+         * before it could respond to our ATN/abort, it hit a dataphase.
+         * The only safe thing to do is to blow it away with a bus
+         * reset.
+         */
+        int found;
+
+        printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
+               "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
+               p->host_no, target, CHAN_TO_INT(channel),
+               inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+
+        found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+
+        printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
+     	       "%d SCBs aborted\n", p->host_no, channel, found);
+      }
+      break;
+
+    case BAD_PHASE:
+      if (inb(p->base + LASTPHASE) == P_BUSFREE)
+      {
+        printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
+               p->host_no, CHAN_TO_INT(channel), target);
+        restart_sequencer(p);
+      }
+      else
+      {
+        printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
+               "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+      }
+      break;
+
+    case EXTENDED_MSG:
+      {
+	unsigned char message_length;
+	unsigned char message_code;
+        unsigned char scb_index;
+
+	message_length = inb(p->base + MSGIN_EXT_LEN);
+	message_code = inb(p->base + MSGIN_EXT_OPCODE);
+        scb_index = inb(p->base + SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+
+	switch (message_code)
+	{
+          case MSG_EXT_SDTR:
           {
-            int scb_index;
+            unsigned char period;
+            unsigned char offset;
+            unsigned char saved_offset;
+            unsigned char targ_scratch;
+            unsigned char max_offset;
+            unsigned char rate;
 
-            outb(CLRCMDINT, CLRINT + base);
-            scb_index = inb(QOUTFIFO + base);
-            if (!(inb(QOUTCNT + base) & p->qcntmask))
-            {
-              intstat &= ~CMDCMPLT;
-            }
-            outscb = (p->scb_array[scb_index]);
-            if (!(outscb->state & SCB_ACTIVE))
+            if (message_length != MSG_EXT_SDTR_LEN)
             {
-	      printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
-	             "during NO_MATCH interrupt\n", scb_index, p->host_no);
-              use_disconnected = TRUE;
+              outb(SEND_REJ, p->base + RETURN_1);
+              break;
             }
+
+            period = inb(p->base + MSGIN_EXT_BYTES);
+            saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
+            targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+            if (targ_scratch & WIDEXFER)
+              max_offset = MAX_OFFSET_16BIT;
             else
+              max_offset = MAX_OFFSET_8BIT;
+            offset = MIN(saved_offset, max_offset);
+
+            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+
+            /*
+             * Preserve the WideXfer flag.
+             */
+            targ_scratch = rate | (targ_scratch & WIDEXFER);
+
+            /*
+             * Update both the target scratch area and current SCSIRATE.
+             */
+            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+            outb(targ_scratch, p->base + SCSIRATE);
+
+            /*
+             * See if we initiated Sync Negotiation and didn't have
+             * have to fall down to async transfers.
+             */
+            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
             {
-              scb->position = outscb->position;
-              outscb->position = SCB_LIST_NULL;
-              outb(scb->position, SCBPTR + base);
-              aic7xxx_putscb(p, scb);
-              scb->state &= ~SCB_PAGED_OUT;
-              outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16);
-              if ((outscb->cmd->flags & WAS_SENSE) && 
-                 !(outscb->cmd->flags & ASKED_FOR_SENSE))
+              /* We started it. */
+              if (saved_offset == offset)
               {
-                /*
-                 * Got sense information.
-                 */
-	        outscb->cmd->flags &= ASKED_FOR_SENSE;
+        	/*
+        	 * Don't send an SDTR back to the target.
+        	 */
+        	outb(0, p->base + RETURN_1);
+              }
+              else
+              {
+        	/* We went too low - force async. */
+        	outb(SEND_REJ, p->base + RETURN_1);
               }
-              p->device_status[TARGET_INDEX(outscb->cmd)].flags
-                |= DEVICE_SUCCESS;
-              aic7xxx_done(p, outscb);
             }
+            else
+            {
+              /*
+               * Send our own SDTR in reply.
+               *
+               * We want to see this message as we don't expect a target
+               * to send us a SDTR request first.
+               */
+              printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
+              aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
+              outb(SEND_MSG, p->base + RETURN_1);
+            }
+            /*
+             * Clear the flags.
+             */
+            p->needsdtr &= ~target_mask;
+            break;
           }
-          else
-          {
-            use_disconnected = TRUE;
-          }
-          if (use_disconnected)
+
+          case MSG_EXT_WDTR:
           {
-    	    u_char tag;
-    	    u_char next;
-    	    u_char disc_scb = inb(DISCONNECTED_SCBH + base);
-    	    if (disc_scb != SCB_LIST_NULL)
+            unsigned char scratch, bus_width;
+
+            if (message_length != MSG_EXT_WDTR_LEN)
             {
-    	      outb(disc_scb, SCBPTR + base);
-    	      tag = inb(SCB_TAG + base);
-    	      outscb = (p->scb_array[tag]);
-    	      next = inb(SCB_NEXT + base);
-    	      if (next != SCB_LIST_NULL)
-              {
-    	        outb(next, SCBPTR + base);
-    	        outb(SCB_LIST_NULL, SCB_PREV + base);
-    	        outb(disc_scb, SCBPTR + base);
-    	      }
-    	      outb(next, DISCONNECTED_SCBH + base);
-    	      aic7xxx_page_scb(p, outscb, scb);
-    	    }
-            else if (inb(QINCNT + base) & p->qcntmask)
+              outb(SEND_REJ, p->base + RETURN_1);
+              break;
+            }
+
+            bus_width = inb(p->base + MSGIN_EXT_BYTES);
+            scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+            if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
             {
-              /* Pull one of our queued commands as a last resort. */
-              disc_scb = inb(QINFIFO + base);
-              outb(disc_scb, SCBPTR + base);
-              tag = inb(SCB_TAG + base);
-              outscb = (p->scb_array[tag]);
-              if ((outscb->control & 0x23) != TAG_ENB)
+              /*
+               * Don't send an WDTR back to the target, since we asked first.
+               */
+              outb(0, p->base + RETURN_1);
+              switch (bus_width)
               {
-                /*
-                 * This is not a simple tagged command so its position
-                 * in the queue matters.  Take the command at the end of
-                 * the queue instead.
-                 */
-                int i;
-                int saved_queue[AIC7XXX_MAXSCB];
-                int queued = inb(QINCNT + base) & p->qcntmask;
-
-                /* Count the command we removed already */
-                saved_queue[0] = disc_scb;
-                queued++;
-
-                /* Empty the input queue. */
-                for (i = 1; i < queued; i++)
-                {
-                  saved_queue[i] = inb(QINFIFO + base);
-                }
-
-                /* Put everyone back but the last entry. */
-                queued--;
-                for (i = 0; i < queued; i++)
-                {
-                  outb(saved_queue[i], QINFIFO + base);
-                }
-
-                outb(saved_queue[queued], SCBPTR + base);
-                tag = inb(SCB_TAG + base);
-                outscb = (p->scb_array[tag]);
+        	case BUS_8_BIT:
+        	  scratch &= 0x7F;
+        	  break;
+
+        	case BUS_16_BIT:
+                  if (aic7xxx_verbose)
+                  {
+        	    printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+  	  	         "bit transfers.\n", p->host_no, target, channel);
+                  }
+        	  scratch |= WIDEXFER;
+        	  break;
+
+        	case BUS_32_BIT:
+        	  outb(SEND_REJ, p->base + RETURN_1);
+                  /* No verbose here!  We want to see this condition. */
+        	  printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
+  			"requesting 32 bit transfers, rejecting...\n",
+                	 p->host_no, target, channel);
+        	  break;
+
+        	default:
+        	  break;
               }
-              scb->position = outscb->position;
-              outscb->position = SCB_LIST_NULL;
-              scbq_insert_head(&p->waiting_scbs, outscb);
-              outscb->state |= SCB_WAITINGQ;
-              aic7xxx_putscb(p, scb);
-              scb->state &= ~SCB_PAGED_OUT;
             }
             else
             {
-  	      printk(KERN_WARNING "scsi%d: Page-in request with no candidates "
-  	  	    "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-    		    p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-              aic7xxx_unbusy_target(scsi_id, channel, base);
-              outb(CLRSELTIMEO, CLRSINT1 + base);
-              outb(0, RETURN_1 + base);
+              /*
+               * Send our own WDTR in reply.
+               */
+              switch (bus_width)
+              {
+        	case BUS_8_BIT:
+        	  scratch &= 0x7F;
+        	  break;
+
+        	case BUS_32_BIT:
+        	case BUS_16_BIT:
+        	  if (p->bus_type == AIC_WIDE)
+        	  {
+                    printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+  			   "bit transfers.\n", p->host_no, target, channel);
+                    bus_width = BUS_16_BIT;
+                    scratch |= WIDEXFER;
+        	  }
+        	  else
+        	  {
+                    bus_width = BUS_8_BIT;
+                    scratch &= 0x7F;  /* XXX - FreeBSD doesn't do this. */
+        	  }
+        	  break;
+
+        	default:
+        	  break;
+              }
+              aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
+              outb(SEND_MSG, p->base + RETURN_1);
             }
-          }
-    	}
-    	else
-        {
-  	  printk(KERN_WARNING "scsi%d: No active SCB for reconnecting "
-  	  	"target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-    		p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-    	  aic7xxx_unbusy_target(scsi_id, channel, base);
-    	  outb(0, SCB_CONTROL + base);
-  	  outb(CLRSELTIMEO, CLRSINT1 + base);
-          outb(0, RETURN_1 + base);
-        }
-  	break;
-
-      case BAD_PHASE:
-	panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
-	break;
-
-      case SEND_REJECT:
-        rej_byte = inb(REJBYTE + base);
-        if ((rej_byte & 0xF0) == 0x20)
-        {
-          scb_index = inb(SCB_TAG + base);
-          scb = (p->scb_array[scb_index]);
-          printk(KERN_WARNING "scsi%d: Tagged message received without identify."
-                 "Disabling tagged commands for target %d channel %c.\n",
-                  p->host_no, scsi_id, channel);
-          scb->cmd->device->tagged_supported = 0;
-          scb->cmd->device->tagged_queue = 0;
-        }
-        else
-        {
-          printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received "
-                 "from target %d channel %c.\n",
-                 p->host_no, rej_byte, scsi_id, channel);
-        }
-	break;
-
-      case NO_IDENT:
-	panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY "
-	      "message. SAVED_TCL 0x%x.\n",
-              p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
-	break;
+            p->needwdtr &= ~target_mask;
+            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
+            outb(scratch, p->base + SCSIRATE);
+            break;
+	  }  /* case MSG_EXT_WDTR */
 
-      case SDTR_MSG:
-	/*
-	 * Help the sequencer to translate the negotiated
-	 * transfer rate. Transfer is 1/4 the period
-	 * in ns as is returned by the sync negotiation
-	 * message. So, we must multiply by four.
-	 */
-	transfer = (inb(ARG_1 + base) << 2);
-	offset = inb(ACCUM + base);
-	scratch = inb(TARG_SCRATCH + base + scratch_offset);
-	/*
-	 * The maximum offset for a wide device is 0x08; for a
-	 * 8-bit bus device the maximum offset is 0x0F.
-	 */
-	if (scratch & WIDEXFER)
-	{
-	  max_offset = 0x08;
-	}
-	else
-	{
-	  max_offset = 0x0F;
-	}
-	aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
-                         scsi_id, channel);
-	/*
-	 * Preserve the wide transfer flag.
-	 */
-	scratch = rate | (scratch & WIDEXFER);
-	outb(scratch, TARG_SCRATCH + base + scratch_offset);
-	outb(scratch, SCSIRATE + base);
-	if ((scratch & 0x0F) == 0)
-	{
-          /*
-           * One of two things happened.  Either the device requested
-           * asynchronous data transfers, or it requested a synchronous
-           * data transfer rate that was so low that asynchronous
-           * transfers are faster (not to mention the controller won't
-           * support them).  In both cases the synchronous data transfer
-           * rate and the offset are set to 0 indicating asynchronous
-           * transfers.
-           *
-           * If the device requested an asynchronous transfer, then
-           * accept the request.  If the device is being forced to
-           * asynchronous data transfers and this is the first time
-           * we've seen the request, accept the request.  If we've
-           * already seen the request, then attempt to force
-           * asynchronous data transfers by rejecting the message.
-           */
-          if ((offset == 0) || (p->sdtr_pending & target_mask))
-          {
+          default:
             /*
-             * Device requested asynchronous transfers or we're
-             * forcing asynchronous transfers for the first time.
+             * Unknown extended message - reject it.
              */
-            outb(0, RETURN_1 + base);
-          }
-          else
-          {
-            /*
-	     * The first time in forcing asynchronous transfers
-             * failed, so we try sending a reject message.
-	     */
-	    outb(SEND_REJ, RETURN_1 + base);
-          }
-	}
-	else
-	{
-	  /*
-	   * See if we initiated Sync Negotiation
-	   */
-	  if (p->sdtr_pending & target_mask)
-	  {
-	    /*
-	     * Don't send an SDTR back to the target.
-	     */
-	    outb(0, RETURN_1 + base);
-	  }
-	  else
-	  {
-	    /*
-	     * Send our own SDTR in reply.
-	     */
-	    printk("aic7xxx: Sending SDTR!!\n");
-	    outb(SEND_SDTR, RETURN_1 + base);
-	  }
-	}
-	/*
-	 * Clear the flags.
-	 */
-	p->needsdtr &= ~target_mask;
-	p->sdtr_pending &= ~target_mask;
-	break;
-
-      case WDTR_MSG:
-      {
-	bus_width = inb(ARG_1 + base);
-	printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c "
-	       "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr);
-	scratch = inb(TARG_SCRATCH + base + scratch_offset);
-
-	if (p->wdtr_pending & target_mask)
-	{
-	  /*
-	   * Don't send an WDTR back to the target, since we asked first.
-	   */
-	  outb(0, RETURN_1 + base);
-	  switch (bus_width)
-	  {
-	    case BUS_8_BIT:
-	      scratch &= 0x7F;
-	      break;
-
-	    case BUS_16_BIT:
-	      printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
-                     "transfers.\n", p->host_no, scsi_id, channel);
-	      scratch |= 0x80;
-	      break;
-
-	    case BUS_32_BIT:
-	      outb(SEND_REJ, RETURN_1 + base);
-	      printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
-                     "transfers, rejecting...\n", p->host_no, scsi_id, channel);
-	      break;
-	  }
-	}
-	else
-	{
-	  /*
-	   * Send our own WDTR in reply.
-	   */
-	  printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
-	  switch (bus_width)
-	  {
-	    case BUS_8_BIT:
-	      scratch &= 0x7F;
-	      break;
-
-	    case BUS_32_BIT:
-	      /*
-               * Negotiate 16 bits.
-               */
-	      bus_width = BUS_16_BIT;
-	      /* Yes, we mean to fall thru here. */
-
-	    case BUS_16_BIT:
-	      printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
-                     "transfers.\n", p->host_no, scsi_id, channel);
-	      scratch |= 0x80;
-	      break;
-	  }
-	  outb(bus_width | SEND_WDTR, RETURN_1 + base);
-	}
-	p->needwdtr &= ~target_mask;
-	p->wdtr_pending &= ~target_mask;
-	outb(scratch, TARG_SCRATCH + base + scratch_offset);
-	outb(scratch, SCSIRATE + base);
-	break;
-      }
+            outb(SEND_REJ, p->base + RETURN_1);
+            break;
+	}  /* switch (message_code) */
+      }  /* case EXTENDED_MSG */
+      break;
 
-      case REJECT_MSG:
+    case REJECT_MSG:
       {
 	/*
-	 * What we care about here is if we had an
-	 * outstanding SDTR or WDTR message for this
-	 * target. If we did, this is a signal that
-	 * the target is refusing negotiation.
+	 * What we care about here is if we had an outstanding SDTR
+	 * or WDTR message for this target. If we did, this is a
+	 * signal that the target is refusing negotiation.
 	 */
+	unsigned char targ_scratch;
+        unsigned char scb_index;
 
-	scratch = inb(TARG_SCRATCH + base + scratch_offset);
+        scb_index = inb(p->base + SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+	targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
 
-	if (p->wdtr_pending & target_mask)
+	if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
 	{
-	  /*
-	   * note 8bit xfers and clear flag
-	   */
-	  scratch &= 0x7F;
-	  p->needwdtr &= ~target_mask;
-	  p->wdtr_pending &= ~target_mask;
-	  printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
-                 "negotiation; using 8 bit transfers.\n",
-                 p->host_no, scsi_id, channel);
+          /*
+           * note 8bit xfers and clear flag
+           */
+          targ_scratch &= 0x7F;
+          p->needwdtr &= ~target_mask;
+          printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+  		 "negotiation; using 8 bit transfers.\n",
+  		 p->host_no, target, channel);
 	}
 	else
 	{
-	  if (p->sdtr_pending & target_mask)
-	  {
-	    /*
-	     * note asynch xfers and clear flag
-	     */
-	    scratch &= 0xF0;
-	    p->needsdtr &= ~target_mask;
-	    p->sdtr_pending &= ~target_mask;
-	    printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
-                   "synchronous negotiation; using asynchronous transfers.\n",
-                   p->host_no, scsi_id, channel);
-	  }
-	  /*
-	   * Otherwise, we ignore it.
-	   */
+          if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+          {
+            /*
+             * note asynch xfers and clear flag
+             */
+            targ_scratch &= 0xF0;
+            p->needsdtr &= ~target_mask;
+            printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
+  		   "synchronous negotiation; using asynchronous transfers.\n",
+  		   p->host_no, target, channel);
+          }
+          /*
+           * Otherwise, we ignore it.
+           */
 	}
-	outb(scratch, TARG_SCRATCH + base + scratch_offset);
-	outb(scratch, SCSIRATE + base);
-	break;
+        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+        outb(targ_scratch, p->base + SCSIRATE);
       }
+      break;
 
-      case BAD_STATUS:
-        /* The sequencer will notify us when a command has an error that
-         * would be of interest to the kernel.  This allows us to leave
-         * the sequencerrunning in the common case of command completes
-         * without error.
-         */
+    case BAD_STATUS:
+      {
+	unsigned char scb_index;
+	struct aic7xxx_hwscb *hscb;
+	Scsi_Cmnd *cmd;
+
+	/* The sequencer will notify us when a command has an error that
+	 * would be of interest to the kernel.  This allows us to leave
+	 * the sequencer running in the common case of command completes
+	 * without error.  The sequencer will have DMA'd the SCB back
+	 * up to us, so we can reference the drivers SCB array.
+	 */
+	scb_index = inb(p->base + SCB_TAG);
+	scb = p->scb_data->scb_array[scb_index];
+	hscb = scb->hscb;
 
-	scb_index = inb(SCB_TAG + base);
-	scb = (p->scb_array[scb_index]);
-	outb(0, RETURN_1 + base);   /* CHECK_CONDITION may change this */
-	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+	/*
+	 * Set the default return value to 0 indicating not to send
+	 * sense.  The sense code will change this if needed and this
+	 * reduces code duplication.
+	 */
+	outb(0, p->base + RETURN_1);
+	if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
-	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
-		 intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+          printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+        	 "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
+        	 intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
 	}
 	else
 	{
-	  cmd = scb->cmd;
-          scb->target_status = inb(SCB_TARGET_STATUS + base);
-	  aic7xxx_status(cmd) = scb->target_status;
+          cmd = scb->cmd;
+  	  hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+          aic7xxx_status(cmd) = hscb->target_status;
 
-	  cmd->result |= scb->target_status;
+          cmd->result |= hscb->target_status;
 
-	  switch (status_byte(scb->target_status))
-	  {
-	    case GOOD:
-              printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
-	      break;
-
-	    case CHECK_CONDITION:
-	      if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
-	      {
-                unsigned char tcl;
-		unsigned int  req_buf; /* must be 32 bits */
+          switch (status_byte(hscb->target_status))
+          {
+            case GOOD:
+  	      printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
+                     "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+              break;
 
-                tcl = scb->target_channel_lun;
+            case CHECK_CONDITION:
+              if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+              {
+        	unsigned int addr;    /* must be 32 bits */
+        	/*
+        	 * XXX - How do we save the residual (if there is one).
+        	 */
+                aic7xxx_calculate_residual(p, scb);
+
+        	/*
+  		 * Send a sense command to the requesting target.
+        	 * XXX - revisit this and get rid of the memcopys.
+  		 */
+        	memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+        	       sizeof(generic_sense));
+
+        	scb->sense_cmd[1] = (cmd->lun << 5);
+        	scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+        	scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
+        	scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+        	cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
 
-		/*
-                 * Send a sense command to the requesting target.
+                /*
+                 * XXX - We should allow disconnection, but can't as it
+                 * might allow overlapped tagged commands.
                  */
-		cmd->flags |= WAS_SENSE;
-		memcpy((void *) scb->sense_cmd, (void *) generic_sense,
-		       sizeof(generic_sense));
-
-		scb->sense_cmd[1] = (cmd->lun << 5);
-		scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
-		scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
-		scb->sg_list[0].length = sizeof(cmd->sense_buffer);
-		req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
-		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
-                scb->control = scb->control & DISCENB;
-		scb->target_channel_lun = tcl;
-		addr = VIRT_TO_BUS(scb->sense_cmd);
-		scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-		memcpy(scb->SCSI_cmd_pointer, &addr,
-		       sizeof(scb->SCSI_cmd_pointer));
-		scb->SG_segment_count = 1;
-		memcpy(scb->SG_list_pointer, &req_buf,
-		       sizeof(scb->SG_list_pointer));
-                scb->data_count = scb->sg_list[0].length;
-		memcpy(scb->data_pointer, &(scb->sg_list[0].address),
-		       sizeof(scb->data_pointer));
+  		/* hscb->control &= DISCENB; */
+                hscb->control = 0;
+        	hscb->target_status = 0;
+        	hscb->SG_segment_count = 1;
+
+        	addr = VIRT_TO_BUS(&scb->sg_list[0]);
+        	memcpy(&hscb->SG_list_pointer, &addr,
+        	       sizeof(hscb->SG_list_pointer));
+
+        	memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
+        	       sizeof(hscb->data_pointer));
+        	/* Maintain SCB_LINKED_NEXT */
+        	hscb->data_count &= 0xFF000000;
+  		hscb->data_count |= scb->sg_list[0].length;
+
+        	addr = VIRT_TO_BUS(scb->sense_cmd);
+        	memcpy(&hscb->SCSI_cmd_pointer, &addr,
+        	       sizeof(hscb->SCSI_cmd_pointer));
+        	hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
 
-                aic7xxx_putscb(p, scb);
+                scb->sg_count = hscb->SG_segment_count;
+        	scb->flags |= SCB_SENSE;
                 /*
-                 * Ensure that the target is "BUSY" so we don't get overlapping
-                 * commands if we happen to be doing tagged I/O.
+                 * Ensure the target is busy since this will be an
+                 * an untagged request.
                  */
-		aic7xxx_busy_target(scsi_id, channel, base);
+                aic7xxx_busy_target(p, target, channel, hscb->tag);
+        	outb(SEND_SENSE, p->base + RETURN_1);
+              }  /* first time sense, no errors */
+  	      else
+  	      {
+        	if (aic7xxx_error(cmd) == 0)
+  		{
+        	  aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+  		}
+  	      }
+              break;
 
-                aic7xxx_add_waiting_scb(base, scb);
-		outb(SEND_SENSE, RETURN_1 + base);
-	      }  /* first time sense, no errors */
-              else
+            case QUEUE_FULL:
+#ifdef NOT_YET
+              if (scb->hscb->control & TAG_ENB)
+              {
+        	if (cmd->device->queue_depth > 2)
+        	{
+                  cmd->device->queue_depth--;  /* Not correct */
+                  printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
+                	 "reduced to %d\n", p->host_no,
+                	 TC_OF_SCB(scb), cmd->device->queue_depth);
+        	}
+        	/*
+        	 * XXX - Requeue this unconditionally?
+        	 */
+
+        	/*
+        	 * We'd like to be able to give the SCB some more time
+        	 * (untimeout, then timeout).
+        	 */
+        	break;
+              }
+#endif
+              printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
+                     "queue depth %d, active %d\n", p->host_no,
+                     TC_OF_SCB(scb), cmd->device->queue_depth,
+                     p->device_status[TARGET_INDEX(cmd)].active_cmds);
+
+              /* Else treat this as if it was a BUSY condition. */
+              scb->hscb->target_status = (BUSY << 1) |
+                  (scb->hscb->target_status & 0x01);
+              /* Fall through to the BUSY case. */
+
+            case BUSY:
+              printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
+                     p->host_no, TC_OF_SCB(scb));
+              if (!aic7xxx_error(cmd))
               {
-                cmd->flags &= ~ASKED_FOR_SENSE;
-	        if (aic7xxx_error(cmd) == 0)
-                {
-		  aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-                }
+  		/*
+        	 * The mid-level SCSI code should be fixed to
+        	 * retry the command at a later time instead of
+        	 * trying right away.
+        	 */
+        	aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
               }
-	      break;
+              udelay(1000);  /*  A small pause (1ms) to help the drive */
+              break;
 
-	    case BUSY:
-	      printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
-                     p->host_no, scb->target_channel_lun);
-	      if (!aic7xxx_error(cmd))
-	      {
-                /* The error code here used to be DID_BUS_BUSY,
-                 * but after extensive testing, it has been determined
-                 * that a DID_BUS_BUSY return is a waste of time.  If
-                 * the problem is something that will go away, then it
-                 * will, if it isn't, then you don't want the endless
-                 * looping that you get with a DID_BUS_BUSY.  Better
-                 * to be on the safe side and specify an error condition
-                 * that will eventually lead to a reset or abort of some
-                 * sort instead of an endless loop.
-                 */
-	        aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-	      }
-	      break;
-
-	    case QUEUE_FULL:
-	      printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no);
-              scb->state |= SCB_ASSIGNEDQ;
-              scbq_insert_tail(&p->assigned_scbs, scb);
-	      break;
-
-	    default:
-	      printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n",
-		     p->host_no, scb->target_status);
-	      if (!aic7xxx_error(cmd))
-	      {
-		aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-	      }
-	      break;
-	  }  /* end switch */
+            default:
+              printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
+                     "status 0x%x.\n", p->host_no,
+        	     TC_OF_SCB(scb), scb->hscb->target_status);
+              if (!aic7xxx_error(cmd))
+              {
+        	aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+              }
+              break;
+          }  /* end switch */
 	}  /* end else of */
-	break;
+      }
+      break;
 
-      case RESIDUAL:
-	scb_index = inb(SCB_TAG + base);
-	scb = (p->scb_array[scb_index]);
-	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-	{
-	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
-		 intstat, scb_index, scb->state, (unsigned long) scb->cmd);
-	}
-	else
-	{
-	  cmd = scb->cmd;
-	  /*
-	   *  Don't destroy valid residual information with
-	   *  residual coming from a check sense operation.
-	   */
-	  if (!(cmd->flags & WAS_SENSE))
-	  {
-	    /*
-	     *  We had an 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 -= (inb(SCB_RESID_DCNT2 + base) << 16) |
-		      (inb(SCB_RESID_DCNT1 + base) <<  8) |
-		      inb(SCB_RESID_DCNT0 + base);
-
-	    if (actual < cmd->underflow)
-	    {
-	      printk(KERN_WARNING "scsi%d: Target %d underflow - "
-		     "Wanted at least %u, got %u, residual SG count %d.\n",
-		     p->host_no, cmd->target, cmd->underflow, actual,
-                     inb(SCB_RESID_SGCNT + base));
-	      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-	      aic7xxx_status(cmd) = scb->target_status;
-	    }
-	  }
-	}
-	break;
+    case AWAITING_MSG:
+      {
+	unsigned char scb_index;
+        unsigned char message_offset;
 
-      case ABORT_TAG:
-	scb_index = inb(SCB_TAG + base);
-	scb = (p->scb_array[scb_index]);
-	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-	{
-	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
-		 intstat, scb_index, scb->state, (unsigned long) scb->cmd);
-	}
-	else
-	{
-	  cmd = scb->cmd;
-	  /*
-	   * We didn't receive a valid tag back from the target
-	   * on a reconnect.
-	   */
-	  printk("scsi%d: Invalid tag received on target %d, channel %c, "
-                 "lun %d - Sending ABORT_TAG.\n", p->host_no,
-		  scsi_id, channel, cmd->lun & 0x07);
+	scb_index = inb(p->base + SCB_TAG);
+	scb = p->scb_data->scb_array[scb_index];
 
-	  cmd->result = (DID_RETRY_COMMAND << 16);
-          aic7xxx_done(p, scb);
-	}
-	break;
-
-      case AWAITING_MSG:
-	scb_index = inb(SCB_TAG + base);
-	scb = (p->scb_array[scb_index]);
-	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+	/*
+	 * This SCB had a MK_MESSAGE set in its control byte informing
+	 * the sequencer that we wanted to send a special message to
+	 * this target.
+	 */
+        message_offset = inb(p->base + MSG_LEN);
+	if (scb->flags & SCB_DEVICE_RESET)
 	{
-	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
-		 intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+          outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
+          outb(1, p->base + MSG_LEN);
+          printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
+        	 p->host_no, TC_OF_SCB(scb));
 	}
-	else
+        else if (scb->flags & SCB_ABORT)
+        {
+          if ((scb->hscb->control & TAG_ENB) != 0)
+          {
+            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+          }
+          else
+          {
+            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+          }
+          outb(message_offset + 1, p->base + MSG_LEN);
+          printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
+                 p->host_no, TC_OF_SCB(scb));
+        }
+	else if (scb->flags & SCB_MSGOUT_WDTR)
 	{
-	  /*
-	   * This SCB had a zero length command, informing the sequencer
-	   * that we wanted to send a special message to this target.
-	   * We only do this for BUS_DEVICE_RESET messages currently.
-	   */
-	   if (scb->state & SCB_DEVICE_RESET)
-	   {
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
-          scsi_id);
-#endif
-	     outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
-	     outb(1, MSG_LEN + base);
-	   }
-	   else
-	   {
-	     panic("scsi%d: AWAITING_SCB for an SCB that does "
-		   "not have a waiting message.\n", p->host_no);
-	   }
-	}
-	break;
-
-      case IMMEDDONE:
-        scb_index = inb(SCB_TAG + base);
-	scb = (p->scb_array[scb_index]);
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
-         scsi_id, scb_index, scb->state);
-#endif
-        if (scb->state & SCB_DEVICE_RESET)
+          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
         {
-          int found;
+          unsigned char target_scratch;
+          unsigned short ultra_enable;
+          int i, sxfr;
 
           /*
-           * Go back to async/narrow transfers and renegotiate.
+           * Pull the user defined setting from scratch RAM.
            */
-          aic7xxx_unbusy_target(scsi_id, channel, base);
-          p->needsdtr |= (p->needsdtr_copy & target_mask);
-          p->needwdtr |= (p->needwdtr_copy & target_mask);
-          p->sdtr_pending &= ~target_mask;
-          p->wdtr_pending &= ~target_mask;
-          scratch = inb(TARG_SCRATCH + base + scratch_offset);
-          scratch &= SXFR;
-          outb(scratch, TARG_SCRATCH + base + scratch_offset);
-          found = aic7xxx_reset_device(p, (int) scsi_id, channel);
-          printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs "
-                 "aborted.\n", p->host_no, found);
-          /* Indicate that we want to call aic7xxx_done_aborted_scbs() */
-          run_aborted_queue = TRUE;
+          target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+          sxfr = target_scratch & SXFR;
+          ultra_enable = inb(p->base + ULTRA_ENB) |
+              (inb(p->base + ULTRA_ENB + 1) << 8);
+          if (ultra_enable & target_mask)
+          {
+            sxfr |= 0x100;
+          }
+          for (i = 0; i < num_aic7xxx_syncrates; i++)
+          {
+            if (sxfr == aic7xxx_syncrates[i].rate)
+            break;
+          }
+          aic7xxx_construct_sdtr(p, message_offset,
+                                 aic7xxx_syncrates[i].period,
+                                 target_scratch & WIDEXFER ?
+                                 MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
         }
-        else
+        else 
         {
-          panic("scsi%d: Immediate complete for unknown operation.\n",
-                p->host_no);
-        }
-        break;
+          panic("aic7xxx: AWAITING_MSG for an SCB that does "
+                "not have a waiting message.");
+	}
+      }
+      break;
 
-      case DATA_OVERRUN:
+    case DATA_OVERRUN:
       {
-        unsigned int overrun;
-
-        scb = (p->scb_array[inb(base + SCB_TAG)]);
-        overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
-                  (inb(base + STCNT2) << 16);
-        overrun =0x00FFFFFF - overrun;
-        printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing "
-               "a retry.\n", p->host_no, overrun);
-        aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
-        break;
+	unsigned char scb_index = inb(p->base + SCB_TAG);
+        unsigned char lastphase = inb(p->base + LASTPHASE);
+	unsigned int i, overrun;
+
+	scb = (p->scb_data->scb_array[scb_index]);
+	overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
+  		  (inb(p->base + STCNT + 2) << 16);
+	overrun = 0x00FFFFFF - overrun;
+	printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
+               "in %s phase, tag %d; forcing a retry.\n",
+               p->host_no, TC_OF_SCB(scb), overrun,
+               lastphase == P_DATAIN ? "Data-In" : "Data-Out",
+               scb->hscb->tag);
+        printk(KERN_WARNING "%s seen Data Phase.  Length = %d, NumSGs = %d.\n",
+               inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+               aic7xxx_length(scb->cmd, 0), scb->sg_count);
+        for (i = 0; i < scb->sg_count; i++)
+        {
+          printk(KERN_INFO "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, scb->sg_list[i].address, scb->sg_list[i].length);
+        }
+	/*
+	 * XXX - What do we really want to do on an overrun?  The
+	 *       mid-level SCSI code should handle this, but for now,
+	 *       we'll just indicate that the command should retried.
+	 */
+	aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
       }
+      break;
 
-#if AIC7XXX_NOT_YET
-      /* XXX Fill these in later */
-      case MESG_BUFFER_BUSY:
-        break;
-      case MSGIN_PHASEMIS:
-        break;
-#endif
+/* #if AIC7XXX_NOT_YET */
+    /* XXX Fill these in later */
+    case MSG_BUFFER_BUSY:
+      printk("aic7xxx: Message buffer busy.\n");
+      break;
+    case MSGIN_PHASEMIS:
+      printk("aic7xxx: Message-in phasemis.\n");
+      break;
+/*#endif */
+
+    case ABORT_CMDCMPLT:
+      /* This interrupt serves to pause the sequencer until we can clean
+       * up the QOUTFIFO allowing us to handle any abort SCBs that may
+       * completed yet still have an SCB in the QINFIFO or waiting for
+       * selection queue.  By the time we get here, we should have
+       * already cleaned up the queues, so all we need to do is unpause
+       * the sequencer.
+       */
+      break;
+
+    default:		   /* unknown */
+      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, intstat, inb(p->base + SCSISIGI));
+      break;
+  }
+
+  /*
+   * Clear the sequencer interrupt and unpause the sequencer.
+   */
+  outb(CLRSEQINT, p->base + CLRINT);
+  unpause_sequencer(p, /* unpause always */ TRUE);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_scsiint
+ *
+ * Description:
+ *   Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  unsigned char scb_index;
+  unsigned char status;
+  struct aic7xxx_scb *scb;
+
+  scb_index = inb(p->base + SCB_TAG);
+  status = inb(p->base + SSTAT1);
 
-      default:               /* unknown */
-	printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-	       p->host_no, intstat, inb(SCSISIGI + base));
-	break;
+  if (scb_index < p->scb_data->numscbs)
+  {
+    scb = p->scb_data->scb_array[scb_index];
+    if ((scb->flags & SCB_ACTIVE) == 0)
+    {
+      scb = NULL;
     }
+  }
+  else
+  {
+    scb = NULL;
+  }
 
+  if ((status & SCSIRSTI) != 0)
+  {
+    char channel;
+
+    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+
+    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
+           p->host_no, channel);
     /*
-     * Clear the sequencer interrupt and unpause the sequencer.
+     * Go through and abort all commands for the channel, but do not
+     * reset the channel again.
      */
-    outb(CLRSEQINT, CLRINT + base);
-    UNPAUSE_SEQUENCER(p);
+    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    scb = NULL;
   }
-
-  if (intstat & SCSIINT)
+  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
   {
-    int status = inb(SSTAT1 + base);
-    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
-    channel = 'A';
-    if (inb(SBLKCTL + base) & SELBUSB)
-    {
-      channel = 'B';
+    /*
+     * First look at what phase we were last in.  If it's message-out,
+     * chances are pretty good that the bus free was in response to
+     * one of our abort requests.
+     */
+    unsigned char lastphase = inb(p->base + LASTPHASE);
+    unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
+    char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+    int printerror = TRUE;
+
+    outb(0, p->base + SCSISEQ);
+    if (lastphase == P_MESGOUT)
+    {
+      unsigned char sindex;
+      unsigned char message;
+
+      sindex = inb(p->base + SINDEX);
+      message = inb(p->base + sindex - 1);
+
+      if (message == MSG_ABORT)
+      {
+        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
+                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
+        aic7xxx_run_done_queue(p, /* complete */ TRUE);
+        scb = NULL;
+        printerror = 0;
+      }
+      else if (message == MSG_ABORT_TAG)
+      {
+        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
+                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
+        aic7xxx_run_done_queue(p, /* complete */ TRUE);
+        scb = NULL;
+        printerror = 0;
+      }
+      else if (message == MSG_BUS_DEV_RESET)
+      {
+        aic7xxx_handle_device_reset(p, target, channel);
+        scb = NULL;
+        printerror = 0;
+      }
     }
+    if (printerror != 0)
+    {
+      if (scb != NULL)
+      {
+        unsigned char tag;
+
+        if ((scb->hscb->control & TAG_ENB) != 0)
+        {
+          tag = scb->hscb->tag;
+        }
+        else
+        {
+          tag = SCB_LIST_NULL;
+        }
+        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+      }
+      else
+      {
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+      }
+      printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, lastphase,
+             (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+    }
+    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    outb(CLRBUSFREE, p->base + CLRSINT1);
+    outb(CLRSCSIINT, p->base + CLRINT);
+    restart_sequencer(p);
+  }
+  else if ((status & SELTO) != 0)
+  {
+    unsigned char scbptr;
+    unsigned char nextscb;
+    Scsi_Cmnd *cmd;
+
+    scbptr = inb(p->base + WAITING_SCBH);
+    outb(scbptr, p->base + SCBPTR);
+    scb_index = inb(p->base + SCB_TAG);
 
-    scb_index = inb(SCB_TAG + base);
-    scb = (p->scb_array[scb_index]);
-    if (status & SCSIRSTI)
+    scb = NULL;
+    if (scb_index < p->scb_data->numscbs)
     {
-      PAUSE_SEQUENCER(p);
-      printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-             p->host_no, channel);
-      /*
-       * Go through and abort all commands for the channel, but do not
-       * reset the channel again.
-       */
-      aic7xxx_reset_channel(p, channel, FALSE);
-      run_aborted_queue = TRUE;
+      scb = p->scb_data->scb_array[scb_index];
+      if ((scb->flags & SCB_ACTIVE) == 0)
+      {
+        scb = NULL;
+      }
     }
-    else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+    if (scb == NULL)
+    {
+      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, scb_index);
+      printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
+             "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
+             inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+             inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+    }
+    else
     {
-      printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no);
       /*
-       * Turn off the interrupt and set status to zero, so that it
-       * falls through the rest of the SCSIINT code.
+       * XXX - If we queued an abort tag, go clean up the disconnected list.
        */
-      outb(status, CLRSINT1 + base);
-      UNPAUSE_SEQUENCER(p);
-      outb(CLRSCSIINT, CLRINT + base);
+      cmd = scb->cmd;
+      cmd->result = (DID_TIME_OUT << 16);
+
+      /*
+       * Clear an pending messages for the timed out
+       * target and mark the target as free.
+       */
+      outb(0, p->base + MSG_LEN);
+      aic7xxx_index_busy_target(p, cmd->target,
+          cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
+      outb(0, p->base + SCB_CONTROL);
+
+      /*
+       * Shift the waiting for selection queue forward
+       */
+      nextscb = inb(p->base + SCB_NEXT);
+      outb(nextscb, p->base + WAITING_SCBH);
+
+      /*
+       * Put this SCB back on the free list.
+       */
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    /*
+     * Stop the selection.
+     */
+    outb(0, p->base + SCSISEQ);
+    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
+    outb(CLRSCSIINT, p->base + CLRINT);
+    restart_sequencer(p);
+  }
+  else if (scb == NULL)
+  {
+    printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+           "during scsiint 0x%x scb(%d)\n"
+           "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
+           p->host_no, status, scb_index, inb(p->base + SIMODE0),
+           inb(p->base + SIMODE1), inb(p->base + SSTAT0),
+           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+    /*
+     * Turn off the interrupt and set status to zero, so that it
+     * falls through the rest of the SCSIINT code.
+     */
+    outb(status, p->base + CLRSINT1);
+    outb(CLRSCSIINT, p->base + CLRINT);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  else if (status & SCSIPERR)
+  {
+    /*
+     * Determine the bus phase and queue an appropriate message.
+     */
+    char  *phase;
+    Scsi_Cmnd *cmd;
+    unsigned char mesg_out = MSG_NOOP;
+    unsigned char lastphase = inb(p->base + LASTPHASE);
+
+    cmd = scb->cmd;
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        phase = "Data-Out";
+        break;
+      case P_DATAIN:
+        phase = "Data-In";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_COMMAND:
+        phase = "Command";
+        break;
+      case P_MESGOUT:
+        phase = "Message-Out";
+        break;
+      case P_STATUS:
+        phase = "Status";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_MESGIN:
+        phase = "Message-In";
+        mesg_out = MSG_PARITY_ERROR;
+        break;
+      default:
+        phase = "unknown";
+        break;
+    }
+
+    /*
+     * A parity error has occurred during a data
+     * transfer phase. Flag it and continue.
+     */
+    printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
+           p->host_no, TC_OF_SCB(scb), phase);
+
+    /*
+     * We've set the hardware to assert ATN if we get a parity
+     * error on "in" phases, so all we need to do is stuff the
+     * message buffer with the appropriate message.  "In" phases
+     * have set mesg_out to something other than MSG_NOP.
+     */
+    if (mesg_out != MSG_NOOP)
+    {
+      outb(mesg_out, p->base + MSG_OUT);
+      outb(1, p->base + MSG_LEN);
       scb = NULL;
     }
-    else if (status & SCSIPERR)
+    else
     {
-      char  *phase;
-      unsigned char mesg_out = MSG_NOP;
-      unsigned char lastphase = inb(LASTPHASE + base);
+      /*
+       * Should we allow the target to make this decision for us?
+       */
+      cmd->result = DID_RETRY_COMMAND << 16;
+    }
+    outb(CLRSCSIPERR, p->base + CLRSINT1);
+    outb(CLRSCSIINT, p->base + CLRINT);
+    unpause_sequencer(p, /* unpause_always */ TRUE);
+  }
+  else
+  {
+    /*
+     * We don't know what's going on. Turn off the
+     * interrupt source and try to continue.
+     */
+    printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
+    outb(status, p->base + CLRSINT1);
+    outb(CLRSCSIINT, p->base + CLRINT);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  if (scb != NULL)
+  {
+    aic7xxx_done(p, scb);
+    aic7xxx_done_cmds_complete(p);
+  }
+}
 
-      cmd = scb->cmd;
-      switch (lastphase)
-      {
-        case P_DATAOUT:
-          phase = "Data-Out";
-          break;
-        case P_DATAIN:
-          phase = "Data-In";
-          mesg_out = MSG_INITIATOR_DET_ERROR;
-          break;
-        case P_COMMAND:
-          phase = "Command";
-          break;
-        case P_MESGOUT:
-          phase = "Message-Out";
-          break;
-        case P_STATUS:
-          phase = "Status";
-          mesg_out = MSG_INITIATOR_DET_ERROR;
-          break;
-        case P_MESGIN:
-          phase = "Message-In";
-          mesg_out = MSG_MSG_PARITY_ERROR;
-          break;
-        default:
-          phase = "unknown";
-          break;
-      }
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   SCSI controller interrupt handler.
+ *
+ *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ *         be disabled all through this function unless we say otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct aic7xxx_host *p;
+  unsigned char intstat;
+  unsigned long flags;
 
-      /*
-       * A parity error has occurred during a data
-       * transfer phase. Flag it and continue.
-       */
-      printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, "
-             "channel %d, lun %d.\n", p->host_no, phase,
-             cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
+  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
 
-      /*
-       * We've set the hardware to assert ATN if we get a parity
-       * error on "in" phases, so all we need to do is stuff the
-       * message buffer with the appropriate message. In phases
-       * have set mesg_out to something other than MSG_NOP.
-       */
-      if (mesg_out != MSG_NOP)
-      {
-        outb(mesg_out, MSG0 + base);
-        outb(1, MSG_LEN + base);
-        cmd->result = DID_PARITY << 16;
-      }
-      else
-      {
-        /*
-         * Should we allow the target to make this decision for us?
-         */
-        cmd->result = DID_RETRY_COMMAND << 16;
-      }
-      aic7xxx_done(p, scb);
+  /*
+   * Search for the host with a pending interrupt.  If we can't find
+   * one, then we've encountered a spurious interrupt.
+   */
+  while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
+  {
+    if (p->next == NULL)
+    {
+      p = NULL;
     }
-    else if (status & SELTO)
+    else
     {
-      unsigned char waiting;
+      p = (struct aic7xxx_host *) p->next->hostdata;
+    }
+  }
 
-      cmd = scb->cmd;
+  if (p == NULL)
+    return;
 
-      cmd->result = (DID_TIME_OUT << 16);
-      /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
-       */
-      ha_flags = inb(FLAGS + base);
-      outb(0, MSG_LEN + base);
-      aic7xxx_unbusy_target(scsi_id, channel, base);
-      /*
-       * Stop the selection.
-       */
-      outb(0, SCSISEQ + base);
-      outb(0, SCB_CONTROL + base);
-      outb(CLRSELTIMEO, CLRSINT1 + base);
-      outb(CLRSCSIINT, CLRINT + base);
+  /*
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
+   */
+  intstat = inb(p->base + INTSTAT);
 
-      /*
-       * Shift the waiting for selection queue forward
-       */
-      waiting = inb(WAITING_SCBH + base);
-      outb(waiting, SCBPTR + base);
-      waiting = inb(SCB_NEXT + base);
-      outb(waiting, WAITING_SCBH + base);
+  /*
+   * Keep track of interrupts for /proc/scsi
+   */
+  p->isr_count++;
 
-      RESTART_SEQUENCER(p);
-      aic7xxx_done(p, scb);
-    }
-    else if (!(status & BUSFREE))
+  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+  {
+    /*
+     * We must only have one card at this IRQ and it must have been
+     * added to the board data before the spurious interrupt occurred.
+     * It is sufficient that we check isr_count and not the spurious
+     * interrupt count.
+     */
+    printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
+    if (intstat)
     {
-      /*
-       * We don't know what's going on. Turn off the
-       * interrupt source and try to continue.
-       */
-      printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
-      outb(status, CLRSINT1 + base);
-      UNPAUSE_SEQUENCER(p);
-      outb(CLRSCSIINT, CLRINT + base);
+      /* Try clearing all interrupts. */
+      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
     }
+    return;
+  }
+
+  if (p->flags & IN_ISR)
+  {
+    printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
+           p->host_no);
+    return;
   }
 
-  if (run_aborted_queue)
-    aic7xxx_done_aborted_scbs(p);
+  /*
+   * Indicate that we're in the interrupt handler.
+   */
+  save_flags(flags);
+  cli();
+  p->flags |= IN_ISR;
 
   if (intstat & CMDCMPLT)
   {
-    int complete;
+    struct aic7xxx_scb *scb = NULL;
+    Scsi_Cmnd *cmd;
+    unsigned char qoutcnt;
+    unsigned char scb_index;
+    int i, interrupts_cleared = 0;
 
     /*
      * 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(QOUTFIFO + base);
+    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
-      scb = (p->scb_array[complete]);
-      if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
-      {
-	printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
-	       "       QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
-               "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
-               inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
-               scb->position);
-	outb(CLRCMDINT, CLRINT + base);
-	continue;
-      }
-      cmd = scb->cmd;
-      cmd->result |= (aic7xxx_error(cmd) << 16);
-      if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+#if 1
+  if (qoutcnt >= p->qfullcount - 1)
+    printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
+           "qoutcnt = %d.\n", qoutcnt);
+#endif
+    while (qoutcnt > 0)
+    {
+      for (i = 0; i < qoutcnt; i++)
       {
-        /*
-         * Got sense information.
-         */
-	cmd->flags &= ASKED_FOR_SENSE;
+        scb_index = inb(p->base + QOUTFIFO);
+        scb = p->scb_data->scb_array[scb_index];
+        if (scb == NULL)
+        {
+	  printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
+	         "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
+                 inb(p->base + QOUTCNT), inb(p->base + QINCNT));
+          continue;
+        }
+        else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+	  printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
+	         "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
+                 p->host_no, scb_index, inb(p->base + QOUTCNT),
+                 inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
+	  continue;
+        }
+        cmd = scb->cmd;
+        if (scb->hscb->residual_SG_segment_count != 0)
+        {
+          aic7xxx_calculate_residual(p, scb);
+        }
+        if ((scb->flags & SCB_QUEUED_ABORT) != 0)
+        {
+          /*
+           * Have to clean up any possible entries in the
+           * waiting queue and the QINFIFO.
+           */
+          int target;
+          char channel;
+          int lun;
+          unsigned char tag;
+
+          tag = SCB_LIST_NULL;
+          target = cmd->target;
+          lun = cmd->lun;
+          channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+          if (scb->hscb->control & TAG_ENB)
+          {
+            tag = scb->hscb->tag;
+          }
+          aic7xxx_reset_device(p, target, channel, lun, tag);
+          /*
+           * Run the done queue, but don't complete the commands; we
+           * do this once at the end of the loop.
+           */
+          aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+        }
+        cmd->result |= (aic7xxx_error(cmd) << 16);
+        p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
+        aic7xxx_done(p, scb);
       }
-      p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-
       /*
        * Clear interrupt status before checking the output queue again.
        * This eliminates a race condition whereby a command could
@@ -3243,56 +3941,152 @@
        * so notification of the command being complete never made it
        * back up to the kernel.
        */
-      outb(CLRCMDINT, CLRINT + base);
-      aic7xxx_done(p, scb);
+      outb(CLRCMDINT, p->base + CLRINT);
+      interrupts_cleared++;
+      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
+    }
 
-#ifdef AIC7XXX_PROC_STATS
-      /*
-       * XXX: we should actually know how much actually transferred
-       * XXX: for each command, but apparently that's too difficult.
-       */
-      actual = aic7xxx_length(cmd, 0);
-      if (!(cmd->flags & WAS_SENSE) && (actual > 0))
+    if (interrupts_cleared == 0)
+    {
+      outb(CLRCMDINT, p->base + CLRINT);
+    }
+
+    aic7xxx_done_cmds_complete(p);
+  }
+
+  if (intstat & BRKADRINT)
+  {
+    int i;
+    unsigned char errno = inb(p->base + ERROR);
+
+    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+    for (i = 0; i < NUMBER(hard_error); i++)
+    {
+      if (errno & hard_error[i].errno)
       {
-        struct aic7xxx_xferstats *sp;
-        long *ptr;
-        int x;
+        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
+      }
+    }
+    printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
+           inb(p->base + ERROR),
+           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+    aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
+    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  }
+
+  if (intstat & SEQINT)
+  {
+    aic7xxx_handle_seqint(p, intstat);
+  }
+
+  if (intstat & SCSIINT)
+  {
+    aic7xxx_handle_scsiint(p, intstat);
+  }
+
+  if (p->waiting_scbs.head != NULL)
+  {
+    aic7xxx_run_waiting_queues(p);
+  }
+
+  p->flags &= ~IN_ISR;
+  restore_flags(flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_device_queue_depth
+ *
+ * Description:
+ *   Determines the queue depth for a given device.  There are two ways
+ *   a queue depth can be obtained for a tagged queueing device.  One
+ *   way is the default queue depth which is determined by whether
+ *   AIC7XXX_CMDS_PER_LUN is defined.  If it is defined, then it is used
+ *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
+ *   default queue depth (dependent on the number of hardware SCBs).
+ *   The other way we determine queue depth is through the use of the
+ *   aic7xxx_tag_info array which is enabled by defining
+ *   AIC7XXX_TAGGED_QUEUEING_BY_DEVICE.  This array can be initialized
+ *   with queue depths for individual devices.  It also allows tagged
+ *   queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static void
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+  int default_depth = 2;
+
+  device->queue_depth = default_depth;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+  if (device->tagged_supported)
+  {
+    unsigned short target_mask;
+    int tag_enabled = TRUE;
 
-        sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
-        sp->xfers++;
+    target_mask = (1 << (device->id | (device->channel << 3)));
+
+#ifdef AIC7XXX_CMDS_PER_LUN
+    default_depth = AIC7XXX_CMDS_PER_LUN;
+#else
+    if (p->scb_data->maxhscbs <= 4)
+    {
+      default_depth = 4;  /* Not many SCBs to work with. */
+    }
+    else
+    {
+      default_depth = 8;
+    }
+#endif
+ 
+    if (!(p->discenable & target_mask))
+    {
+      printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+             "enable tagged queueing.\n",
+             p->host_no, device->id, device->channel);
+    }
+    else
+    {
+#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+      device->queue_depth = default_depth;
+#else
+      if (p->instance > NUMBER(aic7xxx_tag_info))
+      {
+        device->queue_depth = default_depth;
+      }
+      else
+      {
+        unsigned char  tindex;
 
-        if (cmd->request.cmd == WRITE)
+        tindex = device->id | (device->channel << 3);
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
         {
-          sp->w_total++;
-          sp->w_total512 += (actual >> 9);
-          ptr = sp->w_bins;
+          tag_enabled = FALSE;
+          device->queue_depth = 2;  /* Tagged queueing is disabled. */
         }
-        else
+        else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
-          sp->r_total++;
-          sp->r_total512 += (actual >> 9);
-          ptr = sp->r_bins;
+          device->queue_depth = default_depth;
         }
-        for (x = 9; x <= 17; x++)
+        else
         {
-          if (actual < (1 << x))
-          {
-            ptr[x - 9]++;
-            break;
-          }
+          device->queue_depth =
+            aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
-        if (x > 17)
+      }
+#endif
+      if ((device->tagged_queue == 0) && tag_enabled)
+      {
+        if (aic7xxx_verbose)
         {
-          ptr[x - 9]++;
+    	  printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
+    	         "queue depth %d.\n", p->host_no,
+    	         device->id, device->channel, device->queue_depth);
         }
+        device->tagged_queue = 1;
+        device->current_tag = SCB_LIST_NULL;
       }
-#endif /* AIC7XXX_PROC_STATS */
-
-    } while (inb(QOUTCNT + base) & p->qcntmask);
+    }
   }
-  aic7xxx_done_cmds_complete(p);
-  p->flags &= ~IN_ISR;
-  aic7xxx_run_waiting_queues(p);
+#endif
 }
 
 /*+F*************************************************************************
@@ -3307,59 +4101,18 @@
  *   algorithm for determining the queue depth based on the maximum
  *   SCBs for the controller.
  *-F*************************************************************************/
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host *host,
     Scsi_Device *scsi_devs)
 {
-  Scsi_Device *device = scsi_devs;
-  int tq_depth = 2;
+  Scsi_Device *device;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
 
-#ifdef AIC7XXX_CMDS_PER_LUN
-  tq_depth = AIC7XXX_CMDS_PER_LUN;
-#else
-  {
-    if (p->maxhscbs <= 4)
-    {
-      tq_depth = 4;  /* Not many SCBs to work with. */
-    }
-    else
-    {
-      tq_depth = 8;
-    }
-  }
-#endif
-
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
-      device->queue_depth = 2;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-      if (device->tagged_supported)
-      {
-        unsigned short target_mask = (1 << device->id) | device->channel;
-
-        if (!(p->discenable & target_mask))
-        {
-          printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
-                 "tagged queueing for target %d, channel %d, LUN %d.\n",
-                 host->host_no, device->id, device->channel, device->lun);
-        }
-        else
-        {
-          device->queue_depth = tq_depth;
-          if (device->tagged_queue == 0)
-          {
-            printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
-	           "channel %d, LUN %d, queue depth %d.\n", host->host_no,
-                   device->id, device->channel, device->lun,
-                   device->queue_depth);
-            device->tagged_queue = 1;
-            device->current_tag = SCB_LIST_NULL;
-          }
-        }
-      }
-#endif
+      aic7xxx_device_queue_depth(p, device);
     }
   }
 }
@@ -3386,7 +4139,7 @@
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
  *-F*************************************************************************/
-static aha_type
+static aha_chip_type
 aic7xxx_probe(int slot, int base, aha_status_type *bios)
 {
   int i;
@@ -3395,7 +4148,7 @@
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_type type;
+    aha_chip_type type;
     int bios_disabled;
   } AIC7xxx[] = {
     { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
@@ -3434,7 +4187,8 @@
 	return (AIC7xxx[i].type);
       }
 
-      printk("aic7xxx: Disabled at slot %d, ignored.\n", slot);
+      printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+             "disabled at slot %d, ignored.\n", slot);
     }
   }
 
@@ -3461,10 +4215,9 @@
  *   useful in that it gives us an 800 nsec timer.  After a read from the
  *   SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
  *   later.
- *
  *-F*************************************************************************/
 static int
-read_2840_seeprom(int base, struct seeprom_config *sc)
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
 {
   int i = 0, k = 0;
   unsigned char temp;
@@ -3477,11 +4230,11 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0)	\
+  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)	\
   {						\
     ;  /* Do nothing */				\
   }						\
-  (void) inb(SEECTL_2840 + base);
+  (void) inb(p->base + SEECTL_2840);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -3494,8 +4247,8 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
+    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
 
     /*
      * Now we're ready to send the read command followed by the
@@ -3504,11 +4257,11 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
     }
     /*
      * Send the 6 bit address (MSB first, LSB last).
@@ -3518,11 +4271,11 @@
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
     }
 
     /*
@@ -3534,12 +4287,12 @@
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
-      outb(temp, SEECTL_2840 + base);
-      CLOCK_PULSE(base);
+      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
+      outb(temp, p->base + SEECTL_2840);
+      CLOCK_PULSE(p);
     }
     /*
      * The serial EEPROM has a checksum in the last word.  Keep a
@@ -3555,12 +4308,12 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
-    outb(CK_2840, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
-    outb(0, SEECTL_2840 + base);
-    CLOCK_PULSE(base);
+    outb(0, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
+    outb(CK_2840, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
+    outb(0, p->base + SEECTL_2840);
+    CLOCK_PULSE(p);
   }
 
 #if 0
@@ -3589,6 +4342,53 @@
 
 /*+F*************************************************************************
  * Function:
+ *   acquire_seeprom
+ *
+ * Description:
+ *   Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+  int wait;
+
+  /*
+   * Request access of the memory port.  When access is
+   * granted, SEERDY will go high.  We use a 1 second
+   * timeout which should be near 1 second more than
+   * is needed.  Reason: after the 7870 chip reset, there
+   * should be no contention.
+   */
+  outb(SEEMS, p->base + SEECTL);
+  wait = 1000;  /* 1000 msec = 1 second */
+  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+  {
+    wait--;
+    udelay(1000);  /* 1 msec */
+  }
+  if ((inb(p->base + SEECTL) & SEERDY) == 0)
+  {
+    outb(0, p->base + SEECTL);
+    return (0);
+  }
+  return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   release_seeprom
+ *
+ * Description:
+ *   Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline void
+release_seeprom(struct aic7xxx_host *p)
+{
+  outb(0, p->base + SEECTL);
+}
+
+/*+F*************************************************************************
+ * Function:
  *   read_seeprom
  *
  * Description:
@@ -3626,7 +4426,7 @@
  *   first).  The clock cycling from low to high initiates the next data
  *   bit to be sent from the chip.
  *
- *   The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
+ *   The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
  *   register.  After successful arbitration for the memory port, the
  *   SEECS bit of the SEECTL register is connected to the chip select.
  *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
@@ -3636,17 +4436,14 @@
  *   to this is when we first request access to the memory port.  The
  *   SEERDY goes high to signify that access has been granted and, for
  *   this case, has no implied timing.
- *
  *-F*************************************************************************/
 static int
-read_seeprom(int base, int offset, struct seeprom_config *sc,
-    seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
+    unsigned int len, seeprom_chip_type chip)
 {
   int i = 0, k;
-  unsigned long timeout;
   unsigned char temp;
   unsigned short checksum = 0;
-  unsigned short *seeprom = (unsigned short *) sc;
   struct seeprom_cmd {
     unsigned char len;
     unsigned char bits[3];
@@ -3654,43 +4451,33 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(SEECTL + base) & SEERDY) == 0)	\
+  while ((inb(p->base + SEECTL) & SEERDY) == 0)	\
   {						\
     ;  /* Do nothing */				\
   }
 
   /*
-   * Request access of the memory port.  When access is
-   * granted, SEERDY will go high.  We use a 1 second
-   * timeout which should be near 1 second more than
-   * is needed.  Reason: after the 7870 chip reset, there
-   * should be no contention.
+   * Request access of the memory port.
    */
-  outb(SEEMS, SEECTL + base);
-  timeout = jiffies + 100;  /* 1 second timeout */
-  while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
+  if (acquire_seeprom(p) == 0)
   {
-    ; /* Do nothing!  Wait for access to be granted.  */
-  }
-  if ((inb(SEECTL + base) & SEERDY) == 0)
-  {
-    outb(0, SEECTL + base);
     return (0);
   }
 
   /*
-   * Read the first 32 registers of the seeprom.  For the 7870,
-   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
-   * but only the first 32 are used by Adaptec BIOS.  The loop
-   * will range from 0 to 31.
+   * Read 'len' registers of the seeprom.  For the 7870, the 93C46
+   * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+   * the first 32 are used by Adaptec BIOS.  Some adapters use the
+   * 93C56 SEEPROM which is a 2048-bit device.  The loop will range
+   * from 0 to 'len' - 1.
    */
-  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  for (k = 0; k < len; k++)
   {
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, SEECTL + base);
-    CLOCK_PULSE(base);
+    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+    CLOCK_PULSE(p);
 
     /*
      * Now we're ready to send the read command followed by the
@@ -3699,25 +4486,25 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
     }
     /*
-     * Send the 6 bit address (MSB first, LSB last).
+     * Send the 6 or 8 bit address (MSB first, LSB last).
      */
     for (i = ((int) chip - 1); i >= 0; i--)
     {
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
     }
 
     /*
@@ -3729,56 +4516,57 @@
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
-      outb(temp, SEECTL + base);
-      CLOCK_PULSE(base);
+      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
+      outb(temp, p->base + SEECTL);
+      CLOCK_PULSE(p);
     }
 
     /*
-     * The serial EEPROM has a checksum in the last word.  Keep a
-     * running checksum for all words read except for the last
-     * word.  We'll verify the checksum after all words have been
-     * read.
+     * The serial EEPROM should have a checksum in the last word.
+     * Keep a running checksum for all words read except for the
+     * last word.  We'll verify the checksum after all words have
+     * been read.
      */
-    if (k < (sizeof(*sc) / 2) - 1)
+    if (k < (len - 1))
     {
-      checksum = checksum + seeprom[k];
+      checksum = checksum + scarray[k];
     }
 
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, SEECTL + base);
-    CLOCK_PULSE(base);
-    outb(SEEMS | SEECK, SEECTL + base);
-    CLOCK_PULSE(base);
-    outb(SEEMS, SEECTL + base);
-    CLOCK_PULSE(base);
+    outb(SEEMS, p->base + SEECTL);
+    CLOCK_PULSE(p);
+    outb(SEEMS | SEECK, p->base + SEECTL);
+    CLOCK_PULSE(p);
+    outb(SEEMS, p->base + SEECTL);
+    CLOCK_PULSE(p);
   }
 
   /*
    * Release access to the memory port and the serial EEPROM.
    */
-  outb(0, SEECTL + base);
+  release_seeprom(p);
 
 #if 0
-  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+  printk("Computed checksum 0x%x, checksum read 0x%x\n",
+         checksum, scarray[len - 1]);
   printk("Serial EEPROM:");
-  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  for (k = 0; k < len; k++)
   {
     if (((k % 8) == 0) && (k != 0))
     {
       printk("\n              ");
     }
-    printk(" 0x%x", seeprom[k]);
+    printk(" 0x%x", scarray[k]);
   }
   printk("\n");
 #endif
 
-  if (checksum != sc->checksum)
+  if (checksum != scarray[len - 1])
   {
     return (0);
   }
@@ -3789,563 +4577,452 @@
 
 /*+F*************************************************************************
  * Function:
- *   detect_maxscb
+ *   write_brdctl
  *
  * Description:
- *   Detects the maximum number of SCBs for the controller and returns
- *   the count and a mask in config (config->maxscbs, config->qcntmask).
+ *   Writes a value to the BRDCTL register.
  *-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host_config *config)
+static inline void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
 {
-  unsigned char sblkctl_reg;
-  int base, i;
-
-#ifdef AIC7XXX_PAGE_ENABLE
-  config->flags |= PAGE_ENABLED;
-#endif
-  base = config->base;
-  switch (config->type)
-  {
-    case AIC_7770:
-    case AIC_7771:
-    case AIC_284x:
-      /*
-       * Check for Rev C or E boards. Rev E boards can supposedly have
-       * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
-       * It's still not clear extactly what is different about the Rev E
-       * boards, but we think it allows 8 bit entries in the QOUTFIFO to
-       * support "paging" SCBs (more than 4 commands can be active at once).
-       *
-       * The Rev E boards have a read/write autoflush bit in the
-       * SBLKCTL register, while in the Rev C boards it is read only.
-       */
-      sblkctl_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
-      outb(sblkctl_reg, SBLKCTL + base);
-      if (inb(SBLKCTL + base) == sblkctl_reg)
-      {
-        /*
-         * We detected a Rev E board, we allow paging on this board.
-         */
-        printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
-               board_names[config->type]);
-	outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
-      }
-      else
-      {
-        /* Do not allow paging. */
-        config->flags &= ~PAGE_ENABLED;
-        printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
-               board_names[config->type]);
-      }
-      break;
-
-    default:
-      break;
-  }
-
-  /*
-   * Walk the SCBs to determine how many there are.
-   */
-  i = 1;
-  outb(0, SCBPTR + base);
-  outb(0, SCBARRAY + base);
-
-  while (i < AIC7XXX_MAXSCB)
-  {
-    outb(i, SCBPTR + base);
-    outb(i, SCBARRAY + base);
-    if (inb(SCBARRAY + base) != i)
-      break;
-    outb(0, SCBPTR + base);
-    if (inb(SCBARRAY + base) != 0)
-      break;
-
-    outb(i, SCBPTR + base);      /* Clear the control byte. */
-    outb(0, SCBARRAY + base);
-
-    config->qcntmask |= i;       /* Update the count mask. */
-    i++;
-  }
-  outb(i, SCBPTR + base);   /* Ensure we clear the control bytes. */
-  outb(0, SCBARRAY + base);
-  outb(0, SCBPTR + base); 
-  outb(0, SCBARRAY + base);
-
-  config->maxhscbs = i;
-  config->qcntmask |= i;
-  if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB))
-  {
-    config->maxscbs = AIC7XXX_MAXSCB;
-  }
-  else
-  {
-    config->flags &= ~PAGE_ENABLED;  /* Disable paging if we have 255 SCBs!. */
-    config->maxscbs = config->maxhscbs;
-  }
-
-  printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs);
-  if (config->flags & PAGE_ENABLED)
-    printk(", %d page-enabled SCBs.\n", config->maxscbs);
-  else
-    printk(", paging not enabled.\n");
+  unsigned char brdctl;
 
+  brdctl = BRDCS | BRDSTB;
+  outb(brdctl, p->base + BRDCTL);
+  brdctl |= value;
+  outb(brdctl, p->base + BRDCTL);
+  brdctl &= ~BRDSTB;
+  outb(brdctl, p->base + BRDCTL);
+  brdctl &= ~BRDCS;
+  outb(brdctl, p->base + BRDCTL);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_register
+ *   read_brdctl
  *
  * Description:
- *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *   Reads the BRDCTL register.
  *-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template,
-    struct aic7xxx_host_config *config)
+static inline unsigned char
+read_brdctl(struct aic7xxx_host *p)
 {
-  int i;
-  unsigned char sblkctl, flags = 0;
-  int max_targets;
-  int found = 1;
-  unsigned int sram, base;
-  unsigned char target_settings;
-  unsigned char scsi_conf, host_conf;
-  unsigned short ultraenable = 0;
-  int have_seeprom = FALSE;
-  struct Scsi_Host *host;
-  struct aic7xxx_host *p;
-  struct seeprom_config sc;
-
-  base = config->base;
+  outb(BRDRW | BRDCS, p->base + BRDCTL);
+  return (inb(p->base + BRDCTL));
+}
 
-  /*
-   * Lock out other contenders for our i/o space.
-   */
-  request_region(base, MAXREG - MINREG, "aic7xxx");
+/*+F*************************************************************************
+ * Function:
+ *   configure_termination
+ *
+ * Description:
+ *   Configures the termination settings on PCI adapters that have
+ *   SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
+    unsigned short adapter_control, unsigned char max_targ)
+{
+  unsigned char brdctl_int, brdctl_ext;
+  int internal50_present;
+  int internal68_present = 0;
+  int external_present = 0;
+  int eprom_present;
+  int high_on;
+  int low_on;
+  int old_verbose;
+
+  if (acquire_seeprom(p))
+  {
+    if (adapter_control & CFAUTOTERM)
+    {
+      old_verbose = aic7xxx_verbose;
+      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
+                       "verify driver");
+      printk(KERN_INFO "         detected settings and use manual termination "
+                       "if necessary."); 
 
-  switch (config->type)
-  {
-    case AIC_7770:
-    case AIC_7771:
-      /*
-       * Use the boot-time option for the interrupt trigger type.  If not
-       * supplied (-1), then we use BIOS settings to determine the interrupt
-       * trigger type (level or edge) and use this value for pausing and
-       * unpausing the sequencer.
-       */
-      switch (aic7xxx_irq_trigger)
-      {
-        case  0: config->unpause = INTEN;          /* Edge */
-                 break;
-        case  1: config->unpause = IRQMS | INTEN;  /* Level */
-                 break;
-        case -1:
-        default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN; 
-                 break;
-      }
-      config->pause = config->unpause | PAUSE;
+      /* Configure auto termination. */
+      outb(SEECS | SEEMS, p->base + SEECTL);
 
       /*
-       * For some 274x boards, we must clear the CHIPRST bit and pause
-       * the sequencer. For some reason, this makes the driver work.
-       * For 284x boards, we give it a CHIPRST just like the 294x boards.
+       * First read the status of our cables.  Set the rom bank to
+       * 0 since the bank setting serves as a multiplexor for the
+       * cable detection logic.  BRDDAT5 controls the bank switch.
        */
-      outb(config->pause | CHIPRST, HCNTRL + base);
-      aic7xxx_delay(1);
-      if (inb(HCNTRL + base) & CHIPRST)
-      {
-	printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
-      }
-      outb(config->pause, HCNTRL + base);
+      write_brdctl(p, 0);
 
       /*
-       * Just to be on the safe side with the 274x, we will re-read the irq
-       * since there was some issue about resetting the board.
+       * Now read the state of the internal connectors.  The
+       * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
+       * set when cables are not present (BRDDAT6 is INT50 and
+       * BRDDAT7 is INT68).
        */
-      config->irq = inb(INTDEF + base) & 0x0F;
-      if ((config->type == AIC_7771) &&
-          (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
-      {
-        config->bios = AIC_DISABLED;
-        config->flags |= USE_DEFAULTS;
-      }
-      else
+      brdctl_int = read_brdctl(p);
+      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+      if (max_targ > 8)
       {
-        host_conf = inb(HOSTCONF + base);
-        config->bus_speed = host_conf & DFTHRSH;
-        config->busrtime = (host_conf << 2) & BOFF;
+        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
       }
 
       /*
-       * Setup the FIFO threshold and the bus off time
+       * Set the rom bank to 1 and determine
+       * the other signals.
        */
-      outb(config->bus_speed & DFTHRSH, BUSSPD + base);
-      outb(config->busrtime, BUSTIME + base);
+      write_brdctl(p, BRDDAT5);
 
       /*
-       * A reminder until this can be detected automatically.
+       * Now read the state of the external connectors.  BRDDAT6 is
+       * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
+       * set when the eprom is present.
        */
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-	     (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-      break;
-
-    case AIC_284x:
-      outb(CHIPRST, HCNTRL + base);
-      config->unpause = UNPAUSE_284X;
-      config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
-      aic7xxx_delay(1);
-      outb(config->pause, HCNTRL + base);
-
-      config->parity = AIC_ENABLED;
-      config->irq = inb(INTDEF + base) & 0x0F;
-      host_conf = inb(HOSTCONF + base);
-
-      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
-      have_seeprom = read_2840_seeprom(base, &sc);
-      if (!have_seeprom)
-      {
-	printk("aic7xxx: Unable to read SEEPROM.\n");
-      }
-      else
+      brdctl_ext = read_brdctl(p);
+      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
+      eprom_present = brdctl_ext & BRDDAT7;
+      if (aic7xxx_verbose)
       {
-	printk("done.\n");
-        config->flags |= HAVE_SEEPROM;
-        if (sc.bios_control & CF284XEXTEND)
-          config->flags |= EXTENDED_TRANSLATION;
-        if (!(sc.bios_control & CFBIOSEN))
+        if (max_targ > 8)
         {
-          /*
-           * The BIOS is disabled; the values left over in scratch
-           * RAM are still valid.  Do not use defaults as in the
-           * AIC-7770 case.
-           */
-          config->bios = AIC_DISABLED;
+          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+                 "Ext-68 %s)\n",
+                 internal50_present ? "YES" : "NO",
+                 internal68_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
         }
         else
         {
-	  config->parity = (sc.adapter_control & CFSPARITY) ?
-			   AIC_ENABLED : AIC_DISABLED;
-	  config->low_term = (sc.adapter_control & CF284XSTERM) ?
-			        AIC_ENABLED : AIC_DISABLED;
-	  /*
-	   * XXX - Adaptec *does* make 284x wide controllers, but the
-	   *       documents do not say where the high byte termination
-	   *       enable bit is located.
-           */
+          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+                 internal50_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
         }
+        printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
+               "brdctl_ext=0x%x\n",
+               eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
       }
 
-      host_conf = inb(HOSTCONF + base);
-      config->bus_speed = host_conf & DFTHRSH;
-      config->busrtime = (host_conf << 2) & BOFF;
-
-      /*
-       * Setup the FIFO threshold and the bus off time
-       */
-      outb(config->bus_speed & DFTHRSH, BUSSPD + base);
-      outb(config->busrtime, BUSTIME + base);
-
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-	     (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-      break;
-
-    case AIC_7860:
-    case AIC_7861:
-    case AIC_7880:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7883:
-    case AIC_7884:
-      /*
-       * Remember if Ultra was enabled in case there is no SEEPROM.
-       * Fall through to the rest of the AIC_78xx code.
-       */
-      if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
-        config->flags |= ULTRA_ENABLED;
-
-    case AIC_7850:
-    case AIC_7855:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7873:
-    case AIC_7874:
       /*
-       * Grab the SCSI ID before chip reset in case there is no SEEPROM.
+       * Now set the termination based on what we found.  BRDDAT6
+       * controls wide termination enable.
        */
-      config->scsi_id = inb(SCSIID + base) & OID;
-      outb(CHIPRST, HCNTRL + base);
-      config->unpause = UNPAUSE_294X;
-      config->pause = config->unpause | PAUSE;
-      aic7xxx_delay(1);
-      outb(config->pause, HCNTRL + base);
-
-      config->parity = AIC_ENABLED;
+      high_on = FALSE;
+      low_on = FALSE;
+      if ((max_targ > 8) &&
+          ((external_present == 0) || (internal68_present == 0)))
+      {
+        high_on = TRUE;
+      }
 
-      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
-      if ((config->type == AIC_7873) || (config->type == AIC_7883))
+      if ((internal50_present + internal68_present + external_present) <= 1)
       {
-        have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
-                                    &sc, c56_66);
+        low_on = TRUE;
       }
-      else
+          
+      if (internal50_present && internal68_present && external_present)
       {
-        have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
-                                    &sc, c46);
+        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
+               "         Only two connectors on the adapter may be "
+               "used at a time!\n");
       }
-      if (!have_seeprom)
+
+      if (high_on == TRUE)
+        write_brdctl(p, BRDDAT6);
+      else
+        write_brdctl(p, 0);
+
+      if (low_on == TRUE)
+        *sxfrctl1 |= STPWEN;
+
+      if (aic7xxx_verbose)
       {
-        for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
-        {
-          if (inb(sram) != 0x00)
-            break;
-        }
-        if (sram == base + TARG_SCRATCH)
-        {
-          for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
-          {
-            if (inb(sram) != 0xFF)
-              break;
-          }
-        }
-        if ((sram != base + 0x60) && (config->scsi_id != 0))
+        if (max_targ > 8)
         {
-          config->flags &= ~USE_DEFAULTS;
-	  printk("\naic7xxx: Unable to read SEEPROM; "
-                 "using leftover BIOS values.\n");
+          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+                 low_on ? "ON" : "OFF",
+                 high_on ? "ON" : "OFF");
         }
         else
         {
-          printk("\n");
-          printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default "
-                 "settings.\n");
-          config->flags |= USE_DEFAULTS;
-          config->flags &= ~ULTRA_ENABLED;
-          config->scsi_id = 7;
+          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
         }
-        scsi_conf = ENSPCHK | RESET_SCSI;
+      }
+      aic7xxx_verbose = old_verbose;
+    }
+    else
+    {
+      if (adapter_control & CFSTERM)
+      {
+        *sxfrctl1 |= STPWEN;
+      }
+      outb(SEEMS | SEECS, p->base + SEECTL);
+      /*
+       * Configure high byte termination.
+       */
+      if (adapter_control & CFWSTERM)
+      {
+        write_brdctl(p, BRDDAT6);
       }
       else
       {
-	printk("done.\n");
-        config->flags |= HAVE_SEEPROM;
-        if (!(sc.bios_control & CFBIOSEN))
-        {
-          /*
-           * The BIOS is disabled; the values left over in scratch
-           * RAM are still valid.  Do not use defaults as in the
-           * AIC-7770 case.
-           */
-          config->bios = AIC_DISABLED;
-          scsi_conf = ENSPCHK | RESET_SCSI;
-        }
-        else
-        {
-          scsi_conf = 0;
-          if (sc.adapter_control & CFRESETB)
-            scsi_conf |= RESET_SCSI;
-          if (sc.adapter_control & CFSPARITY)
-            scsi_conf |= ENSPCHK;
-	  if (sc.bios_control & CFEXTEND)
-            config->flags |= EXTENDED_TRANSLATION;
-	  config->scsi_id = (sc.brtime_id & CFSCSIID);
-	  config->parity = (sc.adapter_control & CFSPARITY) ?
-			     AIC_ENABLED : AIC_DISABLED;
-	  config->low_term = (sc.adapter_control & CFSTERM) ?
-			       AIC_ENABLED : AIC_DISABLED;
-	  config->high_term = (sc.adapter_control & CFWSTERM) ?
-			        AIC_ENABLED : AIC_DISABLED;
-	  config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
-          if (((config->type == AIC_7880) || (config->type == AIC_7881) ||
-               (config->type == AIC_7882) || (config->type == AIC_7883) ||
-               (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN))
-          {
-            printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
-                   "speed.\n");
-            config->flags |= ULTRA_ENABLED;
-          }
-        }
+        write_brdctl(p, 0);
+      }
+      if (aic7xxx_verbose)
+      {
+        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+               (adapter_control & CFSTERM) ? "ON" : "OFF",
+               (adapter_control & CFWSTERM) ? "ON" : "OFF");
       }
+    }
+    release_seeprom(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   detect_maxscb
+ *
+ * Description:
+ *   Detects the maximum number of SCBs for the controller and returns
+ *   the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+  int i;
+  unsigned char max_scbid = 255;
 
-      outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
-      config->bus_speed = DFTHRSH_100;
-      outb(config->bus_speed, DSPCISTATUS + base);
+  /*
+   * It's possible that we've already done this for multichannel
+   * adapters.
+   */
+  if (p->scb_data->maxhscbs == 0)
+  {
+    /*
+     * We haven't initialized the SCB settings yet.  Walk the SCBs to
+     * determince how many there are.
+     */
+    outb(0, p->base + FREE_SCBH);
 
-      /*
-       * In case we are a wide card...
-       */
-      outb(config->scsi_id, SCSICONF + base + 1);
+    for (i = 0; i < AIC7XXX_MAXSCB; i++)
+    {
+      outb(i, p->base + SCBPTR);
+      outb(i, p->base + SCB_CONTROL);
+      if (inb(p->base + SCB_CONTROL) != i)
+        break;
+      outb(0, p->base + SCBPTR);
+      if (inb(p->base + SCB_CONTROL) != 0)
+        break;
 
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-	     (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-      break;
+      outb(i, p->base + SCBPTR);
+      outb(0, p->base + SCB_CONTROL);   /* Clear the control byte. */
+      outb(i + 1, p->base + SCB_NEXT);  /* Set the next pointer. */
+      outb(SCB_LIST_NULL, p->base + SCB_TAG);  /* Make the tag invalid. */
 
-    default:
-      panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
+      /* Make the non-tagged targets not busy. */
+      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
+      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
+      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
+      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+    }
+
+    /* Make sure the last SCB terminates the free list. */
+    outb(i - 1, p->base + SCBPTR);
+    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+
+    /* Ensure we clear the first (0) SCBs control byte. */
+    outb(0, p->base + SCBPTR);
+    outb(0, p->base + SCB_CONTROL);
+
+    p->scb_data->maxhscbs = i;
   }
 
-  detect_maxscb(config);
+  if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
+  {
+    /* Determine the number of valid bits in the FIFOs. */
+    outb(max_scbid, p->base + QINFIFO);
+    max_scbid = inb(p->base + QINFIFO);
+    p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
+  }
+  else
+  {
+    p->scb_data->maxscbs = p->scb_data->maxhscbs;
+  }
+  if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
+  {
+    /*
+     * Disable paging if the QINFIFO doesn't allow more SCBs than
+     * we have in hardware.
+     */
+    p->flags &= ~PAGE_ENABLED;
+  }
 
-  if (config->chip_type == AIC_777x)
+  /*
+   * Set the Queue Full Count.  Some cards have more queue space than
+   * SCBs.
+   */
+  switch (p->chip_class)
   {
-    if (config->pause & IRQMS)
-    {
-      printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
-    }
-    else
-    {
-      printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
-    }
+    case AIC_777x:
+      p->qfullcount = 4;
+      p->qcntmask = 0x07;
+      break;
+    case AIC_785x:
+    case AIC_786x:
+      p->qfullcount = 8;
+      p->qcntmask = 0x0f;
+      break;
+    case AIC_787x:
+    case AIC_788x:
+      if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
+      {
+        p->qfullcount = AIC7XXX_MAXSCB;
+        p->qcntmask = 0xFF;
+      }
+      else
+      {
+        p->qfullcount = 16;
+        p->qcntmask = 0x1F;
+      }
+      break;
   }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_register
+ *
+ * Description:
+ *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+{
+  int i;
+  unsigned char sblkctl, flags = 0;
+  int max_targets;
+  int found = 1;
+  char channel_ids[] = {'A', 'B', 'C'};
+  unsigned char target_settings;
+  unsigned char scsi_conf, sxfrctl1;
+  unsigned short ultraenable = 0;
+  struct Scsi_Host *host;
+
+  /*
+   * Lock out other contenders for our i/o space.
+   */
+  request_region(p->base, MAXREG - MINREG, "aic7xxx");
 
   /*
    * Read the bus type from the SBLKCTL register. Set the FLAGS
    * register in the sequencer for twin and wide bus cards.
    */
-  sblkctl = inb(SBLKCTL + base);
-  if (config->flags & PAGE_ENABLED)
+  sblkctl = inb(p->base + SBLKCTL);
+  if (p->flags & PAGE_ENABLED)
     flags = PAGESCBS;
 
   switch (sblkctl & SELBUS_MASK)
   {
     case SELNARROW:     /* narrow/normal bus */
-      config->scsi_id = inb(SCSICONF + base) & 0x07;
-      config->bus_type = AIC_SINGLE;
-      outb(flags | SINGLE_BUS, FLAGS + base);
+      p->scsi_id = inb(p->base + SCSICONF) & 0x07;
+      p->bus_type = AIC_SINGLE;
+      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+      if (p->flags & MULTI_CHANNEL)
+      {
+        printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
+               channel_ids[p->chan_num], p->scsi_id);
+      }
+      else
+      {
+        printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
+                p->scsi_id);
+      }
+      outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
       break;
 
     case SELWIDE:     /* Wide bus */
-      config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
-      config->bus_type = AIC_WIDE;
-      printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
-	     board_names[config->type]);
-      outb(flags | WIDE_BUS, FLAGS + base);
-      break;
-
-    case SELBUSB:     /* Twin bus */
-      config->scsi_id = inb(SCSICONF + base) & 0x07;
-#ifdef AIC7XXX_TWIN_SUPPORT
-      config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
-      config->bus_type = AIC_TWIN;
-      printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
-	     board_names[config->type]);
-      outb(flags | TWIN_BUS, FLAGS + base);
-#else
-      config->bus_type = AIC_SINGLE;
-      printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
-	     board_names[config->type]);
-      outb(flags, FLAGS + base);
-#endif
+      p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
+      p->bus_type = AIC_WIDE;
+      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+      if (p->flags & MULTI_CHANNEL)
+      {
+        printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
+               channel_ids[p->chan_num], p->scsi_id);
+      }
+      else
+      {
+        printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
+                p->scsi_id);
+      }
+      outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
       break;
 
-    default:
-      printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
-	     "mail deang@teleport.com\n", inb(SBLKCTL + base));
-      outb(0, FLAGS + base);
-      return (0);
-  }
-
-  /*
-   * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
-   * take the card out of diagnostic mode and make the host adapter
-   * LED follow bus activity (will not always be on).
-   */
-  outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + 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?
-   *
-   * The PCI cards get their interrupt from PCI BIOS.
-   */
-  if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
-  {
-    printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
-          "ignoring.\n");
-    return (0);
+    case SELBUSB:     /* Twin bus */
+      p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
+      p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
+      p->bus_type = AIC_TWIN;
+      printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+             p->scsi_id, p->scsi_id_b);
+      outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
+      break;
+
+    default:
+      printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
+	     "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
+      outb(0, p->base + SEQ_FLAGS);
+      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.
-   */
-  debug_config(config);
-
-  /*
-   * 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.
+   * Detect SCB parameters and initialize the SCB array.
    */
-  host = scsi_register(template, sizeof(struct aic7xxx_host));
-  host->can_queue = config->maxscbs;
+  detect_maxscb(p);
+  printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
+         p->scb_data->maxhscbs, p->scb_data->maxscbs,
+         p->qfullcount, p->qcntmask);
+
+  host = p->host;
+
+  host->can_queue = p->scb_data->maxscbs;
   host->cmd_per_lun = 2;
+  host->sg_tablesize = AIC7XXX_MAX_SG;
   host->select_queue_depths = aic7xxx_select_queue_depth;
-  host->this_id = config->scsi_id;
-  host->io_port = config->base;
+  host->this_id = p->scsi_id;
+  host->io_port = p->base;
   host->n_io_port = 0xFF;
-  host->base = (unsigned char *)config->mbase;
-  host->irq = config->irq;
-  if (config->bus_type == AIC_WIDE)
+  host->base = (unsigned char *) p->mbase;
+  host->irq = p->irq;
+  if (p->bus_type == AIC_WIDE)
   {
     host->max_id = 16;
   }
-  if (config->bus_type == AIC_TWIN)
+  if (p->bus_type == AIC_TWIN)
   {
     host->max_channel = 1;
   }
 
-  p = (struct aic7xxx_host *) host->hostdata;
-
   p->host = host;
-  p->host_no = (int)host->host_no;
+  p->host_no = host->host_no;
   p->isr_count = 0;
-  p->base = base;
-  p->maxscbs = config->maxscbs;
-  p->maxhscbs = config->maxhscbs;
-  p->qcntmask = config->qcntmask;
-  p->mbase = (char *)config->mbase;
-  p->type = config->type;
-  p->chip_type = config->chip_type;
-  p->flags = config->flags;
-  p->chan_num = config->chan_num;
-  p->scb_link = &(p->scb_usage);
-#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
-  if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
-  {
-    shared_3985_scbs = &(p->scb_usage);
-    p->scb_link = &(p->scb_usage);
-  }
-#endif
-  p->scb_link->numscbs = 0;
-  p->bus_type = config->bus_type;
-  p->seeprom = sc;
   p->next = NULL;
   p->completeq.head = NULL;
   p->completeq.tail = NULL;
-  scbq_init(&p->scb_link->free_scbs);
-  scbq_init(&p->page_scbs);
+  scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
-  scbq_init(&p->assigned_scbs);
 
-  p->unpause = config->unpause;
-  p->pause = config->pause;
-
-  for (i = 0; i <= 15; i++)
+  for (i = 0; i <= NUMBER(p->device_status); i++)
   {
     p->device_status[i].commands_sent = 0;
     p->device_status[i].flags = 0;
+    p->device_status[i].active_cmds = 0;
     p->device_status[i].last_reset = 0;
   }
-  if (aic7xxx_boards[config->irq] == NULL)
+  if (aic7xxx_boards[p->irq] == NULL)
   {
+    int result;
+    int irq_flags = 0;
+
+#ifdef AIC7XXX_OLD_ISR_TYPE
+    irg_flags = SA_INTERRUPT;
+#endif
     /*
      * Warning! This must be done before requesting the irq.  It is
      * possible for some boards to raise an interrupt as soon as
@@ -4353,17 +5030,26 @@
      * kernel, an interrupt is triggered immediately.  Therefore, we
      * must ensure the board data is correctly set before the request.
      */
-    aic7xxx_boards[config->irq] = host;
+    aic7xxx_boards[p->irq] = host;
 
     /*
-     * Register IRQ with the kernel.
+     * Register IRQ with the kernel.  Only allow sharing IRQs with
+     * PCI devices.
      */
-    if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
-       "aic7xxx", NULL))
+    if (p->chip_class == AIC_777x)
+    {
+      result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+    }
+    else
+    {
+      result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
+                "aic7xxx", NULL));
+    }
+    if (result < 0)
     {
       printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-             config->irq);
-      aic7xxx_boards[config->irq] = NULL;
+             p->irq);
+      aic7xxx_boards[p->irq] = NULL;
       return (0);
     }
   }
@@ -4374,79 +5060,74 @@
      * registered host adapter. Add this host adapter's Scsi_Host
      * to the beginning of the linked list of hosts at the same IRQ.
      */
-    p->next = aic7xxx_boards[config->irq];
-    aic7xxx_boards[config->irq] = host;
-  }
-
-  /*
-   * 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 :-)
-   */
-  printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
-  aic7xxx_loadseq(base);
-
-  /*
-   * Set Fast Mode and Enable the board
-   */
-  outb(FASTMODE, SEQCTL + base);
-
-  if (p->chip_type == AIC_777x)
-  {
-    outb(ENABLE, BCTL + base);
+    p->next = aic7xxx_boards[p->irq];
+    aic7xxx_boards[p->irq] = host;
   }
 
-  printk("done.\n");
-
   /*
    * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
   if (p->bus_type == AIC_TWIN)
   {
     /*
-     * Select Channel B.
+     * The controller is gated to channel B after a chip reset; set
+     * bus B values first.
      */
-    outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
-
-    outb(config->scsi_id_b, SCSIID + base);
-    scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
-    outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
-    outb(ENSELTIMO, SIMODE1 + base);
-#endif
+    outb(p->scsi_id_b, p->base + SCSIID);
+    scsi_conf = inb(p->base + SCSICONF + 1);
+    sxfrctl1 = inb(p->base + SXFRCTL1);
+    outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
+         ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
     if (p->flags & ULTRA_ENABLED)
     {
-      outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
     }
     else
     {
-      outb(DFON | SPIOEN, SXFRCTL0 + base);
+      outb(DFON | SPIOEN, p->base + SXFRCTL0);
     }
 
-    /*
-     * Select Channel A
-     */
-    outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+    if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+    {
+      /* Reset SCSI bus B. */
+      if (aic7xxx_verbose)
+        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+
+      aic7xxx_reset_current_bus(p);
+    }
+
+    /* Select channel A */
+    outb(SELNARROW, p->base + SBLKCTL);
   }
-  outb(config->scsi_id, SCSIID + base);
-  scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
-  outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
-  outb(ENSELTIMO, SIMODE1 + base);
-#endif
+
+  outb(p->scsi_id, p->base + SCSIID);
+  scsi_conf = inb(p->base + SCSICONF);
+  sxfrctl1 = inb(p->base + SXFRCTL1);
+  outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
+       ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
   if (p->flags & ULTRA_ENABLED)
   {
-    outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
   }
   else
   {
-    outb(DFON | SPIOEN, SXFRCTL0 + base);
+    outb(DFON | SPIOEN, p->base + SXFRCTL0);
+  }
+
+  if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+  {
+    /* Reset SCSI bus A. */
+    if (aic7xxx_verbose)
+      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+
+    aic7xxx_reset_current_bus(p);
+
+    /*
+     * Delay for the reset delay.
+     */
+    aic7xxx_delay(AIC7XXX_RESET_DELAY);
   }
 
   /*
@@ -4473,67 +5154,47 @@
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (have_seeprom)
+  if (p->flags & USE_DEFAULTS)
   {
-    p->discenable = 0x0;
+    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
+           "device parameters.\n");
+    p->discenable = 0xFFFF;
   }
   else
   {
-    if (config->bios == AIC_DISABLED)
-    {
-      printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
-             "device parameters.\n");
-      p->discenable = 0xFFFF;
-    }
-    else
-    {
-      p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
-          inb(DISC_DSB + base));
-    }
+    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
+        inb(p->base + DISC_DSB));
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (config->flags & USE_DEFAULTS)
+    if (p->flags & USE_DEFAULTS)
     {
-      target_settings = 0;  /* 10 MHz */
+      target_settings = 0;  /* 10 or 20 MHz depending on Ultra enable */
       p->needsdtr_copy |= (0x01 << i);
       p->needwdtr_copy |= (0x01 << i);
+      if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+        ultraenable |= (0x01 << i);
     }
     else
     {
-      if (have_seeprom)
+      target_settings = inb(p->base + TARG_SCRATCH + i);
+      if (target_settings & 0x0F)
       {
-  	target_settings = ((sc.device_flags[i] & CFXFER) << 4);
-  	if (sc.device_flags[i] & CFSYNCH)
-  	{
-  	  p->needsdtr_copy |= (0x01 << i);
-  	}
-  	if (sc.device_flags[i] & CFWIDEB)
-  	{
-  	  p->needwdtr_copy |= (0x01 << i);
-  	}
-  	if (sc.device_flags[i] & CFDISC)
-        {
-          p->discenable |= (0x01 << i);
-        }
+        p->needsdtr_copy |= (0x01 << i);
+        /*
+         * Default to asynchronous transfers (0 offset)
+         */
+        target_settings &= 0xF0;
       }
-      else
+      if (target_settings & 0x80)
       {
-        target_settings = inb(TARG_SCRATCH + base + i);
-        if (target_settings & 0x0F)
-        {
-          p->needsdtr_copy |= (0x01 << i);
-          /*
-           * Default to asynchronous transfers (0 offset)
-           */
-          target_settings &= 0xF0;
-        }
-        if (target_settings & 0x80)
-        {
-          p->needwdtr_copy |= (0x01 << i);
-          target_settings &= 0x7F;
-        }
+        p->needwdtr_copy |= (0x01 << i);
+        /*
+         * Clear the wide flag. When wide negotiation is successful,
+         * we'll enable it.
+         */
+        target_settings &= 0x7F;
       }
       if (p->flags & ULTRA_ENABLED)
       {
@@ -4544,126 +5205,471 @@
           case 0x20:
             ultraenable |= (0x01 << i);
             break;
-          case 0x40:
+          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
             target_settings &= ~(0x70);
             break;
           default:
             break;
         }
       }
-    }
-    outb(target_settings, (TARG_SCRATCH + base + i));
+    }
+    outb(target_settings, p->base + TARG_SCRATCH + i);
+  }
+
+  /*
+   * If we are not wide, forget WDTR. This makes the driver
+   * work on some cards that don't leave these fields cleared
+   * when BIOS is not installed.
+   */
+  if (p->bus_type != AIC_WIDE)
+  {
+    p->needwdtr_copy = 0;
+  }
+  p->needsdtr = p->needsdtr_copy;
+  p->needwdtr = p->needwdtr_copy;
+  p->orderedtag = 0;
+  outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
+  outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
+
+  /*
+   * Set the number of available hardware SCBs.
+   */
+  outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
+
+  /*
+   * 2s compliment of maximum tag value.
+   */
+  i = p->scb_data->maxscbs;
+  outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
+
+  /*
+   * Allocate enough hardware scbs to handle the maximum number of
+   * concurrent transactions we can have.  We have to make sure that
+   * the allocated memory is contiguous memory.  The Linux kmalloc
+   * routine should only allocate contiguous memory, but note that
+   * this could be a problem if kmalloc() is changed.
+   */
+  if (p->scb_data->hscbs == NULL)
+  {
+    size_t array_size;
+    unsigned int hscb_physaddr;
+
+    array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+    p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
+    if (p->scb_data->hscbs == NULL)
+    {
+      printk("aic7xxx: Unable to allocate hardware SCB array; "
+             "failing detection.\n");
+      release_region(p->base, MAXREG - MINREG);
+      /*
+       * Ensure that we only free the IRQ when there is _not_ another
+       * aic7xxx adapter sharing this IRQ.  The adapters are always
+       * added to the beginning of the list, so we can grab the next
+       * pointer and place it back in the board array.
+       */
+      if (p->next == NULL)
+      {
+        free_irq(p->irq, aic7xxx_isr);
+      }
+      aic7xxx_boards[p->irq] = p->next;
+      return(0);
+    }
+    /* At least the control byte of each SCB needs to be 0. */
+    memset(p->scb_data->hscbs, 0, array_size);
+
+    /* Tell the sequencer where it can find the hardware SCB array. */
+    hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+    outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
+    outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
+    outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
+    outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
+  }
+
+  /*
+   * QCount mask to deal with broken aic7850s that sporadically get
+   * garbage in the upper bits of their QCNT registers.
+    */
+  outb(p->qcntmask, p->base + QCNTMASK);
+
+  /*
+   * We don't have any waiting selections or disconnected SCBs.
+   */
+  outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
+  outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+
+  /*
+   * Message out buffer starts empty
+   */
+  outb(0, p->base + MSG_LEN);
+
+  /*
+   * 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_loadseq(p);
+
+  if (p->chip_class == AIC_777x)
+  {
+    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
+  }
+
+  /*
+   * 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, /* unpause_always */ TRUE);
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_chip_reset
+ *
+ * Description:
+ *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
+ *   is paused upon return.
+ *-F*************************************************************************/
+static void
+aic7xxx_chip_reset(struct aic7xxx_host *p)
+{
+  unsigned char hcntrl;
+  int wait;
+
+  /* Retain the IRQ type across the chip reset. */
+  hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+
+  /*
+   * For some 274x boards, we must clear the CHIPRST bit and pause
+   * the sequencer. For some reason, this makes the driver work.
+   */
+  outb(PAUSE | CHIPRST, p->base + HCNTRL);
+
+  /*
+   * In the future, we may call this function as a last resort for
+   * error handling.  Let's be nice and not do any unecessary delays.
+   */
+  wait = 1000;  /* 1 second (1000 * 1000 usec) */
+  while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+  {
+    udelay(1000);  /* 1 msec = 1000 usec */
+    wait = wait - 1;
+  }
+
+  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+  {
+    printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
+  }
+
+  outb(hcntrl | PAUSE, p->base + HCNTRL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_alloc
+ *
+ * Description:
+ *   Allocate and initialize a host structure.  Returns NULL upon error
+ *   and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
+    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+{
+  struct aic7xxx_host *p = NULL;
+  struct Scsi_Host *host;
+
+  /*
+   * Allocate a storage area by registering us with the mid-level
+   * SCSI layer.
+   */
+  host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+  if (host != NULL)
+  {
+    p = (struct aic7xxx_host *) host->hostdata;
+    memset(p, 0, sizeof(struct aic7xxx_host));
+    p->host = host;
+
+    if (scb_data != NULL)
+    {
+      /*
+       * We are sharing SCB data areas; use the SCB data pointer
+       * provided.
+       */
+      p->scb_data = scb_data;
+      p->flags |= SHARED_SCBDATA;
+    }
+    else
+    {
+      /*
+       * We are not sharing SCB data; allocate one.
+       */
+      p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+      if (p->scb_data != NULL)
+      {
+        memset(p->scb_data, 0, sizeof(scb_data_type));
+        scbq_init (&p->scb_data->free_scbs);
+      }
+      else
+      {
+        /*
+         * For some reason we don't have enough memory.  Free the
+         * allocated memory for the aic7xxx_host struct, and return NULL.
+         */
+        scsi_unregister(host);
+        p = NULL;
+      }
+    }
+    if (p != NULL)
+    {
+      p->host_no = host->host_no;
+      p->base = base;
+      p->mbase = mbase;
+      p->maddr = NULL;
+      p->flags = flags;
+      p->chip_type = chip_type;
+      p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+      p->pause = p->unpause | PAUSE;
+    }
+  }
+  return (p);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free
+ *
+ * Description:
+ *   Frees and releases all resources associated with an instance of
+ *   the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free (struct aic7xxx_host *p)
+{
+  int i;
+
+  /*
+   * We should be careful in freeing the scb_data area.  For those
+   * adapters sharing external SCB RAM(398x), there will be only one
+   * scb_data area allocated.  The flag SHARED_SCBDATA indicates if
+   * one adapter is sharing anothers SCB RAM.
+   */
+  if (!(p->flags & SHARED_SCBDATA))
+  {
+    /*
+     * Free the allocated hardware SCB space.
+     */
+    if (p->scb_data->hscbs != NULL)
+    {
+      kfree(p->scb_data->hscbs);
+    }
+    /*
+     * Free the driver SCBs.  These were allocated on an as-need
+     * basis.
+     */
+    for (i = 0; i < p->scb_data->numscbs; i++)
+    {
+      kfree(p->scb_data->scb_array[i]);
+    }
+    /*
+     * Free the hardware SCBs.
+     */
+    if (p->scb_data->hscbs != NULL)
+    {
+      kfree(p->scb_data->hscbs);
+    }
+
+    /*
+     * Free the SCB data area.
+     */
+    kfree(p->scb_data);
+  }
+  /*
+   * Free the instance of the device structure.
+   */
+  scsi_unregister(p->host);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_load_seeprom
+ *
+ * Description:
+ *   Load the seeprom and configure adapter and target settings.
+ *   Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static int
+load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+  int have_seeprom = 0;
+  int i, max_targets;
+  unsigned char target_settings, scsi_conf;
+  unsigned short scarray[128];
+  struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+  if (aic7xxx_verbose)
+  {
+    printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+  }
+  switch (p->chip_type)
+  {
+    case AIC_7770:  /* None of these adapters have seeproms. */
+    case AIC_7771:
+    case AIC_7850:
+    case AIC_7855:
+      break;
+
+    case AIC_284x:
+      have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+      break;
+
+    case AIC_7861:
+    case AIC_7870:
+    case AIC_7871:
+    case AIC_7872:
+    case AIC_7874:
+    case AIC_7881:
+    case AIC_7882:
+    case AIC_7884:
+      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+                                  scarray, sizeof(*sc)/2, C46);
+      break;
+
+    case AIC_7860:  /* Motherboard Ultra controllers might have RAID port. */
+    case AIC_7880:
+      have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
+      if (!have_seeprom)
+      {
+        have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
+      }
+      break;
+
+    case AIC_7873:  /* The 3985 adapters use the 93c56 serial EEPROM. */
+    case AIC_7883:
+      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+                                  scarray, sizeof(scarray)/2, C56_66);
+      break;
+
+    default:
+      break;
   }
 
-  /*
-   * If we are not wide, forget WDTR. This makes the driver
-   * work on some cards that don't leave these fields cleared
-   * when BIOS is not installed.
-   */
-  if (p->bus_type != AIC_WIDE)
+  if (!have_seeprom)
   {
-    p->needwdtr_copy = 0;
+    if (aic7xxx_verbose)
+    {
+      printk("\naic7xxx: No SEEPROM available; using defaults.\n");
+    }
+    p->flags |= USE_DEFAULTS;
   }
-  p->needsdtr = p->needsdtr_copy;
-  p->needwdtr = p->needwdtr_copy;
-  p->orderedtag = 0;
-#if 0
-  printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
-  printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
-#endif
-  outb(ultraenable & 0xFF, ULTRA_ENB + base);
-  outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1);
+  else
+  {
+    if (aic7xxx_verbose)
+    {
+      printk("done\n");
+    }
+    p->flags |= HAVE_SEEPROM;
 
-  /*
-   * Set the number of available SCBs.
-   */
-  outb(config->maxhscbs, SCBCOUNT + base);
+    /*
+     * Update the settings in sxfrctl1 to match the termination settings.
+     */
+    *sxfrctl1 = 0;
 
-  /*
-   * 2s compliment of maximum tag value.
-   */
-  i = p->maxscbs;
-  outb(-i & 0xFF, COMP_SCBCOUNT + base);
+    /*
+     * First process the settings that are different between the VLB
+     * and PCI adapter seeproms.
+     */
+    if (p->chip_class == AIC_777x)
+    {
+      /* VLB adapter seeproms */
+      if (sc->bios_control & CF284XEXTEND)
+        p->flags |= EXTENDED_TRANSLATION;
 
-  /*
-   * Set the QCNT (queue count) mask to deal with broken aic7850s that
-   * sporatically get garbage in the upper bits of their QCNT registers.
-   */
-  outb(config->qcntmask, QCNTMASK + base);
+      if (sc->adapter_control & CF284XSTERM)
+        *sxfrctl1 |= STPWEN;
+      /*
+       * The 284x SEEPROM doesn't have a max targets field.  We
+       * set it to 16 to make sure we take care of the 284x-wide
+       * adapters.  For narrow adapters, going through the extra
+       * 8 target entries will not cause any harm since they will
+       * will not be used.
+       *
+       * XXX - We should probably break out the bus detection
+       *       from the register function so we can use it here
+       *       to tell us how many targets there really are.
+       */
+      max_targets = 16;
+    }
+    else
+    {
+      /* PCI adapter seeproms */
+      if (sc->bios_control & CFEXTEND)
+        p->flags |= EXTENDED_TRANSLATION;
 
-  /*
-   * Clear the active flags - no targets are busy.
-   */
-  outb(0, ACTIVE_A + base);
-  outb(0, ACTIVE_B + base);
+      if (sc->adapter_control & CFSTERM)
+        *sxfrctl1 |= STPWEN;
 
-  /*
-   * We don't have any waiting selections or disconnected SCBs.
-   */
-  outb(SCB_LIST_NULL, WAITING_SCBH + base);
-  outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
+      /* Limit to 16 targets just in case. */
+      max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
+    }
 
-  /*
-   * Message out buffer starts empty
-   */
-  outb(0, MSG_LEN + base);
+    for (i = 0; i < max_targets; i++)
+    {
+      target_settings = (sc->device_flags[i] & CFXFER) << 4;
+      if (sc->device_flags[i] & CFSYNCH)
+        target_settings |= SOFS;
+      if (sc->device_flags[i] & CFWIDEB)
+        target_settings |= WIDEXFER;
+      if (sc->device_flags[i] & CFDISC)
+        p->discenable |= (0x01 << i);
+      outb(target_settings, p->base + TARG_SCRATCH + i);
+    }
+    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
+    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
 
-  /*
-   * Reset the SCSI bus. Is this necessary?
-   *   There may be problems for a warm boot without resetting
-   *   the SCSI bus. Either BIOS settings in scratch RAM
-   *   will not get reinitialized, or devices may stay at
-   *   previous negotiated settings (SDTR and WDTR) while
-   *   the driver will think that no negotiations have been
-   *   performed.
-   *
-   * Some devices need a long time to "settle" after a SCSI
-   * bus reset.
-   */
-  if (!aic7xxx_no_reset)
-  {
-    printk("aic7xxx: Resetting the SCSI bus...");
-    if (p->bus_type == AIC_TWIN)
+    p->scsi_id = sc->brtime_id & CFSCSIID;
+
+    scsi_conf = (p->scsi_id & 0x7);
+    if (sc->adapter_control & CFSPARITY)
+      scsi_conf |= ENSPCHK;
+    if (sc->adapter_control & CFRESETB)
+      scsi_conf |= RESET_SCSI;
+
+    if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
     {
       /*
-       * Select Channel B.
+       * We allow the operator to override ultra enable through
+       * the boot prompt.
        */
-      outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
+      if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
+      {
+        /* Treat us as a non-ultra card */
+        p->flags &= ~ULTRA_ENABLED;
+      }
+    }
 
-      outb(SCSIRSTO, SCSISEQ + base);
-      udelay(1000);
-      outb(0, SCSISEQ + base);
-
-      /* Ensure we don't get a RSTI interrupt from this. */
-      outb(CLRSCSIRSTI, CLRSINT1 + base);
-      outb(CLRSCSIINT, CLRINT + base);
+    /* Set the host ID */
+    outb(scsi_conf, p->base + SCSICONF);
+    /* In case we are a wide card */
+    outb(p->scsi_id, p->base + SCSICONF + 1);
 
-     /*
-       * Select Channel A.
+    if (p->chip_class != AIC_777x)
+    {
+      /*
+       * Update the settings in sxfrctl1 to match the termination
+       * settings.
        */
-      outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+      *sxfrctl1 = 0;
+      configure_termination(p, sxfrctl1, sc->adapter_control,
+        (unsigned char) sc->max_targets & CFMAXTARG);
     }
-
-    outb(SCSIRSTO, SCSISEQ + base);
-    udelay(1000);
-    outb(0, SCSISEQ + base);
-
-    /* Ensure we don't get a RSTI interrupt from this. */
-    outb(CLRSCSIRSTI, CLRSINT1 + base);
-    outb(CLRSCSIINT, CLRINT + base);
-
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
-
-    printk("done.\n");
   }
-
-  /*
-   * 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 (found);
+  return (have_seeprom);
 }
 
 /*+F*************************************************************************
@@ -4672,17 +5678,24 @@
  *
  * Description:
  *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe().  A sequence of
+ *       probe(), attach()/detach(), and init() makes more sense than
+ *       one do-it-all function.  This may be useful when (and if) the
+ *       mid-level SCSI code is overhauled.
  *-F*************************************************************************/
 int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
-  int found = 0, slot, base;
-  unsigned char irq = 0;
+  int found = 0;
+  aha_status_type adapter_bios;
+  aha_chip_class_type chip_class;
+  aha_chip_type chip_type;
+  int slot, base;
+  int chan_num = 0;
+  unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
   int i;
-  struct aic7xxx_host_config config;
-
-  template->proc_dir = &proc_scsi_aic7xxx;
-  config.chan_num = 0;
+  struct aic7xxx_host *p;
 
   /*
    * Since we may allow sharing of IRQs, it is imperative
@@ -4696,6 +5709,10 @@
     aic7xxx_boards[i] = NULL;
   }
 
+  template->proc_dir = &proc_scsi_aic7xxx;
+  template->name = aic7xxx_info(NULL);
+  template->sg_tablesize = AIC7XXX_MAX_SG;
+
   /*
    * Initialize the spurious count to 0.
    */
@@ -4717,33 +5734,174 @@
       continue;
     }
 
-    config.type = aic7xxx_probe(slot, HID0 + base, &(config.bios));
-    if (config.type != AIC_NONE)
+    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
+    if (chip_type != AIC_NONE)
     {
+
+      switch (chip_type)
+      {
+        case AIC_7770:
+        case AIC_7771:
+          printk("aic7xxx: <%s> at EISA %d\n",
+                 board_names[chip_type], slot);
+          break;
+        case AIC_284x:
+          printk("aic7xxx: <%s> at VLB %d\n",
+                 board_names[chip_type], slot);
+          break;
+        default:
+          break;
+      }
+
       /*
        * We found a card, allow 1 spurious interrupt.
        */
       aic7xxx_spurious_count = 1;
 
       /*
-       * We "find" a AIC-7770 if we locate the card
-       * signature and we can set it up and register
-       * it with the kernel without incident.
+       * Pause the card preserving the IRQ type.  Allow the operator
+       * to override the IRQ trigger.
        */
-      config.chip_type = AIC_777x;
-      config.base = base;
-      config.mbase = 0;
-      config.irq = irq;
-      config.parity = AIC_ENABLED;
-      config.low_term = AIC_UNKNOWN;
-      config.high_term = AIC_UNKNOWN;
-      config.flags = 0;
-      if (aic7xxx_extended)
-        config.flags |= EXTENDED_TRANSLATION;
-      config.bus_speed = DFTHRSH_100;
-      config.busrtime = BOFF;
-      found += aic7xxx_register(template, &config);
+      if (aic7xxx_irq_trigger == 1)
+        hcntrl = IRQMS;  /* Level */
+      else if (aic7xxx_irq_trigger == 0)
+        hcntrl = 0;  /* Edge */
+      else
+        hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+      outb(hcntrl | PAUSE, base + HCNTRL);
+
+      irq = inb(INTDEF + base) & 0x0F;
+      switch (irq)
+      {
+        case 9:
+        case 10:
+        case 11:
+        case 12:
+        case 14:
+        case 15:
+          break;
+
+        default:
+          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level, ignoring.\n");
+          irq = 0;
+          break;
+      }
+
+      if (irq != 0)
+      {
+        p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
+        if (p == NULL)
+        {
+          printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+          continue;
+        }
+        p->irq = irq & 0x0F;
+        p->chip_class = AIC_777x;
+#ifdef AIC7XXX_PAGE_ENABLE
+        p->flags |= PAGE_ENABLED;
+#endif
+        p->instance = found;
+        if (aic7xxx_extended)
+        {
+          p->flags |= EXTENDED_TRANSLATION;
+        }
+        aic7xxx_chip_reset(p);
+
+        switch (p->chip_type)
+        {
+          case AIC_7770:
+          case AIC_7771:
+          {
+            unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
+
+            /*
+             * Get the primary channel information.  Right now we don't
+             * do anything with this, but someday we will be able to inform
+             * the mid-level SCSI code which channel is primary.
+             */
+            if (biosctrl & CHANNEL_B_PRIMARY)
+            {
+              p->flags |= FLAGS_CHANNEL_B_PRIMARY;
+            }
+
+            if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+            {
+              p->flags |= USE_DEFAULTS;
+            }
+            break;
+          }
 
+          case AIC_284x:
+            if (!load_seeprom(p, &sxfrctl1))
+            {
+              if (aic7xxx_verbose)
+                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+            }
+            break;
+
+          default:  /* Won't get here. */
+            break;
+        }
+        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
+               (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
+               (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+        /*
+         * Check for Rev C or E boards. Rev E boards can supposedly have
+         * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
+         * It's still not clear extactly what is different about the Rev E
+         * boards, but we think it allows 8 bit entries in the QOUTFIFO to
+         * support "paging" SCBs (more than 4 commands can be active at once).
+         *
+         * The Rev E boards have a read/write autoflush bit in the
+         * SBLKCTL register, while in the Rev C boards it is read only.
+         */
+        sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
+        outb(sblkctl, p->base + SBLKCTL);
+        if (inb(p->base + SBLKCTL) == sblkctl)
+        {
+          /*
+           * We detected a Rev E board, we allow paging on this board.
+           */
+          printk("Revision >= E\n");
+          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+        }
+        else
+        {
+          /* Do not allow paging. */
+          p->flags &= ~PAGE_ENABLED;
+          printk("Revision <= C\n");
+        }
+
+        if (aic7xxx_verbose)
+          printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+                 (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+        /*
+         * Set the FIFO threshold and the bus off time.
+         */
+        hostconf = inb(p->base + HOSTCONF);
+        outb(hostconf & DFTHRSH, p->base + BUSSPD);
+        outb((hostconf << 2) & BOFF, p->base + BUSTIME);
+
+        /*
+         * Try to initialize the card and register it with the kernel.
+         */
+        if (aic7xxx_register(template, p))
+        {
+          /*
+           * We successfully found a board and registered it.
+           */
+          found = found + 1;
+        }
+        else
+        {
+          /*
+           * Something went wrong; release and free all resources.
+           */
+          aic7xxx_free(p);
+        }
+      }
       /*
        * Disallow spurious interrupts.
        */
@@ -4759,15 +5917,15 @@
   {
     struct
     {
-      unsigned short vendor_id;
-      unsigned short device_id;
-      aha_type       card_type;
-      aha_chip_type  chip_type;
+      unsigned short      vendor_id;
+      unsigned short      device_id;
+      aha_chip_type       chip_type;
+      aha_chip_class_type chip_class;
     } const aic7xxx_pci_devices[] = {
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_785x},
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
@@ -4780,14 +5938,14 @@
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
     };
 
-    int error;
+    int error, flags;
     int done = 0;
     unsigned int iobase, mbase;
     unsigned short index = 0;
     unsigned char pci_bus, pci_device_fn;
-    unsigned int  csize_lattime;
-    unsigned int  class_revid;
-    unsigned int  devconfig;
+    unsigned char ultra_enb = 0;
+    unsigned int  devconfig, class_revid;
+    scb_data_type *shared_scb_data = NULL;
     char rev_id[] = {'B', 'C', 'D'};
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -4804,36 +5962,33 @@
         }
         else  /* Found an Adaptec PCI device. */
         {
-          config.type = aic7xxx_pci_devices[i].card_type;
-          config.chip_type = aic7xxx_pci_devices[i].chip_type;
-          config.chan_num = 0;
-          config.bios = AIC_ENABLED;  /* Assume bios is enabled. */
-          config.flags = 0;
-          config.busrtime = 40;
-          switch (config.type)
+          chip_class = aic7xxx_pci_devices[i].chip_class;
+          chip_type = aic7xxx_pci_devices[i].chip_type;
+          chan_num = 0;
+          flags = 0;
+          switch (aic7xxx_pci_devices[i].chip_type)
           {
             case AIC_7850:
             case AIC_7855:
-            case AIC_7860:
-            case AIC_7861:
-              config.bios = AIC_DISABLED;
-              config.flags |= USE_DEFAULTS;
-              config.bus_speed = DFTHRSH_100;
+              flags |= USE_DEFAULTS;
               break;
 
             case AIC_7872:  /* 3940 */
             case AIC_7882:  /* 3940-Ultra */
-              config.chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
+              flags |= MULTI_CHANNEL;
+              chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
               number_of_3940s++;
               break;
 
             case AIC_7873:  /* 3985 */
             case AIC_7883:  /* 3985-Ultra */
-              config.chan_num = number_of_3985s;  /* Has 3 controllers */
+              chan_num = number_of_3985s;  /* Has 3 controllers */
+              flags |= MULTI_CHANNEL;
               number_of_3985s++;
               if (number_of_3985s == 3)
               {
                 number_of_3985s = 0;
+                shared_scb_data = NULL;
               }
               break;
 
@@ -4850,39 +6005,165 @@
                                             PCI_INTERRUPT_LINE, &irq);
           error += pcibios_read_config_dword(pci_bus, pci_device_fn,
                                             PCI_BASE_ADDRESS_1, &mbase);
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             DEVCONFIG, &devconfig);
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             CLASS_PROGIF_REVID, &class_revid);
+
+          printk("aic7xxx: <%s> at PCI %d\n",
+                 board_names[chip_type], PCI_SLOT(pci_device_fn));
 
           /*
-           * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+           * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
            * we mask it off.
            */
           iobase &= PCI_BASE_ADDRESS_IO_MASK;
 
+          p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
+                            shared_scb_data);
+
+          if (p == NULL)
+          {
+            printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+            continue;
+          }
+
+          /* Remember to set the channel number, irq, and chip class. */
+          p->chan_num = chan_num;
+          p->irq = irq;
+          p->chip_class = chip_class;
+#ifdef AIC7XXX_PAGE_ENABLE
+          p->flags |= PAGE_ENABLED;
+#endif
+          p->instance = found;
+
           /*
-           * Read the PCI burst size and latency timer.
+           * Remember how the card was setup in case there is no seeprom.
            */
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CSIZE_LATTIME, &csize_lattime);
-          printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
-                 "PCLKS\n", (int) (csize_lattime & CACHESIZE),
-                 (csize_lattime >> 8) & 0x000000ff);
+          p->scsi_id = inb(p->base + SCSIID) & OID;
+          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+          {
+            p->flags |= ULTRA_ENABLED;
+            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+          }
+	  sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
 
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CLASS_PROGIF_REVID, &class_revid);
-          if ((class_revid & DEVREVID) < 3)
+          aic7xxx_chip_reset(p);
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
+          if (devconfig & RAMPSM)
+          {
+            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
+                   "access.\n");
+            /*
+             * XXX - Assume 9 bit SRAM and enable parity checking.
+             */
+            devconfig |= EXTSCBPEN;
+
+            /*
+             * XXX - Assume fast SRAM and only enable 2 cycle access if we
+             *       are sharing the SRAM across multiple adapters (398x).
+             */
+            if ((devconfig & MPORTMODE) == 0)
+            {
+              devconfig |= EXTSCBTIME;
+            }
+            devconfig &= ~SCBRAMSEL;
+            pcibios_write_config_dword(pci_bus, pci_device_fn,
+                                       DEVCONFIG, devconfig);
+          }
+#endif
+
+          if ((p->flags & USE_DEFAULTS) == 0)
           {
-            printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
-                   rev_id[class_revid & DEVREVID]);
+            load_seeprom(p, &sxfrctl1);
           }
 
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             DEVCONFIG, &devconfig);
-          if (error)
+          /*
+           * Take the LED out of diagnostic mode
+           */
+          sblkctl = inb(p->base + SBLKCTL);
+          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+
+          /*
+           * We don't know where this is set in the SEEPROM or by the
+           * BIOS, so we default to 100%.
+           */
+          outb(DFTHRSH_100, p->base + DSPCISTATUS);
+
+          if (p->flags & USE_DEFAULTS)
           {
-            panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
-                  error);
+            int j;
+            /*
+             * Default setup; should only be used if the adapter does
+             * not have a SEEPROM.
+             */
+            /*
+             * Check the target scratch area to see if someone set us
+             * up already.  We are previously set up if the scratch
+             * area contains something other than all zeroes and ones.
+             */
+            for (j = TARG_SCRATCH; j < 0x60; j++)
+            {
+              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
+                break;
+            }
+            if (j == TARG_SCRATCH)
+            {
+              for (j = TARG_SCRATCH; j < 0x60; j++)
+              {
+                if (inb(p->base + 1) != 0xFF)    /* Check for all ones. */
+                  break;
+              }
+            }
+            if ((j != 0x60) && (p->scsi_id != 0))
+            {
+              p->flags &= ~USE_DEFAULTS;
+              if (aic7xxx_verbose)
+              {
+                printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
+              }
+            }
+            else
+            {
+              if (aic7xxx_verbose)
+              {
+                printk(KERN_INFO "aic7xxx: No BIOS found; using default "
+                       "settings.\n");
+              }
+              /*
+               * Assume only one connector and always turn on
+               * termination.
+               */
+              sxfrctl1 = STPWEN;
+              p->scsi_id = 7;
+            }
+            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+                 p->base + SCSICONF);
+            /* In case we are a wide card. */
+            outb(p->scsi_id, p->base + SCSICONF + 1);
+            if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
+            {
+              /*
+               * If there wasn't a BIOS or the board wasn't in this mode
+               * to begin with, turn off Ultra.
+               */
+              p->flags &= ~ULTRA_ENABLED;
+            }
           }
 
-          printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
+          /*
+           * Print some additional information about the adapter.
+           */
+          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
+                 "IO Mem 0x%x, IRQ %d",
+                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
+                 p->base, p->mbase, p->irq);
+          if ((class_revid & DEVREVID) < 3)
+          {
+            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+          }
+          printk("\n");
 
           /*
            * I don't think we need to bother with allowing
@@ -4891,58 +6172,57 @@
            */
           aic7xxx_spurious_count = 1;
 
-          config.base = iobase;
-          config.mbase = mbase;
-          config.irq = irq;
-          config.parity = AIC_ENABLED;
-          config.low_term = AIC_UNKNOWN;
-          config.high_term = AIC_UNKNOWN;
           if (aic7xxx_extended)
-            config.flags |= EXTENDED_TRANSLATION;
-#ifdef AIC7XXX_SHARE_SCBs
-          if (devconfig & RAMPSM)
-#else
-          if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
-              (config.type != AIC_7883))
-#endif
+            p->flags |= EXTENDED_TRANSLATION;
+
+          if (aic7xxx_verbose)
+            printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+                   (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+          /*
+           * Put our termination setting into sxfrctl1 now that the
+           * generic initialization is complete.
+           */
+          sxfrctl1 |= inb(p->base + SXFRCTL1);
+          outb(sxfrctl1, p->base + SXFRCTL1);
+
+          if (aic7xxx_register(template, p) == 0)
+          {
+            aic7xxx_free(p);
+          }
+          else
           {
+            found = found + 1;
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
             /*
-             * External SRAM present.  The probe will walk the SCBs to see
-             * how much SRAM we have and set the number of SCBs accordingly.
-             * We have to turn off SCBRAMSEL to access the external SCB
-             * SRAM.
-             *
-             * It seems that early versions of the aic7870 didn't use these
-             * bits, hence the hack for the 3940 above.  I would guess that
-             * recent 3940s using later aic7870 or aic7880 chips do actually
-             * set RAMPSM.
+             * Set the shared SCB data once we've successfully probed a
+             * 398x adapter.
              *
-             * The documentation isn't clear, but it sounds like the value
-             * written to devconfig must not have RAMPSM set.  The second
-             * sixteen bits of the register are R/O anyway, so it shouldn't
-             * affect RAMPSM either way.
+             * Note that we can only do this if the use of external
+             * SCB RAM is enabled.
              */
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            devconfig &= ~(RAMPSM | SCBRAMSEL);
-            pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                       DEVCONFIG, devconfig);
+            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+            {
+              if (shared_scb_data == NULL)
+              {
+                shared_scb_data = p->scb_data;
+              }
+            }
+#endif
           }
-          found += aic7xxx_register(template, &config);
 
+          index++;
           /*
            * Disable spurious interrupts.
            */
           aic7xxx_spurious_count = 0;
-
-          index++;
         }  /* Found an Adaptec PCI device. */
       }
     }
   }
 #endif CONFIG_PCI
 
-  template->name = aic7xxx_info(NULL);
   return (found);
 }
 
@@ -4958,45 +6238,45 @@
 aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     struct aic7xxx_scb *scb)
 {
-  unsigned int addr; /* must be 32 bits */
   unsigned short mask;
+  struct aic7xxx_hwscb *hscb;
 
   mask = (0x01 << TARGET_INDEX(cmd));
+  hscb = scb->hscb;
+
   /*
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  if (cmd->device->tagged_queue)
+  if (p->discenable & mask)
   {
-    cmd->tag = scb->tag;
-    cmd->device->current_tag = scb->tag;
-    scb->control |= TAG_ENB;
-    p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-    if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200)
-    {
-      scb->control |= 0x02;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
-    }
-#if 0
-    if (p->orderedtag & mask)
+    hscb->control |= DISCENB;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+    if (cmd->device->tagged_queue)
     {
-      scb->control |= 0x02;
-      p->orderedtag = p->orderedtag & ~mask;
+      cmd->tag = hscb->tag;
+      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
+      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+      {
+        hscb->control |= MSG_SIMPLE_Q_TAG;
+      }
+      else
+      {
+        hscb->control |= MSG_ORDERED_Q_TAG;
+        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+      }
     }
-#endif
-  }
-#endif
-  if (p->discenable & mask)
-  {
-    scb->control |= DISCENB;
+#endif  /* Tagged queueing */
   }
+
   if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
   {
     p->wdtr_pending |= mask;
-    scb->control |= NEEDWDTR;
+    hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_MSGOUT_WDTR;
 #if 0
-    printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
+    printk("scsi%d: Sending WDTR request to target %d.\n",
+           p->host_no, cmd->target);
 #endif
   }
   else
@@ -5004,19 +6284,20 @@
     if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
     {
       p->sdtr_pending |= mask;
-      scb->control |= NEEDSDTR;
+      hscb->control |= MK_MESSAGE;
+      scb->flags |= SCB_MSGOUT_SDTR;
 #if 0
-      printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
+      printk("scsi%d: Sending SDTR request to target %d.\n",
+             p->host_no, cmd->target);
 #endif
     }
   }
-
 #if 0
   printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
          "mask(0x%x).\n",
 	 cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
 #endif
-  scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
 	((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
 
   /*
@@ -5030,9 +6311,8 @@
    * XXX - this relies on the host data being stored in a
    *       little-endian format.
    */
-  addr = VIRT_TO_BUS(cmd->cmnd);
-  scb->SCSI_cmd_length = cmd->cmd_len;
-  memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+  hscb->SCSI_cmd_length = cmd->cmd_len;
+  hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
 
   if (cmd->use_sg)
   {
@@ -5052,15 +6332,16 @@
       scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
       scb->sg_list[i].length = (unsigned int) sg[i].length;
     }
-    scb->SG_segment_count = cmd->use_sg;
-    addr = VIRT_TO_BUS(scb->sg_list);
-    memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
-    memcpy(scb->data_pointer, &(scb->sg_list[0].address),
-           sizeof(scb->data_pointer));
-    scb->data_count = scb->sg_list[0].length;
+    hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+    hscb->SG_segment_count = cmd->use_sg;
+    scb->sg_count = hscb->SG_segment_count;
+
+    /* Copy the first SG into the data pointer area. */
+    hscb->data_pointer = scb->sg_list[0].address;
+    hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
 #if 0
     printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
-           cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
+           cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
 #endif
   }
   else
@@ -5069,28 +6350,23 @@
   printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
 	(unsigned long) cmd->request_buffer, cmd->request_bufflen);
 #endif
-    if (cmd->request_bufflen == 0)
+    if (cmd->request_bufflen)
     {
-      /*
-       * In case the higher level SCSI code ever tries to send a zero
-       * length command, ensure the SCB indicates no data.  The driver
-       * will interpret a zero length command as a Bus Device Reset.
-       */
-      scb->SG_segment_count = 0;
-      memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
-      memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
-      scb->data_count = 0;
+      hscb->SG_segment_count = 1;
+      scb->sg_count = 1;
+      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+      scb->sg_list[0].length = cmd->request_bufflen;
+      hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
+      hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
+      hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
     }
     else
     {
-      scb->SG_segment_count = 1;
-      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
-      scb->sg_list[0].length = cmd->request_bufflen;
-      addr = VIRT_TO_BUS(&scb->sg_list[0]);
-      memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
-      scb->data_count = scb->sg_list[0].length;
-      addr = VIRT_TO_BUS(cmd->request_buffer);
-      memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
+      hscb->SG_segment_count = 0;
+      scb->sg_count = 0;
+      hscb->SG_list_pointer = 0;
+      hscb->data_pointer = 0;
+      hscb->data_count = SCB_LIST_NULL << 24;
     }
   }
 }
@@ -5108,7 +6384,6 @@
   long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
-  u_char curscb, intstat;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   if (p->host != cmd->host)
@@ -5140,34 +6415,21 @@
 	cmd->lun & 0x07);
 #endif
 
-  /*
-   * This is a critical section, since we don't want the interrupt
-   * routine mucking with the host data or the card.  For this reason
-   * it is nice to know that this function can only be called in one
-   * of two ways from scsi.c  First, as part of a routine queue command,
-   * in which case, the irq for our card is disabled before this
-   * function is called.  This doesn't help us if there is more than
-   * one card using more than one IRQ in our system, therefore, we
-   * should disable all interrupts on these grounds alone.  Second,
-   * this can be called as part of the scsi_done routine, in which case
-   * we are in the aic7xxx_isr routine already and interrupts are
-   * disabled, therefore we should saveflags first, then disable the
-   * interrupts, do our work, then restore the CPU flags. If it weren't
-   * for the possibility of more than one card using more than one IRQ
-   * in our system, we wouldn't have to touch the interrupt flags at all.
-   */
-  save_flags(processor_flags);
-  cli();
-
+  if (p->device_status[TARGET_INDEX(cmd)].active_cmds
+      > cmd->device->queue_depth)
+  {
+    printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
+           p->host_no, cmd->target, cmd->channel);
+  }
   scb = aic7xxx_allocate_scb(p);
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
+    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
   }
   else
   {
     scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->tag;
+    aic7xxx_position(cmd) = scb->hscb->tag;
 #if 0
     debug_scb(scb);
 #endif;
@@ -5179,14 +6441,14 @@
     aic7xxx_buildscb(p, cmd, scb);
 
 #if 0
-    if (scb != (p->scb_array[scb->position]))
+    if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
     {
       printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
              "address.\n");
     }
     printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
-	   scb->position, (unsigned int) scb->cmd,
-	   scb->state, (unsigned int) p->free_scb);
+	   scb->hscb->tag, (unsigned int) scb->cmd,
+	   scb->flags, (unsigned int) p->free_scb);
 #endif
 
     /*
@@ -5201,70 +6463,28 @@
     cmd->host_scribble = NULL;
     memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
 
-    if (scb->position != SCB_LIST_NULL)
-    {
-      /* We've got a valid slot, yeah! */
-      if (p->flags & IN_ISR)
-      {
-        scbq_insert_tail(&p->assigned_scbs, scb);
-        scb->state |= SCB_ASSIGNEDQ;
-      }
-      else
-      {
-        /*
-         * 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);
-        intstat = inb(INTSTAT + p->base);
-
-        /*
-         * 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.
-         */
-        curscb = inb(SCBPTR + p->base);
-        outb(scb->position, SCBPTR + p->base);
-        aic7xxx_putscb(p, scb);
-        outb(curscb, SCBPTR + p->base);
-        outb(scb->position, QINFIFO + p->base);
-        scb->state |= SCB_ACTIVE;
+    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-        /*
-         * Guard against unpausing the sequencer if there is an interrupt
-         * waiting to happen.
-         */
-        if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
-        {
-          UNPAUSE_SEQUENCER(p);
-        }
-      }
-    }
-    else
+    save_flags(processor_flags);
+    cli();
+    scbq_insert_tail(&p->waiting_scbs, scb);
+    if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
     {
-      scb->state |= SCB_WAITINGQ;
-      scbq_insert_tail(&p->waiting_scbs, scb);
-      if (!(p->flags & IN_ISR))
-      {
-        aic7xxx_run_waiting_queues(p);
-      }
+      aic7xxx_run_waiting_queues(p);
     }
 
+    restore_flags(processor_flags);
 #if 0
     printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
-           (long) cmd, (long) scb->cmd, scb->position);
+           (long) cmd, (long) scb->cmd, scb->hscb->tag);
 #endif;
-    restore_flags(processor_flags);
   }
   return (0);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_abort_reset
+ *   aic7xxx_bus_device_reset
  *
  * Description:
  *   Abort or reset the current SCSI command(s).  If the scb has not
@@ -5276,204 +6496,257 @@
 static int
 aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  struct aic7xxx_scb  *scb;
+  struct aic7xxx_scb   *scb;
+  struct aic7xxx_hwscb *hscb;
   unsigned char bus_state;
-  int base, result = -1;
+  int result = -1;
   char channel;
 
-  scb = (p->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  hscb = scb->hscb;
+
+  /*
+   * Ensure that the card doesn't do anything behind our back.
+   * Also make sure that we didn't just miss an interrupt that
+   * could affect this abort/reset.
+   */
+  pause_sequencer(p);
+  while (inb(p->base + INTSTAT) & INT_PEND);
+  {
+    aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
+    pause_sequencer(p);
+  } 
+  if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
+  {
+    result = SCSI_RESET_NOT_RUNNING;
+    unpause_sequencer(p, /* unpause_always */ TRUE);
+    return(result);
+  }
+
+
+  printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
+         p->host_no, TC_OF_SCB(scb), scb->flags);
+  bus_state = inb(p->base + LASTPHASE);
 
-  channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
-  if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
+  switch (bus_state)
   {
+    case P_DATAOUT:
+      printk("Data-Out phase, ");
+      break;
+    case P_DATAIN:
+      printk("Data-In phase, ");
+      break;
+    case P_COMMAND:
+      printk("Command phase, ");
+      break;
+    case P_MESGOUT:
+      printk("Message-Out phase, ");
+      break;
+    case P_STATUS:
+      printk("Status phase, ");
+      break;
+    case P_MESGIN:
+      printk("Message-In phase, ");
+      break;
+    default:
+      /*
+       * We're not in a valid phase, so assume we're idle.
+       */
+      printk("while idle, LASTPHASE = 0x%x, ", bus_state);
+      break;
+  }
+  printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
+         inb(p->base + SCSISIGI),
+         inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+         inb(p->base + SSTAT0), inb(p->base + SSTAT1));
 
-    if (scb->state & SCB_IN_PROGRESS)
+  channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
+  /*
+   * Determine our course of action.
+   */
+  if (scb->flags & SCB_ABORT)
+  {
+    /*
+     * Been down this road before; do a full bus reset.
+     */
+    scb->flags |= SCB_RECOVERY_SCB;
+    unpause_sequencer(p, /* unpause_always */ TRUE);
+    result = -1;
+  }
+#if 0
+  else if (hscb->control & TAG_ENB)
     {
       /*
-       * Ensure that the card doesn't do anything
-       * behind our back.
+       * We could be starving this command; try sending and ordered tag
+       * command to the target we come from.
        */
-      PAUSE_SEQUENCER(p);
+      scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
+      p->orderedtag = p->orderedtag | 0xFF;
+      result = SCSI_RESET_PENDING;
+      unpause_sequencer(p, /* unpause_always */ TRUE);
+      printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
+             p->host_no);
+    }
+#endif
+  else
+  {
+    unsigned char active_scb_index, saved_scbptr;
+    struct aic7xxx_scb *active_scb;
 
-      printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
-      bus_state = inb(LASTPHASE + p->base);
+    /*
+     * Send an Abort Message:
+     * The target that is holding up the bus may not be the same as
+     * the one that triggered this timeout (different commands have
+     * different timeout lengths).  Our strategy here is to queue an
+     * abort message to the timed out target if it is disconnected.
+     * Otherwise, if we have an active target we stuff the message buffer
+     * with an abort message and assert ATN in the hopes that the target
+     * will let go of the bus and go to the mesgout phase.  If this
+     * fails, we'll get another timeout a few seconds later which will
+     * attempt a bus reset.
+     */
+    saved_scbptr = inb(p->base + SCBPTR);
+    active_scb_index = inb(p->base + SCB_TAG);
+    active_scb = p->scb_data->scb_array[active_scb_index];
 
-      switch (bus_state)
+    if (bus_state != P_BUSFREE)
+    {
+      if (active_scb_index >= p->scb_data->numscbs)
       {
-	case P_DATAOUT:
-          printk("Data-Out phase, ");
-          break;
-	case P_DATAIN:
-          printk("Data-In phase, ");
-          break;
-	case P_COMMAND:
-          printk("Command phase, ");
-          break;
-	case P_MESGOUT:
-          printk("Message-Out phase, ");
-          break;
-	case P_STATUS:
-          printk("Status phase, ");
-          break;
-	case P_MESGIN:
-          printk("Message-In phase, ");
-          break;
-	default:
-          printk("while idle, LASTPHASE = 0x%x, ", bus_state);
-          /*
-           * We're not in a valid phase, so assume we're idle.
-           */
-          bus_state = 0;
-          break;
+        /*
+         * Perform a bus reset.
+         *
+         * XXX - We want to queue an abort for the timedout SCB
+         *       instead.
+         */
+        result = -1;
+        printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
+               "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
       }
-      printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
-
-      /*
-       * First, determine if we want to do a bus reset or simply a bus device
-       * reset.  If this is the first time that a transaction has timed out
-       * and the SCB is not paged out, just schedule a bus device reset.
-       * Otherwise, we reset the bus and abort all pending I/Os on that bus.
-       */
-      if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
+      else
       {
-#if 0
-	if (scb->control & TAG_ENB)
-	{
+        /* Send the abort message to the active SCB. */
+        outb(1, p->base + MSG_LEN);
+        if (active_scb->hscb->control & TAG_ENB)
+        {
+          outb(MSG_ABORT_TAG, p->base + MSG_OUT);
+        }
+        else
+        {
+          outb(MSG_ABORT, p->base + MSG_OUT);
+        }
+        outb(bus_state | ATNO, p->base + SCSISIGO);
+        printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
+               p->host_no);
+        active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
+        if (active_scb != scb)
+        {
           /*
-           * We could be starving this command; try sending and ordered tag
-           * command to the target we come from.
+           * XXX - We would like to increment the timeout on scb, but
+           *       access to that routine is denied because it is hidden
+           *       in scsi.c.  If we were able to do this, it would give
+           *       scb a new lease on life.
            */
-          scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG;
-          p->orderedtag = p->orderedtag | 0xFF;
           result = SCSI_RESET_PENDING;
-          UNPAUSE_SEQUENCER(p);
-          printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n");
-	}
-#endif
-	unsigned char active_scb, control;
-	struct aic7xxx_scb *active_scbp;
+          aic7xxx_error(active_scb->cmd) = DID_RESET;
+        }
+        else
+        {
+          aic7xxx_error(scb->cmd) = DID_RESET;
+          result = SCSI_RESET_PENDING;
+        }
+        unpause_sequencer(p, /* unpause_always */ TRUE);
+      }
+    }
+    else
+    {
+      unsigned char hscb_index, linked_next;
+      int disconnected;
 
-	/*
-	 * Send a Bus Device Reset Message:
-	 * The target we select to send the message to may be entirely
-	 * different than the target pointed to by the scb that timed
-	 * out.  If the command is in the QINFIFO or the waiting for
-	 * selection list, its not tying up the bus and isn't responsible
-	 * for the delay so we pick off the active command which should
-	 * be the SCB selected by SCBPTR.  If its disconnected or active,
-	 * we device reset the target scbp points to.  Although it may
-	 * be that this target is not responsible for the delay, it may
-	 * may also be that we're timing out on a command that just takes
-	 * too much time, so we try the bus device reset there first.
-	 */
-	active_scb = inb(SCBPTR + base);
-	active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
-	control = inb(SCB_CONTROL + base);
+      disconnected = FALSE;
+      hscb_index = aic7xxx_find_scb(p, scb);
+      if (hscb_index == SCB_LIST_NULL)
+      {
+        disconnected = TRUE;
+        linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+      }
+      else
+      {
+        outb(hscb_index, p->base + SCBPTR);
+        if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+        {
+          disconnected = TRUE;
+        }
+        linked_next = inb(p->base + SCB_LINKED_NEXT);
+      }
+      if (disconnected)
+      {
+        /*
+         * Simply set the ABORT_SCB control bit and preserve the
+         * linked next pointer.
+         */
+        scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+        scb->hscb->data_count &= ~0xFF000000;
+        scb->hscb->data_count |= linked_next << 24;
+        if ((p->flags & PAGE_ENABLED) == 0)
+        {
+          scb->hscb->control &= ~DISCONNECTED;
+        }
+        scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+        if (hscb_index != SCB_LIST_NULL)
+        {
+          unsigned char scb_control;
 
-	/*
-	 * Test to see if scbp is disconnected
-	 */
-	outb(scb->position, SCBPTR + base);
-	if (inb(SCB_CONTROL + base) & DISCONNECTED)
-	{
-#ifdef AIC7XXX_DEBUG_ABORT
-          printk("aic7xxx: (abort_scb) scb %d is disconnected; "
-                 "bus device reset message queued.\n", scb->position);
-#endif
-          if (p->flags & PAGE_ENABLED)
-          {
-            /* Pull this SCB out of the disconnected list. */
-            u_char prev = inb(SCB_PREV + base);
-            u_char next = inb(SCB_NEXT + base);
-            if (prev == SCB_LIST_NULL)
-            {
-              /* Head of list */
-              outb(next, DISCONNECTED_SCBH + base);
-            }
-            else
-            {
-              outb(prev, SCBPTR + base);
-              outb(next, SCB_NEXT + base);
-              if (next != SCB_LIST_NULL)
-              {
-        	outb(next, SCBPTR + base);
-        	outb(prev, SCB_PREV + base);
-              }
-              outb(scb->position, SCBPTR + base);
-            }
-          }
-	  scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
-          scb->control = scb->control & DISCENB;
-          scb->SCSI_cmd_length = 0;
-	  scb->SG_segment_count = 0;
-	  memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
-	  memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
-	  scb->data_count = 0;
-	  aic7xxx_putscb(p, scb);
-	  aic7xxx_add_waiting_scb(base, scb);
-	  outb(active_scb, SCBPTR + base);
-          result = SCSI_RESET_PENDING;
-	  UNPAUSE_SEQUENCER(p);
-	}
-	else
-	{
-	  /*
-	   * Is the active SCB really active?
-	   */
-	  if ((active_scbp->state & SCB_ACTIVE) && bus_state)
-	  {
-            /*
-             * Load the message buffer and assert attention.
-             */
-            active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
-            outb(1, MSG_LEN + base);
-            outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
-            outb(bus_state | ATNO, SCSISIGO + base);
-#ifdef AIC7XXX_DEBUG_ABORT
-            printk("aic7xxx: (abort_scb) asserted ATN - "
-                   "bus device reset in message buffer.\n");
-#endif
-            if (active_scbp != scb)
-            {
-              /*
-               * XXX - We would like to increment the timeout on scb, but
-               *       access to that routine is denied because it is hidden
-               *       in scsi.c.  If we were able to do this, it would give
-               *       scb a new lease on life.
-               */
-              ;
-            }
-            aic7xxx_error(scb->cmd) = DID_RESET;
-            /*
-             * Restore the active SCB and unpause the sequencer.
-             */
-            outb(active_scb, SCBPTR + base);
-            if (active_scbp != scb)
-            {
-              /*
-               * The mid-level SCSI code requested us to reset a command
-               * different from the one that we actually reset.  Return
-               * a "not running" indication and hope that the SCSI code
-               * will Do the Right Thing (tm).
-               */
-              result = SCSI_RESET_NOT_RUNNING;
-            }
-            else
-            {
-              result = SCSI_RESET_PENDING;
-            }
-            UNPAUSE_SEQUENCER(p);
-	  }
-	}
+          scb_control = inb(p->base + SCB_CONTROL);
+          outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+        }
+        /*
+         * Actually requeue this SCB in case we can select the
+         * device before it reconnects.  If the transaction we
+         * want to abort is not tagged, unbusy it first so that
+         * we don't get held back from sending the command.
+         */
+        if ((scb->hscb->control & TAG_ENB) == 0)
+        {
+          unsigned char target;
+          int lun;
+
+          target = scb->cmd->target;
+          lun = scb->cmd->lun;
+          aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
+              0, /* requeue */ TRUE);
+        }
+        printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
+               p->host_no, TC_OF_SCB(scb));
+        scbq_insert_head(&p->waiting_scbs, scb);
+        scb->flags |= SCB_WAITINGQ;
+        outb(saved_scbptr, p->base + SCBPTR);
+        if ((p->flags & IN_ISR) == 0)
+        {
+          /*
+           * Processing the waiting queue may unpause us.
+           */
+          aic7xxx_run_waiting_queues(p);
+          /*
+           * If we are using AAP, aic7xxx_run_waiting_queues() will not
+           * unpause us, so ensure we are unpaused.
+           */
+          unpause_sequencer(p, /*unpause_always*/ FALSE);
+        }
+        else
+        {
+          unpause_sequencer(p, /*unpause_always*/ TRUE);
+        }
+        result = SCSI_RESET_PENDING;
+      }
+      else
+      {
+        scb->flags |= SCB_RECOVERY_SCB;
+        unpause_sequencer(p, /* unpause_always */ TRUE);
+        result = -1;
       }
     }
   }
-  /* Make sure the sequencer is unpaused upon return. */
-  if (result == -1)
-  {
-    UNPAUSE_SEQUENCER(p);
-  }
   return (result);
 }
 
@@ -5491,16 +6764,48 @@
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
   int    base, result;
+  unsigned long processor_flags;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_array[aic7xxx_position(cmd)]);
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
 
+  save_flags(processor_flags);
+  cli();
+
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
-         scb->position, TCL_OF_SCB(scb));
+  if (scb != NULL)
+  {
+    printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  }
+  else
+  {
+    printk("aic7xxx: Abort called with no SCB for cmd.\n");
+  }
 #endif
 
+  if (p->flags & IN_TIMEOUT)
+  {
+    /*
+     * We've already started a recovery operation.
+     */
+    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+    {
+      restore_flags(processor_flags);
+      return (SCSI_ABORT_PENDING);
+    }
+    else
+    {
+      /*
+       * This is the second time we've tried to abort the recovery
+       * SCB.  We want the mid-level SCSI code to call the reset
+       * function to reset the SCSI bus.
+       */
+      restore_flags(processor_flags);
+      return (SCSI_ABORT_NOT_RUNNING);
+    }
+  }
   if (cmd->serial_number != cmd->serial_number_at_timeout)
   {
     result = SCSI_ABORT_NOT_RUNNING;
@@ -5509,14 +6814,34 @@
   {
     result = SCSI_ABORT_NOT_RUNNING;
   }
-  else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
+  else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
   {
     result = SCSI_ABORT_NOT_RUNNING;
   }
   else
   {
-    result = SCSI_ABORT_SNOOZE;
+    /*
+     * XXX - Check use of IN_TIMEOUT to see if we're Doing the
+     *       Right Thing with it.
+     */
+    p->flags |= IN_TIMEOUT;
+    result = aic7xxx_bus_device_reset(p, scb->cmd);
+    switch (result)
+    {
+      case SCSI_RESET_NOT_RUNNING:
+        p->flags &= ~IN_TIMEOUT;
+        result = SCSI_ABORT_NOT_RUNNING;
+        break;
+      case SCSI_RESET_PENDING:
+        result = SCSI_ABORT_PENDING;
+        break;
+      default:
+        p->flags &= ~IN_TIMEOUT;
+        result = SCSI_ABORT_SNOOZE;
+        break;
+     }
   }
+  restore_flags(processor_flags);
   return (result);
 }
 
@@ -5536,18 +6861,27 @@
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
-  int    base, found, tindex, min_target, max_target, result = -1;
+  int    base, found, tindex, min_target, max_target;
+  int    result = -1;
   char   channel = 'A';
   unsigned long processor_flags;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_array[aic7xxx_position(cmd)]);
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
   channel = cmd->channel ? 'B': 'A';
   tindex = (cmd->channel << 4) | cmd->target;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
+#ifdef 0   /* AIC7XXX_DEBUG_ABORT */
+  if (scb != NULL)
+  {
+    printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
+           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  }
+  else
+  {
+    printk("aic7xxx: Reset called with no SCB for cmd.\n");
+  }
 #endif
 
   /* 
@@ -5562,34 +6896,45 @@
   if (scb->cmd != cmd)
     scb = NULL;
 
-  if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET)) 
-      && (scb != NULL))
+  if (p->flags & IN_TIMEOUT)
   {
     /*
-     * Attempt a bus device reset if commands have completed successfully
-     * since the last bus device reset, or it has been less than 100ms
-     * since the last reset.
+     * We've already started a recovery operation.
      */
-    if ((p->flags & DEVICE_SUCCESS) ||
-        ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
     {
-      if (cmd->serial_number != cmd->serial_number_at_timeout)
-      {
-        result = SCSI_RESET_NOT_RUNNING;
-      }
-      else
+      restore_flags(processor_flags);
+      return (SCSI_RESET_PENDING);
+    }
+  }
+  else
+  {
+    if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
+        && (scb != NULL))
+    {
+      /*
+       * Attempt a bus device reset if commands have completed successfully
+       * since the last bus device reset, or it has been less than 100ms
+       * since the last reset.
+       */
+      if ((p->flags & DEVICE_SUCCESS) ||
+          ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
       {
-        if (scb == NULL)
+	if (cmd->serial_number != cmd->serial_number_at_timeout)
+	{
+          result = SCSI_RESET_NOT_RUNNING;
+	}
+	else if (scb == NULL)
         {
           result = SCSI_RESET_NOT_RUNNING;
         }
         else if (flags & SCSI_RESET_ASYNCHRONOUS)
         {
-          if (scb->state & SCB_ABORTED)
+          if (scb->flags & SCB_ABORTED)
           {
             result = SCSI_RESET_PENDING;
           }
-          else if (!(scb->state & SCB_IN_PROGRESS))
+          else if (!(scb->flags & SCB_ACTIVE))
           {
             result = SCSI_RESET_NOT_RUNNING;
           }
@@ -5600,20 +6945,23 @@
           if ((flags & SCSI_RESET_SYNCHRONOUS) &&
               (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
           {
-            scb->state |= SCB_ABORTED;
+            scb->flags |= SCB_ABORTED;
             result = SCSI_RESET_PENDING;
           }
           else
           {
+            p->flags |= IN_TIMEOUT;
             result = aic7xxx_bus_device_reset(p, cmd);
             if (result == 0)
+            {
+              p->flags &= ~IN_TIMEOUT;
               result = SCSI_RESET_PENDING;
+            }
           }
-        }
+	}
       }
     }
   }
-
   if (result == -1)
   {
     /*
@@ -5626,11 +6974,11 @@
       {
 	result = SCSI_RESET_NOT_RUNNING;
       }
-      else if (!(scb->state & SCB_IN_PROGRESS))
+      else if (!(scb->flags & SCB_ACTIVE))
       {
 	result = SCSI_RESET_NOT_RUNNING;
       }
-      else if ((scb->state & SCB_ABORTED) &&
+      else if ((scb->flags & SCB_ABORTED) &&
                (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
       {
 	result = SCSI_RESET_PENDING;
@@ -5642,8 +6990,9 @@
       /*
        * The reset channel function assumes that the sequencer is paused.
        */
-      PAUSE_SEQUENCER(p);
+      pause_sequencer(p);
       found = aic7xxx_reset_channel(p, channel, TRUE);
+      p->flags = p->flags & ~IN_TIMEOUT;
 
       /*
        * If this is a synchronous reset and there is no SCB for this
@@ -5689,8 +7038,10 @@
       }
 
       result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+      p->flags &= ~IN_TIMEOUT;
     }
   }
+  aic7xxx_run_waiting_queues(p);
   restore_flags(processor_flags);
   return (result);
 }
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h
--- v2.1.47/linux/drivers/scsi/aic7xxx.h	Sat Aug 10 00:44:18 1996
+++ linux/drivers/scsi/aic7xxx.h	Thu Jul 31 12:37:17 1997
@@ -40,13 +40,13 @@
 	aic7xxx_info,						\
 	NULL,							\
 	aic7xxx_queue,						\
-	aic7xxx_abort,						\
+	NULL,							\
 	aic7xxx_reset,						\
 	NULL,							\
 	aic7xxx_biosparam,					\
 	-1,			/* max simultaneous cmds      */\
 	-1,			/* scsi id of host adapter    */\
-	SG_ALL,			/* max scatter-gather cmds    */\
+	0,			/* max scatter-gather cmds    */\
 	2,			/* cmds per lun (linked cmds) */\
 	0,			/* number of 7xxx's present   */\
 	0,			/* no memory DMA restrictions */\
@@ -57,7 +57,6 @@
 extern int aic7xxx_biosparam(Disk *, kdev_t, 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 *, unsigned int);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
--- v2.1.47/linux/drivers/scsi/aic7xxx.seq	Sun Oct 13 03:44:34 1996
+++ linux/drivers/scsi/aic7xxx.seq	Wed Dec 31 16:00:00 1969
@@ -1,1127 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux and FreeBSD.
- *
- * Copyright (c) 1994 John Aycock
- *   The University of Calgary Department of Computer Science.
- *
- *Modifications/enhancements:
- *  Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
- *
- * 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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
- * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
- *
- * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
- *
- *-M*************************************************************************/
-
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 4.0 1996/10/13 08:23:42 deang Exp $"
-
-#ifdef linux
-#include "aic7xxx_reg.h"
-#else
-#if defined(__NetBSD__)
-#include "../../../../dev/ic/aic7xxxreg.h"
-#elif defined(__FreeBSD__)
-#include "../../dev/aic7xxx/aic7xxx_reg.h"
-#endif
-#endif
-
-/*
- * We can't just use ACCUM in the sequencer code because it
- * must be treated specially by the assembler, and it currently
- * looks for the symbol 'A'.  This is the only register defined in
- * the assembler's symbol space.
- */
-A = ACCUM
-
-/* After starting the selection hardware, we check for reconnecting targets
- * as well as for our selection to complete just in case the reselection wins
- * bus arbitration.  The problem with this is that we must keep track of the
- * SCB that we've already pulled from the QINFIFO and started the selection
- * on just in case the reselection wins so that we can retry the selection at
- * a later time.  This problem cannot be resolved by holding a single entry
- * in scratch ram since a reconnecting target can request sense and this will
- * create yet another SCB waiting for selection.  The solution used here is to 
- * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
- * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB offsets, 
- * SCB_LIST_NULL is 0xff which is out of range.  The kernel driver must
- * add an entry to this list every time a request sense occurs.  The sequencer
- * will automatically consume the entries.
- */
-
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
-reset:
-	clr	DFCNTRL
-	clr	SCSISIGO		/* De-assert BSY */
-/*
- * We jump to start after every bus free.
- */
-start:
-	and	FLAGS,0x0f		/* clear target specific flags */
-	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
-	clr	SCSIRATE		/*
-					 * We don't know the target we will
-					 * connect to, so default to narrow
-					 * transfers to avoid parity problems.
-					 */
-poll_for_work:
-	/*
-	 * Are we a twin channel device?
-	 * For fairness, we check the other bus first,
-	 * since we just finished a transaction on the
-	 * current channel.
-	 */
-	test	FLAGS,TWIN_BUS	jz start2
-	xor	SBLKCTL,SELBUSB			/* Toggle to the other bus */
-	test	SSTAT0,SELDI	jnz reselect
-	xor	SBLKCTL,SELBUSB			/* Toggle to the original bus */
-start2:
-	test	SSTAT0,SELDI	jnz reselect
-	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting
-	mov	A, QCNTMASK
-	test	QINCNT,A	jz poll_for_work
-
-/*
- * We have at least one queued SCB now and we don't have any 
- * SCBs in the list of SCBs awaiting selection.  Set the SCB
- * pointer from the FIFO so we see the right bank of SCB 
- * registers.
- */
-	mov	SCBPTR,QINFIFO
-
-/*
- * See if there is not already an active SCB for this target.  This code
- * locks out on a per target basis instead of target/lun.  Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands.  It may be beneficial to make findscb a more general procedure
- * to see if the added cost of the search is negligible.  This code also 
- * assumes that the kernel driver will clear the active flags on board 
- * initialization, board reset, and a target SELTO.  Tagged commands
- * don't set the active bits since you can queue more than one command
- * at a time.  We do, however, look to see if there are any non-tagged
- * I/Os in progress, and requeue the command if there are.  Tagged and
- * non-tagged commands cannot be mixed to a single target.
- */
-
-test_busy:
-	mov	FUNCTION1,SCB_TCL
-	mov	A,FUNCTION1
-	test	SCB_TCL,0x88	jz test_a	/* Id < 8 && A channel */
-
-	test	ACTIVE_B,A	jnz requeue
-	test	SCB_CONTROL,TAG_ENB	jnz start_scb
-	/* Mark the current target as busy */
-	or	ACTIVE_B,A
-	jmp	start_scb
-
-/* Place the currently active SCB back on the queue for later processing */
-requeue:
-	mov	QINFIFO, SCBPTR
-	jmp	poll_for_work
-
-/*
- * Pull the first entry off of the waiting for selection list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the waiting_scb list.
- */
-start_waiting:
-	mov	SCBPTR,WAITING_SCBH
-	jmp	start_scb2
-
-test_a:
-	test	ACTIVE_A,A jnz requeue
-	test	SCB_CONTROL,TAG_ENB jnz start_scb
-	/* Mark the current target as busy */
-	or	ACTIVE_A,A
-
-start_scb:
-	mov	SCB_NEXT,WAITING_SCBH
-	mov	WAITING_SCBH, SCBPTR
-start_scb2:
-	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
-	and	A,0x08,SCB_TCL		/* Get new channel bit */
-	or	SINDEX,A
-	mov	SBLKCTL,SINDEX		/* select channel */
-	mov	SCB_TCL	call initialize_scsiid
-
-/*
- * Enable selection phase as an initiator, and do automatic ATN
- * after the selection.  We do this now so that we can overlap the
- * rest of our work to set up this target with the arbitration and
- * selection bus phases.
- */
-start_selection:
-	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
-
-/*
- * 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.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
-	test	SCB_CMDLEN,0xff jnz mk_identify	/* 0 Length Command? */
-
-/*
- * The kernel has sent us an SCB with no command attached.  This implies
- * that the kernel wants to send a message of some sort to this target,
- * so we interrupt the driver, allow it to fill the message buffer, and
- * then go back into the arbitration loop
- */
-	mvi     INTSTAT,AWAITING_MSG
-	jmp     wait_for_selection
-
-mk_identify:
-	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
-
-	and	MSG0,0x7,SCB_TCL	/* lun */
-	or	MSG0,A			/* or in disconnect privledge */
-	or	MSG0,MSG_IDENTIFY
-	mvi	MSG_LEN, 1
-
-	test	SCB_CONTROL,0xb0 jz  !message	/* WDTR, SDTR or TAG?? */
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-
-mk_tag:
-	mvi	DINDEX, MSG1
-	test	SCB_CONTROL,TAG_ENB jz mk_tag_done
-	and	DINDIR,0x23,SCB_CONTROL
-	mov	DINDIR,SCB_TAG
-
-	add	MSG_LEN,COMP_MSG0,DINDEX	/* update message length */
-
-mk_tag_done:
-
-	test	SCB_CONTROL,0x90 jz !message	/* NEEDWDTR|NEEDSDTR */
-	mov	DINDEX	call mk_dtr	/* build DTR message if needed */
-
-!message:
-wait_for_selection:
-	test	SSTAT0,SELDO	jnz select 
-	test	SSTAT0,SELDI	jz wait_for_selection
-
-/*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target
- * yet.
- */
-reselect:
-	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
-	mov	SELID		call initialize_scsiid
-	or	FLAGS,RESELECTED
-	jmp	select2
-
-/*
- * After the selection, remove this SCB from the "waiting for selection"
- * list.  This is achieved by simply moving our "next" pointer into
- * WAITING_SCBH.  Our next pointer will be set to null the next time this
- * SCB is used, so don't bother with it now.
- */
-select:
-	mov	WAITING_SCBH,SCB_NEXT
-	or	FLAGS,SELECTED
-select2:
-/*
- * 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.
- */
-	or	SXFRCTL0,CLRCHN
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- */
-	call	ndx_dtr
-	mov	SCSIRATE,SINDIR
-
-/*
- * Initialize Ultra mode setting.
- */
-	mov	FUNCTION1,SCSIID
-	mov	A,FUNCTION1
-	and	SINDEX,0xdf,SXFRCTL0		/* default to Ultra disabled */
-	test	SCSIID, 0x80	 jnz ultra_b	/* Target ID > 7 */
-	test	SBLKCTL, SELBUSB jnz ultra_b	/* Second channel device */
-	test	ULTRA_ENB,A	 jz  set_sxfrctl0
-	or	SINDEX, ULTRAEN  jmp set_sxfrctl0
-ultra_b:
-	test	ULTRA_ENB_B,A	 jz  set_sxfrctl0
-	or	SINDEX, ULTRAEN
-
-set_sxfrctl0:
-	mov	SXFRCTL0,SINDEX
-
-	mvi	SCSISEQ,ENAUTOATNP		/*
-						 * ATN on parity errors
-						 * for "in" phases
-						 */
-	mvi	CLRSINT1,CLRBUSFREE
-	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
-/*
- * 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.
- *
- */
-ITloop:
-	test	SSTAT1,BUSFREE	jnz p_busfree
-	test	SSTAT1,REQINIT	jz ITloop
-
-	and	A,PHASE_MASK,SCSISIGI
-	mov	LASTPHASE,A
-	mov	SCSISIGO,A
-
-	cmp	ALLZEROS,A	je p_dataout
-	cmp	A,P_DATAIN	je p_datain
-	cmp	A,P_COMMAND	je p_command
-	cmp	A,P_MESGOUT	je p_mesgout
-	cmp	A,P_STATUS	je p_status
-	cmp	A,P_MESGIN	je p_mesgin
-
-	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
-	jmp	ITloop			/* Try reading the bus again. */
-
-p_dataout:
-	mvi	DMAPARAMS,0x7d			/*
-						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
-						 * DIRECTION|FIFORESET
-						 */
-	jmp	data_phase_init
-
-/*
- * If we re-enter the data phase after going through another phase, the
- * STCNT may have been cleared, so restore it from the residual field.
- */
-data_phase_reinit:
-	mov	STCNT0,SCB_RESID_DCNT0
-	mov	STCNT1,SCB_RESID_DCNT1
-	mov	STCNT2,SCB_RESID_DCNT2
-	jmp	data_phase_loop
-
-p_datain:
-	mvi	DMAPARAMS,0x79		/*
-					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
-					 * !DIRECTION|FIFORESET
-					 */
-data_phase_init:
-	call	assert
-
-	test	FLAGS, DPHASE	jnz data_phase_reinit
-	call	sg_scb2ram
-	or	FLAGS, DPHASE		/* We have seen a data phase */
-
-data_phase_loop:
-/* Guard against overruns */
-	test	SG_COUNT, 0xff jnz data_phase_inbounds
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
-	or	SXFRCTL1,BITBUCKET
-	mvi	STCNT0,0xff
-	mvi	STCNT1,0xff
-	mvi	STCNT2,0xff
-
-data_phase_inbounds:
-/* If we are the last SG block, don't set wideodd. */
-	cmp	SG_COUNT,0x01 jne data_phase_wideodd
-	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
-data_phase_wideodd:
-	mov	DMAPARAMS  call dma
-
-/* Go tell the host about any overruns */
-	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
-
-/* Exit if we had an underrun */
-	test	SSTAT0,SDONE	jz data_phase_finish /* underrun STCNT != 0 */
-
-/*
- * Advance the scatter-gather pointers if needed 
- */
-sg_advance:
-	dec	SG_COUNT	/* one less segment to go */
-
-	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
-
-	clr	A			/* add sizeof(struct scatter) */
-	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
-	adc	SG_NEXT1,A,SG_NEXT1
-
-/*
- * Load a struct scatter 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 all DMA's, assumes a little-endian host data storage.
- */
-sg_load:
-	clr	HCNT2
-	clr	HCNT1
-	mvi	HCNT0,SG_SIZEOF
-
-	mov	HADDR0,SG_NEXT0
-	mov	HADDR1,SG_NEXT1
-	mov	HADDR2,SG_NEXT2
-	mov	HADDR3,SG_NEXT3
-
-	or	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.
- */
-dma_finish:
-	test	DFSTATUS,HDONE	jz dma_finish
-	/* Turn off DMA preserving WIDEODD */
-	and	DFCNTRL,WIDEODD
-dma_finish2:
-	test	DFCNTRL,HDMAENACK jnz dma_finish2
-
-/*
- * Copy data from FIFO into SCB data pointer and data count.  In
- * both FreeBSD and Linux, the scatter list entry is 8 bytes.
- * 
- * struct ahc_dma_seg {
- *       physaddr addr;                  four bytes, little-endian order
- *       long    len;                    four bytes, little endian order
- * };
- */
-
-	mov	HADDR0,DFDAT
-	mov	HADDR1,DFDAT
-	mov	HADDR2,DFDAT
-	mov	HADDR3,DFDAT
-	mov	HCNT0,DFDAT
-	mov	HCNT1,DFDAT
-	mov	HCNT2,DFDAT
-
-/* Load STCNT as well.  It is a mirror of HCNT */
-	mov	STCNT0,HCNT0
-	mov	STCNT1,HCNT1
-	mov	STCNT2,HCNT2
-        test    SSTAT1,PHASEMIS  jz data_phase_loop
-
-data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
- * were transferred on the SCSI (as opposed to the host) bus.
- */
-	mov	SCB_RESID_DCNT0,STCNT0
-	mov	SCB_RESID_DCNT1,STCNT1
-	mov	SCB_RESID_DCNT2,STCNT2
-	mov	SCB_RESID_SGCNT, SG_COUNT
-	jmp	ITloop
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
-	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
-	mvi	INTSTAT,DATA_OVERRUN
-	jmp	ITloop
-
-/*
- * Command phase.  Set up the DMA registers and let 'er rip.
- */
-p_command:
-	call	assert
-
-/*
- * Load HADDR and HCNT.
- */
-	mov	HADDR0, SCB_CMDPTR0
-	mov	HADDR1, SCB_CMDPTR1
-	mov	HADDR2, SCB_CMDPTR2
-	mov	HADDR3, SCB_CMDPTR3
-	mov	HCNT0, SCB_CMDLEN
-	clr	HCNT1
-	clr	HCNT2
-
-	mov	STCNT0, HCNT0
-	mov	STCNT1, HCNT1
-	mov	STCNT2, HCNT2
-
-	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	SCB_TARGET_STATUS	call inb_first
-	jmp	mesgin_done
-
-/*
- * Message out phase.  If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
- */
-p_mesgout:
-	test	MSG_LEN, 0xff	jnz  p_mesgout_start
-	mvi	MSG_NOP		call mk_mesg	/* build NOP message */
-
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG0.  Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
-	mvi	SINDEX,MSG0
-	mov	DINDEX,MSG_LEN
-
-/*
- * 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.
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
- */
-p_mesgout_loop:
-	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
-	test	SSTAT0,SPIORDY	jz p_mesgout_loop
-	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
-	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
-	mvi	CLRSINT1,CLRATNO			/* drop ATN */
-p_mesgout_outb:
-	dec	DINDEX
-	or	CLRSINT0, CLRSPIORDY
-	mov	SCSIDATL,SINDIR
-	
-p_mesgout4:
-	test	DINDEX,0xff	jnz p_mesgout_loop
-
-/*
- * 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_mesgout_snoop:
-	test	SSTAT1,BUSFREE	jnz p_mesgout_done
-	test	SSTAT1,REQINIT	jz p_mesgout_snoop
-
-	test	SSTAT1,PHASEMIS	jnz p_mesgout_done
-
-	or	SCSISIGO,ATNO			/* turn on ATNO */
-
-	jmp	ITloop
-
-p_mesgout_phasemis:
-	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
-p_mesgout_done:
-	clr	MSG_LEN			/* no active msg */
-	jmp	ITloop
-
-/*
- * Message in phase.  Bytes are read using Automatic PIO mode.
- */
-p_mesgin:
-	mvi	A		call inb_first	/* read the 1st message byte */
-	mov	REJBYTE,A			/* save it for the driver */
-
-	test	A,MSG_IDENTIFY		jnz mesgin_identify
-	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
-	cmp	A,MSG_SDPTRS		je mesgin_sdptrs
-	cmp	ALLZEROS,A		je mesgin_complete
-	cmp	A,MSG_RDPTRS		je mesgin_rdptrs
-	cmp	A,MSG_EXTENDED		je mesgin_extended
-	cmp	A,MSG_REJECT		je mesgin_reject
-
-rej_mesgin:
-/*
- * 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.
- */
-	or	SCSISIGO,ATNO			/* turn on ATNO */
-	mvi	INTSTAT,SEND_REJECT		/* let driver know */
-
-	mvi	MSG_REJECT	call mk_mesg
-
-mesgin_done:
-	call	inb_last			/*ack & turn auto PIO back on*/
-	jmp	ITloop
-
-
-mesgin_complete:
-/*
- * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
- * and trigger a completion interrupt.  Check status for non zero return
- * and interrupt driver if needed.  This allows the driver to interpret
- * errors only when they occur instead of always uploading the scb.  If
- * the status is SCSI_CHECK, the driver will download a new scb requesting
- * sense to replace the old one, modify the "waiting for selection" SCB list
- * and set RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE the
- * sequencer imediately jumps to main loop where it will run down the waiting
- * SCB list and process the sense request.  If the kernel driver does not
- * wish to request sense, it need only clear RETURN_1, and the command is
- * allowed to complete.  We don't bother to post to the QOUTFIFO in the
- * error case since it would require extra work in the kernel driver to
- * ensure that the entry was removed before the command complete code tried
- * processing it.
- *
- * First check for residuals
- */
-	test	SCB_RESID_SGCNT,0xff	jz check_status
-/*
- * If we have a residual count, interrupt and tell the host.  Other
- * alternatives are to pause the sequencer on all command completes (yuck),
- * dma the resid directly to the host (slick, we may have space to do it now)
- * or have the sequencer pause itself when it encounters a non-zero resid 
- * (unnecessary pause just to flag the command -yuck-, but takes one instruction
- * and since it shouldn't happen that often is good enough for our purposes).  
- */
-resid:
-	mvi	INTSTAT,RESIDUAL
-
-check_status:
-	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
-	mvi	INTSTAT,BAD_STATUS			/* let driver know */
-	cmp	RETURN_1, SEND_SENSE	jne status_ok
-	jmp	mesgin_done
-
-status_ok:
-/* First, mark this target as free. */
-	test	SCB_CONTROL,TAG_ENB jnz test_immediate	/*
-							 * Tagged commands
-							 * don't busy the
-							 * target.
-							 */
-	mov	FUNCTION1,SCB_TCL
-	mov	A,FUNCTION1
-	test	SCB_TCL,0x88 jz clear_a
-	xor	ACTIVE_B,A
-	jmp	test_immediate
-
-clear_a:
-	xor	ACTIVE_A,A
-
-test_immediate:
-	test    SCB_CMDLEN,0xff jnz complete  /* Immediate message complete */
-/*
- * Pause the sequencer until the driver gets around to handling the command
- * complete.  This is so that any action that might require careful timing
- * with the completion of this command can occur.
- */
-	mvi	INTSTAT,IMMEDDONE
-	jmp	start
-complete:
-	mov	QOUTFIFO,SCB_TAG
-	mvi	INTSTAT,CMDCMPLT
-	jmp	mesgin_done
-
-
-/*
- * Is it an extended message?  We only support the synchronous and wide data
- * transfer request messages, which will probably be in response to
- * WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
- * apparently this can be done after any message in byte, according
- * to the SCSI-2 spec.
- */
-mesgin_extended:
-	mvi	ARG_1		call inb_next	/* extended message length */
-	mvi	REJBYTE_EXT	call inb_next	/* extended message code */
-
-	cmp	REJBYTE_EXT,MSG_SDTR	je p_mesginSDTR
-	cmp	REJBYTE_EXT,MSG_WDTR	je p_mesginWDTR
-	jmp	rej_mesgin
-
-p_mesginWDTR:
-	cmp	ARG_1,2		jne rej_mesgin	/* extended mesg length=2 */
-	mvi	ARG_1		call inb_next	/* Width of bus */
-	mvi	INTSTAT,WDTR_MSG		/* let driver know */
-	test	RETURN_1,0xff jz mesgin_done	/* Do we need to send WDTR? */
-	cmp	RETURN_1,SEND_REJ je rej_mesgin /*
-						 * Bus width was too large 
-						 * Reject it.
-						 */
-
-/* We didn't initiate the wide negotiation, so we must respond to the request */
-	and	RETURN_1,0x7f			/* Clear the SEND_WDTR Flag */
-	mvi	DINDEX,MSG0
-	mvi	MSG0	call mk_wdtr		/* build WDTR message */
-	or	SCSISIGO,ATNO			/* turn on ATNO */
-	jmp	mesgin_done
-
-p_mesginSDTR:
-	cmp	ARG_1,3		jne rej_mesgin	/* extended mesg length=3 */
-	mvi	ARG_1		call inb_next	/* xfer period */
-	mvi	A		call inb_next	/* REQ/ACK offset */
-	mvi	INTSTAT,SDTR_MSG		/* call driver to convert */
-
-	test	RETURN_1,0xff	jz mesgin_done  /* Do we need to mk_sdtr/rej */
-	cmp	RETURN_1,SEND_REJ je rej_mesgin /*
-						 * Requested SDTR too small
-						 * Reject it.
-						 */
-	clr	ARG_1				/* Use the scratch ram rate */
-	mvi	DINDEX, MSG0
-	mvi     MSG0     call mk_sdtr
-	or	SCSISIGO,ATNO			/* turn on ATNO */
-	jmp	mesgin_done
-
-/*
- * Is it a disconnect message?  Set a flag in the SCB to remind us
- * and await the bus going free.
- */
-mesgin_disconnect:
-	or	SCB_CONTROL,DISCONNECTED
-	test	FLAGS, PAGESCBS jz mesgin_done
-/*
- * Link this SCB into the DISCONNECTED list.  This list holds the
- * candidates for paging out an SCB if one is needed for a new command.
- * Modifying the disconnected list is a critical(pause dissabled) section.
- */
-	mvi	SCB_PREV, SCB_LIST_NULL
-	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
-	mov	SCB_NEXT, DISCONNECTED_SCBH
-	mov	DISCONNECTED_SCBH, SCBPTR
-	cmp	SCB_NEXT,SCB_LIST_NULL je linkdone
-	mov	SCBPTR,SCB_NEXT
-	mov	SCB_PREV,DISCONNECTED_SCBH
-	mov	SCBPTR,DISCONNECTED_SCBH
-linkdone:
-	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
-	jmp	mesgin_done
-
-/*
- * Save data pointers message?  Copy working values into the SCB,
- * usually in preparation for a disconnect.
- */
-mesgin_sdptrs:
-	call	sg_ram2scb
-	jmp	mesgin_done
-
-/*
- * Restore pointers message?  Data pointers are recopied from the
- * SCB anytime we enter a data phase for the first time, so all
- * we need to do is clear the DPHASE flag and let the data phase
- * code do the rest.
- */
-mesgin_rdptrs:
-	and	FLAGS,0xef			/*
-						 * !DPHASE we'll reload them
-						 * the next time through
-						 */
-	jmp	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.
- */
-mesgin_identify:
-	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
-
-	and	A,0x07			/* lun in lower three bits */
-	or      SAVED_TCL,A,SELID          
-	and     SAVED_TCL,0xf7
-	and     A,SELBUSB,SBLKCTL	/* B Channel?? */
-	or      SAVED_TCL,A
-	call	inb_last		/* ACK */
-
-/*
- * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to switch to find the proper
- * SCB.  With SCB paging, this requires using findSCB for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
- */
-	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
-snoop_tag_loop:
-	test	SSTAT1,BUSFREE	jnz use_findSCB
-	test	SSTAT1,REQINIT	jz snoop_tag_loop
-	test	SSTAT1,PHASEMIS	jnz use_findSCB
-	mvi	A		call inb_first
-	cmp	A,MSG_SIMPLE_TAG jne use_findSCB
-get_tag:
-	mvi	ARG_1	call inb_next	/* tag value */
-/*
- * See if the tag is in range.  The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incoming tag and there is
- * no carry.
- */
-	mov	A,COMP_SCBCOUNT	
-	add	SINDEX,A,ARG_1
-	jc	abort_tag
-
-/*
- * Ensure that the SCB the tag points to is for a SCB transaction
- * to the reconnecting target.
- */
-	test	FLAGS, PAGESCBS	jz index_by_tag
-	call	inb_last			/* Ack Tag */
-use_findSCB:
-	mov	ALLZEROS	call findSCB	  /* Have to search */
-setup_SCB:
-	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
-	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
-	jmp	ITloop
-index_by_tag:
-	mov	SCBPTR,ARG_1
-	mov	A,SAVED_TCL
-	cmp	SCB_TCL,A		jne abort_tag
-	test	SCB_CONTROL,TAG_ENB	jz  abort_tag
-	call	inb_last			/* Ack Successful tag */
-	jmp	setup_SCB
-
-abort_tag:
-	or	SCSISIGO,ATNO			/* turn on ATNO */
-	mvi	INTSTAT,ABORT_TAG 		/* let driver know */
-	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
-	jmp	mesgin_done
-
-/*
- * Message reject?  Let the kernel driver handle this.  If we have an 
- * outstanding WDTR or SDTR negotiation, assume that it's a response from 
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
-	mvi	INTSTAT, REJECT_MSG
-	jmp	mesgin_done
-
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * 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,CLRATNO
-	clr	LASTPHASE
-
-/*
- * if this is an immediate command, perform a pseudo command complete to
- * notify the driver.
- */
-	test	SCB_CMDLEN,0xff	jz status_ok
-	jmp	start
-
-/*
- * 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,0x50			/* PAUSEDIS|FASTMODE */
-	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
-	
-	/*
-	 * Hmmm.  For some reason the mesg buffer is in use.
-	 * Tell the driver.  It should look at SINDEX to find
-	 * out what we wanted to use the buffer for and resolve
-	 * the conflict.
-	 */
-	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
-	mvi	INTSTAT,MSG_BUFFER_BUSY
-
-mk_mesg1:
-	mvi	MSG_LEN,1		/* length = 1 */
-	mov	MSG0,SINDEX		/* 1-byte message */
-	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
-
-/*
- * Functions to read data in Automatic PIO mode.
- *
- * 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_next:
-	or	CLRSINT0, CLRSPIORDY
-	mov	NONE,SCSIDATL			/*dummy read from latch to ACK*/
-inb_next_wait:
-	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
-	test	SSTAT0,SPIORDY	jz inb_next_wait /* wait for next byte */
-inb_first:
-	mov	DINDEX,SINDEX
-	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
-	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
-inb_last:
-	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
-
-mesgin_phasemis:
-/*
- * We expected to receive another byte, but the target changed phase
- */
-	mvi	INTSTAT, MSGIN_PHASEMIS
-	jmp	ITloop
-
-/*
- * 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:
-	test	SSTAT0,DMADONE	jnz dma3
-	test	SSTAT1,PHASEMIS	jz dma1		/* 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,DIRECTION	jnz dma5
-dma4:
-	test	DFSTATUS,FIFOEMP	jz dma4
-
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are 
- * actually off first lest we get an ILLSADDR.
- */
-dma5:
-	/* disable DMA, but maintain WIDEODD */
-	and	DFCNTRL,WIDEODD
-dma6:
-	test	DFCNTRL,0x38	jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
-
-	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_scsiid:
-	and	SINDEX,0xf0		/* Get target ID */
-	and	A,0x0f,SCSIID
-	or	SINDEX,A
-	mov	SCSIID,SINDEX ret
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
-	test	FLAGS,RESELECTED	jz return	/* reselected? */
-	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
-
-	mvi	INTSTAT,NO_IDENT 	ret	/* no - cause a kernel panic */
-
-/*
- * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
- * value in ARG_1.  If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
- * SCB.  Have the kernel print a warning message if it can't be found, and
- * generate an ABORT/ABORT_TAG message to the target.  SINDEX should be
- * cleared on call.
- */
-findSCB:
-	mov	A,SAVED_TCL
-	mov	SCBPTR,SINDEX			/* switch to next SCB */
-	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
-	cmp	SCB_TCL,A	jne findSCB1 /* target ID/channel/lun match? */
-	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
-	test	SCB_CONTROL,TAG_ENB jnz findTaggedSCB
-	cmp	ARG_1,SCB_LIST_NULL je foundSCB
-	jmp	findSCB1
-findTaggedSCB:
-	mov	A, ARG_1			/* Tag passed in ARG_1 */
-	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
-foundSCB:
-	test	FLAGS,PAGESCBS	jz foundSCB_ret
-/* Remove this SCB from the disconnection list */
-	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
-	mov	SAVED_LINKPTR, SCB_PREV
-	mov	SCBPTR, SCB_NEXT
-	mov	SCB_PREV, SAVED_LINKPTR
-	mov	SCBPTR, SINDEX
-unlink_prev:
-	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
-	mov	SAVED_LINKPTR, SCB_NEXT
-	mov	SCBPTR, SCB_PREV
-	mov	SCB_NEXT, SAVED_LINKPTR
-	mov	SCBPTR, SINDEX
-	mvi	SEQCTL,0x10	ret		/* !PAUSEDIS|FASTMODE */
-rHead:
-	mov	DISCONNECTED_SCBH,SCB_NEXT
-foundSCB_ret:
-	mvi	SEQCTL,0x10	ret		/* !PAUSEDIS|FASTMODE */
-
-findSCB1:
-	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
-	inc	SINDEX
-	mov	A,SCBCOUNT
-	cmp	SINDEX,A	jne findSCB
-
-	mvi	INTSTAT,NO_MATCH		/* not found - signal kernel */
-	cmp	RETURN_1,SCB_PAGEDIN je return
-	or	SCSISIGO,ATNO			/* assert ATNO */
-	cmp	ARG_1,SCB_LIST_NULL jne find_abort_tag
-	mvi	MSG_ABORT	call mk_mesg
-	jmp	ITloop
-find_abort_tag:
-	mvi	MSG_ABORT_TAG	call mk_mesg
-	jmp	ITloop
-
-/*
- * Make a working copy of the scatter-gather parameters from the SCB.
- */
-sg_scb2ram:
-	mov	HADDR0, SCB_DATAPTR0
-	mov	HADDR1, SCB_DATAPTR1
-	mov	HADDR2, SCB_DATAPTR2
-	mov	HADDR3, SCB_DATAPTR3
-	mov	HCNT0, SCB_DATACNT0
-	mov	HCNT1, SCB_DATACNT1
-	mov	HCNT2, SCB_DATACNT2
-
-	mov	STCNT0, HCNT0
-	mov	STCNT1, HCNT1
-	mov	STCNT2, HCNT2
-
-	mov	SG_COUNT,SCB_SGCOUNT
-
-	mov	SG_NEXT0, SCB_SGPTR0
-	mov	SG_NEXT1, SCB_SGPTR1
-	mov	SG_NEXT2, SCB_SGPTR2
-	mov	SG_NEXT3, SCB_SGPTR3 ret
-
-/*
- * Copying RAM values back to SCB, for Save Data Pointers message, but
- * only if we've actually been into a data phase to change them.  This
- * protects against bogus data in scratch ram and the residual counts
- * since they are only initialized when we go into data_in or data_out.
- */
-sg_ram2scb:
-	test	FLAGS, DPHASE	jz return
-	mov	SCB_SGCOUNT,SG_COUNT
-
-	mov	SCB_SGPTR0,SG_NEXT0
-	mov	SCB_SGPTR1,SG_NEXT1
-	mov	SCB_SGPTR2,SG_NEXT2
-	mov	SCB_SGPTR3,SG_NEXT3
-	
-	mov	SCB_DATAPTR0,SHADDR0
-	mov	SCB_DATAPTR1,SHADDR1
-	mov	SCB_DATAPTR2,SHADDR2
-	mov	SCB_DATAPTR3,SHADDR3
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer
- */
-	mov	SCB_DATACNT0,SCB_RESID_DCNT0
-	mov	SCB_DATACNT1,SCB_RESID_DCNT1
-	mov	SCB_DATACNT2,SCB_RESID_DCNT2 ret
-
-/*
- * Add the array base TARG_SCRATCH 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_dtr:
-	shr	A,SCSIID,4
-	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
-	or	A,0x08		/* Channel B entries add 8 */
-ndx_dtr_2:
-	add	SINDEX,TARG_SCRATCH,A ret
-
-/*
- * If we need to negotiate transfer parameters, build the WDTR or SDTR message
- * starting at the address passed in SINDEX.  DINDEX is modified on return.
- * The SCSI-II spec requires that Wide negotiation occur first and you can
- * only negotiate one or the other at a time otherwise in the event of a message
- * reject, you wouldn't be able to tell which message was the culprit.
- */
-mk_dtr:
-	test	SCB_CONTROL,NEEDWDTR jnz  mk_wdtr_16bit
-	mvi	ARG_1, MAXOFFSET	/* Force an offset of 15 or 8 if WIDE */
-
-mk_sdtr:
-	mvi	DINDIR,1		/* extended message */
-	mvi	DINDIR,3		/* extended message length = 3 */
-	mvi	DINDIR,1		/* SDTR code */
-	call	sdtr_to_rate
-	mov	DINDIR,RETURN_1		/* REQ/ACK transfer period */
-	cmp	ARG_1, MAXOFFSET je mk_sdtr_max_offset
-	and	DINDIR,0x0f,SINDIR	/* Sync Offset */
-
-mk_sdtr_done:
-	add	MSG_LEN,COMP_MSG0,DINDEX ret	/* update message length */
-
-mk_sdtr_max_offset:
-/*
- * We're initiating sync negotiation, so request the max offset we can (15 or 8)
- */
-	/* Talking to a WIDE device? */
-	test	SCSIRATE, WIDEXFER	jnz wmax_offset	
-	mvi	DINDIR, MAX_OFFSET_8BIT
-	jmp	mk_sdtr_done
-
-wmax_offset:
-	mvi	DINDIR, MAX_OFFSET_16BIT
-	jmp	mk_sdtr_done
-
-mk_wdtr_16bit:
-	mvi	ARG_1,BUS_16_BIT
-mk_wdtr:
-	mvi	DINDIR,1		/* extended message */
-	mvi	DINDIR,2		/* extended message length = 2 */
-	mvi	DINDIR,3		/* WDTR code */
-	mov	DINDIR,ARG_1		/* bus width */
-
-	add	MSG_LEN,COMP_MSG0,DINDEX ret	/* update message length */
-	
-sdtr_to_rate:
-	call	ndx_dtr			/* index scratch space for target */
-	shr	A,SINDIR,0x4
-	dec	SINDEX			/* Preserve SINDEX */
-	and	A,0x7
-	clr	RETURN_1
-sdtr_to_rate_loop:
-	test	A,0x0f	jz sdtr_to_rate_done
-	add	RETURN_1,0x19
-	dec	A	
-	jmp	sdtr_to_rate_loop
-sdtr_to_rate_done:
-	shr	RETURN_1,0x2
-	add	RETURN_1,0x19
-	test	SXFRCTL0,ULTRAEN jz return
-	shr	RETURN_1,0x1
-return:
-	ret
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx_asm.c linux/drivers/scsi/aic7xxx_asm.c
--- v2.1.47/linux/drivers/scsi/aic7xxx_asm.c	Sat Apr 20 10:59:10 1996
+++ linux/drivers/scsi/aic7xxx_asm.c	Wed Dec 31 16:00:00 1969
@@ -1,734 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx sequencer code assembler.
- *
- * Copyright (c) 1994 John Aycock
- *   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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- *      <label>*
- *      <label>*  <undef-sym> = <value>
- *      <label>*  <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
- * are token separators.
- *-M*************************************************************************/
-static const char id[] = "$Id: aic7xxx_asm.c,v 3.0 1996/04/16 08:52:23 deang Exp $";
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define MEMORY		448
-#define MAXLINE		1024
-#define MAXTOKEN	32
-#define ADOTOUT		"a.out"
-#define NOVALUE		-1
-
-#ifndef TRUE
-#  define TRUE 1
-#endif
-#ifndef FALSE
-#  define FALSE 0
-#endif
-#define MAX_ARGS	16
-static const char *cpp[] = {
-  "/lib/cpp -P - -",
-  "/usr/lib/cpp -P - -",
-  "/usr/bin/cpp -P - -",
-  "/usr/bin/gcc -E -P -",
-  "/usr/bin/cc -E -P -"
-};
-
-#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
-
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX	0x65
-#define R_ALLONES	0x69
-#define R_ALLZEROS	0x6a
-#define R_NONE		0x6a
-
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
-
-void 
-error(const char *s)
-{
-	fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
-	exit(EXIT_FAILURE);
-}
-
-void *
-Malloc(size_t size)
-{
-	void *p = malloc(size);
-	if (!p)
-		error("out of memory");
-	return(p);
-}
-
-void *
-Realloc(void *ptr, size_t size)
-{
-	void *p = realloc(ptr, size);
-	if (!p)
-		error("out of memory");
-	return(p);
-}
-
-char *
-Strdup(char *s)
-{
-	char *p = (char *)Malloc(strlen(s) + 1);
-	strcpy(p, s);
-	return(p);
-}
-
-typedef struct sym_t {
-	struct sym_t	*next;		/* MUST BE FIRST */
-	char		*name;
-	int		value;
-	int		npatch; 
-	int		*patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
-	sym_t *p, *q;
-
-	for (p = head, q = (sym_t *)&head; p; p = p->next) {
-		if (!strcmp(p->name, name))
-			error("redefined symbol");
-		q = p;
-	}
-
-	p = q->next = (sym_t *)Malloc(sizeof(sym_t));
-	p->next = NULL;
-	p->name = Strdup(name);
-	p->value = value;
-	p->npatch = 0;
-	p->patch = NULL;
-
-	if (debug) {
-		fprintf(stderr, "\"%s\" ", p->name);
-		if (p->value != NOVALUE)
-			fprintf(stderr, "defined as 0x%x\n", p->value);
-		else
-			fprintf(stderr, "undefined\n");
-	}
-}
-
-sym_t *
-lookup(char *name)
-{
-	sym_t *p;
-
-	for (p = head; p; p = p->next)
-		if (!strcmp(p->name, name))
-			return(p);
-	return(NULL);
-}
-
-void 
-patch(sym_t *p, int location)
-{
-	p->npatch += 1;
-	p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
-
-	p->patch[p->npatch - 1] = location;
-}
-
-void backpatch(void)
-{
-	int i;
-	sym_t *p;
-
-	for (p = head; p; p = p->next) {
-
-		if (p->value == NOVALUE) {
-			fprintf(stderr,
-				"%s: undefined symbol \"%s\"\n",
-				filename, p->name);
-			exit(EXIT_FAILURE);
-		}
-
-		if (p->npatch) {
-			if (debug)
-				fprintf(stderr,
-					"\"%s\" (0x%x) patched at",
-					p->name, p->value);
-
-			for (i = 0; i < p->npatch; i++) {
-				M[p->patch[i]][0] &= ~1;
-				M[p->patch[i]][0] |= ((p->value >> 8) & 1);
-				M[p->patch[i]][1] = p->value & 0xff;
-
-				if (debug)
-					fprintf(stderr, " 0x%x", p->patch[i]);
-			}
-
-			if (debug)
-				fputc('\n', stderr);
-		}
-	}
-}
-
-/*
- *  Output words in byte-reversed order (least significant first)
- *  since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
-	int i;
-
-	for (i = 0; i < LC; i++)
-		fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
-			M[i][3],
-			M[i][2],
-			M[i][1],
-			M[i][0]);
-	printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
-{
-	int i;
-	char *p, *quote;
-	static char buf[MAXLINE];
-	static char *a[MAXTOKEN];
-
-	i = 0;
-
-	while (fgets(buf, sizeof(buf), stdin)) {
-
-		lineno += 1;
-
-		if (buf[strlen(buf)-1] != '\n')
-			error("line too long");
-
-		p = strchr(buf, '#');
-		if (p)
-			*p = '\0';
-		p = buf;
-rescan:
-		quote = strchr(p, '\"');
-		if (quote)
-			*quote = '\0';
-		for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
-			if (i < MAXTOKEN-1)
-				a[i++] = p;
-			else
-				error("too many tokens");
-		if (quote) {
-			quote++; 
-			p = strchr(quote, '\"');
-			if (!p)
-				error("unterminated string constant");
-			else if (i < MAXTOKEN-1) {
-				a[i++] = quote;
-				*p = '\0';
-				p++;
-			}
-			else
-				error("too many tokens");
-			goto rescan;
-		}		
-		if (i) {
-			*n = i;
-			return(a);
-		}
-	}
-	return(NULL);
-}
-
-#define A	0x8000		/* `A'ccumulator ok */
-#define I	0x4000		/* use as immediate value */
-#define SL	0x2000		/* shift left */
-#define SR	0x1000		/* shift right */
-#define RL	0x0800		/* rotate left */
-#define RR	0x0400		/* rotate right */
-#define LO	0x8000		/* lookup: ori-{jmp,jc,jnc,call} */
-#define LA	0x4000		/* lookup: and-{jz,jnz} */
-#define LX	0x2000		/* lookup: xor-{je,jne} */
-#define NA	-1		/* not applicable */
-
-struct {
-	const char *name;
-	int n;			/* number of operands, including opcode */
-	unsigned int op;	/* immediate or L?|pos_from_0 */
-	unsigned int dest;	/* NA, pos_from_0, or I|immediate */
-	unsigned int src;	/* NA, pos_from_0, or I|immediate */
-	unsigned int imm;	/* pos_from_0, A|pos_from_0, or I|immediate */
-	unsigned int addr;	/* NA or pos_from_0 */
-	int fmt;		/* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- *		  N  OP    DEST		SRC		IMM	ADDR	FMT
- */
-	{ "mov",  3, 1,	   1,		2,		I|0xff,	NA,	1 },
-	{ "mov",  4, LO|2, NA,		1,		I|0,	3,	3 },
-	{ "mvi",  3, 0,	   1,		I|R_ALLZEROS,	A|2,	NA,	1 },
-	{ "mvi",  4, LO|2, NA,		I|R_ALLZEROS,	1,	3,	3 },
-	{ "not",  2, 2,	   1,		1,		I|0xff,	NA,	1 },
-	{ "and",  3, 1,	   1,		1,		A|2,	NA,	1 },
-	{ "and",  4, 1,	   1,		3,		A|2,	NA,	1 },
-	{ "or",	  3, 0,	   1,		1,		A|2,	NA,	1 },
-	{ "or",	  4, 0,	   1,		3,		A|2,	NA,	1 },
-	{ "or",   5, LO|3, NA,		1,		2,	4,	3 },
-	{ "xor",  3, 2,	   1,		1,		A|2,	NA,	1 },
-	{ "xor",  4, 2,	   1,		3,		A|2,	NA,	1 },
-	{ "nop",  1, 1,	   I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,	1 },
-	{ "inc",  2, 3,	   1,		1,		I|1,	NA,	1 },
-	{ "inc",  3, 3,	   1,		2,		I|1,	NA,	1 },
-	{ "dec",  2, 3,	   1,		1,		I|0xff,	NA,	1 },
-	{ "dec",  3, 3,	   1,		2,		I|0xff,	NA,	1 },
-	{ "jmp",  2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
-	{ "jc",   2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
-	{ "jnc",  2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
-	{ "call", 2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
-	{ "test", 5, LA|3,   NA,	1,		A|2,	4,	3 },
-	{ "cmp",  5, LX|3,   NA,	1,		A|2,	4,	3 },
-	{ "ret",  1, 1,	 I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,	1 },
-	{ "ret",  1, 1,	 I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,	1 },
-	{ "clc",  1, 3,	 I|R_NONE,	I|R_ALLZEROS,	I|1,	NA,	1 },
-	{ "clc",  4, 3,	 2,		I|R_ALLZEROS,	A|3,	NA,	1 },
-	{ "stc",  2, 3,	 1,		I|R_ALLONES,	I|1,	NA,	1 },
-	{ "add",  3, 3,	 1,		1,		A|2,	NA,	1 },
-	{ "add",  4, 3,	 1,		3,		A|2,	NA,	1 },
-	{ "adc",  3, 4,	 1,		1,		A|2,	NA,	1 },
-	{ "adc",  4, 4,	 1,		3,		A|2,	NA,	1 },
-	{ "shl",  3, 5,	 1,		1,		SL|2,	NA,	2 },
-	{ "shl",  4, 5,	 1,		2,		SL|3,	NA,	2 },
-	{ "shr",  3, 5,	 1,		1,		SR|2,	NA,	2 },
-	{ "shr",  4, 5,	 1,		2,		SR|3,	NA,	2 },
-	{ "rol",  3, 5,	 1,		1,		RL|2,	NA,	2 },
-	{ "rol",  4, 5,	 1,		2,		RL|3,	NA,	2 },
-	{ "ror",  3, 5,	 1,		1,		RR|2,	NA,	2 },
-	{ "ror",  4, 5,	 1,		2,		RR|3,	NA,	2 },
-	/*
-	 *  Extensions (note also that mvi allows A)
-	 */
- 	{ "clr",  2, 1,	 1,	I|R_ALLZEROS,		I|0xff,	NA,	1 },
-	{ 0,      0, 0,  0, 	0,			0,	0,	0 }
-};
-
-int 
-eval_operand(char **a, int spec)
-{
-	int i;
-	unsigned int want = spec & (LO|LA|LX);
-
-	static struct {
-		unsigned int what;
-		const char *name;
-		int value;
-	} jmptab[] = {
-		{ LO,	"jmp",		8  },
-		{ LO,	"jc",		9  },
-		{ LO,	"jnc",		10 },
-		{ LO,	"call",		11 },
-		{ LA,	"jz",		15 },
-		{ LA,	"jnz",		13 },
-		{ LX,	"je",		14 },
-		{ LX,	"jne",		12 },
-	};
-
-	spec &= ~(LO|LA|LX);
-
-	for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
-		if (jmptab[i].what == want &&
-		    !strcmp(jmptab[i].name, a[spec]))
-		{
-			return(jmptab[i].value);
-		}
-
-	if (want)
-		error("invalid jump");
-
-	return(spec);		/* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
-	sym_t *p;
-	unsigned val;
-
-	if (spec == NA)
-		return(NA);
-
-	switch (spec & (A|I|SL|SR|RL|RR)) {
-	    case SL:
-	    case SR:
-	    case RL:
-	    case RR:
-		if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
-			val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
-		else {
-			p = lookup(a[spec &~ (SL|SR|RL|RR)]);
-			if (!p)
-				error("undefined symbol used");
-			val = p->value;
-		}
-
-		switch (spec & (SL|SR|RL|RR)) {		/* blech */
-		    case SL:
-			if (val > 7)
-				return(0xf0);
-			return(((val % 8) << 4) |
-			       (val % 8));
-		    case SR:
-			if (val > 7)
-				return(0xf0);
-			return(((val % 8) << 4) |
-			       (1 << 3) |
-			       ((8 - (val % 8)) % 8));
-		    case RL:
-			return(val % 8);
-		    case RR:
-			return((8 - (val % 8)) % 8);
-		}
-	    case I:
-		return(spec &~ I);
-	    case A:
-		/*
-		 *  An immediate field of zero selects
-		 *  the accumulator.  Vigorously object
-		 *  if zero is given otherwise - it's
-		 *  most likely an error.
-		 */
-		spec &= ~A;
-		if (!strcmp("A", a[spec]))
-			return(0);
-		if (isdigit(*a[spec]) &&
-		    strtol(a[spec], NULL, 0) == 0)
-		{
-			error("immediate value of zero selects accumulator");
-		}
-		/* falls through */
-	    case 0:
-		if (isdigit(*a[spec]))
-			return(strtol(a[spec], NULL, 0));
-		p = lookup(a[spec]);
-		if (p)
-			return(p->value);
-		error("undefined symbol used");
-	}
-
-	return(NA);		/* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
-	sym_t *p;
-
-	if (spec == NA)
-		return(NA);
-	if (isdigit(*a[spec]))
-		return(strtol(a[spec], NULL, 0));
-
-	p = lookup(a[spec]);
-
-	if (p) {
-		if (p->value != NOVALUE)
-			return(p->value);
-		patch(p, LC);
-	} else {
-		define(a[spec], NOVALUE);
-		p = lookup(a[spec]);
-		patch(p, LC);
-	}
-
-	return(NA);		/* will be patched in later */
-}
-
-int
-crack(char **a, int n)
-{
-	int i;
-	int I_imm, I_addr;
-	int I_op, I_dest, I_src, I_ret;
-
-	/*
-	 *  Check for "ret" at the end of the line; remove
-	 *  it unless it's "ret" alone - we still want to
-	 *  look it up in the table.
-	 */
-	I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
-	if (I_ret && n > 1)
-		n -= 1;
-
-	for (i = 0; instr[i].name; i++) {
-		/*
-		 *  Look for match in table given constraints,
-		 *  currently just the name and the number of
-		 *  operands.
-		 */
-		if (!strcmp(instr[i].name, *a) && instr[i].n == n)
-			break;
-	}
-	if (!instr[i].name)
-		error("unknown opcode or wrong number of operands");
-
-	I_op	= eval_operand(a, instr[i].op);
-	I_src	= eval_sdi(a, instr[i].src);
-	I_imm	= eval_sdi(a, instr[i].imm);
-	I_dest	= eval_sdi(a, instr[i].dest);
-	I_addr	= eval_addr(a, instr[i].addr);
-
-	if( LC >= MEMORY )
-		error("Memory exhausted!\n");
-
-	switch (instr[i].fmt) {
-	    case 1:
-	    case 2:
-		M[LC][0] = (I_op << 1) | I_ret;
-		M[LC][1] = I_dest;
-		M[LC][2] = I_src;
-		M[LC][3] = I_imm;
-		break;
-	    case 3:
-		if (I_ret)
-			error("illegal use of \"ret\"");
-		M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
-		M[LC][1] = I_addr & 0xff;
-		M[LC][2] = I_src;
-		M[LC][3] = I_imm;
-		break;
-	}
-
-	return (1);		/* no two-byte instructions yet */
-}
-
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
-void
-assemble(FILE *ofile)
-{
-	int n;
-	char **a;
-	sym_t *p;
-
-	while ((a = getl(&n))) {
-
-		while (a[0][strlen(*a)-1] == ':') {
-			a[0][strlen(*a)-1] = '\0';
-			p = lookup(*a);
-			if (p)
-				p->value = LC;
-			else
-				define(*a, LC);
-			a += 1;
-			n -= 1;
-		}
-
-		if (!n)			/* line was all labels */
-			continue;
-
-		if (n == 3 && !strcmp("VERSION", *a))
-			fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
-		else {
-			if (n == 3 && !strcmp("=", a[1]))
-				define(*a, strtol(a[2], NULL, 0));
-			else
-				LC += crack(a, n);
-		}
-	}
-
-	backpatch();
-	output(ofile);
-
-	if (debug)
-		output(stderr);
-}
-
-int
-main(int argc, char **argv)
-{
-	int c;
-	int pid;
-	int ifile;
-	int status;
-	FILE *ofile;
-	char *ofilename;
-	int fd[2];
-
-	ofile = NULL;
-	ofilename = NULL;
-	while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
-		switch (c) {
-		    case 'd':
-			debug = !0;
-			break;
-		    case 'D':
-		    {
-			char *p;
-			if ((p = strchr(optarg, '=')) != NULL) {
-				*p = '\0';
-				define(optarg, strtol(p + 1, NULL, 0));
-			}
-			else
-				define(optarg, 1);
-			break;
-		    }
-		    case 'o':
-		        ofilename = optarg;
-			if ((ofile = fopen(ofilename, "w")) == NULL) {
-				perror(optarg);
-				exit(EXIT_FAILURE);
-			}
-			break;
-		    case 'h':
-			printf("usage: %s [-d] [-Dname] [-ooutput] input\n", 
-				*argv);
-			exit(EXIT_SUCCESS);
-			break;
-		    case 'v':
-			printf("%s\n", id);
-			exit(EXIT_SUCCESS);
-			break;
-		    default:
-			exit(EXIT_FAILURE);
-			break;
-		}
-	}
-
-	if (argc - optind != 1) {
-		fprintf(stderr, "%s: must have one input file\n", *argv);
-		exit(EXIT_FAILURE);
-	}
-	filename = argv[optind];
-
-	
-	if ((ifile = open(filename, O_RDONLY)) < 0) {
-		perror(filename);
-		exit(EXIT_FAILURE);
-	}
-
-	if (!ofilename) {
-		ofilename = ADOTOUT;
-		if ((ofile = fopen(ofilename, "w")) < 0) {
-			perror(ofilename);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	if (pipe(fd) < 0) {
-		perror("pipe failed");
-		exit(1);
-	}
-
-	if ((pid = fork()) < 0 ) {
-		perror("fork failed");
-		exit(1);
-	}
-	else if (pid > 0) {		/* Parent */
-		close(fd[1]);		/* Close write end */
-		if (fd[0] != STDIN_FILENO) {
-			if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
-				perror("dup2 error on stdin");
-				exit(EXIT_FAILURE);
-			}
-			close(fd[0]);
-		}
-		assemble(ofile);
-		if (wait(&status) < 0) {
-			perror("wait error");
-		}
-
-		if (status != 0) {
-			unlink(ofilename);
-		}
-		exit(status);
-	} else {				/* Child */
-                int i, arg_cnt, found;
-		char *args[MAX_ARGS];
-		char *buf;
-
-                arg_cnt = 0;
-                found = FALSE;
-                for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
-			char *bp;
-
-			buf = strdup(cpp[i]);
-
-			for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
-                             bp != NULL;
-                             bp = strtok(NULL, " \t\n"), arg_cnt++) {
-				if (arg_cnt == 0) {
-					if (access(bp, X_OK) == 0) {
-						found = TRUE;
-					}
-				}
-
-				args[arg_cnt] = bp;
-			}
-
-                        if (!found) {
-				free(buf);
-                        }
-                }
-		args[arg_cnt] = NULL;
-
-                if (found) {
-			close(fd[0]);		/* Close Read end */
-			if (fd[1] != STDOUT_FILENO) {
-				if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
-					perror("dup2 error on stdout");
-					exit(EXIT_FAILURE);
-				}
-				close(fd[1]);
-			}
-			if (ifile != STDIN_FILENO) {
-				if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
-					perror("dup2 error on stdin");
-					exit(EXIT_FAILURE);
-				}
-				close(ifile);
-			}
-
-			if (execvp(args[0], args) < 0) {
-				perror("execvp() error");
-				exit(EXIT_FAILURE);
-			}
-        	} else {
-			fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
-			exit(EXIT_FAILURE);
-		}
-	}
-	return(EXIT_SUCCESS);
-}
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.1.47/linux/drivers/scsi/aic7xxx_proc.c	Sun Oct 13 03:44:34 1996
+++ linux/drivers/scsi/aic7xxx_proc.c	Thu Jul 31 12:37:17 1997
@@ -24,7 +24,7 @@
  *
  *  Dean W. Gehnert, deang@teleport.com, 05/01/96
  *
- *  $Id: aic7xxx_proc.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
  *-M*************************************************************************/
 
 #define BLS buffer + len + size
@@ -77,16 +77,18 @@
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
   static u8 buff[512];
-  int   i; 
+  int   i;
+  int   found = FALSE;
   int   size = 0;
   int   len = 0;
   off_t begin = 0;
   off_t pos = 0;
   static char *bus_names[] = { "Single", "Twin", "Wide" };
-  static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-787x", "AIC-788x" };
+  static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
+      "AIC-787x", "AIC-788x" };
 
   HBAptr = NULL;
-  for (i = 0; i < NUMBER(aic7xxx_boards); i++)
+  for (i=0; i < NUMBER(aic7xxx_boards); i++)
   {
     if ((HBAptr = aic7xxx_boards[i]) != NULL)
     {
@@ -95,16 +97,23 @@
         break;
       }
 
-      while ((HBAptr->hostdata != NULL) &&
+      while ((HBAptr->hostdata != NULL) && !found &&
           ((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
       {
         if (HBAptr->host_no == hostno)
         {
-          break; break;
+          found = TRUE;
         }
       }
 
-      HBAptr = NULL;
+      if (!found)
+      {
+        HBAptr = NULL;
+      }
+      else
+      {
+        break;
+      }
     }
   }
 
@@ -129,8 +138,10 @@
 
   size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
   size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
-  size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_H_VERSION));
+  size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
+#if 0
   size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
+#endif
   len += size; pos = begin + len; size = 0;
 
   size += sprintf(BLS, "\n");
@@ -141,11 +152,6 @@
 #ifdef AIC7XXX_CMDS_PER_LUN
   size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
 #endif
-#ifdef AIC7XXX_TWIN_SUPPORT
-  size += sprintf(BLS, "  AIC7XXX_TWIN_SUPPORT   : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_TWIN_SUPPORT   : Disabled\n");
-#endif
 #ifdef AIC7XXX_TAGGED_QUEUEING
   size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
 #else
@@ -165,16 +171,18 @@
 
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
-  size += sprintf(BLS, "          SCSI Adapter: %s\n", board_names[p->type]);
+  size += sprintf(BLS, "          SCSI Adapter: %s\n",
+      board_names[p->chip_type]);
   size += sprintf(BLS, "                        (%s chipset)\n",
-      chip_names[p->chip_type]);
+      chip_names[p->chip_class]);
   size += sprintf(BLS, "              Host Bus: %s\n", bus_names[p->bus_type]);
   size += sprintf(BLS, "               Base IO: %#.4x\n", p->base);
+  size += sprintf(BLS, "        Base IO Memory: 0x%x\n", p->mbase);
   size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
   size += sprintf(BLS, "                  SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_link->numscbs, p->maxhscbs, p->maxscbs);
+      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
   size += sprintf(BLS, "            Interrupts: %d", p->isr_count);
-  if (p->chip_type == AIC_777x)
+  if (p->chip_class == AIC_777x)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.1.47/linux/drivers/scsi/aic7xxx_reg.h	Sun Oct 13 03:44:34 1996
+++ linux/drivers/scsi/aic7xxx_reg.h	Thu Jul 31 12:37:17 1997
@@ -1,771 +1,469 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
- * All rights reserved.
- *
- * 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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h
- *
- * $Id: aic7xxx_reg.h,v 4.0 1996/10/13 08:23:42 deang Exp $
- *-M*************************************************************************/
-
-/*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
-
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ			0x000
-#define		TEMODEO		0x80
-#define		ENSELO		0x40
-#define		ENSELI		0x20
-#define		ENRSELI		0x10
-#define		ENAUTOATNO	0x08
-#define		ENAUTOATNI	0x04
-#define		ENAUTOATNP	0x02
-#define		SCSIRSTO	0x01
-
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define	SXFRCTL0		0x001
-#define		DFON		0x80
-#define		DFPEXP		0x40
-#define		ULTRAEN		0x20
-#define		CLRSTCNT	0x10
-#define		SPIOEN		0x08
-#define		SCAMEN		0x04
-#define		CLRCHN		0x02
-/*  UNUSED			0x01 */
-
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define	SXFRCTL1		0x002
-#define		BITBUCKET	0x80
-#define		SWRAPEN		0x40
-#define		ENSPCHK		0x20
-#define		STIMESEL	0x18
-#define		ENSTIMER	0x04
-#define		ACTNEGEN	0x02
-#define		STPWEN		0x01	/* Powered Termination */
-
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI		0x003
-#define		CDI		0x80
-#define		IOI		0x40
-#define		MSGI		0x20
-#define		ATNI		0x10
-#define		SELI		0x08
-#define		BSYI		0x04
-#define		REQI		0x02
-#define		ACKI		0x01
-
-/*
- * Possible phases in SCSISIGI
- */
-#define		PHASE_MASK	0xe0
-#define		P_DATAOUT	0x00
-#define		P_DATAIN	0x40
-#define		P_COMMAND	0x80
-#define		P_MESGOUT	0xa0
-#define		P_STATUS	0xc0
-#define		P_MESGIN	0xe0
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus.  Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO		0x003
-#define		CDO		0x80
-#define		IOO		0x40
-#define		MSGO		0x20
-#define		ATNO		0x10
-#define		SELO		0x08
-#define		BSYO		0x04
-#define		REQO		0x02
-#define		ACKO		0x01
-
-/* 
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE		0x004
-#define		WIDEXFER	0x80		/* Wide transfer control */
-#define		SXFR		0x70		/* Sync transfer rate */
-#define		SOFS		0x0f		/* Sync offset */
-
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID			0x005
-#define		TID		0xf0		/* Target ID mask */
-#define		OID		0x0f		/* Our ID mask */
-
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode.  SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronous data phase transfer.
- */
-#define SCSIDATL		0x006
-#define SCSIDATH		0x007
-
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus.  The counter is decremented only once
- * the data has been safely transfered.  SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */ 
-#define STCNT			0x008
-#define STCNT0			0x008
-#define STCNT1			0x009
-#define STCNT2			0x00a
-
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define	CLRSINT0		0x00b
-#define		CLRSELDO	0x40
-#define		CLRSELDI	0x20
-#define		CLRSELINGO	0x10
-#define		CLRSWRAP	0x08
-/*  UNUSED			0x04 */
-#define		CLRSPIORDY	0x02
-/*  UNUSED			0x01 */
-
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0			0x00b
-#define		TARGET		0x80		/* Board acting as target */
-#define		SELDO		0x40		/* Selection Done */
-#define		SELDI		0x20		/* Board has been selected */
-#define		SELINGO		0x10		/* Selection In Progress */
-#define		SWRAP		0x08		/* 24bit counter wrap */
-#define		SDONE		0x04		/* STCNT = 0x000000 */
-#define		SPIORDY		0x02		/* SCSI PIO Ready */
-#define		DMADONE		0x01		/* DMA transfer completed */
-
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1		0x00c
-#define		CLRSELTIMEO	0x80
-#define		CLRATNO		0x40
-#define		CLRSCSIRSTI	0x20
-/*  UNUSED			0x10 */
-#define		CLRBUSFREE	0x08
-#define		CLRSCSIPERR	0x04
-#define		CLRPHASECHG	0x02
-#define		CLRREQINIT	0x01
-
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1			0x00c
-#define		SELTO		0x80
-#define		ATNTARG 	0x40
-#define		SCSIRSTI	0x20
-#define		PHASEMIS	0x10
-#define		BUSFREE		0x08
-#define		SCSIPERR	0x04
-#define		PHASECHG	0x02
-#define		REQINIT		0x01
-
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define	SIMODE1			0x011
-#define		ENSELTIMO	0x80
-#define		ENATNTARG	0x40
-#define		ENSCSIRST	0x20
-#define		ENPHASEMIS	0x10
-#define		ENBUSFREE	0x08
-#define		ENSCSIPERR	0x04
-#define		ENPHASECHG	0x02
-#define		ENREQINIT	0x01
-
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define	SCSIBUSL		0x012
-#define	SCSIBUSH		0x013
-
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus.  They are counted up in the same
- * manner as STCNT is counted down.  SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be skewed by write ahead.
- */
-#define	SHADDR			0x014
-#define	SHADDR0			0x014
-#define	SHADDR1			0x015
-#define	SHADDR2			0x016
-#define	SHADDR3			0x017
-
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID			0x019
-#define		SELID_MASK	0xf0
-#define		ONEBIT		0x08
-/*  UNUSED			0x07 */
-
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection.  In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL			0x01f
-#define		DIAGLEDEN	0x80	/* Aic78X0 only */
-#define		DIAGLEDON	0x40	/* Aic78X0 only */
-#define		AUTOFLUSHDIS	0x20
-/*  UNUSED			0x10 */
-#define		SELBUS_MASK	0x0a
-#define		SELBUSB		0x08
-/*  UNUSED			0x04 */
-#define		SELWIDE		0x02
-/*  UNUSED			0x01 */
-#define		SELNARROW	0x00
-
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL			0x060
-#define		PERRORDIS	0x80
-#define		PAUSEDIS	0x40
-#define		FAILDIS		0x20
-#define 	FASTMODE	0x10
-#define		BRKADRINTEN	0x08
-#define		STEP		0x04
-#define		SEQRESET	0x02
-#define		LOADRAM		0x01
-
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
- * four bytes in succession.  The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM			0x061
-
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0		0x062
-#define SEQADDR1		0x063
-#define 	SEQADDR1_MASK	0x01
-
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM			0x064
-
-#define SINDEX			0x065
-#define DINDEX			0x066
-#define ALLZEROS		0x06a
-#define NONE			0x06a
-#define SINDIR			0x06c
-#define DINDIR			0x06d
-#define FUNCTION1		0x06e
-
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#define HADDR			0x088
-#define HADDR0			0x088
-#define HADDR1			0x089
-#define HADDR2			0x08a
-#define HADDR3			0x08b
-
-#define HCNT			0x08c
-#define HCNT0			0x08c
-#define HCNT1			0x08d
-#define HCNT2			0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR			0x090
-
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL			0x084
-/*   RSVD			0xf0 */
-#define		ACE		0x08	/* Support for external processors */
-/*   RSVD			0x06 */
-#define		ENABLE		0x01
-
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define	DSCOMMAND		0x084
-#define		CACHETHEN	0x80	/* Cache Threshold enable */
-#define		DPARCKEN	0x40	/* Data Parity Check Enable */
-#define		MPARCKEN	0x20	/* Memory Parity Check Enable */
-#define		EXTREQLCK	0x10	/* External Request Lock */
-
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME			0x085
-#define		BOFF		0xf0
-#define		BON		0x0f
-
-/*
- * Bus Speed (p. 3-45)
- */
-#define	BUSSPD			0x086
-#define		DFTHRSH		0xc0
-#define		STBOFF		0x38
-#define		STBON		0x07
-#define		DFTHRSH_100	0xc0
-
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-#define HCNTRL			0x087
-/*    UNUSED			0x80 */
-#define		POWRDN		0x40
-/*    UNUSED			0x20 */
-#define		SWINT		0x10
-#define		IRQMS		0x08
-#define		PAUSE		0x04
-#define		INTEN		0x02
-#define		CHIPRST		0x01
-#define		CHIPRSTACK	0x01
-
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT			0x091
-#define		SEQINT_MASK	0xf1		/* SEQINT Status Codes */
-#define			BAD_PHASE	0x01	/* unknown scsi bus phase */
-#define			SEND_REJECT	0x11	/* sending a message reject */
-#define			NO_IDENT	0x21	/* no IDENTIFY after reconnect*/
-#define			NO_MATCH	0x31	/* no cmd match for reconnect */
-#define			SDTR_MSG	0x41	/* SDTR message received */
-#define			WDTR_MSG	0x51	/* WDTR message received */
-#define			REJECT_MSG	0x61	/* Reject message received */
-#define			BAD_STATUS	0x71	/* Bad status from target */
-#define			RESIDUAL	0x81	/* Residual byte count != 0 */
-#define			ABORT_TAG	0x91	/* Sent an ABORT_TAG message */
-#define			AWAITING_MSG	0xa1	/*
-						 * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-#define			IMMEDDONE	0xb1	/*
-						 * An immediate command has
-						 * completed
-						 */
-#define			MSG_BUFFER_BUSY	0xc1	/*
-						 * Sequencer wants to use the
-						 * message buffer, but it
-						 * already contains a message
-						 */
-#define			MSGIN_PHASEMIS	0xd1	/*
-						 * Target changed phase on us
-						 * when we were expecting
-						 * another msgin byte.
-						 */
-#define			DATA_OVERRUN	0xe1	/*
-						 * Target attempted to write
-						 * beyond the bounds of its
-						 * command.
-						 */
-#define 	BRKADRINT 0x08
-#define		SCSIINT	  0x04
-#define		CMDCMPLT  0x02
-#define		SEQINT    0x01
-#define		INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
-
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors.  You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR			0x092
-/*    UNUSED			0xf0 */
-#define		PARERR		0x08
-#define		ILLOPCODE	0x04
-#define		ILLSADDR	0x02
-#define		ILLHADDR	0x01
-
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT			0x092
-#define		CLRBRKADRINT	0x08
-#define		CLRSCSIINT      0x04
-#define		CLRCMDINT 	0x02
-#define		CLRSEQINT 	0x01
-
-#define	DFCNTRL			0x093
-#define		WIDEODD		0x40
-#define		SCSIEN		0x20
-#define		SDMAEN		0x10
-#define		SDMAENACK	0x10
-#define		HDMAEN		0x08
-#define		HDMAENACK	0x08
-#define		DIRECTION	0x04
-#define		FIFOFLUSH	0x02
-#define		FIFORESET	0x01
-
-#define	DFSTATUS		0x094
-#define		HDONE		0x08
-#define		FIFOEMP		0x01
-
-#define	DFDAT			0x099
-
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT			0x09a
-#define		SCBAUTO		0x80
-#define		SCBCNT_MASK	0x1f
-
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the sequencer has yet to start)
- */
-#define QINFIFO			0x09b
-
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT			0x09c
-
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO		0x09d
-
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT			0x09e
-
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requeued because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR respectively when starting this command.
- */
-#define SCBARRAY		0x0a0
-#define	SCB_CONTROL		0x0a0
-#define		NEEDWDTR        0x80
-#define		DISCENB         0x40
-#define		TAG_ENB		0x20
-#define		NEEDSDTR	0x10
-#define		DISCONNECTED	0x04
-#define		SCB_TAG_TYPE	0x03
-#define	SCB_TCL			0x0a1
-#define	SCB_TARGET_STATUS	0x0a2
-#define	SCB_SGCOUNT		0x0a3
-#define	SCB_SGPTR		0x0a4
-#define		SCB_SGPTR0	0x0a4
-#define		SCB_SGPTR1	0x0a5
-#define		SCB_SGPTR2	0x0a6
-#define		SCB_SGPTR3	0x0a7
-#define	SCB_RESID_SGCNT		0x0a8
-#define SCB_RESID_DCNT		0x0a9
-#define		SCB_RESID_DCNT0	0x0a9
-#define		SCB_RESID_DCNT1	0x0aa
-#define		SCB_RESID_DCNT2	0x0ab
-#define SCB_DATAPTR		0x0ac
-#define		SCB_DATAPTR0	0x0ac
-#define		SCB_DATAPTR1	0x0ad
-#define		SCB_DATAPTR2	0x0ae
-#define		SCB_DATAPTR3	0x0af
-#define	SCB_DATACNT		0x0b0
-#define		SCB_DATACNT0	0x0b0
-#define		SCB_DATACNT1	0x0b1
-#define		SCB_DATACNT2	0x0b2
-/* UNUSED - QUAD PADDING	0x0b3 */
-#define SCB_CMDPTR		0x0b4
-#define		SCB_CMDPTR0	0x0b4
-#define		SCB_CMDPTR1	0x0b5
-#define		SCB_CMDPTR2	0x0b6
-#define		SCB_CMDPTR3	0x0b7
-#define	SCB_CMDLEN		0x0b8
-#define SCB_TAG			0x0b9
-#define	SCB_NEXT		0x0ba
-#define	SCB_PREV		0x0bb
-
-#define	SG_SIZEOF		0x08		/* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define	SEECTL_2840		0x0c0
-/*	UNUSED			0xf8 */
-#define		CS_2840		0x04
-#define		CK_2840		0x02
-#define		DO_2840		0x01
-
-#define	STATUS_2840		0x0c1
-#define		EEPROM_TF	0x80
-#define		BIOS_SEL	0x60
-#define		ADSEL		0x1e
-#define		DI_2840		0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS		0x086
-
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  
- *
- * After successful arbitration for the memory port, the SEECS bit of 
- * the SEECTL register is connected to the chip select.  The SEECK, 
- * SEEDO, and SEEDI are connected to the clock, data out, and data in 
- * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
- * gives us an 800 nsec timer.  After a write to the SEECTL register, 
- * the SEERDY goes high 800 nsec later.  The one exception to this is 
- * when we first request access to the memory port.  The SEERDY goes 
- * high to signify that access has been granted and, for this case, has 
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to 
- * read the serial EEPROM.
- */
-#define SEECTL			0x01e
-#define		EXTARBACK	0x80
-#define		EXTARBREQ	0x40
-#define		SEEMS		0x20
-#define		SEERDY		0x10
-#define		SEECS		0x08
-#define		SEECK		0x04
-#define		SEEDO		0x02
-#define		SEEDI		0x01
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, 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).  The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space.  This should work regardless of
- * whether the bios has been installed.
- */
-
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH		0x020
-
-/*
- * The sequencer will stick the frist byte of any rejected message here so
- * we can see what is getting thrown away.  Extended messages put the
- * extended message type in REJBYTE_EXT.
- */
-#define REJBYTE			0x030
-#define REJBYTE_EXT		0x031
-
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define	DISC_DSB		0x032
-#define		DISC_DSB_A	0x032
-#define		DISC_DSB_B	0x033
-
-/*
- * Length of pending message
- */
-#define MSG_LEN			0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0			0x035
-#define		COMP_MSG0	0xcb      /* 2's complement of MSG0 */
-#define MSG1			0x036
-#define MSG2			0x037
-#define MSG3			0x038
-#define MSG4			0x039
-#define MSG5			0x03a
-#define MSG6			0x03b
-#define MSG7			0x03c
-
 /*
- * These are offsets into the card's scratch ram.  Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define LASTPHASE		0x03d
-#define ARG_1			0x03e
-#define		MAXOFFSET	0x01
-#define RETURN_1		0x03f
-#define		SEND_WDTR	0x80
-#define		SEND_SDTR	0x60
-#define		SEND_SENSE	0x40
-#define		SEND_REJ	0x20
-#define		SCB_PAGEDIN	0x10
-
-#define SIGSTATE		0x040
-
-#define DMAPARAMS		0x041	/* Parameters for DMA Logic */
-
-#define	SG_COUNT		0x042
-#define	SG_NEXT			0x043	/* working value of SG pointer */
-#define		SG_NEXT0	0x043
-#define		SG_NEXT1	0x044
-#define		SG_NEXT2	0x045
-#define		SG_NEXT3	0x046
-
-#define	SCBCOUNT		0x047	/*
-					 * Number of SCBs supported by
-					 * this card.
-					 */
-#define	COMP_SCBCOUNT		0x048	/*
-					 * Two's compliment of SCBCOUNT
-					 */
-#define QCNTMASK		0x049	/*
-					 * Mask of bits to test against
-					 * when looking at the Queue Count
-					 * registers.  Works around a bug
-					 * on aic7850 chips. 
-					 */
-#define FLAGS			0x04a
-#define		SINGLE_BUS	0x00
-#define		TWIN_BUS	0x01
-#define		WIDE_BUS	0x02
-#define		PAGESCBS	0x04
-#define		DPHASE		0x10
-#define		SELECTED	0x20
-#define		IDENTIFY_SEEN	0x40
-#define		RESELECTED	0x80
-
-#define	SAVED_TCL		0x04b	/*
-					 * Temporary storage for the
-					 * target/channel/lun of a
-					 * reconnecting target
-					 */
-#define	ACTIVE_A		0x04c
-#define	ACTIVE_B		0x04d
-#define WAITING_SCBH		0x04e	/*
-					 * head of list of SCBs awaiting
-					 * selection
-					 */
-#define DISCONNECTED_SCBH	0x04f	/*
-					 * head of list of SCBs that are
-					 * disconnected.  Used for SCB
-					 * paging.
-					 */
-#define		SCB_LIST_NULL	0xff
-
-#define SAVED_LINKPTR		0x050
-#define SAVED_SCBPTR		0x051
-#define ULTRA_ENB		0x052
-#define ULTRA_ENB_B		0x053
-
-#define SCSICONF		0x05a
-#define		RESET_SCSI	0x40
-
-#define HOSTCONF		0x05d
-
-#define HA_274_BIOSCTRL		0x05f
-#define BIOSMODE		0x30
-#define BIOSDISABLED		0x30
-#define CHANNEL_B_PRIMARY	0x08
-
-/* Message codes */
-#define MSG_EXTENDED		0x01
-#define		MSG_SDTR	0x01
-#define		MSG_WDTR	0x03
-#define MSG_SDPTRS		0x02
-#define MSG_RDPTRS		0x03
-#define MSG_DISCONNECT		0x04
-#define MSG_INITIATOR_DET_ERROR	0x05
-#define MSG_ABORT		0x06
-#define	MSG_REJECT		0x07
-#define MSG_NOP			0x08
-#define MSG_MSG_PARITY_ERROR	0x09
-#define MSG_BUS_DEVICE_RESET	0x0c
-#define MSG_ABORT_TAG		0x0d
-#define MSG_SIMPLE_TAG		0x20
-#define MSG_IDENTIFY		0x80
-
-/* WDTR Message values */
-#define	BUS_8_BIT		0x00
-#define BUS_16_BIT		0x01
-#define BUS_32_BIT		0x02
+  * DO NOT EDIT - This file is automatically generated.
+  */
 
-#define MAX_OFFSET_8BIT		0x0f
-#define MAX_OFFSET_16BIT	0x08
+#define	SCSISEQ         		0x00
+#define		TEMODE          	0x80
+#define		ENSELO          	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		ENAUTOATNO      	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNP      	0x02
+#define		SCSIRSTO        	0x01
+
+#define	SXFRCTL0        		0x01
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		FAST20          	0x20
+#define		CLRSTCNT        	0x10
+#define		SPIOEN          	0x08
+#define		SCAMEN          	0x04
+#define		CLRCHN          	0x02
+
+#define	SXFRCTL1        		0x02
+#define		BITBUCKET       	0x80
+#define		SWRAPEN         	0x40
+#define		ENSPCHK         	0x20
+#define		STIMESEL        	0x18
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	SCSISIGO        		0x03
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	SCSISIGI        		0x03
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIRATE        		0x04
+#define		WIDEXFER        	0x80
+#define		SXFR            	0x70
+#define		SOFS            	0x0f
+
+#define	SCSIID          		0x05
+#define		OID             	0x0f
+
+#define	SCSIDATL        		0x06
+
+#define	SCSIDATH        		0x07
+
+#define	STCNT           		0x08
+
+#define	CLRSINT0        		0x0b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRSWRAP        	0x08
+#define		CLRSPIORDY      	0x02
+
+#define	SSTAT0          		0x0b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		SWRAP           	0x08
+#define		SDONE           	0x04
+#define		SPIORDY         	0x02
+#define		DMADONE         	0x01
+
+#define	CLRSINT1        		0x0c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRPHASECHG     	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x0c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		PHASECHG        	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x0d
+#define		OVERRUN         	0x80
+#define		SFCNT           	0x1f
+
+#define	SSTAT3          		0x0e
+#define		SCSICNT         	0xf0
+#define		OFFCNT          	0x0f
+
+#define	SCSITEST        		0x0f
+#define		RQAKCNT         	0x04
+#define		CNTRTEST        	0x02
+#define		CMODE           	0x01
+
+#define	SIMODE0         		0x10
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENSWRAP         	0x08
+#define		ENSDONE         	0x04
+#define		ENSPIORDY       	0x02
+#define		ENDMADONE       	0x01
+
+#define	SIMODE1         		0x11
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENPHASECHG      	0x02
+#define		ENREQINIT       	0x01
+
+#define	SCSIBUSL        		0x12
+
+#define	SCSIBUSH        		0x13
+
+#define	SHADDR          		0x14
+
+#define	SELTIMER        		0x18
+#define		STAGE6          	0x20
+#define		STAGE5          	0x10
+#define		STAGE4          	0x08
+#define		STAGE3          	0x04
+#define		STAGE2          	0x02
+#define		STAGE1          	0x01
+
+#define	SELID           		0x19
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	BRDCTL          		0x1d
+#define		BRDDAT7         	0x80
+#define		BRDDAT6         	0x40
+#define		BRDDAT5         	0x20
+#define		BRDSTB          	0x10
+#define		BRDCS           	0x08
+#define		BRDRW           	0x04
+#define		BRDCTL1         	0x02
+#define		BRDCTL0         	0x01
+
+#define	SEECTL          		0x1e
+#define		EXTARBACK       	0x80
+#define		EXTARBREQ       	0x40
+#define		SEEMS           	0x20
+#define		SEERDY          	0x10
+#define		SEECS           	0x08
+#define		SEECK           	0x04
+#define		SEEDO           	0x02
+#define		SEEDI           	0x01
+
+#define	SBLKCTL         		0x1f
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		AUTOFLUSHDIS    	0x20
+#define		SELWIDE         	0x02
+
+#define	SRAM_BASE       		0x20
+
+#define	TARG_SCRATCH    		0x20
+
+#define	ULTRA_ENB       		0x30
+
+#define	DISC_DSB        		0x32
+
+#define	MSG_LEN         		0x34
+
+#define	MSG_OUT         		0x35
+
+#define	DMAPARAMS       		0x3d
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAENACK       	0x10
+#define		SDMAEN          	0x10
+#define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SCBCOUNT        		0x3e
+
+#define	COMP_SCBCOUNT   		0x3f
+
+#define	QCNTMASK        		0x40
+
+#define	SEQ_FLAGS       		0x41
+#define		RESELECTED      	0x80
+#define		IDENTIFY_SEEN   	0x40
+#define		TAGGED_SCB      	0x20
+#define		DPHASE          	0x10
+#define		PAGESCBS        	0x04
+#define		WIDE_BUS        	0x02
+#define		TWIN_BUS        	0x01
+
+#define	SAVED_TCL       		0x42
+
+#define	SG_COUNT        		0x43
+
+#define	SG_NEXT         		0x44
+
+#define	WAITING_SCBH    		0x48
+
+#define	SAVED_LINKPTR   		0x49
+
+#define	SAVED_SCBPTR    		0x4a
+
+#define	REJBYTE         		0x4b
+
+#define	LASTPHASE       		0x4c
+#define		P_MESGIN        	0xe0
+#define		PHASE_MASK      	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		P_DATAIN        	0x40
+#define		MSGI            	0x20
+#define		P_BUSFREE       	0x01
+#define		P_DATAOUT       	0x00
+
+#define	MSGIN_EXT_LEN   		0x4d
+
+#define	MSGIN_EXT_OPCODE		0x4e
+
+#define	MSGIN_EXT_BYTES 		0x4f
+
+#define	DISCONNECTED_SCBH		0x52
+
+#define	FREE_SCBH       		0x53
+
+#define	HSCB_ADDR       		0x54
+
+#define	CUR_SCBID       		0x58
+
+#define	ARG_1           		0x59
+#define	RETURN_1        		0x59
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+
+#define	SCSICONF        		0x5a
+#define		RESET_SCSI      	0x40
+
+#define	HOSTCONF        		0x5d
+
+#define	HA_274_BIOSCTRL 		0x5f
+#define		BIOSMODE        	0x30
+#define		BIOSDISABLED    	0x30
+#define		CHANNEL_B_PRIMARY	0x08
+
+#define	SEQCTL          		0x60
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQRAM          		0x61
+
+#define	SEQADDR0        		0x62
+
+#define	SEQADDR1        		0x63
+#define		SEQADDR1_MASK   	0x01
+
+#define	ACCUM           		0x64
+
+#define	SINDEX          		0x65
+
+#define	DINDEX          		0x66
+
+#define	ALLONES         		0x69
+
+#define	ALLZEROS        		0x6a
+
+#define	NONE            		0x6a
+
+#define	FLAGS           		0x6b
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SINDIR          		0x6c
+
+#define	DINDIR          		0x6d
+
+#define	FUNCTION1       		0x6e
+
+#define	STACK           		0x6f
+
+#define	BCTL            		0x84
+#define		ACE             	0x08
+#define		ENABLE          	0x01
+
+#define	DSCOMMAND       		0x84
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+
+#define	BUSTIME         		0x85
+#define		BOFF            	0xf0
+#define		BON             	0x0f
+
+#define	BUSSPD          		0x86
+#define		DFTHRSH_100     	0xc0
+#define		DFTHRSH         	0xc0
+#define		STBOFF          	0x38
+#define		STBON           	0x07
+
+#define	DSPCISTATUS     		0x86
+
+#define	HCNTRL          		0x87
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		IRQMS           	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HADDR           		0x88
+
+#define	HCNT            		0x8c
+
+#define	SCBPTR          		0x90
+
+#define	INTSTAT         		0x91
+#define		SEQINT_MASK     	0xf1
+#define		DATA_OVERRUN    	0xe1
+#define		MSGIN_PHASEMIS  	0xd1
+#define		MSG_BUFFER_BUSY 	0xc1
+#define		AWAITING_MSG    	0xa1
+#define		ABORT_CMDCMPLT  	0x91
+#define		RESIDUAL        	0x81
+#define		BAD_STATUS      	0x71
+#define		REJECT_MSG      	0x61
+#define		NO_MATCH_BUSY   	0x51
+#define		EXTENDED_MSG    	0x41
+#define		NO_MATCH        	0x31
+#define		NO_IDENT        	0x21
+#define		SEND_REJECT     	0x11
+#define		INT_PEND        	0x0f
+#define		BRKADRINT       	0x08
+#define		SCSIINT         	0x04
+#define		CMDCMPLT        	0x02
+#define		BAD_PHASE       	0x01
+#define		SEQINT          	0x01
+
+#define	CLRINT          		0x92
+#define		CLRBRKADRINT    	0x08
+#define		CLRSCSIINT      	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSEQINT       	0x01
+
+#define	ERROR           		0x92
+#define		PARERR          	0x08
+#define		ILLOPCODE       	0x04
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
+#define	DFCNTRL         		0x93
+
+#define	DFSTATUS        		0x94
+#define		DWORDEMP        	0x20
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	DFDAT           		0x99
+
+#define	SCBCNT          		0x9a
+#define		SCBAUTO         	0x80
+#define		SCBCNT_MASK     	0x1f
+
+#define	QINFIFO         		0x9b
+
+#define	QINCNT          		0x9c
+
+#define	QOUTFIFO        		0x9d
+
+#define	QOUTCNT         		0x9e
+
+#define	SCB_CONTROL     		0xa0
+#define		MK_MESSAGE      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		MUST_DMAUP_SCB  	0x10
+#define		ABORT_SCB       	0x08
+#define		DISCONNECTED    	0x04
+#define		SCB_TAG_TYPE    	0x03
+
+#define	SCB_BASE        		0xa0
+
+#define	SCB_TCL         		0xa1
+#define		TID             	0xf0
+#define		SELBUSB         	0x08
+#define		LID             	0x07
+
+#define	SCB_TARGET_STATUS		0xa2
+
+#define	SCB_SGCOUNT     		0xa3
+
+#define	SCB_SGPTR       		0xa4
+
+#define	SCB_RESID_SGCNT 		0xa8
+
+#define	SCB_RESID_DCNT  		0xa9
+
+#define	SCB_DATAPTR     		0xac
+
+#define	SCB_DATACNT     		0xb0
+
+#define	SCB_LINKED_NEXT 		0xb3
+
+#define	SCB_CMDPTR      		0xb4
+
+#define	SCB_CMDLEN      		0xb8
+
+#define	SCB_TAG         		0xb9
+
+#define	SCB_NEXT        		0xba
+
+#define	SCB_PREV        		0xbb
+
+#define	SCB_BUSYTARGETS 		0xbc
+
+#define	SEECTL_2840     		0xc0
+#define		CS_2840         	0x04
+#define		CK_2840         	0x02
+#define		DO_2840         	0x01
+
+#define	STATUS_2840     		0xc1
+#define		EEPROM_TF       	0x80
+#define		BIOS_SEL        	0x60
+#define		ADSEL           	0x1e
+#define		DI_2840         	0x01
+
+
+#define	BUS_8_BIT	0x00
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_16_BIT	0x01
+#define	MAX_OFFSET_16BIT	0x08
+#define	SCB_LIST_NULL	0xff
+#define	SG_SIZEOF	0x08
+#define	BUS_32_BIT	0x02
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/aic7xxx_seq.h linux/drivers/scsi/aic7xxx_seq.h
--- v2.1.47/linux/drivers/scsi/aic7xxx_seq.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_seq.h	Sun Aug  3 19:39:57 1997
@@ -0,0 +1,479 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+static u_int8_t seqprog[] = {
+	0xff, 0x6a, 0x03, 0x02,
+	0x12, 0x6a, 0x00, 0x00,
+	0x00, 0x65, 0x6f, 0x16,
+	0x40, 0x0b, 0x3c, 0x1a,
+	0x20, 0x0b, 0x37, 0x1a,
+	0x40, 0x00, 0x03, 0x1a,
+	0x08, 0x1f, 0x1f, 0x04,
+	0x40, 0x0b, 0x3c, 0x1a,
+	0x20, 0x0b, 0x37, 0x1a,
+	0x40, 0x00, 0x03, 0x1a,
+	0x08, 0x1f, 0x1f, 0x04,
+	0xff, 0x48, 0x2c, 0x18,
+	0xff, 0x40, 0x64, 0x02,
+	0x00, 0x9c, 0x03, 0x1e,
+	0x00, 0x6a, 0xaa, 0x17,
+	0xff, 0x65, 0x03, 0x1c,
+	0xff, 0x9b, 0x58, 0x02,
+	0xff, 0x58, 0x90, 0x02,
+	0x0d, 0x6a, 0x3d, 0x00,
+	0x00, 0x58, 0x74, 0x17,
+	0x28, 0xa0, 0x2a, 0x1a,
+	0x50, 0x6a, 0x60, 0x00,
+	0xff, 0x90, 0x4a, 0x02,
+	0x00, 0xa1, 0x9e, 0x17,
+	0xff, 0x6c, 0x59, 0x02,
+	0xff, 0x59, 0x27, 0x1c,
+	0xff, 0x4a, 0x90, 0x02,
+	0x00, 0x65, 0xa7, 0x17,
+	0x00, 0x6a, 0x4f, 0x17,
+	0xff, 0x65, 0x1f, 0x18,
+	0x51, 0x6a, 0x91, 0x00,
+	0xff, 0x58, 0xb3, 0x02,
+	0x00, 0x65, 0xb8, 0x17,
+	0x10, 0x6a, 0x60, 0x00,
+	0x00, 0x65, 0x03, 0x10,
+	0xff, 0x59, 0x90, 0x02,
+	0xff, 0x58, 0xb3, 0x02,
+	0x10, 0x6a, 0x60, 0x00,
+	0x00, 0x65, 0x03, 0x10,
+	0xff, 0x58, 0x6d, 0x02,
+	0xff, 0x4a, 0x90, 0x02,
+	0x10, 0x6a, 0x60, 0x00,
+	0xff, 0x48, 0xba, 0x02,
+	0xff, 0x90, 0x48, 0x02,
+	0xff, 0x48, 0x90, 0x02,
+	0x00, 0x65, 0x2f, 0x16,
+	0x00, 0x65, 0x03, 0x10,
+	0xf7, 0x1f, 0x65, 0x02,
+	0x08, 0xa1, 0x64, 0x02,
+	0x00, 0x65, 0x65, 0x00,
+	0xff, 0x65, 0x1f, 0x02,
+	0xf0, 0xa1, 0x64, 0x02,
+	0x0f, 0x05, 0x05, 0x02,
+	0x00, 0x05, 0x05, 0x00,
+	0x5a, 0x6a, 0x00, 0x01,
+	0xff, 0x6a, 0x34, 0x02,
+	0x20, 0x6a, 0x0b, 0x00,
+	0xf0, 0x19, 0x42, 0x02,
+	0x80, 0x41, 0x41, 0x00,
+	0x00, 0x65, 0x4c, 0x10,
+	0x12, 0x6a, 0x00, 0x00,
+	0x40, 0x6a, 0x0b, 0x00,
+	0xff, 0x48, 0x90, 0x02,
+	0xff, 0xba, 0x48, 0x02,
+	0xff, 0xa1, 0x42, 0x02,
+	0x07, 0xa1, 0x35, 0x02,
+	0x40, 0xa0, 0x64, 0x02,
+	0x00, 0x35, 0x35, 0x00,
+	0x80, 0x35, 0x35, 0x00,
+	0x01, 0x6a, 0x34, 0x00,
+	0x20, 0xa0, 0x4a, 0x1e,
+	0x23, 0xa0, 0x36, 0x02,
+	0xff, 0xb9, 0x37, 0x02,
+	0x02, 0x34, 0x34, 0x06,
+	0x80, 0xa0, 0x4c, 0x1e,
+	0xa1, 0x6a, 0x91, 0x00,
+	0x08, 0x6a, 0x0c, 0x00,
+	0x08, 0x11, 0x11, 0x00,
+	0x1a, 0x01, 0x01, 0x00,
+	0x31, 0x6a, 0x65, 0x00,
+	0x80, 0x42, 0x52, 0x1a,
+	0xff, 0x65, 0x65, 0x06,
+	0xff, 0x42, 0x6e, 0x02,
+	0xff, 0x6e, 0x64, 0x02,
+	0x00, 0x6c, 0x56, 0x1e,
+	0x20, 0x01, 0x01, 0x00,
+	0x4c, 0x42, 0x64, 0x0a,
+	0x08, 0x1f, 0x5a, 0x1e,
+	0x08, 0x42, 0x42, 0x00,
+	0x08, 0x64, 0x64, 0x00,
+	0x20, 0x64, 0x65, 0x06,
+	0xff, 0x6c, 0x04, 0x02,
+	0x01, 0x0c, 0x5c, 0x1e,
+	0x04, 0x0c, 0x5c, 0x1a,
+	0xe0, 0x03, 0x64, 0x02,
+	0xff, 0x64, 0x4c, 0x02,
+	0xff, 0x64, 0x03, 0x02,
+	0x00, 0x6a, 0x74, 0x1c,
+	0x40, 0x64, 0x79, 0x1c,
+	0x80, 0x64, 0xa5, 0x1c,
+	0xa0, 0x64, 0xb0, 0x1c,
+	0xc0, 0x64, 0xad, 0x1c,
+	0xe0, 0x64, 0xc3, 0x1c,
+	0x01, 0x6a, 0x91, 0x00,
+	0x00, 0x65, 0x5c, 0x10,
+	0xf7, 0x11, 0x11, 0x02,
+	0x00, 0x65, 0x6f, 0x16,
+	0xff, 0x06, 0x6a, 0x02,
+	0x09, 0x0c, 0x6c, 0x1e,
+	0x08, 0x0c, 0x03, 0x1a,
+	0x01, 0x6a, 0x91, 0x00,
+	0xff, 0x6a, 0x93, 0x02,
+	0xff, 0x6a, 0x04, 0x02,
+	0xdf, 0x01, 0x01, 0x02,
+	0x01, 0x6a, 0x4c, 0x00,
+	0x0f, 0x41, 0x41, 0x03,
+	0x7d, 0x6a, 0x3d, 0x00,
+	0x00, 0x65, 0x7a, 0x10,
+	0x08, 0x6a, 0x66, 0x00,
+	0xa9, 0x6a, 0x71, 0x17,
+	0x00, 0x65, 0x82, 0x10,
+	0x79, 0x6a, 0x3d, 0x00,
+	0x00, 0x65, 0x4c, 0x17,
+	0x10, 0x41, 0x76, 0x1a,
+	0x88, 0x6a, 0x66, 0x00,
+	0xac, 0x6a, 0x6d, 0x17,
+	0x00, 0x65, 0x6a, 0x17,
+	0xff, 0xa3, 0x43, 0x02,
+	0x44, 0x6a, 0x66, 0x00,
+	0xa4, 0x6a, 0x70, 0x17,
+	0xff, 0x43, 0x88, 0x1a,
+	0x80, 0x02, 0x02, 0x00,
+	0xff, 0x6a, 0x8c, 0x00,
+	0xff, 0x6a, 0x8d, 0x00,
+	0xff, 0x6a, 0x8e, 0x00,
+	0x00, 0x65, 0x6a, 0x17,
+	0x01, 0x43, 0x8a, 0x18,
+	0xbf, 0x3d, 0x3d, 0x02,
+	0x00, 0x3d, 0x41, 0x17,
+	0x80, 0x02, 0xa2, 0x1a,
+	0xff, 0x65, 0x9c, 0x1e,
+	0xff, 0x43, 0x43, 0x06,
+	0xff, 0x43, 0x9c, 0x1e,
+	0xff, 0x6a, 0x64, 0x02,
+	0x08, 0x44, 0x44, 0x06,
+	0x00, 0x45, 0x45, 0x08,
+	0x88, 0x6a, 0x66, 0x00,
+	0x44, 0x6a, 0x70, 0x17,
+	0x08, 0x6a, 0x8c, 0x00,
+	0xff, 0x6a, 0x8d, 0x02,
+	0xff, 0x6a, 0x8e, 0x02,
+	0x0d, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0x9a, 0x17,
+	0x88, 0x6a, 0x92, 0x17,
+	0x00, 0x65, 0x6a, 0x17,
+	0x10, 0x0c, 0x82, 0x1e,
+	0xff, 0x08, 0xa9, 0x02,
+	0xff, 0x09, 0xaa, 0x02,
+	0xff, 0x0a, 0xab, 0x02,
+	0xff, 0x43, 0xa8, 0x02,
+	0x10, 0x41, 0x41, 0x00,
+	0x00, 0x65, 0x5c, 0x10,
+	0x7f, 0x02, 0x02, 0x02,
+	0xe1, 0x6a, 0x91, 0x00,
+	0x00, 0x65, 0x5c, 0x10,
+	0x00, 0x65, 0x4c, 0x17,
+	0x88, 0x6a, 0x66, 0x00,
+	0xb4, 0x6a, 0x6f, 0x17,
+	0xff, 0x6a, 0x8d, 0x02,
+	0xff, 0x6a, 0x8e, 0x02,
+	0x00, 0x65, 0x6a, 0x17,
+	0x3d, 0x6a, 0x41, 0x17,
+	0x00, 0x65, 0x5c, 0x10,
+	0x00, 0x65, 0x4c, 0x17,
+	0xff, 0x06, 0xa2, 0x02,
+	0x00, 0x65, 0x5c, 0x10,
+	0xff, 0x34, 0xb2, 0x1a,
+	0x08, 0x6a, 0x2f, 0x17,
+	0x35, 0x6a, 0x65, 0x00,
+	0xff, 0x34, 0x66, 0x02,
+	0x01, 0x0c, 0xb4, 0x1e,
+	0x04, 0x0c, 0xb4, 0x1a,
+	0xe0, 0x03, 0x4c, 0x02,
+	0xa0, 0x4c, 0xc0, 0x18,
+	0xff, 0x66, 0xbb, 0x1a,
+	0x10, 0x4c, 0x03, 0x00,
+	0x00, 0x65, 0xb2, 0x10,
+	0x01, 0x66, 0xbd, 0x18,
+	0x40, 0x6a, 0x0c, 0x00,
+	0xff, 0x66, 0x66, 0x06,
+	0xff, 0x6c, 0x06, 0x02,
+	0x00, 0x65, 0xb4, 0x10,
+	0x40, 0x6a, 0x0c, 0x00,
+	0xff, 0x6a, 0x34, 0x02,
+	0x00, 0x65, 0x5c, 0x10,
+	0x64, 0x6a, 0x3c, 0x17,
+	0xff, 0x64, 0x4b, 0x02,
+	0x80, 0x64, 0x0b, 0x1b,
+	0x04, 0x64, 0xfe, 0x1c,
+	0x02, 0x64, 0x01, 0x1d,
+	0x00, 0x6a, 0xd1, 0x1c,
+	0x03, 0x64, 0x09, 0x1d,
+	0x01, 0x64, 0xf2, 0x1c,
+	0x07, 0x64, 0x2d, 0x1d,
+	0x08, 0x64, 0xcf, 0x1c,
+	0x11, 0x6a, 0x91, 0x00,
+	0x07, 0x6a, 0x2f, 0x17,
+	0xff, 0x06, 0x6a, 0x02,
+	0x00, 0x65, 0x5c, 0x10,
+	0xff, 0xa8, 0xd3, 0x1a,
+	0xff, 0xa2, 0xda, 0x1e,
+	0x01, 0x6a, 0x3d, 0x00,
+	0x00, 0xb9, 0x74, 0x17,
+	0xff, 0xa2, 0xda, 0x1e,
+	0x71, 0x6a, 0x91, 0x00,
+	0x40, 0x59, 0xda, 0x18,
+	0xff, 0xb9, 0xb3, 0x02,
+	0x00, 0x65, 0xe4, 0x10,
+	0x20, 0xa0, 0xe0, 0x1a,
+	0xff, 0x90, 0x4a, 0x02,
+	0xff, 0xb3, 0x49, 0x02,
+	0x00, 0xa1, 0x9e, 0x17,
+	0xff, 0x49, 0x6d, 0x02,
+	0xff, 0x4a, 0x90, 0x02,
+	0xff, 0xb9, 0x9d, 0x02,
+	0x02, 0x6a, 0x91, 0x00,
+	0x08, 0xa0, 0xe4, 0x1e,
+	0x91, 0x6a, 0x91, 0x00,
+	0xff, 0xb3, 0xf0, 0x1c,
+	0xff, 0xb3, 0x64, 0x02,
+	0x00, 0xb9, 0xea, 0x1c,
+	0x00, 0x65, 0xa7, 0x17,
+	0xff, 0x64, 0x90, 0x02,
+	0x00, 0x65, 0xec, 0x10,
+	0x0d, 0x6a, 0x3d, 0x00,
+	0x00, 0xb3, 0x74, 0x17,
+	0xff, 0x48, 0xba, 0x02,
+	0xff, 0x90, 0x48, 0x02,
+	0x00, 0x65, 0x2f, 0x16,
+	0x00, 0x65, 0x69, 0x10,
+	0x00, 0x65, 0xa7, 0x17,
+	0x00, 0x65, 0x69, 0x10,
+	0x4d, 0x6a, 0x37, 0x17,
+	0xff, 0x4d, 0x64, 0x02,
+	0x00, 0x66, 0x37, 0x17,
+	0xff, 0x64, 0x64, 0x06,
+	0x52, 0x66, 0xf8, 0x18,
+	0xff, 0x66, 0x66, 0x06,
+	0xff, 0x64, 0xf4, 0x1a,
+	0x41, 0x6a, 0x91, 0x00,
+	0x20, 0x59, 0xcd, 0x1c,
+	0x80, 0x59, 0xcf, 0x18,
+	0x10, 0x4c, 0x03, 0x00,
+	0x00, 0x65, 0xcf, 0x10,
+	0x04, 0xa0, 0xa0, 0x00,
+	0x00, 0x65, 0xb8, 0x17,
+	0x00, 0x65, 0x69, 0x10,
+	0x10, 0x41, 0xcf, 0x1e,
+	0xff, 0x43, 0xa3, 0x02,
+	0xa4, 0x6a, 0x66, 0x00,
+	0x44, 0x6a, 0x70, 0x17,
+	0xac, 0x6a, 0x66, 0x00,
+	0x14, 0x6a, 0x70, 0x17,
+	0xa9, 0x6a, 0x71, 0x17,
+	0x00, 0x65, 0xcf, 0x10,
+	0xef, 0x41, 0x41, 0x02,
+	0x00, 0x65, 0xcf, 0x10,
+	0x78, 0x64, 0xcd, 0x1a,
+	0x07, 0x64, 0x64, 0x02,
+	0x00, 0x42, 0x42, 0x00,
+	0x00, 0x42, 0x9e, 0x17,
+	0xff, 0x6c, 0x59, 0x02,
+	0xff, 0x59, 0x25, 0x19,
+	0xff, 0x59, 0x15, 0x1d,
+	0xff, 0x59, 0x90, 0x02,
+	0x04, 0xa0, 0x2a, 0x1f,
+	0x00, 0x65, 0x27, 0x11,
+	0xff, 0x06, 0x6a, 0x02,
+	0x01, 0x0c, 0x16, 0x1f,
+	0x04, 0x0c, 0x16, 0x1b,
+	0xe0, 0x03, 0x4c, 0x02,
+	0xe0, 0x4c, 0x2a, 0x19,
+	0x20, 0x12, 0x2a, 0x19,
+	0x20, 0x41, 0x41, 0x00,
+	0x59, 0x6a, 0x37, 0x17,
+	0xff, 0x3f, 0x64, 0x02,
+	0x00, 0x59, 0x65, 0x06,
+	0x00, 0x65, 0x2a, 0x13,
+	0xff, 0x59, 0x90, 0x02,
+	0xff, 0x42, 0x64, 0x02,
+	0x00, 0xa1, 0x2a, 0x19,
+	0x20, 0xa0, 0x2a, 0x1f,
+	0x04, 0xa0, 0x2a, 0x1f,
+	0x00, 0x6a, 0x4f, 0x17,
+	0xff, 0x65, 0x2a, 0x1d,
+	0xfb, 0xa0, 0xa0, 0x02,
+	0x40, 0x41, 0x41, 0x00,
+	0x00, 0x65, 0xcf, 0x10,
+	0x31, 0x6a, 0x91, 0x00,
+	0x0c, 0x6a, 0x2f, 0x17,
+	0x00, 0x65, 0xcf, 0x10,
+	0x61, 0x6a, 0x91, 0x00,
+	0x00, 0x65, 0xcf, 0x10,
+	0x50, 0x6a, 0x60, 0x00,
+	0xff, 0x34, 0x33, 0x1f,
+	0x10, 0x6a, 0x60, 0x00,
+	0xc1, 0x6a, 0x91, 0x00,
+	0x10, 0x4c, 0x03, 0x00,
+	0x01, 0x6a, 0x34, 0x00,
+	0xff, 0x65, 0x35, 0x02,
+	0x10, 0x6a, 0x60, 0x01,
+	0xff, 0x06, 0x6a, 0x02,
+	0x01, 0x0c, 0x38, 0x1f,
+	0x04, 0x0c, 0x38, 0x1b,
+	0xe0, 0x03, 0x4c, 0x02,
+	0xe0, 0x4c, 0x3f, 0x19,
+	0xff, 0x65, 0x66, 0x02,
+	0xff, 0x12, 0x6d, 0x03,
+	0xff, 0x06, 0x6a, 0x03,
+	0xd1, 0x6a, 0x91, 0x00,
+	0x00, 0x65, 0x5c, 0x10,
+	0xff, 0x65, 0x93, 0x02,
+	0x01, 0x0b, 0x49, 0x1b,
+	0x10, 0x0c, 0x42, 0x1f,
+	0x04, 0x0b, 0x46, 0x1b,
+	0xff, 0x6a, 0x65, 0x02,
+	0x04, 0x93, 0x48, 0x1b,
+	0x01, 0x94, 0x47, 0x1f,
+	0x10, 0x94, 0x48, 0x1b,
+	0xc7, 0x93, 0x93, 0x02,
+	0x38, 0x93, 0x4a, 0x1b,
+	0xff, 0x6a, 0x6a, 0x03,
+	0x80, 0x41, 0x4b, 0x1f,
+	0x40, 0x41, 0x4b, 0x1b,
+	0x21, 0x6a, 0x91, 0x01,
+	0xff, 0x65, 0x90, 0x02,
+	0xff, 0x59, 0x64, 0x02,
+	0x00, 0xb9, 0x53, 0x19,
+	0x04, 0xa0, 0x5d, 0x1b,
+	0x01, 0x65, 0x65, 0x06,
+	0xff, 0x3e, 0x64, 0x02,
+	0x00, 0x65, 0x4f, 0x19,
+	0x00, 0x6a, 0xaa, 0x17,
+	0x0d, 0x6a, 0x3d, 0x00,
+	0x00, 0x59, 0x74, 0x17,
+	0xff, 0xa8, 0x5b, 0x1f,
+	0x10, 0xa0, 0xa0, 0x00,
+	0x08, 0xa0, 0x4b, 0x1f,
+	0xff, 0x6a, 0x65, 0x01,
+	0x08, 0xa0, 0x5c, 0x1b,
+	0xff, 0xba, 0x63, 0x1d,
+	0xff, 0xbb, 0x49, 0x02,
+	0xff, 0xba, 0x90, 0x02,
+	0xff, 0x49, 0xbb, 0x02,
+	0xff, 0x65, 0x90, 0x02,
+	0xff, 0xbb, 0x68, 0x1d,
+	0xff, 0xba, 0x49, 0x02,
+	0xff, 0xbb, 0x90, 0x02,
+	0xff, 0x49, 0xba, 0x02,
+	0xff, 0x65, 0x90, 0x03,
+	0xff, 0xba, 0x52, 0x03,
+	0xff, 0x6a, 0x6a, 0x03,
+	0xff, 0x8c, 0x08, 0x02,
+	0xff, 0x8d, 0x09, 0x02,
+	0xff, 0x8e, 0x0a, 0x03,
+	0xff, 0x6c, 0x6d, 0x02,
+	0xff, 0x6c, 0x6d, 0x02,
+	0xff, 0x6c, 0x6d, 0x02,
+	0xff, 0x6c, 0x6d, 0x02,
+	0xff, 0x6c, 0x6d, 0x02,
+	0xff, 0x6c, 0x6d, 0x02,
+	0xff, 0x6c, 0x6d, 0x03,
+	0x3d, 0x65, 0x66, 0x0a,
+	0x55, 0x65, 0x64, 0x0a,
+	0x00, 0x54, 0x88, 0x06,
+	0xff, 0x66, 0x64, 0x02,
+	0x00, 0x55, 0x89, 0x08,
+	0xff, 0x6a, 0x64, 0x02,
+	0x00, 0x56, 0x8a, 0x08,
+	0x00, 0x57, 0x8b, 0x08,
+	0x1c, 0x6a, 0x8c, 0x00,
+	0xff, 0x6a, 0x8d, 0x02,
+	0xff, 0x6a, 0x8e, 0x02,
+	0xff, 0x3d, 0x93, 0x02,
+	0x04, 0x3d, 0x8c, 0x1b,
+	0xa0, 0x6a, 0x65, 0x00,
+	0x1c, 0x65, 0x64, 0x06,
+	0xff, 0x6c, 0x99, 0x02,
+	0xff, 0x6c, 0x99, 0x02,
+	0xff, 0x6c, 0x99, 0x02,
+	0xff, 0x6c, 0x99, 0x02,
+	0xff, 0x6c, 0x99, 0x02,
+	0xff, 0x6c, 0x99, 0x02,
+	0xff, 0x6c, 0x99, 0x02,
+	0x00, 0x65, 0x83, 0x19,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0x9a, 0x17,
+	0x04, 0x3d, 0x4b, 0x1f,
+	0xa0, 0x6a, 0x92, 0x17,
+	0x00, 0x65, 0x93, 0x17,
+	0x00, 0x65, 0x93, 0x17,
+	0x00, 0x65, 0x93, 0x11,
+	0xff, 0x65, 0x66, 0x02,
+	0xff, 0x99, 0x6d, 0x02,
+	0xff, 0x99, 0x6d, 0x02,
+	0xff, 0x99, 0x6d, 0x02,
+	0xff, 0x99, 0x6d, 0x02,
+	0xff, 0x99, 0x6d, 0x02,
+	0xff, 0x99, 0x6d, 0x02,
+	0xff, 0x99, 0x6d, 0x03,
+	0x08, 0x94, 0x9a, 0x1f,
+	0xf7, 0x93, 0x93, 0x02,
+	0x08, 0x93, 0x9c, 0x1b,
+	0xff, 0x6a, 0x6a, 0x03,
+	0xff, 0x65, 0x66, 0x02,
+	0x4c, 0x66, 0x66, 0x0a,
+	0x03, 0x66, 0x66, 0x02,
+	0xbc, 0x66, 0x66, 0x06,
+	0x6a, 0x65, 0x64, 0x0a,
+	0x08, 0x65, 0xa5, 0x1f,
+	0x02, 0x64, 0x64, 0x06,
+	0xff, 0x64, 0x90, 0x02,
+	0xff, 0x66, 0x65, 0x03,
+	0xff, 0x53, 0xba, 0x02,
+	0xff, 0x6a, 0xb9, 0x00,
+	0xff, 0x90, 0x53, 0x03,
+	0xff, 0x53, 0xb6, 0x19,
+	0xff, 0x52, 0xad, 0x19,
+	0xff, 0x6a, 0x65, 0x01,
+	0xff, 0x52, 0x90, 0x02,
+	0x10, 0xa0, 0xb1, 0x1f,
+	0xef, 0xa0, 0xa0, 0x02,
+	0x00, 0x65, 0xb3, 0x11,
+	0xff, 0xa8, 0xb3, 0x1b,
+	0xff, 0xb3, 0xb5, 0x1d,
+	0x01, 0x6a, 0x3d, 0x00,
+	0x00, 0xb9, 0x74, 0x17,
+	0x00, 0x90, 0x5e, 0x11,
+	0xff, 0x53, 0x90, 0x02,
+	0xff, 0xba, 0x53, 0x03,
+	0xff, 0x6a, 0xbb, 0x00,
+	0xff, 0x52, 0xba, 0x02,
+	0xff, 0x90, 0x52, 0x02,
+	0xff, 0xba, 0x4b, 0x1d,
+	0xff, 0xba, 0x90, 0x02,
+	0xff, 0x52, 0xbb, 0x02,
+	0xff, 0x52, 0x90, 0x03,
+};
+#define	ULTRA           	0x8
+#define	SCB_PAGING      	0x4
+#define	TWIN_CHANNEL    	0x2
+struct patch {
+	int	options;
+	int	negative;
+	int	begin;
+	int	end;
+} patches[] = {
+	{ 0x00000002, 0, 0x006, 0x00b },
+	{ 0x00000004, 0, 0x00e, 0x010 },
+	{ 0x00000004, 1, 0x011, 0x012 },
+	{ 0x00000004, 0, 0x01a, 0x023 },
+	{ 0x00000004, 1, 0x023, 0x027 },
+	{ 0x00000002, 0, 0x02f, 0x033 },
+	{ 0x00000008, 0, 0x04f, 0x056 },
+	{ 0x00000004, 1, 0x0e5, 0x0ea },
+	{ 0x00000004, 0, 0x0ff, 0x100 },
+	{ 0x00000004, 0, 0x110, 0x111 },
+	{ 0x00000004, 1, 0x111, 0x115 },
+	{ 0x00000004, 1, 0x120, 0x125 },
+	{ 0x00000004, 0, 0x125, 0x127 },
+	{ 0x00000004, 0, 0x14f, 0x169 },
+	{ 0x00000004, 1, 0x169, 0x16a },
+	{ 0x00000004, 0, 0x1aa, 0x1bf },
+	{ 0x00000000, 0, 0x000, 0x000 }
+};
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v2.1.47/linux/drivers/scsi/atari_scsi.c	Sat May 24 09:10:24 1997
+++ linux/drivers/scsi/atari_scsi.c	Thu Jul 31 13:09:17 1997
@@ -90,6 +90,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/nvram.h>
 
 #include <asm/setup.h>
 #include <asm/atarihw.h>
@@ -596,20 +597,6 @@
 #endif
 
 
-#define	RTC_READ(reg)				\
-    ({	unsigned char	__val;			\
-		outb(reg,&tt_rtc.regsel);	\
-		__val = tt_rtc.data;		\
-		__val;				\
-	})
-
-#define	RTC_WRITE(reg,val)			\
-    do {					\
-		outb(reg,&tt_rtc.regsel);	\
-		tt_rtc.data = (val);		\
-	} while(0)
-    
-				   
 int atari_scsi_detect (Scsi_Host_Template *host)
 {
 	static int called = 0;
@@ -645,20 +632,11 @@
 		/* use 7 as default */
 		host->this_id = 7;
 		/* Test if a host id is set in the NVRam */
-		if (ATARIHW_PRESENT(TT_CLK)) {
-			unsigned char sum = 0, b;
-			int i;
-			
-			/* Make checksum */
-			for( i = 14; i < 62; ++i )
-				sum += RTC_READ(i);
-			
-			if (/* NV-Ram checksum valid? */
-				RTC_READ(62) == sum && RTC_READ(63) == ~sum &&
-				/* Arbitration enabled? (for TOS) */
-				(b = RTC_READ( 30 )) & 0x80) {
+		if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+			unsigned char b = nvram_read_byte( 14 );
+			/* Arbitration enabled? (for TOS) If yes, use configured host ID */
+			if (b & 0x80)
 				host->this_id = b & 7;
-			}
 		}
 	}
 
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.1.47/linux/drivers/scsi/esp.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/esp.c	Thu Jul 31 13:09:17 1997
@@ -1705,7 +1705,7 @@
 	 * the nexus and tell the device to abort.  However, we really
 	 * cannot 'reconnect' per se, therefore we tell the upper layer
 	 * the safest thing we can.  This is, wait a bit, if nothing
-	 * happens, we are really hung so reset the bug.
+	 * happens, we are really hung so reset the bus.
 	 */
 
 	return SCSI_ABORT_SNOOZE;
@@ -1743,11 +1743,10 @@
 					     done_SC->request_bufflen,
 					     esp->edev->my_bus);
 		} else {
-			struct scatterlist *scl = (struct scatterlist *)done_SC->buffer;
 #ifdef DEBUG_ESP_SG
 			printk("esp%d: unmapping sg ", esp->esp_id);
 #endif
-			mmu_release_scsi_sgl((struct mmu_sglist *) scl,
+			mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
 					     done_SC->use_sg - 1,
 					     esp->edev->my_bus);
 #ifdef DEBUG_ESP_SG
@@ -2010,7 +2009,7 @@
 		if(sz > 0x1000000)
 			sz = 0x1000000;
 	} else {
-		base = ((__u32)sp->SCp.ptr);
+		base = ((__u32)((unsigned long)sp->SCp.ptr));
 		base &= (0x1000000 - 1);
 		end = (base + sp->SCp.this_residual);
 		if(end > 0x1000000)
@@ -2280,11 +2279,12 @@
 			tmp |= DMA_ST_WRITE;
 		else
 			tmp &= ~(DMA_ST_WRITE);
-		dregs->st_addr = ((__u32)SCptr->SCp.ptr);
+		dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr));
 		dregs->cond_reg = tmp;
 	} else {
 		esp_setcount(eregs, hmuch, 0);
-		dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
+		dma_setup(dregs, esp->dma->revision,
+			  ((__u32)((unsigned long)SCptr->SCp.ptr)),
 			  hmuch, (thisphase == in_datain));
 		ESPDATA(("DMA|TI --> do_intr_end\n"));
 		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
@@ -4059,8 +4059,12 @@
 }
 #else
 
+/* XXX Gross hack for sun4u SMP, fix it right later... -DaveM */
 #ifdef __sparc_v9__
-#error Dave you need to fix some things first...
+extern unsigned char ino_to_pil[];
+#define INO_TO_PIL(esp)		(ino_to_pil[(esp)->irq])
+#else
+#define INO_TO_PIL(esp)		((esp)->irq & 0xf)
 #endif
 
 /* For SMP we only service one ESP on the list list at our IRQ level! */
@@ -4070,7 +4074,7 @@
 
 	/* Handle all ESP interrupts showing at this IRQ level. */
 	for_each_esp(esp) {
-		if((esp->irq & 0xf) == irq) {
+		if(INO_TO_PIL(esp) == irq) {
 			if(DMA_IRQ_P(esp->dregs)) {
 				DMA_INTSOFF(esp->dregs);
 
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.1.47/linux/drivers/scsi/ppa.c	Mon Jul  7 08:24:28 1997
+++ linux/drivers/scsi/ppa.c	Sun Aug  3 00:08:52 1997
@@ -144,7 +144,7 @@
 	"Unknown"};
 
 typedef struct {
-	struct ppd *dev;	/* Parport device entry          */
+	struct pardevice *dev;	/* Parport device entry          */
 	int speed;		/* General PPA delay constant   */
 	int speed_fast;		/* Const for nibble/byte modes  */
 	int epp_speed;		/* Reset time period            */
@@ -210,22 +210,22 @@
 #define w_fifo(x,y)     outb(y, PPA_BASE(x)+0x400)
 #define w_ecr(x,y)      outb(y, PPA_BASE(x)+0x402)
 
-int ppa_wakeup(void *ref)
+static void ppa_wakeup(void *ref)
 {
 	ppa_struct *ppa_dev = (ppa_struct *) ref;
 
 	if (!ppa_dev->ppa_wait_q)
-		return 1;	/* Wake up whom ? */
+		return;	/* Wake up whom ? */
 
 	/* Claim the Parport */
 	if (parport_claim(ppa_dev->dev))
-		return 1;	/* Shouldn't happen */
+		return;	/* Shouldn't happen */
 
 	wake_up(&ppa_dev->ppa_wait_q);
-	return 0;
+	return;
 }
 
-int ppa_release(struct Scsi_Host *host)
+static int ppa_release(struct Scsi_Host *host)
 {
 	int host_no = host->unique_id;
 
@@ -1137,7 +1137,7 @@
 		int modes = pb->modes;
 
 		/* We only understand PC-style ports */
-		if (modes & PARPORT_MODE_SPP) {
+		if (modes & PARPORT_MODE_PCSPP) {
 
 			/* transfer global values here */
 			if (ppa_speed >= 0)
@@ -1156,16 +1156,16 @@
 			w_ctr(i, 0x0c);
 
 			ppa_hosts[i].mode = PPA_NIBBLE;
-			if (modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) {
+			if (modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP)) {
 				ppa_hosts[i].mode = PPA_EPP_32;
-				printk("PPA: Parport [ EPP ]\n");
-			} else if (modes & PARPORT_MODE_ECP) {
+				printk("PPA: Parport [ PCEPP ]\n");
+			} else if (modes & PARPORT_MODE_PCECP) {
 				w_ecr(i, 0x20);
 				ppa_hosts[i].mode = PPA_PS2;
-				printk("PPA: Parport [ ECP in PS2 submode ]\n");
-			} else if (modes & PARPORT_MODE_PS2) {
+				printk("PPA: Parport [ PCECP in PS2 submode ]\n");
+			} else if (modes & PARPORT_MODE_PCPS2) {
 				ppa_hosts[i].mode = PPA_PS2;
-				printk("PPA: Parport [ PS2 ]\n");
+				printk("PPA: Parport [ PCPS2 ]\n");
 			}
 			/* Done configuration */
 			ppa_pb_release(i);
diff -u --recursive --new-file v2.1.47/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h
--- v2.1.47/linux/drivers/scsi/ppa.h	Mon Jul  7 16:03:00 1997
+++ linux/drivers/scsi/ppa.h	Mon Aug  4 14:00:47 1997
@@ -52,7 +52,7 @@
 int ppa_reset(Scsi_Cmnd *, unsigned int);
 int ppa_proc_info(char *, char **, off_t, int, int, int);
 int ppa_biosparam(Disk *, kdev_t, int*);
-int ppa_release(struct Scsi_Host *);
+static int ppa_release(struct Scsi_Host *);
 
 #ifndef	MODULE
 #ifdef	PPA_CODE
diff -u --recursive --new-file v2.1.47/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.1.47/linux/fs/autofs/autofs_i.h	Mon Jul  7 16:03:41 1997
+++ linux/fs/autofs/autofs_i.h	Mon Aug  4 14:02:04 1997
@@ -58,12 +58,14 @@
 #endif
 
 #ifdef DEBUG
-#define DPRINTK(D) printk D;
+#define DPRINTK(D) (printk D)
 #else
-#define DPRINTK(D)
+#define DPRINTK(D) ((void)0)
 #endif
 
 #define AUTOFS_SUPER_MAGIC 0x0187
+
+#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ)	/* Time before asking the daemon again */
 
 /* Structures associated with the root directory hash */
 
diff -u --recursive --new-file v2.1.47/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.1.47/linux/fs/autofs/dir.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/autofs/dir.c	Wed Jul 30 20:53:50 1997
@@ -44,16 +44,20 @@
 }
 
 static struct file_operations autofs_dir_operations = {
-	NULL,			/* lseek */
+	NULL,			/* llseek */
 	NULL,			/* read */
 	NULL,			/* write */
 	autofs_dir_readdir,	/* readdir */
-	NULL,			/* select */
+	NULL,			/* poll */
 	NULL,			/* ioctl */
 	NULL,			/* mmap */
 	NULL,			/* open */
 	NULL,			/* release */
-	NULL			/* fsync */
+	NULL,			/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
 };
 
 struct inode_operations autofs_dir_inode_operations = {
@@ -68,10 +72,14 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* read_page */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL			/* revalidate */
 };
 
diff -u --recursive --new-file v2.1.47/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.1.47/linux/fs/autofs/inode.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/autofs/inode.c	Wed Jul 30 20:53:50 1997
@@ -172,27 +172,27 @@
 	unlock_super(s);
 	s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
 	if (!s->s_root) {
-		s->s_dev = 0;
-		kfree(sbi);
 		printk("autofs: get root inode failed\n");
+		kfree(sbi);
+		s->s_dev = 0;
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
 	if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+		printk("autofs: called with bogus options\n");
 		dput(s->s_root);
-		s->s_dev = 0;
 		kfree(sbi);
-		printk("autofs: called with bogus options\n");
+		s->s_dev = 0;
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
 	if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+		printk("autofs: kernel does not match daemon version\n");
 		dput(s->s_root);
-		s->s_dev = 0;
 		kfree(sbi);
-		printk("autofs: kernel does not match daemon version\n");
+		s->s_dev = 0;
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
@@ -207,8 +207,8 @@
 			printk("autofs: could not open pipe file descriptor\n");
 		}
 		dput(s->s_root);
-		s->s_dev = 0;
 		kfree(sbi);
+		s->s_dev = 0;
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
diff -u --recursive --new-file v2.1.47/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.47/linux/fs/autofs/root.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/autofs/root.c	Wed Jul 30 20:53:50 1997
@@ -24,16 +24,20 @@
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
 static struct file_operations autofs_root_operations = {
-        NULL,                   /* lseek */
+        NULL,                   /* llseek */
         NULL,                   /* read */
         NULL,                   /* write */
         autofs_root_readdir,    /* readdir */
-        NULL,                   /* select */
+        NULL,                   /* poll */
         autofs_root_ioctl,	/* ioctl */
         NULL,                   /* mmap */
         NULL,                   /* open */
         NULL,                   /* release */
-        NULL                    /* fsync */
+        NULL,			/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
 };
 
 struct inode_operations autofs_root_inode_operations = {
@@ -53,7 +57,10 @@
         NULL,                   /* writepage */
         NULL,                   /* bmap */
         NULL,                   /* truncate */
-        NULL                    /* permission */
+        NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL			/* revalidate */
 };
 
 static int autofs_root_readdir(struct inode *inode, struct file *filp,
@@ -97,24 +104,31 @@
 {
 	struct inode * inode;
 	struct autofs_dir_ent *ent;
-	
+
 	while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
 		int status = autofs_wait(sbi, &dentry->d_name);
 
 		/* Turn this into a real negative dentry? */
 		if (status == -ENOENT) {
-			dentry->d_flags = 0;
-			return 0;
+			dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
+			dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+			return 1;
+		} else if (status) {
+			/* Return a negative dentry, but leave it "pending" */
+			return 1;
 		}
-		if (status)
-			return status;
 	}
 
+	/* Abuse this field as a pointer to the directory entry, used to
+	   find the expire list pointers */
+	dentry->d_time = (unsigned long) ent;
+	
 	if (!dentry->d_inode) {
 		inode = iget(sb, ent->ino);
-		if (!inode)
-			return -EACCES;
-
+		if (!inode) {
+			/* Failed, but leave pending for next time */
+			return 1;
+		}
 		dentry->d_inode = inode;
 	}
 
@@ -122,8 +136,11 @@
 		while (dentry == dentry->d_mounts)
 			schedule();
 	}
-	dentry->d_flags = 0;
-	return 0;
+
+	autofs_update_usage(&sbi->dirhash,ent);
+
+	dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+	return 1;
 }
 
 
@@ -133,28 +150,30 @@
  * yet completely filled in, and revalidate has to delay such
  * lookups..
  */
-static struct dentry * autofs_revalidate(struct dentry * dentry)
+static int autofs_revalidate(struct dentry * dentry)
 {
 	struct autofs_sb_info *sbi;
 	struct inode * dir = dentry->d_parent->d_inode;
+	struct autofs_dir_ent *ent;
 
 	sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
 
-	/* Incomplete dentry? */
-	if (dentry->d_flags) {
+	/* Pending dentry */
+	if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
 		if (autofs_oz_mode(sbi))
-			return dentry;
+			return 1;
 
-		try_to_fill_dentry(dentry, dir->i_sb, sbi);
-		return dentry;
+		return try_to_fill_dentry(dentry, dir->i_sb, sbi);
 	}
 
-	/* Negative dentry.. Should we time these out? */
+	/* Negative dentry.. invalidate if "old" */
 	if (!dentry->d_inode)
-		return dentry;
+		return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
 
-	/* We should update the usage stuff here.. */
-	return dentry;
+	/* Update the usage list */
+	ent = (struct autofs_dir_ent *) dentry->d_time;
+	autofs_update_usage(&sbi->dirhash,ent);
+	return 1;
 }
 
 static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
@@ -186,12 +205,13 @@
 	 * We need to do this before we release the directory semaphore.
 	 */
 	dentry->d_revalidate = autofs_revalidate;
-	dentry->d_flags = 1;
+	dentry->d_flags |= DCACHE_AUTOFS_PENDING;
 	d_add(dentry, NULL);
 
 	up(&dir->i_sem);
 	autofs_revalidate(dentry);
 	down(&dir->i_sem);
+	
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.47/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c
--- v2.1.47/linux/fs/autofs/symlink.c	Mon Jul  7 12:58:01 1997
+++ linux/fs/autofs/symlink.c	Wed Jul 30 20:53:50 1997
@@ -51,5 +51,8 @@
 	NULL,			/* writepage */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.1.47/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.1.47/linux/fs/binfmt_aout.c	Sun Jul 20 20:41:58 1997
+++ linux/fs/binfmt_aout.c	Mon Jul 28 14:04:09 1997
@@ -212,7 +212,6 @@
 close_coredump:
 	if (file.f_op->release)
 		file.f_op->release(inode,&file);
-done_coredump:
 	put_write_access(inode);
 end_coredump:
 	set_fs(fs);
diff -u --recursive --new-file v2.1.47/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.1.47/linux/fs/binfmt_misc.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/binfmt_misc.c	Mon Jul 28 13:55:11 1997
@@ -69,6 +69,7 @@
 static struct binfmt_entry *entries = NULL;
 static int free_id = 1;
 static int enabled = 1;
+
 static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
 
 
diff -u --recursive --new-file v2.1.47/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.47/linux/fs/buffer.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/buffer.c	Wed Jul 30 19:31:17 1997
@@ -49,8 +49,9 @@
 
 #define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
 #define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
-#define MAX_UNUSED_BUFFERS 30 /* don't ever have more than this number of 
-				 unused buffer heads */
+#define NR_RESERVED (2*MAX_BUF_PER_PAGE)
+#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this 
+					     number of unused buffer heads */
 #define HASH_PAGES         4  /* number of pages to use for the hash table */
 #define HASH_PAGES_ORDER   2
 #define NR_HASH (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *))
@@ -560,6 +561,7 @@
 		if (!bh)
 			return NULL;
 		bh->b_count++;
+		bh->b_lru_time = jiffies;
 		wait_on_buffer(bh);
 		if (bh->b_dev == dev		&&
 		    bh->b_blocknr == block	&&
@@ -642,34 +644,20 @@
 	}
 }
 
-/* Check if a buffer is OK to be reclaimed. */
-static inline int can_reclaim(struct buffer_head *bh, int size)
-{
-	if (bh->b_count			|| 
-	    buffer_protected(bh)	||
-	    buffer_locked(bh))
-		return 0;
-			 
-	if (buffer_dirty(bh)) {
-		refile_buffer(bh);
-		return 0;
-	}
-
-	if (bh->b_size != size)
-		return 0;
-
-	return 1;
-}
-
-/* Find a candidate buffer to be reclaimed. */
-static struct buffer_head *find_candidate(struct buffer_head *list,
+/*
+ * Find a candidate buffer to be reclaimed. 
+ * N.B. Must search the entire BUF_LOCKED list rather than terminating
+ * when the first locked buffer is found.  Buffers are unlocked at 
+ * completion of IO, and under some conditions there may be (many)
+ * unlocked buffers after the first locked one.
+ */
+static struct buffer_head *find_candidate(struct buffer_head *bh,
 					  int *list_len, int size)
 {
-	struct buffer_head *bh;
-	
-	for (bh = list; 
-	     bh && (*list_len) > 0; 
-	     bh = bh->b_next_free, (*list_len)--) {
+	if (!bh)
+		goto no_candidate;
+
+	for (; (*list_len) > 0; bh = bh->b_next_free, (*list_len)--) {
 		if (size != bh->b_size) {
 			/* This provides a mechanism for freeing blocks
 			 * of other sizes, this is necessary now that we
@@ -680,110 +668,144 @@
 				break;
 			continue;
 		}
-
-		if (buffer_locked(bh) && bh->b_list == BUF_LOCKED) {
-			/* Buffers are written in the order they are placed 
-			 * on the locked list. If we encounter a locked
-			 * buffer here, this means that the rest of them
-			 * are also locked.
-			 */
-			(*list_len) = 0;
-			return NULL;
-		}
-
-		if (can_reclaim(bh,size))
-		    return bh;
+		else if (!bh->b_count		&& 
+			 !buffer_locked(bh)	&& 
+			 !buffer_protected(bh)	&&
+			 !buffer_dirty(bh)) 
+			return bh;
 	}
 
+no_candidate:
 	return NULL;
 }
 
 static void refill_freelist(int size)
 {
-	struct buffer_head * bh;
+	struct buffer_head * bh, * next;
 	struct buffer_head * candidate[BUF_DIRTY];
-	unsigned int best_time, winner;
 	int buffers[BUF_DIRTY];
 	int i;
-	int needed;
+	int needed, obtained=0;
 
 	refilled = 1;
-	/* If there are too many dirty buffers, we wake up the update process
-	 * now so as to ensure that there are still clean buffers available
-	 * for user processes to use (and dirty).
-	 */
 	
 	/* We are going to try to locate this much memory. */
 	needed = bdf_prm.b_un.nrefill * size;  
 
-	while ((nr_free_pages > min_free_pages*2)	&&
-	       (needed > 0)				&&
-	       grow_buffers(GFP_BUFFER, size))
-		needed -= PAGE_SIZE;
+	while ((nr_free_pages > min_free_pages*2) && 
+		grow_buffers(GFP_BUFFER, size)) {
+		obtained += PAGE_SIZE;
+		if (obtained >= needed)
+			return;
+	}
 
+	/*
+	 * Update the needed amount based on the number of potentially
+	 * freeable buffers. We don't want to free more than one quarter
+	 * of the available buffers.
+	 */
+	i = (nr_buffers_type[BUF_CLEAN] + nr_buffers_type[BUF_LOCKED]) >> 2;
+	if (i < bdf_prm.b_un.nrefill) {
+		needed = i * size;
+		if (needed < PAGE_SIZE)
+			needed = PAGE_SIZE;
+	}
+
+	/* 
+	 * OK, we cannot grow the buffer cache, now try to get some
+	 * from the lru list.
+	 */
 repeat:
-	if(needed <= 0)
+	if (obtained >= needed)
 		return;
 
-	/* OK, we cannot grow the buffer cache, now try to get some
-	 * from the lru list.
-	 *
+	/*
 	 * First set the candidate pointers to usable buffers.  This
-	 * should be quick nearly all of the time.
+	 * should be quick nearly all of the time.  N.B. There must be 
+	 * no blocking calls after setting up the candidate[] array!
 	 */
-
-	for(i=0; i<BUF_DIRTY; i++) {
+	for (i = BUF_CLEAN; i<BUF_DIRTY; i++) {
 		buffers[i] = nr_buffers_type[i];
 		candidate[i] = find_candidate(lru_list[i], &buffers[i], size);
 	}
 	
-	/* Now see which candidate wins the election. */
-	
-	winner = best_time = UINT_MAX;	
-	for(i=0; i<BUF_DIRTY; i++) {
-		if(!candidate[i])
-			continue;
-		if(candidate[i]->b_lru_time < best_time) {
-			best_time = candidate[i]->b_lru_time;
-			winner = i;
-		}
-	}
-	
-	/* If we have a winner, use it, and then get a new candidate from that list. */
-	if(winner != UINT_MAX) {
-		i = winner;
-		while (needed>0 && (bh=candidate[i])) {
-			candidate[i] = bh->b_next_free;
-			if(candidate[i] == bh)
-				candidate[i] = NULL;  /* Got last one */		
-			remove_from_queues(bh);
-			bh->b_dev = B_FREE;
-			put_last_free(bh);
-			needed -= bh->b_size;
-			buffers[i]--;
-			if(buffers[i] == 0)
-				candidate[i] = NULL;
-		
-			if (candidate[i] && !can_reclaim(candidate[i],size))
-				candidate[i] = find_candidate(candidate[i],
-							      &buffers[i], size);
+	/*
+	 * Select the older of the available buffers until we reach our goal.
+	 */
+	for (;;) {
+		i = BUF_CLEAN;
+		if (!candidate[BUF_CLEAN]) {
+			if (!candidate[BUF_LOCKED])
+				break;
+			i = BUF_LOCKED;
 		}
-		goto repeat;
-	}
+		else if (candidate[BUF_LOCKED] &&
+				(candidate[BUF_LOCKED]->b_lru_time < 
+				 candidate[BUF_CLEAN ]->b_lru_time))
+			i = BUF_LOCKED;
+		/*
+		 * Free the selected buffer and get the next candidate.
+		 */
+		bh = candidate[i];
+		next = bh->b_next_free;
+
+		obtained += bh->b_size;
+		remove_from_queues(bh);
+		put_last_free(bh);
+		if (obtained >= needed)
+			return;
+
+		if (--buffers[i] && bh != next)
+			candidate[i] = find_candidate(next, &buffers[i], size);
+		else
+			candidate[i] = NULL;
+	}	
+
+	/*
+	 * If we achieved at least half of our goal, return now.
+	 */
+	if (obtained >= (needed >> 1))
+		return;
 	
 	/* Too bad, that was not enough. Try a little harder to grow some. */
 	if (nr_free_pages > min_free_pages + 5) {
 		if (grow_buffers(GFP_BUFFER, size)) {
-			needed -= PAGE_SIZE;
+			obtained += PAGE_SIZE;
 			goto repeat;
 		}
 	}
-	
-	/* And repeat until we find something good. */
+
+	/*
+	 * Make one more attempt to allocate some buffers.
+	 */
 	if (grow_buffers(GFP_ATOMIC, size))
-		needed -= PAGE_SIZE;
-	else
-		wakeup_bdflush(1);
+		obtained += PAGE_SIZE;
+
+	/*
+	 * If we got any buffers, or another task freed some, 
+	 * return now to let this task proceed.
+	 */
+	if (obtained || free_list[BUFSIZE_INDEX(size)]) {
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: obtained %d of %d, free list=%d\n", 
+obtained, needed, free_list[BUFSIZE_INDEX(size)] != NULL);
+#endif
+		return;
+	}
+
+	/*
+	 * System is _very_ low on memory ... wake up bdflush and wait.
+	 */
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: waking bdflush\n");
+#endif
+	wakeup_bdflush(1);
+	/*
+	 * While we slept, other tasks may have needed buffers and entered
+	 * refill_freelist.  This could be a big problem ... reset the 
+	 * needed amount to the absolute minimum.
+	 */
+	needed = size;
 	goto repeat;
 }
 
@@ -831,6 +853,8 @@
 	 * and that it's unused (b_count=0), unlocked (buffer_locked=0), and clean.
 	 */
 	bh->b_count=1;
+	bh->b_list	= BUF_CLEAN;
+	bh->b_lru_time	= jiffies;
 	bh->b_flushtime=0;
 	bh->b_state=(1<<BH_Touched);
 	bh->b_dev=dev;
@@ -856,6 +880,16 @@
 
 
 /*
+ * Put a buffer into the appropriate list, without side-effects.
+ */
+static inline void file_buffer(struct buffer_head *bh, int list)
+{
+	remove_from_queues(bh);
+	bh->b_list = list;
+	insert_into_queues(bh);
+}
+
+/*
  * A buffer may need to be moved from one buffer list to another
  * (e.g. in case it is not shared any more). Handle this.
  */
@@ -873,15 +907,9 @@
 		dispose = BUF_LOCKED;
 	else
 		dispose = BUF_CLEAN;
-	if(dispose == BUF_CLEAN)
-		buf->b_lru_time = jiffies;
 	if(dispose != buf->b_list) {
-		if(dispose == BUF_DIRTY)
-			 buf->b_lru_time = jiffies;
-		remove_from_queues(buf);
-		buf->b_list = dispose;
-		insert_into_queues(buf);
-		if (dispose == BUF_DIRTY) {
+		file_buffer(buf, dispose);
+		if(dispose == BUF_DIRTY) {
 			int too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
 
 			/* This buffer is dirty, maybe we need to start flushing.
@@ -1034,34 +1062,11 @@
 	nr_unused_buffer_heads++;
 	bh->b_next_free = unused_list;
 	unused_list = bh;
+	if (!waitqueue_active(&buffer_wait))
+		return;
 	wake_up(&buffer_wait);
 }
 
-static void get_more_buffer_heads(void)
-{
-	struct buffer_head * bh;
-
-	while (!unused_list) {
-		/* This is critical.  We can't swap out pages to get
-		 * more buffer heads, because the swap-out may need
-		 * more buffer-heads itself.  Thus SLAB_ATOMIC.
-		 */
-		if((bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC)) != NULL) {
-			put_unused_buffer_head(bh);
-			nr_buffer_heads++;
-			return;
-		}
-
-		/* Uhhuh. We're _really_ low on memory. Now we just
-		 * wait for old buffer heads to become free due to
-		 * finishing IO..
-		 */
-		run_task_queue(&tq_disk);
-		sleep_on(&buffer_wait);
-	}
-
-}
-
 /* 
  * We can't put completed temporary IO buffer_heads directly onto the
  * unused_list when they become unlocked, since the device driver
@@ -1083,18 +1088,59 @@
 	}
 }
 
-static struct buffer_head * get_unused_buffer_head(void)
+/*
+ * Reserve NR_RESERVED buffer heads for async IO requests to avoid
+ * no-buffer-head deadlock.  Return NULL on failure; waiting for
+ * buffer heads is now handled in create_buffers().
+ */ 
+static struct buffer_head * get_unused_buffer_head(int async)
 {
 	struct buffer_head * bh;
 
 	recover_reusable_buffer_heads();
-	get_more_buffer_heads();
-	if (!unused_list)
-		return NULL;
-	bh = unused_list;
-	unused_list = bh->b_next_free;
-	nr_unused_buffer_heads--;
-	return bh;
+	if (nr_unused_buffer_heads > NR_RESERVED) {
+		bh = unused_list;
+		unused_list = bh->b_next_free;
+		nr_unused_buffer_heads--;
+		return bh;
+	}
+
+	/* This is critical.  We can't swap out pages to get
+	 * more buffer heads, because the swap-out may need
+	 * more buffer-heads itself.  Thus SLAB_ATOMIC.
+	 */
+	if((bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC)) != NULL) {
+		memset(bh, 0, sizeof(*bh));
+		nr_buffer_heads++;
+		return bh;
+	}
+
+	/*
+	 * If we need an async buffer, use the reserved buffer heads.
+	 */
+	if (async && unused_list) {
+		bh = unused_list;
+		unused_list = bh->b_next_free;
+		nr_unused_buffer_heads--;
+		return bh;
+	}
+
+#if 0
+	/*
+	 * (Pending further analysis ...)
+	 * Ordinary (non-async) requests can use a different memory priority
+	 * to free up pages. Any swapping thus generated will use async
+	 * buffer heads.
+	 */
+	if(!async &&
+	   (bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL)) != NULL) {
+		memset(bh, 0, sizeof(*bh));
+		nr_buffer_heads++;
+		return bh;
+	}
+#endif
+
+	return NULL;
 }
 
 /*
@@ -1102,16 +1148,22 @@
  * the size of each buffer.. Use the bh->b_this_page linked list to
  * follow the buffers created.  Return NULL if unable to create more
  * buffers.
+ * The async flag is used to differentiate async IO (paging, swapping)
+ * from ordinary buffer allocations, and only async requests are allowed
+ * to sleep waiting for buffer heads. 
  */
-static struct buffer_head * create_buffers(unsigned long page, unsigned long size)
+static struct buffer_head * create_buffers(unsigned long page, 
+						unsigned long size, int async)
 {
+	struct wait_queue wait = { current, NULL };
 	struct buffer_head *bh, *head;
 	long offset;
 
+try_again:
 	head = NULL;
 	offset = PAGE_SIZE;
 	while ((offset -= size) >= 0) {
-		bh = get_unused_buffer_head();
+		bh = get_unused_buffer_head(async);
 		if (!bh)
 			goto no_grow;
 
@@ -1138,7 +1190,35 @@
 		bh = bh->b_this_page;
 		put_unused_buffer_head(head);
 	}
-	return NULL;
+
+	/*
+	 * Return failure for non-async IO requests.  Async IO requests
+	 * are not allowed to fail, so we have to wait until buffer heads
+	 * become available.  But we don't want tasks sleeping with 
+	 * partially complete buffers, so all were released above.
+	 */
+	if (!async)
+		return NULL;
+
+	/* Uhhuh. We're _really_ low on memory. Now we just
+	 * wait for old buffer heads to become free due to
+	 * finishing IO.  Since this is an async request and
+	 * the reserve list is empty, we're sure there are 
+	 * async buffer heads in use.
+	 */
+	run_task_queue(&tq_disk);
+
+	/* 
+	 * Set our state for sleeping, then check again for buffer heads.
+	 * This ensures we won't miss a wake_up from an interrupt.
+	 */
+	add_wait_queue(&buffer_wait, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	recover_reusable_buffer_heads();
+	schedule();
+	remove_wait_queue(&buffer_wait, &wait);
+	current->state = TASK_RUNNING;
+	goto try_again;
 }
 
 /* Run the hooks that have to be done when a page I/O has completed. */
@@ -1189,12 +1269,13 @@
 	clear_bit(PG_uptodate, &page->flags);
 	clear_bit(PG_error, &page->flags);
 	/*
-	 * Allocate buffer heads pointing to this page, just for I/O.
+	 * Allocate async buffer heads pointing to this page, just for I/O.
 	 * They do _not_ show up in the buffer hash table!
 	 * They are _not_ registered in page->buffers either!
 	 */
-	bh = create_buffers(page_address(page), size);
+	bh = create_buffers(page_address(page), size, 1);
 	if (!bh) {
+		/* WSH: exit here leaves page->count incremented */
 		clear_bit(PG_locked, &page->flags);
 		wake_up(&page->wait);
 		return -ENOMEM;
@@ -1405,16 +1486,15 @@
 		return 0;
 	}
 
-	isize = BUFSIZE_INDEX(size);
-
 	if (!(page = __get_free_page(pri)))
 		return 0;
-	bh = create_buffers(page, size);
+	bh = create_buffers(page, size, 0);
 	if (!bh) {
 		free_page(page);
 		return 0;
 	}
 
+	isize = BUFSIZE_INDEX(size);
 	insert_point = free_list[isize];
 
 	tmp = bh;
@@ -1554,6 +1634,18 @@
 				      SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if(!bh_cachep)
 		panic("Cannot create buffer head SLAB cache\n");
+	/*
+	 * Allocate the reserved buffer heads.
+	 */
+	while (nr_buffer_heads < NR_RESERVED) {
+		struct buffer_head * bh;
+
+		bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC);
+		if (!bh)
+			break;
+		put_unused_buffer_head(bh);
+		nr_buffer_heads++;
+	}
 
 	lru_list[BUF_CLEAN] = 0;
 	grow_buffers(GFP_KERNEL, BLOCK_SIZE);
diff -u --recursive --new-file v2.1.47/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.47/linux/fs/dcache.c	Sun Jul 27 12:11:00 1997
+++ linux/fs/dcache.c	Mon Jul 28 15:31:08 1997
@@ -353,27 +353,43 @@
 	dentry->d_parent = newdir;
 	d_insert_to_parent(dentry, newdir);
 }
-
 /*
- * This is broken in more ways than one. Unchecked recursion,
- * unchecked buffer size. Get rid of it.
+ * "buflen" should be PAGE_SIZE or more.
  */
-int d_path(struct dentry * entry, struct dentry * chroot, char * buf)
+char * d_path(struct dentry *dentry, char *buffer, int buflen)
 {
-	if (IS_ROOT(entry) || (chroot && entry == chroot)) {
-		*buf = '/';
-		return 1;
-	} else {
-		int len = d_path(entry->d_covers->d_parent, chroot, buf);
+	char * end = buffer+buflen;
+	char * retval;
+	struct dentry * root = current->fs->root;
+
+	*--end = '\0';
+	buflen--;
+
+	/* Get '/' right */
+	retval = end-1;
+	*retval = '/';
+
+	for (;;) {
+		struct dentry * parent;
+		int namelen;
 
-		buf += len;
-		if (len > 1) {
-			*buf++ = '/';
-			len++;
-		}
-		memcpy(buf, entry->d_name.name, entry->d_name.len);
-		return len + entry->d_name.len;
+		if (dentry == root)
+			break;
+		dentry = dentry->d_covers;
+		parent = dentry->d_parent;
+		if (dentry == parent)
+			break;
+		namelen = dentry->d_name.len;
+		buflen -= namelen + 1;
+		if (buflen < 0)
+			break;
+		end -= namelen;
+		memcpy(end, dentry->d_name.name, namelen);
+		*--end = '/';
+		retval = end;
+		dentry = parent;
 	}
+	return retval;
 }
 
 __initfunc(void dcache_init(void))
diff -u --recursive --new-file v2.1.47/linux/fs/devices.c linux/fs/devices.c
--- v2.1.47/linux/fs/devices.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/devices.c	Thu Jul 31 14:54:33 1997
@@ -210,7 +210,9 @@
 	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
 		kdevname(dev));
 
-	invalidate_inodes(dev);
+	if (invalidate_inodes(dev))
+		printk("VFS: busy inodes on changed media..\n");
+
 	invalidate_buffers(dev);
 
 	if (fops->revalidate)
diff -u --recursive --new-file v2.1.47/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.47/linux/fs/dquot.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/dquot.c	Sun Aug  3 15:31:57 1997
@@ -20,6 +20,8 @@
  * Fixes:   Dmitry Gorodchanin <begemot@bgm.rosprint.net>, 11 Feb 96
  *	    removed race conditions in dqput(), dqget() and iput(). 
  *          Andi Kleen removed all verify_area() calls, 31 Dec 96  
+ *          Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97
+ *          Fixed a condition where user and group quotas could get mixed up.
  *
  * (C) Copyright 1994, 1995 Marco van Wieringen 
  *
@@ -555,12 +557,14 @@
 repeat:
 	dquot = *(hash(dev, id, type));
 	while (dquot) {
-		if (dquot->dq_dev != dev || dquot->dq_id != id) {
+		if (dquot->dq_dev != dev || dquot->dq_id != id ||
+		    dquot->dq_type != type) {
 			dquot = dquot->dq_hash_next;
 			continue;
 		}
 		wait_on_dquot(dquot);
-		if (dquot->dq_dev != dev || dquot->dq_id != id)
+		if (dquot->dq_dev != dev || dquot->dq_id != id ||
+		    dquot->dq_type != type)
 			goto repeat;
 		if (!dquot->dq_count)
 			nr_free_dquots--;
diff -u --recursive --new-file v2.1.47/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.1.47/linux/fs/ext2/ialloc.c	Sun Jul 20 20:41:58 1997
+++ linux/fs/ext2/ialloc.c	Mon Aug  4 12:41:11 1997
@@ -290,8 +290,18 @@
 	struct ext2_group_desc * tmp;
 	struct ext2_super_block * es;
 
-	if (!dir || !(inode = get_empty_inode ()))
+	/* Cannot create files in a deleted directory */
+	if (!dir || !dir->i_nlink) {
+		*err = -EPERM;
 		return NULL;
+	}
+
+	inode = get_empty_inode ();
+	if (!inode) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+
 	sb = dir->i_sb;
 	inode->i_sb = sb;
 	inode->i_flags = sb->s_flags;
diff -u --recursive --new-file v2.1.47/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.1.47/linux/fs/ext2/namei.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/ext2/namei.c	Mon Aug  4 12:32:05 1997
@@ -905,10 +905,14 @@
 			goto end_rename;
 	}
 	retval = -EPERM;
-	if (new_inode && (new_dir->i_mode & S_ISVTX) &&
-	    current->fsuid != new_inode->i_uid &&
-	    current->fsuid != new_dir->i_uid && !fsuser())
-		goto end_rename;
+	if (new_inode) {
+		if ((new_dir->i_mode & S_ISVTX) &&
+		    current->fsuid != new_inode->i_uid &&
+		    current->fsuid != new_dir->i_uid && !fsuser())
+			goto end_rename;
+		if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
+			goto end_rename;
+	}
 	if (S_ISDIR(old_inode->i_mode)) {
 		retval = -ENOTDIR;
 		if (new_inode && !S_ISDIR(new_inode->i_mode))
diff -u --recursive --new-file v2.1.47/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.1.47/linux/fs/fat/cache.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/fat/cache.c	Thu Jul 31 13:09:17 1997
@@ -276,8 +276,7 @@
 		}
 	}
 	if (last)
-		fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
-		    12 ? EOF_FAT12 : EOF_FAT16);
+		fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb));
 	else {
 		MSDOS_I(inode)->i_start = 0;
 		mark_inode_dirty(inode);
diff -u --recursive --new-file v2.1.47/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v2.1.47/linux/fs/fat/fatfs_syms.c	Fri Jan  3 01:33:26 1997
+++ linux/fs/fat/fatfs_syms.c	Sun Jul 27 12:24:35 1997
@@ -23,6 +23,7 @@
 EXPORT_SYMBOL(fat_cache_inval_inode);
 EXPORT_SYMBOL(fat_code2uni);
 EXPORT_SYMBOL(fat_date_unix2dos);
+EXPORT_SYMBOL(fat_delete_inode);
 EXPORT_SYMBOL(fat_dir_operations);
 EXPORT_SYMBOL(fat_file_read);
 EXPORT_SYMBOL(fat_file_write);
diff -u --recursive --new-file v2.1.47/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.1.47/linux/fs/fat/misc.c	Sun Jul 27 12:11:00 1997
+++ linux/fs/fat/misc.c	Thu Jul 31 13:09:17 1997
@@ -138,8 +138,7 @@
 		unlock_fat(sb);
 		return -ENOSPC;
 	}
-	fat_access(sb,nr,MSDOS_SB(sb)->fat_bits == 12 ?
-	    EOF_FAT12 : EOF_FAT16);
+	fat_access(sb,nr,EOF_FAT(sb));
 	if (MSDOS_SB(sb)->free_clusters != -1)
 		MSDOS_SB(sb)->free_clusters--;
 	unlock_fat(sb);
diff -u --recursive --new-file v2.1.47/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v2.1.47/linux/fs/hpfs/hpfs_fs.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/hpfs/hpfs_fs.c	Sun Aug  3 00:20:28 1997
@@ -1127,13 +1127,14 @@
 	ino_t ino;
 	const char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
+	int retval;
 
 	/* In case of madness */
 
 	if (dir == 0)
 		return -ENOENT;
 	if (!S_ISDIR(dir->i_mode))
-		goto bail;
+		return -ENOENT;
 
 	/*
 	 * Read in the directory entry. "." is there under the name ^A^A .
@@ -1153,8 +1154,9 @@
 	 * This is not really a bailout, just means file not found.
 	 */
 
+	inode = NULL;
 	if (!de)
-		goto bail;
+		goto add_dentry;
 
 	/*
 	 * Get inode number, what we're after.
@@ -1169,8 +1171,9 @@
 	 * Go find or make an inode.
 	 */
 
+	retval = -EACCES;
 	if (!(inode = iget(dir->i_sb, ino)))
-		goto bail1;
+		goto free4;
 
 	/*
 	 * Fill in the info from the directory if this is a newly created
@@ -1195,24 +1198,16 @@
 		}
 	}
 
-	brelse4(&qbh);
-
 	/*
-	 * Made it.
+	 * Add the dentry, negative or otherwise.
 	 */
+      add_dentry:
+	d_add(dentry, inode);
+	retval = 0;
 
-	d_instantiate(dentry, inode);
-	iput(dir);
-	return 0;
-
-	/*
-	 * Didn't.
-	 */
- bail1:
+      free4:
 	brelse4(&qbh);
- bail:
-	iput(dir);
-	return -ENOENT;
+	return retval;
 }
 
 /*
diff -u --recursive --new-file v2.1.47/linux/fs/inode.c linux/fs/inode.c
--- v2.1.47/linux/fs/inode.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/inode.c	Sun Aug  3 00:22:23 1997
@@ -206,14 +206,36 @@
 	inode->i_state = 0;
 }
 
-#define CAN_UNUSE(inode) \
-	(((inode)->i_count == 0) && \
-	 ((inode)->i_nrpages == 0) && \
-	 (!(inode)->i_state))
+/*
+ * Dispose-list gets a local list, so it doesn't need to
+ * worry about list corruption.
+ */
+static void dispose_list(struct list_head * head)
+{
+	struct list_head *next;
+
+	next = head->next;
+	for (;;) {
+		struct list_head * tmp = next;
+		struct inode * inode;
 
-static void invalidate_list(struct list_head *head, kdev_t dev)
+		next = next->next;
+		if (tmp == head)
+			break;
+		inode = list_entry(tmp, struct inode, i_list);
+		truncate_inode_pages(inode, 0);
+	}
+
+	/* Add them all to the unused list in one fell swoop */
+	spin_lock(&inode_lock);
+	list_splice(head, &inode_unused);
+	spin_unlock(&inode_lock);
+}
+
+static int invalidate_list(struct list_head *head, kdev_t dev, struct list_head * dispose)
 {
 	struct list_head *next;
+	int busy = 0;
 
 	next = head->next;
 	for (;;) {
@@ -225,22 +247,39 @@
 			break;
 		inode = list_entry(tmp, struct inode, i_list);
 		if (inode->i_dev != dev)
-			continue;		
-		if (!CAN_UNUSE(inode))
 			continue;
-		list_del(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_hash);
-		list_del(&inode->i_list);
-		list_add(&inode->i_list, &inode_unused);
+		if (!inode->i_count && !inode->i_state) {
+			list_del(&inode->i_hash);
+			INIT_LIST_HEAD(&inode->i_hash);
+			list_del(&inode->i_list);
+			list_add(&inode->i_list, dispose);
+			continue;
+		}
+		busy = 1;
 	}
+	return busy;
 }
 
-void invalidate_inodes(kdev_t dev)
+/*
+ * This is a two-stage process. First we collect all
+ * offending inodes onto the throw-away list, and in
+ * the second stage we actually dispose of them. This
+ * is because we don't want to sleep while messing
+ * with the global lists..
+ */
+int invalidate_inodes(kdev_t dev)
 {
+	int busy;
+	LIST_HEAD(throw_away);
+
 	spin_lock(&inode_lock);
-	invalidate_list(&inode_in_use, dev);
-	invalidate_list(&inode_dirty, dev);
+	busy = invalidate_list(&inode_in_use, dev, &throw_away);
+	busy |= invalidate_list(&inode_dirty, dev, &throw_away);
 	spin_unlock(&inode_lock);
+
+	dispose_list(&throw_away);
+
+	return busy;
 }
 
 /*
@@ -251,6 +290,11 @@
  * Otherwise we just move the inode to be the first inode and expect to
  * get back to the problem later..
  */
+#define CAN_UNUSE(inode) \
+	(((inode)->i_count == 0) && \
+	 ((inode)->i_nrpages == 0) && \
+	 (!(inode)->i_state))
+
 static void try_to_free_inodes(void)
 {
 	struct list_head * tmp;
@@ -504,7 +548,22 @@
 	return root->d_count == 1;
 }
 
+/* This belongs in file_table.c, not here... */
 int fs_may_remount_ro(struct super_block *sb)
 {
-	return 1;
+	struct file *file;
+	kdev_t dev = sb->s_dev;
+
+	/* Check that no files are currently opened for writing. */
+	for (file = inuse_filps; file; file = file->f_next) {
+		struct inode *inode;
+		if (!file->f_dentry)
+			continue;
+		inode = file->f_dentry->d_inode;
+		if (!inode || inode->i_dev != dev)
+			continue;
+		if (S_ISREG(inode->i_mode) && file->f_mode & FMODE_WRITE)
+			return 0;
+	}
+	return 1; /* Tis' cool bro. */
 }
diff -u --recursive --new-file v2.1.47/linux/fs/namei.c linux/fs/namei.c
--- v2.1.47/linux/fs/namei.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/namei.c	Mon Aug  4 09:37:25 1997
@@ -240,45 +240,44 @@
 	struct dentry * result;
 	struct inode *dir = parent->d_inode;
 
-	result = ERR_PTR(-ENOTDIR);
-	if (dir->i_op && dir->i_op->lookup) {
-		down(&dir->i_sem);
-		result = d_lookup(parent, name);
-		if (!result) {
-			int error;
-			result = d_alloc(parent, name);
-			error = dir->i_op->lookup(dir, result);
-			if (error) {
-				d_free(result);
-				result = ERR_PTR(error);
-			}
+	down(&dir->i_sem);
+	result = d_lookup(parent, name);
+	if (!result) {
+		int error;
+		result = d_alloc(parent, name);
+		error = dir->i_op->lookup(dir, result);
+		if (error) {
+			d_free(result);
+			result = ERR_PTR(error);
 		}
-		up(&dir->i_sem);
 	}
+	up(&dir->i_sem);
 	return result;
 }
 
-/* Internal lookup() using the new generic dcache. */
+/*
+ * Internal lookup() using the new generic dcache.
+ *
+ * Note the revalidation: we have to drop the dcache
+ * lock when we revalidate, so we need to update the
+ * counts around it.
+ */
 static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
 {
 	struct dentry * dentry = d_lookup(parent, name);
 
-	if (dentry) {
-		if (dentry->d_revalidate) {
-			/* spin_unlock(&dentry_lock); */
-			dentry = dentry->d_revalidate(dentry);
-			/* spin_lock(&dentry_lock); */
-		}
-
-		/*
-		 * The parent d_count _should_ be at least 2: one for the
-		 * dentry we found, and one for the fact that we are using
-		 * it.
-		 */
-		if (parent->d_count <= 1) {
-			printk("lookup of %s success in %s, but parent count is %d\n",
-				dentry->d_name.name, parent->d_name.name, parent->d_count);
+	if (dentry && dentry->d_revalidate) {
+		int validated, (*revalidate)(struct dentry *) = dentry->d_revalidate;
+		struct dentry * save;
+
+		dentry->d_count++;
+		validated = revalidate(dentry);
+		save = dentry;
+		if (!validated) {
+			d_drop(dentry);
+			dentry = NULL;
 		}
+		dput(save);
 	}
 	return dentry;
 }
@@ -311,15 +310,8 @@
 /* In difference to the former version, lookup() no longer eats the dir. */
 static struct dentry * lookup(struct dentry * dir, struct qstr * name)
 {
-	int err;
 	struct dentry * result;
 
-	/* Check permissions before traversing mount-points. */
-	err = permission(dir->d_inode, MAY_EXEC);
-	result = ERR_PTR(err);
- 	if (err)
-		goto done_error;
-
 	result = reserved_lookup(dir, name);
 	if (result)
 		goto done_noerror;
@@ -334,7 +326,6 @@
 done_noerror:
 		result = dget(result->d_mounts);
 	}
-done_error:
 	return result;
 }
 
@@ -396,14 +387,26 @@
 
 	/* At this point we know we have a real path component. */
 	for(;;) {
-		int len;
+		int len, err;
 		unsigned long hash;
 		struct qstr this;
+		struct inode *inode;
 		char c, follow;
 
 		dentry = ERR_PTR(-ENOENT);
-		if (!base->d_inode)
+		inode = base->d_inode;
+		if (!inode)
+			break;
+
+		dentry = ERR_PTR(-ENOTDIR);
+		if (!inode->i_op || !inode->i_op->lookup)
+			break;
+
+		err = permission(inode, MAY_EXEC);
+		dentry = ERR_PTR(err);
+ 		if (err)
 			break;
+
 		this.name = name;
 		hash = init_name_hash();
 		len = 0;
@@ -831,6 +834,10 @@
 
 	dir = lock_parent(dentry);
 
+	error = -ENOENT;
+	if (!dentry->d_inode)
+		goto exit_lock;
+
 	error = -EROFS;
 	if (IS_RDONLY(dir))
 		goto exit_lock;
@@ -890,11 +897,11 @@
 	if (IS_ERR(dentry))
 		goto exit;
 
+	dir = lock_parent(dentry);
+
 	error = -EEXIST;
 	if (dentry->d_inode)
-		goto exit;
-
-	dir = lock_parent(dentry);
+		goto exit_lock;
 
 	error = -EROFS;
 	if (IS_RDONLY(dir))
@@ -1037,13 +1044,19 @@
 		down(s2);
 	} else if (s1 == s2) {
 		down(s1);
-		atomic_dec(&s1->count);
 	} else {
 		down(s2);
 		down(s1);
 	}
 }
 
+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
+{
+	up(s1);
+	if (s1 != s2)
+		up(s2);
+}
+
 static inline int is_reserved(struct dentry *dentry)
 {
 	if (dentry->d_name.name[0] == '.') {
@@ -1126,8 +1139,7 @@
 	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
 
 exit_lock:
-	up(&new_dir->i_sem);
-	up(&old_dir->i_sem);
+	double_up(&new_dir->i_sem, &old_dir->i_sem);
 	dput(new_dentry);
 exit_old:
 	dput(old_dentry);
diff -u --recursive --new-file v2.1.47/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.47/linux/fs/nfs/dir.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/nfs/dir.c	Mon Aug  4 12:48:16 1997
@@ -326,7 +326,28 @@
 		cache->entry = NULL;
 	}
 }
- 
+
+/*
+ * This is called every time the dcache has a lookup hit,
+ * and we should check whether we can really trust that
+ * lookup.
+ *
+ * NOTE! The hit can be a negative hit too, don't assume
+ * we have an inode!
+ *
+ * The decision to drop the dentry should probably be
+ * smarter than this. Right now we believe in directories
+ * for 10 seconds, and in normal files for five..
+ */
+static int nfs_lookup_revalidate(struct dentry * dentry)
+{
+	unsigned long time = jiffies - dentry->d_time;
+	unsigned long max = 5*HZ;
+
+	if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+		max = 10*HZ;
+	return time < max;
+}
 
 static int nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
@@ -358,6 +379,8 @@
 	} else if (error != -ENOENT)
 		return error;
 
+	dentry->d_time = jiffies;
+	dentry->d_revalidate = nfs_lookup_revalidate;
 	d_add(dentry, inode);
 	return 0;
 }
@@ -394,6 +417,7 @@
 	if (!inode)
 		return -EACCES;
 
+	nfs_invalidate_dircache(dir);
 	d_instantiate(dentry, inode);
 	return 0;
 }
@@ -433,6 +457,7 @@
 	if (!inode)
 		return -EACCES;
 
+	nfs_invalidate_dircache(dir);
 	d_instantiate(dentry, inode);
 	return 0;
 }
@@ -470,6 +495,7 @@
 	if (!inode)
 		return -EACCES;
 
+	nfs_invalidate_dircache(dir);
 	d_instantiate(dentry, inode);
 	return 0;
 }
@@ -493,6 +519,7 @@
 	if (error)
 		return error;
 
+	nfs_invalidate_dircache(dir);
 	d_delete(dentry);
 	return 0;
 }
@@ -520,6 +547,7 @@
 	if (error)
 		return error;
 
+	nfs_invalidate_dircache(dir);
 	d_delete(dentry);
 	return 0;
 }
@@ -560,6 +588,7 @@
 	if (!inode)
 		return -EACCES;
 
+	nfs_invalidate_dircache(dir);
 	d_instantiate(dentry, inode);
 	return 0;
 }
@@ -586,6 +615,7 @@
 	if (error)
 		return error;
 
+	nfs_invalidate_dircache(dir);
 	inode->i_count++;
 	d_instantiate(dentry, inode);
 	return 0;
@@ -628,6 +658,9 @@
 
 	if (error)
 		return error;
+
+	nfs_invalidate_dircache(old_dir);
+	nfs_invalidate_dircache(new_dir);
 
 	/* Update the dcache */
 	d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
diff -u --recursive --new-file v2.1.47/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.47/linux/fs/pipe.c	Sun Jul 20 20:41:58 1997
+++ linux/fs/pipe.c	Mon Jul 28 13:33:18 1997
@@ -483,6 +483,7 @@
 close_f12_inode_i:
 	put_unused_fd(i);
 close_f12_inode:
+	free_page((unsigned long) PIPE_BASE(*inode));
 	iput(inode);
 close_f12:
 	put_filp(f2);
diff -u --recursive --new-file v2.1.47/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.47/linux/fs/proc/array.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/proc/array.c	Thu Jul 31 13:09:18 1997
@@ -455,7 +455,7 @@
 		return ((unsigned long *)schedule_frame)[12];
 	    }
 	    return pc;
-	}
+	}	
 #elif defined(__mc68000__)
 	{
 	    unsigned long fp, pc;
@@ -480,6 +480,8 @@
 		    fp = *(unsigned long *) fp;
 	    } while (count++ < 16);
 	}
+#elif defined(__powerpc__)
+	return (p->tss.wchan);
 #endif
 	return 0;
 }
@@ -505,6 +507,9 @@
 	      eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc;	 \
         eip; })
 #define	KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__powerpc__)
+#define KSTK_EIP(tsk)	((tsk)->tss.regs->nip)
+#define KSTK_ESP(tsk)	((tsk)->tss.regs->gpr[1])
 #elif defined (__sparc_v9__)
 # define KSTK_EIP(tsk)  ((tsk)->tss.kregs->tpc)
 # define KSTK_ESP(tsk)  ((tsk)->tss.kregs->u_regs[UREG_FP])
diff -u --recursive --new-file v2.1.47/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.1.47/linux/fs/proc/link.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/proc/link.c	Mon Jul 28 13:47:43 1997
@@ -138,15 +138,18 @@
 	if (!IS_ERR(dentry)) {
 		error = -ENOENT;
 		if (dentry) {
-			char * tmp = (char*)__get_free_page(GFP_KERNEL);
-			int len = d_path(dentry, current->fs->root, tmp);
-			int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
-			if(len <= min)
-				min = len+1;
+			char * tmp = (char*)__get_free_page(GFP_KERNEL), *path;
+			int len;
+
+			path = d_path(dentry, tmp, PAGE_SIZE);
+			len = tmp + PAGE_SIZE - path;
+
+			if (len < buflen)
+				buflen = len;
 			dput(dentry);
-			copy_to_user(buffer, tmp, min);
+			copy_to_user(buffer, path, buflen);
 			free_page((unsigned long)tmp);
-			error = len;
+			error = buflen;
 		}
 	}
 	return error;
diff -u --recursive --new-file v2.1.47/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.47/linux/fs/proc/openpromfs.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/proc/openpromfs.c	Thu Jul 31 13:09:18 1997
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
+/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -54,12 +54,10 @@
 #define NODE2INO(node) (node + PROC_OPENPROM_FIRST)
 #define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
 
-static int openpromfs_create (struct inode *, const char *, int, int,
-			      struct inode **);
+static int openpromfs_create (struct inode *, struct dentry *, int);
 static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int openpromfs_lookup(struct inode *, const char *, int,
-			     struct inode **);
-static int openpromfs_unlink (struct inode *, const char *, int);
+static int openpromfs_lookup(struct inode *, struct dentry *dentry);
+static int openpromfs_unlink (struct inode *, struct dentry *dentry);
 
 static long nodenum_read(struct inode *inode, struct file *file,
 			 char *buf, unsigned long count)
@@ -602,8 +600,7 @@
 	return 0;
 }
 
-static int openpromfs_lookup(struct inode * dir, const char * name, int len,
-	struct inode ** result)
+static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
 {
 	int ino = 0;
 #define OPFSL_DIR	0
@@ -613,40 +610,21 @@
 	int type = 0;
 	char buffer[128];
 	char *p;
+	const char *name;
 	u32 n;
 	u16 dirnode;
+	unsigned int len;
 	int i;
 	struct inode *inode;
 	struct openpromfs_dev *d = NULL;
 	char buffer2[64];
 	
-	*result = NULL;
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		iput(dir);
-		return -ENOTDIR;
-	}
-	*result = dir;
-	if (!len) return 0;
-	if (name [0] == '.') {
-		if (len == 1)
-			return 0;
-		if (name [1] == '.' && len == 2) {
-			if (dir->i_ino == PROC_OPENPROM) {
-				inode = proc_get_inode (dir->i_sb,
-							PROC_ROOT_INO,
-							&proc_root);
-				iput(dir);
-				if (!inode)
-					return -EINVAL;
-				*result = inode;
-				return 0;
-			}
-			ino = NODE2INO(NODE(dir->i_ino).parent);
-			type = OPFSL_DIR;
-		} else if (len == 5 && !strncmp (name + 1, "node", 4)) {
-			ino = NODEP2INO(NODE(dir->i_ino).first_prop);
-			type = OPFSL_NODENUM;
-		}
+	inode = NULL;
+	name = dentry->d_name.name;
+	len = dentry->d_name.len;
+	if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) {
+		ino = NODEP2INO(NODE(dir->i_ino).first_prop);
+		type = OPFSL_NODENUM;
 	}
 	if (!ino) {
 		u16 node = NODE(dir->i_ino).child;
@@ -712,13 +690,10 @@
 		ino = lookup_children (NODE(dir->i_ino).child, name, len);
 		if (ino)
 			type = OPFSL_DIR;
-		else {
-			iput(dir);
+		else
 			return -ENOENT;
-		}
 	}
 	inode = proc_get_inode (dir->i_sb, ino, 0);
-	iput(dir);
 	if (!inode)
 		return -EINVAL;
 	switch (type) {
@@ -762,7 +737,7 @@
 		inode->i_rdev = d->rdev;
 		break;
 	}		
-	*result = inode;
+	d_add(dentry, inode);
 	return 0;
 }
 
@@ -858,16 +833,14 @@
 	return 0;
 }
 
-static int openpromfs_create (struct inode *dir, const char *name, int len, 
-			      int mode, struct inode **result)
+static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode)
 {
 	char *p;
 	struct inode *inode;
 	
-	*result = NULL;
 	if (!dir)
 		return -ENOENT;
-	if (len > 256) {
+	if (dentry->d_name.len > 256) {
 		iput (dir);
 		return -EINVAL;
 	}
@@ -875,13 +848,13 @@
 		iput (dir);
 		return -EIO;
 	}
-	p = kmalloc (len + 1, GFP_KERNEL);
+	p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
 	if (!p) {
 		iput (dir);
 		return -ENOMEM;
 	}
-	strncpy (p, name, len);
-	p [len] = 0;
+	strncpy (p, dentry->d_name.name, dentry->d_name.len);
+	p [dentry->d_name.len] = 0;
 	alias_names [aliases_nodes++] = p;
 	inode = proc_get_inode (dir->i_sb,
 				NODEP2INO(NODE(dir->i_ino).first_prop)
@@ -895,17 +868,19 @@
 	if (inode->i_size < 0) inode->i_size = 0;
 	inode->u.generic_ip = (void *)(long)(((u16)aliases) | 
 			(((u16)(aliases_nodes - 1)) << 16));
-	*result = inode;
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
-static int openpromfs_unlink (struct inode *dir, const char *name, int len)
+static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
 {
+	unsigned int len;
 	char *p;
+	const char *name;
 	int i;
 	
-	if (!dir)
-		return -ENOENT;
+	name = dentry->d_name.name;
+	len = dentry->d_name.len;
 	for (i = 0; i < aliases_nodes; i++)
 		if ((strlen (alias_names [i]) == len)
 		    && !strncmp (name, alias_names[i], len)) {
@@ -919,7 +894,7 @@
 			buffer [10 + len] = 0;
 			prom_feval (buffer);
 		}
-	iput (dir);
+	d_delete(dentry);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.47/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.47/linux/fs/proc/root.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/proc/root.c	Thu Jul 31 13:09:18 1997
@@ -151,14 +151,14 @@
 #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
 
 static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **);
+static int (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
 void (*proc_openprom_use)(struct inode *, int) = 0;
 static struct openpromfs_dev *proc_openprom_devices = NULL;
 static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
 
 struct inode_operations *
 proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
-		       int (*lookup)(struct inode *, struct qstr *, struct inode **),
+		       int (*lookup)(struct inode *, struct dentry *),
 		       void (*use)(struct inode *, int),
 		       struct openpromfs_dev ***devices)
 {
@@ -220,13 +220,13 @@
 }
 
 static int 
-proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result)
+proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
 {
 	request_module("openpromfs");
 	if (proc_openprom_inode_operations.lookup !=
 	    proc_openprom_deflookup)
 		return proc_openprom_inode_operations.lookup 
-				(dir, str, result);
+				(dir, dentry);
 	return -ENOENT;
 }
 #endif
diff -u --recursive --new-file v2.1.47/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.1.47/linux/fs/romfs/inode.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/romfs/inode.c	Thu Jul 31 08:31:06 1997
@@ -19,14 +19,24 @@
  *					Changed for 2.1.19 modules
  *	Jan 1997			Initial release
  *	Jun 1997			2.1.43+ changes
- *	Jul 1997			proper page locking in readpage
+ *					Proper page locking in readpage
  *					Changed to work with 2.1.45+ fs
- *					Fixed follow_link
+ *	Jul 1997			Fixed follow_link
+ *			2.1.47
+ *					lookup shouldn't return -ENOENT
+ *					from Horst von Brand:
+ *					  fail on wrong checksum
+ *					  double unlock_super was possible
+ *					  correct namelen for statfs
+ *					spotted by Bill Hawes:
+ *					  readlink shouldn't iput()
  */
 
 /* todo:
  *	- see Documentation/filesystems/romfs.txt
  *	- use malloced memory for file names?
+ *	- quicklist routines from fs/namei.c, get_page is possibly not
+ *	  intended to be used now
  *	- considering write access...
  *	- network (tftp) files?
  *	- in the ancient times something leaked to made umounts
@@ -106,6 +116,7 @@
 	if (romfs_checksum(rsb, min(sz,512))) {
 		printk ("romfs: bad initial checksum on dev "
 			"%s.\n", kdevname(dev));
+		goto out;
 	}
 
 	s->s_magic = ROMFS_MAGIC;
@@ -123,11 +134,11 @@
 	s->s_op	= &romfs_ops;
 	s->s_root = d_alloc_root(iget(s, sz), NULL);
 
-	unlock_super(s);
-
 	if (!s->s_root)
 		goto outnobh;
 
+	unlock_super(s);
+
 	/* Ehrhm; sorry.. :)  And thanks to Hans-Joachim Widmaier  :) */
 	if (0) {
 out:
@@ -165,7 +176,7 @@
 	tmp.f_type = ROMFS_MAGIC;
 	tmp.f_bsize = ROMBSIZE;
 	tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
-	/* XXX tmp.f_namelen = relevant? */
+	tmp.f_namelen = ROMFS_MAXFN;
 	return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
 }
 
@@ -314,16 +325,14 @@
 	const char *name;		/* got from dentry */
 	int len;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		res = -EBADF;
+	res = -EBADF;
+	if (!dir || !S_ISDIR(dir->i_mode))
 		goto out;
-	}
 
+	res = 0;			/* instead of ENOENT */
 	offset = dir->i_ino & ROMFH_MASK;
-	if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
-		res = -ENOENT;
+	if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
 		goto out;
-	}
 
 	maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
 	offset = ntohl(ri.spec) & ROMFH_MASK;
@@ -336,10 +345,8 @@
 
 	for(;;) {
 		if (!offset || offset >= maxoff
-		    || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
-			res = -ENOENT;
+		    || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
 			goto out;
-		}
 
 		/* try to match the first 16 bytes of name */
 		fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
@@ -367,9 +374,9 @@
 	if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
 		offset = ntohl(ri.spec) & ROMFH_MASK;
 
-	res = -EACCES;
-	if ((inode = iget(dir->i_sb, offset))!=NULL) {
-		res = 0;
+	if ((inode = iget(dir->i_sb, offset))==NULL) {
+		res = -EACCES;
+	} else {
 		d_add(dentry, inode);
 	}
 
@@ -439,7 +446,6 @@
 	copy_to_user(buffer, buf, mylen);
 
 out:
-	iput(inode);
 	return mylen;
 }
 
@@ -597,6 +603,8 @@
 			printk("romfs: read error for inode 0x%x\n", ino);
 			return;
 		}
+		/* XXX: do romfs_checksum here too (with name) */
+
 		nextfh = ntohl(ri.next);
 		if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
 			break;
diff -u --recursive --new-file v2.1.47/linux/fs/super.c linux/fs/super.c
--- v2.1.47/linux/fs/super.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/super.c	Thu Jul 31 14:57:33 1997
@@ -618,6 +618,9 @@
 	d_umount(sb->s_root);
 	sb->s_root = NULL;
 
+	/* Forget any inodes */
+	invalidate_inodes(dev);
+
 	if (sb->s_op) {
 		if (sb->s_op->write_super && sb->s_dirt)
 			sb->s_op->write_super(sb);
diff -u --recursive --new-file v2.1.47/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c
--- v2.1.47/linux/fs/ufs/ufs_namei.c	Thu Jul 17 10:06:08 1997
+++ linux/fs/ufs/ufs_namei.c	Thu Jul 31 13:09:18 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_namei.c,v 1.8 1997/07/17 02:24:14 davem Exp $
+ * $Id: ufs_namei.c,v 1.9 1997/07/22 06:40:12 davem Exp $
  *
  */
 
@@ -131,8 +131,11 @@
 	                        break;
 	                }
 	                if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-	                        printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  d_reclen %u  d_namlen %u  d_name `%s'\n",
-	                               lfragno, (unsigned int)d, ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen), ufs_swab16(d->d_namlen), d->d_name);
+	                        printk("lfragno 0x%lx  direct d 0x%x  d_ino %u  "
+				       "d_reclen %u  d_namlen %u  d_name `%s'\n",
+	                               lfragno, (unsigned int)((unsigned long)d),
+				       ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen),
+				       ufs_swab16(d->d_namlen), d->d_name);
 	                }
 	                if ((ufs_swab16(d->d_namlen) == len) &&
 	                    /* XXX - don't use strncmp() - see ext2fs */
diff -u --recursive --new-file v2.1.47/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.47/linux/fs/vfat/namei.c	Thu Jul 17 10:06:08 1997
+++ linux/fs/vfat/namei.c	Sat Aug  2 17:11:14 1997
@@ -69,13 +69,14 @@
 
 static struct super_operations vfat_sops = { 
 	vfat_read_inode,
-	fat_notify_change,
 	fat_write_inode,
 	fat_put_inode,
+	fat_delete_inode,
+	fat_notify_change,
 	vfat_put_super,
-	NULL, /* added in 0.96c */
+	NULL, /* write_super */
 	fat_statfs,
-	NULL
+	NULL  /* remount */
 };
 
 static int parse_options(char *options,	struct fat_mount_options *opts)
@@ -227,7 +228,7 @@
 static char bad_if_strict[] = "+=,; []";
 static char replace_chars[] = "[];,+=";
 
-static int vfat_find(struct inode *dir,const char *name,int len,
+static int vfat_find(struct inode *dir,struct qstr* name,
 		      int find_long,int new_filename,int is_dir,
 		      struct slot_info *sinfo_out);
 
@@ -409,6 +410,7 @@
 	char buf[8];
 	struct slot_info sinfo;
 	const char *name_start;
+	struct qstr qname;
 
 	PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
 	sz = 0;			/* Make compiler happy */
@@ -427,7 +429,9 @@
 		res = vfat_format_name('x', msdos_name, len, name_res, 1);
 		if (res > -1) {
 			PRINTK(("vfat_create_shortname 1\n"));
-			res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
+			qname.name=msdos_name;
+			qname.len=len;
+			res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
 			PRINTK(("vfat_create_shortname 2\n"));
 			if (res > -1) return -EEXIST;
 			return 0;
@@ -516,7 +520,9 @@
 	totlen = baselen + extlen + (extlen > 0);
 	res = 0;
 	if (MSDOS_SB(dir->i_sb)->options.numtail == 0) {
-		res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+		qname.name=msdos_name;
+		qname.len=totlen;
+		res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
 	}
 	i = 0;
 	while (res > -1) {
@@ -537,7 +543,9 @@
 		strcpy(&msdos_name[baselen+sz+2], ext);
 
 		totlen = baselen + sz + 1 + extlen + (extlen > 0);
-		res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+		qname.name=msdos_name;
+		qname.len=totlen;
+		res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
 	}
 	res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
 	return res;
@@ -803,7 +811,7 @@
 	return -1;
 }
 
-static int vfat_find(struct inode *dir,const char *name,int len,
+static int vfat_find(struct inode *dir,struct qstr* qname,
     int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
 {
 	struct super_block *sb = dir->i_sb;
@@ -820,8 +828,8 @@
 
 	PRINTK(("Entering vfat_find\n"));
 	fil.f_pos = 0;
-	vf.name = name;
-	vf.len = len;
+	vf.name = qname->name;
+	vf.len = qname->len;
 	vf.new_filename = new_filename;
 	vf.found = 0;
 	vf.posix = MSDOS_SB(sb)->options.posixfs;
@@ -847,7 +855,8 @@
 	if (!vf.found && !new_filename)
 		return -ENOENT;
 	
-	res = vfat_build_slots(dir, name, len, ds, &slots, &is_long);
+	res = vfat_build_slots(dir, qname->name, qname->len, ds, 
+			       &slots, &is_long);
 	if (res < 0) return res;
 
 	de = (struct msdos_dir_entry *) ds;
@@ -910,71 +919,54 @@
 	return -ENOENT;
 }
 
-int vfat_lookup(struct inode *dir,const char *name,int len,
-    struct inode **result)
+int vfat_lookup(struct inode *dir,struct dentry *dentry)
 {
-	int res, ino;
+	int res;
 	struct inode *next;
 	struct slot_info sinfo;
+	struct inode *result;
 	
-	PRINTK (("vfat_lookup: name=%s, len=%d\n", name, len));
+	PRINTK (("vfat_lookup: name=%s, len=%d\n", 
+		 dentry->d_name.name, dentry->d_name.len));
 
-	*result = NULL;
-	if (!dir) return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		iput(dir);
-		return -ENOENT;
-	}
-	PRINTK (("vfat_lookup 2\n"));
-	if (len == 1 && name[0] == '.') {
-		*result = dir;
-		return 0;
-	}
-	if (len == 2 && name[0] == '.' && name[1] == '.') {
-		ino = fat_parent_ino(dir,0);
-		iput(dir);
-		if (ino < 0) return ino;
-		if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
+	result = NULL;
+	if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0) {
+		d_add(dentry,NULL);
 		return 0;
 	}
-	PRINTK (("vfat_lookup 3\n"));
-	if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
-		iput(dir);
-		return res;
-	}
 	PRINTK (("vfat_lookup 4.5\n"));
-	if (!(*result = iget(dir->i_sb,sinfo.ino))) {
-		iput(dir);
+	if (!(result = iget(dir->i_sb,sinfo.ino)))
 		return -EACCES;
-	}
 	PRINTK (("vfat_lookup 5\n"));
-	if (!(*result)->i_sb ||
-	    ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
+	if (!result->i_sb ||
+	    (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
 		/* crossed a mount point into a non-msdos fs */
-		iput(dir);
+		d_add(dentry,result);
 		return 0;
 	}
-	if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
-		iput(*result);
-		iput(dir);
-		return -ENOENT;
+	if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
+		iput(result);
+		d_add(dentry,NULL);
+		return 0;
 	}
 	PRINTK (("vfat_lookup 6\n"));
-	while (MSDOS_I(*result)->i_old) {
-		next = MSDOS_I(*result)->i_old;
-		iput(*result);
-		if (!(*result = iget(next->i_sb,next->i_ino))) {
+	while (MSDOS_I(result)->i_old) {
+		next = MSDOS_I(result)->i_old;
+		iput(result);
+		if (!(result = iget(next->i_sb,next->i_ino))) {
 			fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen");
 			iput(dir);
 			return -ENOENT;
 		}
 	}
-	iput(dir);
+	PRINTK (("vfat_lookup 7\n"));
+	d_add(dentry,result);
+	PRINTK (("vfat_lookup 8\n"));	
 	return 0;
 }
 
 
-static int vfat_create_entry(struct inode *dir,const char *name,int len,
+static int vfat_create_entry(struct inode *dir,struct qstr* qname,
     int is_dir, struct inode **result)
 {
 	struct super_block *sb = dir->i_sb;
@@ -984,8 +976,9 @@
 	struct msdos_dir_entry *de;
 	struct slot_info sinfo;
 
+	*result=0;
 	PRINTK(("vfat_create_entry 1\n"));
-	res = vfat_find(dir, name, len, 1, 1, is_dir, &sinfo);
+	res = vfat_find(dir, qname, 1, 1, is_dir, &sinfo);
 	if (res < 0) {
 		return res;
 	}
@@ -1017,19 +1010,18 @@
 	return 0;
 }
 
-int vfat_create(struct inode *dir,const char *name,int len,int mode,
-	struct inode **result)
+int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
 {
 	int res;
+	struct inode *result;
 
-	if (!dir) return -ENOENT;
-
+	result=NULL;
 	fat_lock_creation();
-	res = vfat_create_entry(dir,name,len,0,result);
+	res = vfat_create_entry(dir,&dentry->d_name,0,&result);
 	if (res < 0) PRINTK(("vfat_create: unable to get new entry\n"));
 
 	fat_unlock_creation();
-	iput(dir);
+	d_instantiate(dentry,result);
 	return res;
 }
 
@@ -1148,115 +1140,107 @@
 }
 
 static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
-     struct msdos_dir_entry *de,int ino)
+     struct msdos_dir_entry *de,struct dentry* dentry)
 {
 	struct super_block *sb = dir->i_sb;
-	struct inode *inode;
 	int res;
 
-	if (ino < 0) return -EINVAL;
-	if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
-	if (!S_ISDIR(inode->i_mode)) {
-		iput(inode);
+	if (!S_ISDIR(dentry->d_inode->i_mode)) {
 		return -ENOTDIR;
 	}
-	if (dir->i_dev != inode->i_dev || dir == inode) {
-		iput(inode);
+	if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) {
 		return -EBUSY;
 	}
-	res = vfat_empty(inode);
+	res = vfat_empty(dentry->d_inode);
 	if (res) {
-		iput(inode);
 		return res;
 	}
-	inode->i_nlink = 0;
-	inode->i_mtime = dir->i_mtime = CURRENT_TIME;
-	inode->i_atime = dir->i_atime = CURRENT_TIME;
+	dentry->d_inode->i_nlink = 0;
+	dentry->d_inode->i_mtime = dir->i_mtime = CURRENT_TIME;
+	dentry->d_inode->i_atime = dir->i_atime = CURRENT_TIME;
 	dir->i_nlink--;
 	mark_inode_dirty(dir);
-	mark_inode_dirty(inode);
+	mark_inode_dirty(dentry->d_inode);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh, 1);
-	iput(inode);
 
 	return 0;
 }
 
 static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh,
-     struct msdos_dir_entry *de,int ino,int nospc)
+     struct msdos_dir_entry *de,struct dentry* dentry,int nospc)
 {
 	struct super_block *sb = dir->i_sb;
-	struct inode *inode;
-	if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
-	if ((!S_ISREG(inode->i_mode) && nospc) || IS_IMMUTABLE(inode)) {
-		iput(inode);
+	if ((!S_ISREG(dentry->d_inode->i_mode) && nospc) || 
+	    IS_IMMUTABLE(dentry->d_inode)) {
 		return -EPERM;
 	}
-	inode->i_nlink = 0;
-	inode->i_mtime = dir->i_mtime = CURRENT_TIME;
-	inode->i_atime = dir->i_atime = CURRENT_TIME;
+	dentry->d_inode->i_nlink = 0;
+	dentry->d_inode->i_mtime = dir->i_mtime = CURRENT_TIME;
+	dentry->d_inode->i_atime = dir->i_atime = CURRENT_TIME;
 	dir->i_version = ++event;
-	MSDOS_I(inode)->i_busy = 1;
+	MSDOS_I(dentry->d_inode)->i_busy = 1;
 	mark_inode_dirty(dir);
-	mark_inode_dirty(inode);
+	mark_inode_dirty(dentry->d_inode);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh, 1);
 
-	iput(inode);
 	return 0;
 }
 
 static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
-     struct buffer_head **bh,struct msdos_dir_entry **de,
+     struct buffer_head **bh,struct dentry* dentry,
      int is_dir,int nospc)
 {
 	struct super_block *sb = dir->i_sb;
 	loff_t offset;
+	struct msdos_dir_entry *de;
 	int res, i;
 
 	/* remove the shortname */
 	offset = sinfo->shortname_offset;
-	res = fat_get_entry(dir, &offset, bh, de);
+	res = fat_get_entry(dir, &offset, bh, &de);
 	if (res < 0) return res;
 	if (is_dir) {
-		res = vfat_rmdir_free_ino(dir,*bh,*de,res);
+		res = vfat_rmdir_free_ino(dir,*bh,de,dentry);
 	} else {
-		res = vfat_unlink_free_ino(dir,*bh,*de,res,nospc);
+		res = vfat_unlink_free_ino(dir,*bh,de,dentry,nospc);
 	}
 	if (res < 0) return res;
 		
 	/* remove the longname */
 	offset = sinfo->longname_offset;
 	for (i = sinfo->long_slots; i > 0; --i) {
-		res = fat_get_entry(dir, &offset, bh, de);
+		res = fat_get_entry(dir, &offset, bh, &de);
 		if (res < 0) {
 			printk("vfat_remove_entry: problem 1\n");
 			continue;
 		}
-		(*de)->name[0] = DELETED_FLAG;
-		(*de)->attr = 0;
+		de->name[0] = DELETED_FLAG;
+		de->attr = 0;
 		fat_mark_buffer_dirty(sb, *bh, 1);
 	}
 	return 0;
 }
 
 
-static int vfat_rmdirx(struct inode *dir,const char *name,int len)
+static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
 {
 	struct super_block *sb = dir->i_sb;
 	int res;
 	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
 	struct slot_info sinfo;
 
 	bh = NULL;
 	res = -EPERM;
-	if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
+	if (dentry->d_name.name[0] == '.' && 
+	    (dentry->d_name.len == 1 || (dentry->d_name.len == 2 && 
+					 dentry->d_name.name[1] == '.')))
 		goto rmdir_done;
-	res = vfat_find(dir,name,len,1,0,0,&sinfo);
+	res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
 
 	if (res >= 0 && sinfo.total_slots > 0) {
-		res = vfat_remove_entry(dir,&sinfo,&bh,&de,1,0);
+		res = vfat_remove_entry(dir,&sinfo,&bh,dentry,1,0);
 		if (res > 0) {
 			res = 0;
 		}
@@ -1271,33 +1255,31 @@
 }
 
 /***** Remove a directory */
-int vfat_rmdir(struct inode *dir,const char *name,int len)
+int vfat_rmdir(struct inode *dir,struct dentry* dentry)
 {
 	int res;
 
-	res = vfat_rmdirx(dir, name, len);
-	iput(dir);
+	res = vfat_rmdirx(dir, dentry);
+	d_delete(dentry);
 	return res;
 }
 
 static int vfat_unlinkx(
 	struct inode *dir,
-	const char *name,
-	int len,
+	struct dentry* dentry,
 	int nospc)	/* Flag special file ? */
 {
 	struct super_block *sb = dir->i_sb;
 	int res;
 	struct buffer_head *bh;
-	struct msdos_dir_entry *de;
 	struct slot_info sinfo;
 
 	bh = NULL;
-	if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0)
+	if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0)
 		goto unlink_done;
 
 	if (res >= 0 && sinfo.total_slots > 0) {
-		res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc);
+		res = vfat_remove_entry(dir,&sinfo,&bh,dentry,0,nospc);
 		if (res > 0) {
 			res = 0;
 		}
@@ -1311,15 +1293,14 @@
 }
 
 
-int vfat_mkdir(struct inode *dir,const char *name,int len,int mode)
+int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
 {
 	struct inode *inode;
 	int res;
 
 	fat_lock_creation();
-	if ((res = vfat_create_entry(dir,name,len,1,&inode)) < 0) {
+	if ((res = vfat_create_entry(dir,&dentry->d_name,1,&inode)) < 0) {
 		fat_unlock_creation();
-		iput(dir);
 		return res;
 	}
 
@@ -1330,28 +1311,27 @@
 	res = vfat_create_dotdirs(inode, dir);
 	fat_unlock_creation();
 	MSDOS_I(inode)->i_busy = 0;
-	iput(inode);
-	iput(dir);
+	d_instantiate(dentry,inode);
 	if (res < 0) {
-		if (vfat_rmdir(dir,name,len) < 0)
+		if (vfat_rmdir(dir,dentry) < 0)
 			fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
 	}
 	return res;
 }
 
 /***** Unlink, as called for msdosfs */
-int vfat_unlink(struct inode *dir,const char *name,int len)
+int vfat_unlink(struct inode *dir,struct dentry* dentry)
 {
 	int res;
 
-	res = vfat_unlinkx (dir,name,len,1);
-	iput(dir);
+	res = vfat_unlinkx (dir,dentry,1);
+	d_delete(dentry);
 	return res;
 }
 
 
-int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
-		struct inode *new_dir,const char *new_name,int new_len)
+int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
+		struct inode *new_dir,struct dentry *new_dentry)
 {
 	struct super_block *sb = old_dir->i_sb;
 	struct buffer_head *old_bh,*new_bh,*dotdot_bh;
@@ -1364,13 +1344,15 @@
 	struct slot_info sinfo;
 
 	PRINTK(("vfat_rename 1\n"));
-	if (old_dir == new_dir && old_len == new_len &&
-	    strncmp(old_name, new_name, old_len) == 0)
+	if (old_dir == new_dir && 
+	    old_dentry->d_name.len == new_dentry->d_name.len &&
+	    strncmp(old_dentry->d_name.name, new_dentry->d_name.name, 
+		    old_dentry->d_name.len) == 0)
 		return 0;
 
 	old_bh = new_bh = NULL;
 	old_inode = new_inode = NULL;
-	res = vfat_find(old_dir,old_name,old_len,1,0,0,&sinfo);
+	res = vfat_find(old_dir,&old_dentry->d_name,1,0,0,&sinfo);
 	PRINTK(("vfat_rename 2\n"));
 	if (res < 0) goto rename_done;
 
@@ -1383,8 +1365,7 @@
 	if (res < 0) goto rename_done;
 
 	res = -ENOENT;
-	if (!(old_inode = iget(old_dir->i_sb,old_ino)))
-		goto rename_done;
+	old_inode = old_dentry->d_inode;
 	is_dir = S_ISDIR(old_inode->i_mode);
 	if (is_dir) {
 		if ((old_dir->i_dev != new_dir->i_dev) ||
@@ -1413,7 +1394,7 @@
 		iput(walk);
 	}
 
-	res = vfat_find(new_dir,new_name,new_len,1,0,is_dir,&sinfo);
+	res = vfat_find(new_dir,&new_dentry->d_name,1,0,is_dir,&sinfo);
 
 	PRINTK(("vfat_rename 4\n"));
 	if (res > -1) {
@@ -1432,12 +1413,12 @@
 		iput(new_inode);
 		if (new_is_dir) {
 			PRINTK(("vfat_rename 7\n"));
-			res = vfat_rmdirx(new_dir,new_name,new_len);
+			res = vfat_rmdirx(new_dir,&new_dentry);
 			PRINTK(("vfat_rename 8\n"));
 			if (res < 0) goto rename_done;
 		} else {
 			PRINTK(("vfat_rename 9\n"));
-			res = vfat_unlinkx(new_dir,new_name,new_len,1);
+			res = vfat_unlinkx(new_dir,new_dentry,1);
 			PRINTK(("vfat_rename 10\n"));
 			if (res < 0) goto rename_done;
 		}
@@ -1445,7 +1426,7 @@
 
 	PRINTK(("vfat_rename 11\n"));
 	fat_lock_creation(); locked = 1;
-	res = vfat_find(new_dir,new_name,new_len,1,1,is_dir,&sinfo);
+	res = vfat_find(new_dir,&new_dentry->d_name,1,1,is_dir,&sinfo);
 
 	PRINTK(("vfat_rename 12\n"));
 	if (res < 0) goto rename_done;
@@ -1524,6 +1505,8 @@
 	}
 
 	if (res > 0) res = 0;
+	d_instantiate(new_dentry,new_inode);
+	d_delete(old_dentry);
 
 rename_done:
 	if (locked)
@@ -1532,10 +1515,6 @@
 		fat_brelse(sb, old_bh);
 	if (new_bh)
 		fat_brelse(sb, new_bh);
-	if (old_inode)
-		iput(old_inode);
-	iput(old_dir);
-	iput(new_dir);
 	return res;
 }
 
@@ -1554,6 +1533,7 @@
 	NULL,			/* mknod */
 	vfat_rename,		/* rename */
 	NULL,			/* readlink */
+	NULL,			/* followlink */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.47/linux/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h
--- v2.1.47/linux/include/asm-alpha/keyboard.h	Mon Jun 16 16:35:59 1997
+++ linux/include/asm-alpha/keyboard.h	Thu Jul 31 13:09:18 1997
@@ -24,6 +24,7 @@
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
@@ -32,8 +33,11 @@
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
 #define kbd_init_hw		pckbd_init_hw
+#define kbd_sysrq_xlate		pckbd_sysrq_xlate
 
 #define INIT_KBD
+
+#define SYSRQ_KEY 0x54
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h
--- v2.1.47/linux/include/asm-i386/keyboard.h	Mon Jun 16 16:35:59 1997
+++ linux/include/asm-i386/keyboard.h	Thu Jul 31 13:09:18 1997
@@ -24,6 +24,7 @@
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
@@ -32,6 +33,9 @@
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
 #define kbd_init_hw		pckbd_init_hw
+#define kbd_sysrq_xlate		pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-i386/smp_lock.h linux/include/asm-i386/smp_lock.h
--- v2.1.47/linux/include/asm-i386/smp_lock.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-i386/smp_lock.h	Thu Jul 31 13:09:18 1997
@@ -39,6 +39,8 @@
 } while (0)
 	
 
+extern const char lk_lockmsg[]; 
+
 /* Locking the kernel */
 extern __inline__ void lock_kernel(void)
 {
@@ -46,7 +48,7 @@
 
 	if (local_irq_count[cpu]) {
 		__label__ l1;
-l1:		printk("lock from interrupt context at %p\n", &&l1);
+l1:		printk(lk_lockmsg, &&l1);
 	}
 	if (cpu == global_irq_holder) {
 		__label__ l2;
diff -u --recursive --new-file v2.1.47/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- v2.1.47/linux/include/asm-m68k/serial.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/serial.h	Thu Jul 31 13:09:18 1997
@@ -31,7 +31,7 @@
 #define	SER_AMIGA	105	/* Amiga built-in serial port */
 #define SER_IOEXT	106	/* Amiga GVP IO-Extender (16c552) */
 #define SER_MFC_III	107	/* Amiga BSC Multiface Card III (MC68681) */
-
+#define SER_WHIPPET	108	/* Amiga Hisoft Whippet PCMCIA (16c550B) */
 
 struct serial_struct {
 	int	type;
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/byteorder.h linux/include/asm-mips/byteorder.h
--- v2.1.47/linux/include/asm-mips/byteorder.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/byteorder.h	Thu Jul 31 13:09:18 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: byteorder.h,v 1.5 1997/06/25 19:10:18 ralf Exp $
+ * $Id: byteorder.h,v 1.6 1997/07/20 15:15:01 ralf Exp $
  */
 #ifndef __ASM_MIPS_BYTEORDER_H
 #define __ASM_MIPS_BYTEORDER_H
@@ -24,7 +24,7 @@
 #if defined (__MIPSEB__)
 
 #ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
 #endif
 
 #ifndef __BIG_ENDIAN_BITFIELD
@@ -36,8 +36,27 @@
 #define __constant_htonl(x) (x)
 #define __constant_htons(x) (x)
 
+#elif defined (__MIPSEL__)
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
+#endif
+
+#define __constant_ntohl(x) __swap32(x)
+#define __constant_ntohs(x) __swap16(x)
+#define __constant_htonl(x) __swap32(x)
+#define __constant_htons(x) __swap16(x)
+
+#endif /* defined(__MIPSEL_) */
+
 #ifdef __KERNEL__
 
+#if defined (__MIPSEB__)
+
 /*
  * In-kernel byte order macros to handle stuff like
  * byte-order-dependent filesystems etc.
@@ -52,25 +71,8 @@
 #define cpu_to_be16(x) (x)
 #define be16_to_cpu(x) (x)
 
-#endif /* __KERNEL__ */
-
 #elif defined (__MIPSEL__)
 
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN
-#endif
-
-#ifndef __LITTLE_ENDIAN_BITFIELD
-#define __LITTLE_ENDIAN_BITFIELD
-#endif
-
-#define __constant_ntohl(x) __swap32(x)
-#define __constant_ntohs(x) __swap16(x)
-#define __constant_htonl(x) __swap32(x)
-#define __constant_htons(x) __swap16(x)
-
-#ifdef __KERNEL__
-
 /*
  * In-kernel byte order macros to handle stuff like
  * byte-order-dependent filesystems etc.
@@ -85,8 +87,6 @@
 #define cpu_to_be16(x) __swap16((x))
 #define be16_to_cpu(x) __swap16((x))
 
-#endif /* __KERNEL__ */
-
 #else
 #error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
 #endif
@@ -144,7 +144,8 @@
 #define be16_to_cpus(x) cpu_to_be16s(x)
 #define be32_to_cpus(x) cpu_to_be32s(x)
 
-#ifdef __KERNEL__
+#endif /* __KERNEL__ */
+
 extern unsigned long int ntohl(unsigned long int __x);
 extern unsigned short int ntohs(unsigned short int __x);
 extern unsigned short int htons(unsigned short int __x);
@@ -170,6 +171,5 @@
 {
 	return __constant_htons(__x);
 }
-#endif /* __KERNEL__ */
 
 #endif /* __ASM_MIPS_BYTEORDER_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/ioctls.h linux/include/asm-mips/ioctls.h
--- v2.1.47/linux/include/asm-mips/ioctls.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/ioctls.h	Thu Jul 31 13:09:18 1997
@@ -96,6 +96,8 @@
 
 #define TCSBRKP		0x5486	/* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT	0x5487  /* For debugging only */
+#define TIOCSBRK	0x5427  /* BSD compatibility */
+#define TIOCCBRK	0x5428  /* BSD compatibility */
 
 #define TIOCSERCONFIG	0x5488
 #define TIOCSERGWILD	0x5489
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/jazz.h linux/include/asm-mips/jazz.h
--- v2.1.47/linux/include/asm-mips/jazz.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/jazz.h	Thu Jul 31 13:09:18 1997
@@ -210,7 +210,7 @@
 #define JAZZ_SERIAL2_IRQ        4
 #define JAZZ_PARALLEL_IRQ       5
 #define JAZZ_FLOPPY_IRQ         6 /* needs to be consistent with floppy driver! */
-
+#define JAZZ_SCSI_INTERRUPT     12
 
 /*
  * JAZZ DMA Channels
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/jazzdma.h linux/include/asm-mips/jazzdma.h
--- v2.1.47/linux/include/asm-mips/jazzdma.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/jazzdma.h	Thu Jul 31 13:09:18 1997
@@ -28,7 +28,7 @@
 #define VDMA_PAGESIZE		4096
 #define VDMA_PGTBL_ENTRIES	4096
 #define VDMA_PGTBL_SIZE		(sizeof(VDMA_PGTBL_ENTRY) * VDMA_PGTBL_ENTRIES)
-#define VDMA_PAGE_EMPTY		0
+#define VDMA_PAGE_EMPTY		0xff000000
 
 /*
  * Macros to get page no. and offset of a given address
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.1.47/linux/include/asm-mips/pgtable.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/pgtable.h	Thu Jul 31 13:09:18 1997
@@ -494,6 +494,9 @@
 #define SWP_OFFSET(entry) ((entry) >> 15)
 #define SWP_ENTRY(type,offset) (((type) << 8) | ((offset) << 15))
 
+#define module_map      vmalloc
+#define module_unmap    vfree
+
 /* TLB operations. */
 extern inline void tlb_probe(void)
 {
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/system.h linux/include/asm-mips/system.h
--- v2.1.47/linux/include/asm-mips/system.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/system.h	Thu Jul 31 13:09:18 1997
@@ -108,13 +108,13 @@
 #define save_and_cli(x) __save_and_cli(x)
 #define restore_flags(x) __restore_flags(x)
 
-#define sync_mem()                       \
-__asm__ __volatile__(                    \
-	".set\tnoreorder\n\t"            \
-	"sync\n\t"                       \
-	".set\treorder"                  \
-        : /* no output */                \
-	: /* no input */                 \
+#define mb()						\
+__asm__ __volatile__(					\
+	"# prevent instructions being moved around\n\t"	\
+	".set\tnoreorder\n\t"				\
+	".set\treorder"					\
+        : /* no output */				\
+	: /* no input */				\
 	: "memory")
 
 #if !defined (__LANGUAGE_ASSEMBLY__)
diff -u --recursive --new-file v2.1.47/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h
--- v2.1.47/linux/include/asm-mips/unistd.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/unistd.h	Thu Jul 31 13:09:18 1997
@@ -1177,11 +1177,13 @@
 #define __NR_query_module		(__NR_Linux + 187)
 #define __NR_poll			(__NR_Linux + 188)
 #define __NR_nfsservctl			(__NR_Linux + 189)
+#define __NR_setresgid			(__NR_Linux + 190)
+#define __NR_getresgid			(__NR_Linux + 191)
 
 /*
  * Offset of the last Linux flavoured syscall
  */
-#define __NR_Linux_syscalls		189
+#define __NR_Linux_syscalls		191
 
 #ifndef __LANGUAGE_ASSEMBLY__
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- v2.1.47/linux/include/asm-ppc/atomic.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-ppc/atomic.h	Thu Jul 31 13:09:18 1997
@@ -5,23 +5,116 @@
 #ifndef _ASM_PPC_ATOMIC_H_ 
 #define _ASM_PPC_ATOMIC_H_
 
+#ifdef __SMP__
+typedef struct { volatile int counter; } atomic_t;
+#else
 typedef struct { int counter; } atomic_t;
-#define ATOMIC_INIT(i)	{ (i) }
+#endif
 
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define ATOMIC_INIT(i)	{ (i) }
 
 #define atomic_read(v)		((v)->counter)
-#define atomic_set(v)		(((v)->counter) = i)
+#define atomic_set(v,i)		(((v)->counter) = (i))
 
-#define atomic_dec_return(v) ({atomic_sub(1,(v));(v);})
-#define atomic_inc_return(v) ({atomic_add(1,(v));(v);})
+extern void atomic_add(int a, atomic_t *v);
+extern void atomic_sub(int a, atomic_t *v);
+extern void atomic_inc(atomic_t *v);
+extern int  atomic_inc_return(atomic_t *v);
+extern void atomic_dec(atomic_t *v);
+extern int  atomic_dec_return(atomic_t *v);
+extern int  atomic_dec_and_test(atomic_t *v);
 
-#define atomic_inc(v) atomic_add(1,(v))
-#define atomic_dec(v) atomic_sub(1,(v))
-#endif
+extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
+extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
+
+#if 0	/* for now */
+extern __inline__ void atomic_add(atomic_t a, atomic_t *v)
+{
+	atomic_t t;
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3\n\
+	add	%0,%2,%0\n\
+	stwcx.	%0,0,%3\n\
+	bne	1b"
+	: "=&r" (t), "=m" (*v)
+	: "r" (a), "r" (v)
+	: "cc");
+}
+
+extern __inline__ void atomic_sub(atomic_t a, atomic_t *v)
+{
+	atomic_t t;
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3\n\
+	subf	%0,%2,%0\n\
+	stwcx.	%0,0,%3\n\
+	bne	1b"
+	: "=&r" (t), "=m" (*v)
+	: "r" (a), "r" (v)
+	: "cc");
+}
+
+extern __inline__ int atomic_sub_and_test(atomic_t a, atomic_t *v)
+{
+	atomic_t t;
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3\n\
+	subf	%0,%2,%0\n\
+	stwcx.	%0,0,%3\n\
+	bne	1b"
+	: "=&r" (t), "=m" (*v)
+	: "r" (a), "r" (v)
+	: "cc");
+
+	return t == 0;
+}
+
+extern __inline__ void atomic_inc(atomic_t *v)
+{
+	atomic_t t;
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2\n\
+	addic	%0,%0,1\n\
+	stwcx.	%0,0,%2\n\
+	bne	1b"
+	: "=&r" (t), "=m" (*v)
+	: "r" (v)
+	: "cc");
+}
+
+extern __inline__ void atomic_dec(atomic_t *v)
+{
+	atomic_t t;
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2\n\
+	addic	%0,%0,-1\n\
+	stwcx.	%0,0,%2\n\
+	bne	1b"
+	: "=&r" (t), "=m" (*v)
+	: "r" (v)
+	: "cc");
+}
+
+extern __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+	atomic_t t;
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%2\n\
+	addic	%0,%0,-1\n\
+	stwcx.	%0,0,%2\n\
+	bne	1b"
+	: "=&r" (t), "=m" (*v)
+	: "r" (v)
+	: "cc");
+
+	return t == 0;
+}
+#endif /* 0 */
 
+#endif /* _ASM_PPC_ATOMIC_H_ */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h
--- v2.1.47/linux/include/asm-ppc/bitops.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/bitops.h	Thu Jul 31 13:09:18 1997
@@ -3,66 +3,154 @@
 
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <linux/kernel.h> /* for printk */
 
 #define BIT(n) 1<<(n&0x1F)
 typedef unsigned long BITFIELD;
 
 
-/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
- * is in the highest of the four bytes and bit '31' is the high bit
- * within the first byte. powerpc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
+/*
+ * These are ifdef'd out here because using : "cc" as a constraing
+ * results in errors from gcc. -- Cort
  */
-extern __inline__ int set_bit(int nr, void * add)
+#if 0
+extern __inline__ int set_bit(int nr, void * addr)
 {
-  BITFIELD *addr = add;
-	long	mask,oldbit;       
-#ifdef __KERNEL__
-	int s = _disable_interrupts();
-#endif
-	addr += nr >> 5;
-	mask = BIT(nr);
-	oldbit = (mask & *addr) != 0;
-	*addr |= mask;
-#ifdef __KERNEL__	
-	_enable_interrupts(s);
-#endif
-	return oldbit;
+	unsigned long old, t;
+	unsigned long mask = 1 << (nr & 0x1f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+	
+	if ((unsigned long)addr & 3)
+		printk("set_bit(%lx, %p)\n", nr, addr);
+
+	__asm__ __volatile__(
+		"1:lwarx %0,0,%3 \n\t"
+		"or	%1,%0,%2 \n\t"
+		"stwcx.	%1,0,%3 \n\t"
+		"bne	1b \n\t"
+		: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+		: "r" (mask), "r" (p)
+		/*: "cc" */);
+
+n	return (old & mask) != 0;
 }
 
-extern __inline__ int change_bit(int nr, void *add)
+extern __inline__  unsigned long clear_bit(unsigned long nr, void *addr)
 {
-  	BITFIELD *addr = add;
-	int	mask, retval;
-#ifdef __KERNEL__
-	int s = _disable_interrupts();
-#endif
-	addr += nr >> 5;
-	mask = BIT(nr);
-	retval = (mask & *addr) != 0;
-	*addr ^= mask;
-#ifdef __KERNEL__
-	_enable_interrupts(s);
-#endif
-	return retval;
+	unsigned long old, t;
+	unsigned long mask = 1 << (nr & 0x1f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk("clear_bit(%lx, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3
+	andc	%1,%0,%2
+	stwcx.	%1,0,%3
+	bne	1b"
+	: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+      /*: "cc"*/);
+
+	return (old & mask) != 0;
 }
 
-extern __inline__ int clear_bit(int nr, void *add)
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
 {
-        BITFIELD *addr = add;
-	int	mask, retval;
-#ifdef __KERNEL__
-	int s = _disable_interrupts();
-#endif
-	addr += nr >> 5;
-	mask = BIT(nr);
-	retval = (mask & *addr) != 0;
-	*addr &= ~mask;
-#ifdef __KERNEL__	
-	_enable_interrupts(s);
+	unsigned long old, t;
+	unsigned long mask = 1 << (nr & 0x1f);
+	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+	if ((unsigned long)addr & 3)
+		printk("change_bit(%lx, %p)\n", nr, addr);
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3
+	xor	%1,%0,%2
+	stwcx.	%1,0,%3
+	bne	1b"
+	: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+      /*: "cc"*/);
+
+	return (old & mask) != 0;
+}
 #endif
-	return retval;
+
+extern __inline__ int ffz(unsigned int x)
+{
+	int n;
+
+	x = ~x & (x+1);		/* set LS zero to 1, other bits to 0 */
+	__asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+	return 31 - n;
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
+{
+	unsigned int * p = ((unsigned int *) addr);
+	unsigned int result = 0;
+	unsigned int tmp;
+
+	if (size == 0)
+		return 0;
+	while (size & ~31UL) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+	tmp |= ~0UL << size;
+found_middle:
+	return result + ffz(tmp);
 }
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
+				 unsigned long offset)
+{
+	unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+	unsigned int result = offset & ~31UL;
+	unsigned int 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 & ~31UL) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+found_first:
+	tmp |= ~0UL << size;
+found_middle:
+	return result + ffz(tmp);
+}
+
 
 #define _EXT2_HAVE_ASM_BITOPS_
 #define ext2_find_first_zero_bit(addr, size) \
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/bugs.h linux/include/asm-ppc/bugs.h
--- v2.1.47/linux/include/asm-ppc/bugs.h	Sat Nov 25 09:49:06 1995
+++ linux/include/asm-ppc/bugs.h	Thu Jul 31 13:09:18 1997
@@ -2,7 +2,5 @@
  * This file is included by 'init/main.c'
  */
 
-void
-check_bugs(void)
-{
-} 
+extern void
+check_bugs(void);
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/byteorder.h linux/include/asm-ppc/byteorder.h
--- v2.1.47/linux/include/asm-ppc/byteorder.h	Mon Jun 16 16:36:00 1997
+++ linux/include/asm-ppc/byteorder.h	Thu Jul 31 13:09:18 1997
@@ -1,6 +1,8 @@
 #ifndef _PPC_BYTEORDER_H
 #define _PPC_BYTEORDER_H
 
+#include <asm/types.h>
+
 #ifndef __BIG_ENDIAN
 #define __BIG_ENDIAN
 #endif
@@ -16,21 +18,50 @@
 
 #define __htonl(x) ntohl(x)
 #define __htons(x) ntohs(x)
+
+#define __constant_ntohs(x) ntohs(x)
+#define __constant_ntohl(x) ntohl(x)
 #define __constant_htonl(x) ntohl(x)
 #define __constant_htons(x) ntohs(x)
 
 #ifdef __KERNEL__
+/*
+ * 16 and 32 bit little-endian loads and stores.
+ */
+extern inline unsigned ld_le16(volatile unsigned short *addr)
+{
+	unsigned val;
 
-/* Convert from CPU byte order, to specified byte order. */
-extern __inline__ __u16 cpu_to_le16(__u16 value)
+	asm volatile("lhbrx %0,0,%1" : "=r" (val) : "r" (addr));
+	return val;
+}
+
+extern inline void st_le16(volatile unsigned short *addr, unsigned val)
+{
+	asm volatile("sthbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned ld_le32(volatile unsigned *addr)
+{
+	unsigned val;
+
+	asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+	return val;
+}
+
+extern inline void st_le32(volatile unsigned *addr, unsigned val)
 {
-	return (value >> 8) | (value << 8);
+	asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
 }
 
+
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+	return ld_le16(&value);
+}
 extern __inline__ __u32 cpu_to_le32(__u32 value)
 {
-	return((value>>24) | ((value>>8)&0xff00) |
-	       ((value<<8)&0xff0000) | (value<<24));
+	return ld_le32(&value);
 }
 #define cpu_to_be16(x)  (x)
 #define cpu_to_be32(x)  (x)
@@ -38,33 +69,33 @@
 /* The same, but returns converted value from the location pointer by addr. */
 extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
 {
-	return cpu_to_le16(*addr);
+	return ld_le16(addr);
 }
 
 extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
 {
-	return cpu_to_le32(*addr);
+	return ld_le32(addr);
 }
 
 extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
 {
-	return cpu_to_be16(*addr);
+	return *addr;
 }
 
 extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
 {
-	return cpu_to_be32(*addr);
+	return *addr;
 }
 
 /* The same, but do the conversion in situ, ie. put the value back to addr. */
 extern __inline__ void cpu_to_le16s(__u16 *addr)
 {
-	*addr = cpu_to_le16(*addr);
+	st_le16(addr,*addr);
 }
 
 extern __inline__ void cpu_to_le32s(__u32 *addr)
 {
-	*addr = cpu_to_le32(*addr);
+	st_le32(addr,*addr);
 }
 
 #define cpu_to_be16s(x) do { } while (0)
@@ -86,5 +117,12 @@
 #define be16_to_cpus(x) cpu_to_be16s(x)
 #define be32_to_cpus(x) cpu_to_be32s(x)
 
+
 #endif /* __KERNEL__ */
 #endif /* !(_PPC_BYTEORDER_H) */
+
+
+
+
+
+
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/cache.h linux/include/asm-ppc/cache.h
--- v2.1.47/linux/include/asm-ppc/cache.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-ppc/cache.h	Thu Jul 31 13:09:18 1997
@@ -5,7 +5,8 @@
 #define __ARCH_PPC_CACHE_H
 
 /* bytes per L1 cache line */
-#define        L1_CACHE_BYTES  32      /* a guess */
+/* a guess */ /* a correct one -- Cort */
+#define        L1_CACHE_BYTES  32      
 
 #define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/checksum.h linux/include/asm-ppc/checksum.h
--- v2.1.47/linux/include/asm-ppc/checksum.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/checksum.h	Thu Jul 31 13:09:18 1997
@@ -47,6 +47,20 @@
  */
 #define csum_partial_copy_fromuser csum_partial_copy
 
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ *
+ * right now - it just calls csum_partial_copy()
+ *   -- Cort
+ */
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+						int len, int sum, int *err_ptr)
+{
+	int *dst_err_ptr=NULL;
+	return csum_partial_copy( src, dst, len, sum);
+}
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/current.h linux/include/asm-ppc/current.h
--- v2.1.47/linux/include/asm-ppc/current.h	Mon Dec 30 01:58:35 1996
+++ linux/include/asm-ppc/current.h	Thu Jul 31 13:09:18 1997
@@ -1,12 +1,10 @@
 #ifndef _PPC_CURRENT_H
 #define _PPC_CURRENT_H
 
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel.  For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()])	/* Current on this processor */
+#include <linux/config.h>
+
+extern struct task_struct *current_set[1];
+
+register struct task_struct *current asm("r2");
 
 #endif /* !(_PPC_CURRENT_H) */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/delay.h linux/include/asm-ppc/delay.h
--- v2.1.47/linux/include/asm-ppc/delay.h	Sat Nov 25 09:49:06 1995
+++ linux/include/asm-ppc/delay.h	Thu Jul 31 13:09:18 1997
@@ -1,14 +1,31 @@
 #ifndef _PPC_DELAY_H
 #define _PPC_DELAY_H
 
+/*
+ * Copyright 1996, Paul Mackerras.
+ *
+ * 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.
+ */
 
-extern __inline__ void __delay(unsigned long );
-extern __inline__ void __udelay(unsigned long );
-
+extern __inline__ void __delay(unsigned int loops)
+{
+	if (loops != 0)
+		__asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
+				     "r" (loops) : "ctr");
+}
 
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
+extern __inline__ void udelay(unsigned long usecs)
 {
-	return (a*b)/c;
+	unsigned long loops;
+
+	/* compute (usecs * 2^32 / 10^6) * loops_per_sec / 2^32 */
+	usecs *= 0x10c6;		/* 2^32 / 10^6 */
+	__asm__("mulhwu %0,%1,%2" : "=r" (loops) :
+		"r" (usecs), "r" (loops_per_sec));
+	__delay(loops);
 }
 
 #endif /* defined(_PPC_DELAY_H) */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.1.47/linux/include/asm-ppc/dma.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/dma.h	Thu Jul 31 13:09:18 1997
@@ -1,16 +1,21 @@
-/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+/* $Id: dma.h,v 1.3 1997/03/16 06:20:39 cort Exp $
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
  * and John Boyd, Nov. 1992.
  */
 
+#include <linux/config.h>
+
 /*
  * Note: Adapted for PowerPC by Gary Thomas
  * Modified by Cort Dougan <cort@cs.nmt.edu>
  *
+ * None of this really applies for Power Macintoshes.  There is
+ * basically just enough here to get kernel/dma.c to compile.
+ *
  * There may be some comments or restrictions made here which are
- * not valid for the PowerPC (PreP) platform.  Take what you read
+ * not valid for the PReP platform.  Take what you read
  * with a grain of salt.
  */
  
@@ -18,6 +23,7 @@
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
+#ifdef CONFIG_PREP
 #include <asm/io.h>		/* need byte IO */
 
 
@@ -295,5 +301,6 @@
 /* These are in kernel/dma.c: */
 extern void free_dma(unsigned int dmanr);	/* release it again */
 
+#endif /* CONFIG_PREP */
 
 #endif /* _ASM_DMA_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/errno.h linux/include/asm-ppc/errno.h
--- v2.1.47/linux/include/asm-ppc/errno.h	Mon Apr 14 16:28:19 1997
+++ linux/include/asm-ppc/errno.h	Thu Jul 31 13:09:18 1997
@@ -133,4 +133,6 @@
 #define ERESTARTNOHAND	514	/* restart if no handler.. */
 #define ENOIOCTLCMD	515	/* No ioctl command */
 
+#define _LAST_ERRNO	515
+
 #endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.1.47/linux/include/asm-ppc/hardirq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/hardirq.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,23 @@
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
+
+#ifndef __SMP__
+
+#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_endlock(cpu)	do { } while (0)
+
+#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
+#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+
+#define synchronize_irq()	do { } while (0)
+
+#else
+
+#error Somebody should do SMP support for PPC...
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.1.47/linux/include/asm-ppc/ide.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/ide.h	Thu Jul 31 13:09:18 1997
@@ -1,5 +1,5 @@
 /*
- *  linux/include/asm-i386/ide.h
+ *  linux/include/asm-ppc/ide.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
  */
@@ -13,7 +13,7 @@
 
 #ifdef __KERNEL__
 
-typedef unsigned short ide_ioreg_t;
+#include <linux/config.h>
 
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	4
@@ -21,11 +21,15 @@
 
 #define ide_sti()	sti()
 
+#ifdef CONFIG_PREP
+
+typedef unsigned short ide_ioreg_t;
+
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
-		case 0x1f0: return 14;
-		case 0x170: return 15;
+		case 0x1f0: return 13;
+		case 0x170: return 13;
 		case 0x1e8: return 11;
 		case 0x168: return 10;
 		default:
@@ -66,18 +70,7 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return request_irq(irq, handler, flags, device, dev_id);
-}			
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
+} select_t;
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
@@ -94,25 +87,91 @@
 	release_region(from, extent);
 }
 
-/*
- * The following are not needed for the non-m68k ports
- */
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+#define ide_fix_driveid(id)		do {} while (0)
+
+#endif
+
+#ifdef CONFIG_PMAC
+
+#include <asm/io.h>		/* so we can redefine insw/outsw */
+
+typedef unsigned long ide_ioreg_t;
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+	return 0;
+}
+
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+	return index;
+}
+
+extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit7		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned unit		: 1;	/* drive select number, 0/1 */
+		unsigned head		: 4;	/* always zeros here */
+	} b;
+} select_t;
+
+#undef	SUPPORT_SLOW_DATA_PORTS
+#define	SUPPORT_SLOW_DATA_PORTS	0
+#undef	SUPPORT_VLB_SYNC
+#define SUPPORT_VLB_SYNC	0
+
+static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
-	return(1);
+	return 0;
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
 }
 
-static __inline__ void ide_release_lock (int *ide_lock)
+static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
 }
 
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+#undef insw
+#undef outsw
+#define insw(port, buf, ns)	ide_insw((port), (buf), (ns))
+#define outsw(port, buf, ns)	ide_outsw((port), (buf), (ns))
+
+void ide_insw(ide_ioreg_t port, void *buf, int ns);
+void ide_outsw(ide_ioreg_t port, void *buf, int ns);
+
+#define ide_fix_driveid(id)	do {			\
+	int nh;						\
+	unsigned short *p = (unsigned short *) id;	\
+	for (nh = SECTOR_WORDS * 2; nh != 0; --nh, ++p)	\
+		*p = (*p << 8) + (*p >> 8);		\
+} while (0)
+
+#endif
+
+static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+			unsigned long flags, const char *device, void *dev_id)
 {
+	return request_irq(irq, handler, flags, device, dev_id);
+}			
+
+static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
+{
+	free_irq(irq, dev_id);
 }
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(base, irq)		(1)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/init.h linux/include/asm-ppc/init.h
--- v2.1.47/linux/include/asm-ppc/init.h	Wed Apr 16 14:15:00 1997
+++ linux/include/asm-ppc/init.h	Thu Jul 31 13:09:18 1997
@@ -1,14 +1,23 @@
 #ifndef _PPC_INIT_H
 #define _PPC_INIT_H
 
-/* Throwing the initialization code and data out is not supported yet... */
-
-#define	__init
+#define __init
 #define __initdata
-#define __initfunc(__arginit) __arginit
-/* For assembly routines */
+#define __initfunc(x) x
+/*
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+	__arginit __init; \
+	__arginit
+*/
+	/* For assembly routines */
 #define __INIT
 #define __FINIT
 #define __INITDATA
-
+/*	
+#define __INIT		.section	".text.init",#alloc,#execinstr
+#define __FINIT	.previous
+#define __INITDATA	.section	".data.init",#alloc,#write
+*/
 #endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.1.47/linux/include/asm-ppc/io.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/io.h	Thu Jul 31 13:09:18 1997
@@ -1,8 +1,11 @@
 #ifndef _PPC_IO_H
 #define _PPC_IO_H
 
+#include <linux/config.h>
 #include <asm/page.h>
+#include <asm/byteorder.h>
 
+#ifdef CONFIG_PREP
 /* from the Carolina Technical Spec -- Cort */
 #define IBM_ACORN 0x82A
 #define SIO_CONFIG_RA	0x398
@@ -14,15 +17,67 @@
 #define IBM_L2_INVALIDATE 0x814
 #define IBM_SYS_CTL       0x81c
 
-
-
-/* Define the particulars of outb/outw/outl "instructions" */
 #define SLOW_DOWN_IO
 
 #ifndef PCI_DRAM_OFFSET
 #define PCI_DRAM_OFFSET  0x80000000
 #endif
 
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+void outsl(int port, long *ptr, int len);
+
+__inline__ unsigned char outb(unsigned char val, int port);
+__inline__ unsigned short outw(unsigned short val, int port);
+__inline__ unsigned long outl(unsigned long val, int port);
+__inline__ unsigned char inb(int port);
+__inline__ unsigned short inw(int port);
+__inline__ unsigned long inl(int port);
+
+#define inb_p inb
+#define inw_p inw
+#define inl_p inl
+#define outb_p outb
+#define outw_p outw
+#define outl_p outl
+
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
+/*
+ * Read and write the non-volatile RAM.
+ */
+extern int nvram_readb(int addr);
+extern void nvram_writeb(int addr, int val);
+
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET  0
+#endif
+
+#define inb(port)		in_8((unsigned char *)(port))
+#define outb(val, port)		out_8((unsigned char *)(port), (val))
+#define inw(port)		in_le16((unsigned short *)(port))
+#define outw(val, port)		out_le16((unsigned short *)(port), (val))
+#define inl(port)		in_le32((unsigned long *)(port))
+#define outl(val, port)		out_le32((unsigned long *)(port), (val))
+
+#define inb_p(port)		in_8((unsigned char *)(port))
+#define outb_p(val, port)	out_8((unsigned char *)(port), (val))
+#define inw_p(port)		in_le16((unsigned short *)(port))
+#define outw_p(val, port)	out_le16((unsigned short *)(port), (val))
+#define inl_p(port)		in_le32(((unsigned long *)port))
+#define outl_p(val, port)	out_le32((unsigned long *)(port), (val))
+
+#define insw(port, buf, ns)	_insw((unsigned short *)(port), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw((unsigned short *)(port), (buf), (ns))
+#define insl(port, buf, nl)	_insl((unsigned long *)(port), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl((unsigned long *)(port), (buf), (nl))
+#endif /* CONFIG_PMAC */
 
 /*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
@@ -42,19 +97,12 @@
         if (address == 0) return 0;
         return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
 }
-/* #define virt_to_bus(a) ((unsigned long)(((char *)a==(char *) 0) ? ((char *)0) \
-			: ((char *)((long)a - KERNELBASE + PCI_DRAM_OFFSET))))
-#define bus_to_virt(a) ((void *) (((char *)a==(char *)0) ? ((char *)0) \
-			: ((char *)((long)a - PCI_DRAM_OFFSET + KERNELBASE))))
-*/
-
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
 
+/*
+ * Map in an area of physical address space, for accessing
+ * I/O devices etc.
+ */
+extern void *ioremap(unsigned long address, unsigned long size);
 
 /*
  * Change virtual addresses to physical addresses and vv.
@@ -72,27 +120,101 @@
 	return (void *) address;
 }
 
-/* from arch/ppc/kernel/port_io.c
- *               -- Cort
+#define _IO_BASE ((unsigned long)0x80000000)
+
+/*
+ * These are much more useful le/be io functions from Paul
+ * than leXX_to_cpu() style functions since the ppc has
+ * load/store byte reverse instructions
+ *  -- Cort
  */
-unsigned char inb(int port);
-unsigned short inw(int port);
-unsigned long inl(int port);
-unsigned char outb(unsigned char val,int port);
-unsigned short outw(unsigned short val,int port);
-unsigned long outl(unsigned long val,int port);
-void outsl(int port, long *ptr, int len);
 
-static inline unsigned char  inb_p(int port) {return (inb(port)); }
-static inline unsigned short inw_p(int port) {return (inw(port)); }
-static inline unsigned long  inl_p(int port) {return (inl(port)); }
+/*
+ * Enforce In-order Execution of I/O:
+ * Acts as a barrier to ensure all previous I/O accesses have
+ * completed before any further ones are issued.
+ */
+extern inline void eieio(void)
+{
+	asm volatile ("eieio" : :);
+}
 
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ */
+extern inline int in_8(volatile unsigned char *addr)
+{
+	int ret;
 
+	ret = *addr;
+	eieio();
+	return ret;
+}
 
-static inline unsigned char  outb_p(unsigned char val,int port) { return (outb(val,port)); }
-static inline unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-static inline unsigned long  outl_p(unsigned long val,int port) { return (outl(val,port)); }
+extern inline void out_8(volatile unsigned char *addr, int val)
+{
+	*addr = val;
+	eieio();
+}
+
+extern inline int in_le16(volatile unsigned short *addr)
+{
+	int ret;
 
+	ret = ld_le16(addr);
+	eieio();
+	return ret;
+}
+
+extern inline int in_be16(volatile unsigned short *addr)
+{
+	int ret;
+
+	ret = *addr;
+	eieio();
+	return ret;
+}
+
+extern inline void out_le16(volatile unsigned short *addr, int val)
+{
+	st_le16(addr, val);
+	eieio();
+}
 
+extern inline void out_be16(volatile unsigned short *addr, int val)
+{
+	*addr = val;
+	eieio();
+}
+
+extern inline unsigned in_le32(volatile unsigned *addr)
+{
+	unsigned ret;
+
+	ret = ld_le32(addr);
+	eieio();
+	return ret;
+}
+
+extern inline int in_be32(volatile unsigned *addr)
+{
+	int ret;
+
+	ret = *addr;
+	eieio();
+	return ret;
+}
+
+extern inline void out_le32(volatile unsigned *addr, int val)
+{
+	st_le32(addr, val);
+	eieio();
+}
+
+extern inline void out_be32(volatile unsigned *addr, int val)
+{
+	*addr = val;
+	eieio();
+}
 
 #endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/ioctls.h linux/include/asm-ppc/ioctls.h
--- v2.1.47/linux/include/asm-ppc/ioctls.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-ppc/ioctls.h	Thu Jul 31 13:09:18 1997
@@ -83,8 +83,8 @@
 #define TIOCGETD	0x5424
 #define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.1.47/linux/include/asm-ppc/irq.h	Mon May 27 02:00:59 1996
+++ linux/include/asm-ppc/irq.h	Thu Jul 31 13:09:18 1997
@@ -1,7 +1,13 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
+#include <linux/config.h>
+
+#ifdef CONFIG_PMAC
 #define NR_IRQS	32
+#else
+#define NR_IRQS	16
+#endif
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.1.47/linux/include/asm-ppc/keyboard.h	Mon Jun 16 16:36:00 1997
+++ linux/include/asm-ppc/keyboard.h	Thu Jul 31 13:09:18 1997
@@ -2,10 +2,12 @@
  *  linux/include/asm-ppc/keyboard.h
  *
  *  Created 3 Nov 1996 by Geert Uytterhoeven
+ *  Modified for Power Macintosh by Paul Mackerras
  */
 
 /*
- *  This file contains the ppc architecture specific keyboard definitions
+ * This file contains the ppc architecture specific keyboard definitions -
+ * like the intel pc for prep systems, different for power macs.
  */
 
 #ifndef __ASMPPC_KEYBOARD_H
@@ -13,6 +15,29 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
+
+#ifdef CONFIG_MAC_KEYBOARD
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern int mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+
+#define kbd_setkeycode		mackbd_setkeycode
+#define kbd_getkeycode		mackbd_getkeycode
+#define kbd_pretranslate	mackbd_pretranslate
+#define kbd_translate		mackbd_translate
+#define kbd_unexpected_up	mackbd_unexpected_up
+#define kbd_leds		mackbd_leds
+#define kbd_init_hw		mackbd_init_hw
+
+#else /* CONFIG_MAC_KEYBOARD */
+
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
@@ -34,6 +59,7 @@
 #define kbd_init_hw		pckbd_init_hw
 
 #define INIT_KBD
+#endif /* CONFIG_MAC_KEYBOARD */
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/mc146818rtc.h linux/include/asm-ppc/mc146818rtc.h
--- v2.1.47/linux/include/asm-ppc/mc146818rtc.h	Mon May 27 02:00:59 1996
+++ linux/include/asm-ppc/mc146818rtc.h	Wed Dec 31 16:00:00 1969
@@ -1,109 +0,0 @@
-/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
- * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
- * derived from Data Sheet, Copyright Motorola 1984 (!).
- * It was written to be part of the Linux operating system.
- */
-/* permission is hereby granted to copy, modify and redistribute this code
- * in terms of the GNU Library General Public License, Version 2 or later,
- * at your option.
- */
-
-#ifndef _MC146818RTC_H
-#define _MC146818RTC_H
-#include <asm/io.h>
-
-#ifndef MCRTC_PORT
-#define MCRTC_PORT(x)	(0x70 + (x))
-#define MCRTC_ALWAYS_BCD	1
-#endif
-
-#define CMOS_MCRTC_READ(addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-inb_p(MCRTC_PORT(1)); \
-})
-#define CMOS_MCRTC_WRITE(val, addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-outb_p((val),MCRTC_PORT(1)); \
-})
-
-/**********************************************************************
- * register summary
- **********************************************************************/
-#define MCRTC_SECONDS		0
-#define MCRTC_SECONDS_ALARM	1
-#define MCRTC_MINUTES		2
-#define MCRTC_MINUTES_ALARM	3
-#define MCRTC_HOURS		4
-#define MCRTC_HOURS_ALARM		5
-/* RTC_*_alarm is always true if 2 MSBs are set */
-# define MCRTC_ALARM_DONT_CARE 	0xC0
-
-#define MCRTC_DAY_OF_WEEK		6
-#define MCRTC_DAY_OF_MONTH	7
-#define MCRTC_MONTH		8
-#define MCRTC_YEAR		9
-
-/* control registers - Moto names
- */
-#define MCRTC_REG_A		10
-#define MCRTC_REG_B		11
-#define MCRTC_REG_C		12
-#define MCRTC_REG_D		13
-
-/**********************************************************************
- * register details
- **********************************************************************/
-#define MCRTC_FREQ_SELECT	MCRTC_REG_A
-
-/* update-in-progress  - set to "1" 244 microsecs before RTC goes off the bus,
- * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
- * totalling to a max high interval of 2.228 ms.
- */
-# define MCRTC_UIP		0x80
-# define MCRTC_DIV_CTL		0x70
-   /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
-#  define MCRTC_REF_CLCK_4MHZ	0x00
-#  define MCRTC_REF_CLCK_1MHZ	0x10
-#  define MCRTC_REF_CLCK_32KHZ	0x20
-   /* 2 values for divider stage reset, others for "testing purposes only" */
-#  define MCRTC_DIV_RESET1	0x60
-#  define MCRTC_DIV_RESET2	0x70
-  /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
-# define MCRTC_RATE_SELECT 	0x0F
-
-/**********************************************************************/
-#define MCRTC_CONTROL	MCRTC_REG_B
-# define MCRTC_SET 0x80		/* disable updates for clock setting */
-# define MCRTC_PIE 0x40		/* periodic interrupt enable */
-# define MCRTC_AIE 0x20		/* alarm interrupt enable */
-# define MCRTC_UIE 0x10		/* update-finished interrupt enable */
-# define MCRTC_SQWE 0x08		/* enable square-wave output */
-# define MCRTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
-# define MCRTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
-# define MCRTC_DST_EN 0x01	/* auto switch DST - works f. USA only */
-
-/**********************************************************************/
-#define MCRTC_INTR_FLAGS	MCRTC_REG_C
-/* caution - cleared by read */
-# define MCRTC_IRQF 0x80		/* any of the following 3 is active */
-# define MCRTC_PF 0x40
-# define MCRTC_AF 0x20
-# define MCRTC_UF 0x10
-
-/**********************************************************************/
-#define MCRTC_VALID	MCRTC_REG_D
-# define MCRTC_VRT 0x80		/* valid RAM and time */
-/**********************************************************************/
-
-/* example: !(CMOS_READ(MCRTC_CONTROL) & MCRTC_DM_BINARY) 
- * determines if the following two #defines are needed
- */
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
-#endif /* _MC146818RTC_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/mmu.h linux/include/asm-ppc/mmu.h
--- v2.1.47/linux/include/asm-ppc/mmu.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/mmu.h	Thu Jul 31 13:09:18 1997
@@ -32,42 +32,68 @@
 
 /* Segment Register */
 typedef struct _SEGREG
-   {
-      unsigned long t:1;	/* Normal or I/O  type */
-      unsigned long ks:1;	/* Supervisor 'key' (normally 0) */
-      unsigned long kp:1;	/* User 'key' (normally 1) */
-      unsigned long n:1;	/* No-execute */
-      unsigned long :4;		/* Unused */
-      unsigned long vsid:24;	/* Virtual Segment Identifier */
-   } SEGREG;
+{
+  unsigned long t:1;	/* Normal or I/O  type */
+  unsigned long ks:1;	/* Supervisor 'key' (normally 0) */
+  unsigned long kp:1;	/* User 'key' (normally 1) */
+  unsigned long n:1;	/* No-execute */
+  unsigned long :4;		/* Unused */
+  unsigned long vsid:24;	/* Virtual Segment Identifier */
+} SEGREG;
 
 /* Block Address Translation (BAT) Registers */
+typedef struct _P601_BATU
+{
+  unsigned long bepi:15;	/* Effective page index (virtual address) */
+  unsigned long :8;		/* unused */
+  unsigned long w:1;
+  unsigned long i:1;		/* Cache inhibit */
+  unsigned long m:1;		/* Memory coherence */
+  unsigned long vs:1;	/* Supervisor valid */
+  unsigned long vp:1;	/* User valid */
+  unsigned long pp:2;	/* Page access protections */
+} P601_BATU;
+
 typedef struct _BATU		/* Upper part of BAT */
-   {
-      unsigned long bepi:15;	/* Effective page index (virtual address) */
-      unsigned long :4;		/* Unused */
-      unsigned long bl:11;	/* Block size mask */
-      unsigned long vs:1;	/* Supervisor valid */
-      unsigned long vp:1;	/* User valid */
-   } BATU;   
+{
+  unsigned long bepi:15;	/* Effective page index (virtual address) */
+  unsigned long :4;		/* Unused */
+  unsigned long bl:11;	/* Block size mask */
+  unsigned long vs:1;	/* Supervisor valid */
+  unsigned long vp:1;	/* User valid */
+} BATU;   
+
+typedef struct _P601_BATL
+{
+  unsigned long brpn:15;	/* Real page index (physical address) */
+  unsigned long :10;		/* Unused */
+  unsigned long v:1;		/* valid/invalid */
+  unsigned long bl:6;		/* Block size mask */
+} P601_BATL;
 
 typedef struct _BATL		/* Lower part of BAT */
-   {
-      unsigned long brpn:15;	/* Real page index (physical address) */
-      unsigned long :10;	/* Unused */
-      unsigned long w:1;	/* Write-thru cache */
-      unsigned long i:1;	/* Cache inhibit */
-      unsigned long m:1;	/* Memory coherence */
-      unsigned long g:1;	/* Guarded (MBZ) */
-      unsigned long :1;		/* Unused */
-      unsigned long pp:2;	/* Page access protections */
-   } BATL;
+{
+  unsigned long brpn:15;	/* Real page index (physical address) */
+  unsigned long :10;		/* Unused */
+  unsigned long w:1;	/* Write-thru cache */
+  unsigned long i:1;	/* Cache inhibit */
+  unsigned long m:1;	/* Memory coherence */
+  unsigned long g:1;	/* Guarded (MBZ) */
+  unsigned long :1;		/* Unused */
+  unsigned long pp:2;	/* Page access protections */
+} BATL;
 
 typedef struct _BAT
-   {
-      BATU batu;		/* Upper register */
-      BATL batl;		/* Lower register */
-   } BAT;
+{
+  BATU batu;		/* Upper register */
+  BATL batl;		/* Lower register */
+} BAT;
+
+typedef struct _P601_BAT
+{
+  P601_BATU batu;		/* Upper register */
+  P601_BATL batl;		/* Lower register */
+} P601_BAT;
 
 /* Block size masks */
 #define BL_128K	0x000
@@ -118,15 +144,6 @@
       pte	**pmap;		/* Two-level page-map structure */
    } MMU_context;
 
-#if 0
-BAT	ibat[4];	/* Instruction BAT images */
-BAT	dbat[4];	/* Data BAT images */
-PTE	*hash_table;	/* Hardware hashed page table */
-int	hash_table_size;
-int	hash_table_mask;
-unsigned long sdr;	/* Hardware image of SDR */
-#endif   
-
 /* Used to set up SDR register */
 #define HASH_TABLE_SIZE_64K	0x00010000
 #define HASH_TABLE_SIZE_128K	0x00020000
@@ -142,7 +159,5 @@
 #define HASH_TABLE_MASK_1M	0x00F   
 #define HASH_TABLE_MASK_2M	0x01F   
 #define HASH_TABLE_MASK_4M	0x03F   
-
-extern inline int MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg);
 
 #endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/mmu_context.h linux/include/asm-ppc/mmu_context.h
--- v2.1.47/linux/include/asm-ppc/mmu_context.h	Mon Dec 30 03:03:13 1996
+++ linux/include/asm-ppc/mmu_context.h	Thu Jul 31 13:09:18 1997
@@ -1,13 +1,59 @@
 #ifndef __PPC_MMU_CONTEXT_H
 #define __PPC_MMU_CONTEXT_H
 
+/* the way contexts are handled on the ppc they are vsid's and
+   don't need any special treatment right now.
+   perhaps I can defer flushing the tlb by keeping a list of
+   zombie vsid/context's and handling that through destroy_context
+   later -- Cort
+ */
+
+#define NO_CONTEXT	0
+#define LAST_CONTEXT	0xfffff
+
+extern int next_mmu_context;
+extern void mmu_context_overflow(void);
+extern void set_context(int context);
+
 /*
- * get a new mmu context.. PowerPC's don't know about contexts [yet]
+ * Allocating context numbers this way tends to spread out
+ * the entries in the hash table better than a simple linear
+ * allocation.
  */
-#define get_mmu_context(x) do { } while (0)
+#define MUNGE_CONTEXT(n)	(((n) * 897) & LAST_CONTEXT)
 
-#define init_new_context(mm)	do { } while(0)
-#define destroy_context(mm)	do { } while(0)
+/*
+ * Get a new mmu context for task tsk if necessary.
+ */
+#define get_mmu_context(tsk)					\
+do { 								\
+	struct mm_struct *mm = (tsk)->mm;			\
+	if (mm->context == NO_CONTEXT) {			\
+	        int i; \
+		if (next_mmu_context == LAST_CONTEXT)		\
+			mmu_context_overflow();			\
+		mm->context = MUNGE_CONTEXT(++next_mmu_context);\
+	 	if ( tsk == current )                           \
+			set_context(mm->context);               \
+	}							\
+} while (0)
 
-#endif
+/*
+ * Set up the context for a new address space.
+ */
+#define init_new_context(mm)	((mm)->context = NO_CONTEXT)
+
+/*
+ * We're finished using the context for an address space.
+ */
+#define destroy_context(mm)	do { } while (0)
 
+/*
+ * compute the vsid from the context and segment
+ * segments > 7 are kernel segments and their
+ * vsid is the segment -- Cort
+ */
+#define	VSID_FROM_CONTEXT(segment,context) \
+   ((segment < 8) ? ((segment) | (context)<<4) : (segment))
+
+#endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/namei.h linux/include/asm-ppc/namei.h
--- v2.1.47/linux/include/asm-ppc/namei.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/namei.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,21 @@
+/* $Id: namei.h,v 1.1 1997/07/25 09:28:40 cort Exp $
+ * linux/include/asm-i386/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+#ifndef __I386_NAMEI_H
+#define __I386_NAMEI_H
+
+/* These dummy routines maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define translate_namei(pathname, base, follow_links, res_inode)	\
+	do { } while (0)
+
+#define translate_open_namei(pathname, flag, mode, res_inode, base) \
+	do { } while (0)
+
+#endif /* __I386_NAMEI_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/nvram.h linux/include/asm-ppc/nvram.h
--- v2.1.47/linux/include/asm-ppc/nvram.h	Mon May 27 02:00:59 1996
+++ linux/include/asm-ppc/nvram.h	Thu Jul 31 13:09:18 1997
@@ -9,6 +9,7 @@
 #define NVRAM_AS1  0x75
 #define NVRAM_DATA 0x77
 
+
 /* RTC Offsets */
 
 #define RTC_SECONDS		0x1FF9
@@ -18,6 +19,8 @@
 #define RTC_DAY_OF_MONTH	0x1FFD
 #define RTC_MONTH		0x1FFE
 #define RTC_YEAR		0x1FFF
+#define RTC_CONTROLA            0x1FF8
+#define RTC_CONTROLB            0x1FF9
 
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.1.47/linux/include/asm-ppc/page.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/page.h	Thu Jul 31 13:09:18 1997
@@ -1,11 +1,32 @@
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
 
+#include <linux/config.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
+/* This handles the memory map.. */
+
+/*
+ * these virtual mappings for prep and pmac
+ * on the prep machine the io areas are at different physical locations
+ * than their virtual address.  On the pmac the io areas
+ * are mapped 1-1 virtual/physical.
+ * -- Cort
+ */
+#ifdef CONFIG_PREP
+#define KERNELBASE	0x90000000
+#endif
+#ifdef CONFIG_PMAC
+#define KERNELBASE	0xc0000000
+#endif
+#define PAGE_OFFSET	KERNELBASE
+
+
+#ifndef __ASSEMBLY__
 #ifdef __KERNEL__
 
 #define STRICT_MM_TYPECHECKS
@@ -50,13 +71,13 @@
 
 #endif
 
+
+/* align addr on a size boundry - adjust address up if needed -- Cort */
+#define _ALIGN(addr,size)	(((addr)+size-1)&(~(size-1)))
+
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
-/* This handles the memory map.. */
-
-#define KERNELBASE	0x90000000
-#define PAGE_OFFSET	KERNELBASE
 
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
@@ -67,7 +88,8 @@
 #define MAP_NR(addr)	(__pa(addr) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED	(1<<15)
 
+extern __inline__ unsigned long get_prezerod_page(void);
 
 #endif /* __KERNEL__ */
-
+#endif /* __ASSEMBLY__ */
 #endif /* _PPC_PAGE_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.1.47/linux/include/asm-ppc/pgtable.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-ppc/pgtable.h	Thu Jul 31 13:09:18 1997
@@ -1,22 +1,31 @@
-/* * Last edited: Nov  7 23:44 1995 (cort) */
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
 
+#include <linux/config.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 
-inline void flush_tlb(void);
-inline void flush_tlb_all(void);
-inline void flush_tlb_mm(struct mm_struct *mm);
-inline void flush_tlb_page(struct vm_area_struct *vma, long vmaddr);
-inline void flush_tlb_range(struct mm_struct *mm, long start, long end);
-inline void flush_page_to_ram(unsigned long);
-inline void really_flush_cache_all(void);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+			    unsigned long end);
+extern void flush_tlb(void);
+
+/* Caches aren't brain-dead on the ppc. */
+#define flush_cache_all()			
+#define flush_cache_mm(mm)			
+#define flush_cache_range(mm, start, end)	
+#define flush_cache_page(vma, vmaddr)		
+/*
+ * For the page specified, write modified lines in the data cache
+ * out to memory, and invalidate lines in the instruction cache.
+ */
+extern void flush_page_to_ram(unsigned long);
 
-/* only called from asm in head.S, so why bother? */
-/*void MMU_init(void);*/
+extern unsigned long va_to_phys(unsigned long address);
 
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
+/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
 #define PMD_SHIFT	22
 #define PMD_SIZE	(1UL << PMD_SHIFT)
 #define PMD_MASK	(~(PMD_SIZE-1))
@@ -27,8 +36,8 @@
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
 /*
- * entries per page directory level: the i386 is two-level, so
- * we don't really have any PMD directory physically.
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
  */
 #define PTRS_PER_PTE	1024
 #define PTRS_PER_PMD	1
@@ -41,41 +50,42 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-/* this must be a decent size since the ppc bat's can map only certain sizes
-   but these can be different from the physical ram size configured.
-   bat mapping must map at least physical ram size and vmalloc start addr
-   must beging AFTER the area mapped by the bat.
-   32 works for now, but may need to be changed with larger differences.
-   offset = next greatest bat mapping to ramsize - ramsize
-   (ie would be 0 if batmapping = ramsize)
-        -- Cort 10/6/96
-   */
-#define VMALLOC_OFFSET	(32*1024*1024)
+#define VMALLOC_OFFSET	(0x2000000) /* 32M */
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
-#define _PAGE_PRESENT	0x001
-#define _PAGE_RW	0x002
-#define _PAGE_USER	0x004
-#define _PAGE_PCD	0x010
-#define _PAGE_ACCESSED	0x020
-#define _PAGE_DIRTY	0x040
-#define _PAGE_COW	0x200	/* implemented in software (one of the AVL bits) */
-#define _PAGE_NO_CACHE	0x400
+/*
+ * Bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+#define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
+#define _PAGE_USER	0x002	/* matches one of the PP bits */
+#define _PAGE_RW	0x004	/* software: user write access allowed */
+#define _PAGE_GUARDED	0x008
+#define _PAGE_COHERENT	0x010	/* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE	0x020	/* I: cache inhibit */
+#define _PAGE_WRITETHRU	0x040	/* W: cache write-through */
+#define _PAGE_DIRTY	0x080	/* C: page changed */
+#define _PAGE_ACCESSED	0x100	/* R: page referenced */
+#define _PAGE_HWWRITE	0x200	/* software: _PAGE_RW & _PAGE_DIRTY */
 
-#define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
+				 _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_NO_CACHE	__pgprot(_PAGE_NO_CACHE | _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+				 _PAGE_HWWRITE | _PAGE_ACCESSED)
+#define PAGE_KERNEL_CI	__pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
+				 _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
 
 /*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis.  So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
  */
 #define __P000	PAGE_NONE
 #define __P001	PAGE_READONLY
@@ -96,18 +106,6 @@
 #define __S111	PAGE_SHARED
 
 /*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
-#if 0
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-#endif
-
-/*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
  * BAD_PAGE is used for a bogus page.
  *
@@ -119,49 +117,36 @@
 
 extern unsigned long empty_zero_page[1024];
 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define BAD_PAGETABLE	__bad_pagetable()
+#define BAD_PAGE	__bad_page()
+#define ZERO_PAGE	((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR			(8*sizeof(unsigned long))
+#define BITS_PER_PTR	(8*sizeof(unsigned long))
 
 /* to align the pointer to a pointer address */
-#define PTR_MASK			(~(sizeof(void*)-1))
+#define PTR_MASK	(~(sizeof(void*)-1))
 
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* sizeof(void*) == 1<<SIZEOF_PTR_LOG2 */
 /* 64-bit machines, beware!  SRB. */
-#define SIZEOF_PTR_LOG2			2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+#define SIZEOF_PTR_LOG2	2
 
 /* to set the page-dir */
 /* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
-	(tsk)->tss.pg_tables = (unsigned long *)(pgdir); \
-	if ((tsk) == current) \
-	{ \
-/*_printk("Change page tables = %x\n", pgdir);*/ \
-	} \
-} while (0)
-
-/* comes from include/linux/mm.h now -- Cort */
-/*extern void *high_memory;*/
+#define SET_PAGE_DIR(tsk,pgdir) ({ \
+	((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
+})
 
 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_PRESENT; }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
 
 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; }
-extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_PRESENT; }
-extern inline int pmd_inuse(pmd_t *pmdp)	{ return 0; }
+extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != 0; }
+extern inline int pmd_present(pmd_t pmd)	{ return (pmd_val(pmd) & PAGE_MASK) != 0; }
 extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)	{ }
 
+     
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -172,7 +157,6 @@
 extern inline int pgd_present(pgd_t pgd)	{ return 1; }
 extern inline void pgd_clear(pgd_t * pgdp)	{ }
 
-
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -182,48 +166,82 @@
 extern inline int pte_exec(pte_t pte)		{ return pte_val(pte) & _PAGE_USER; }
 extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
-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_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~_PAGE_USER; 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_ACCESSED; 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_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)	{ pte_val(pte) |= _PAGE_USER; 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_ACCESSED; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte)	{ pte_val(pte) |= _PAGE_COW; return pte; }
+extern inline int pte_uncache(pte_t pte)        { return pte_val(pte) |= _PAGE_NO_CACHE; }
+extern inline int pte_cache(pte_t pte)          { return pte_val(pte) &= ~_PAGE_NO_CACHE; }
 
-/*
- * 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 pte_rdprotect(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkclean(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkold(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+extern inline pte_t pte_mkread(pte_t pte) {
+	pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte) {
+	pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_RW;
+	if (pte_val(pte) & _PAGE_DIRTY)
+		pte_val(pte) |= _PAGE_HWWRITE;
+	return pte;
+}
+extern inline pte_t pte_mkdirty(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_DIRTY;
+	if (pte_val(pte) & _PAGE_RW)
+		pte_val(pte) |= _PAGE_HWWRITE;
+	return pte;
+}
+extern inline pte_t pte_mkyoung(pte_t pte) {
+	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#if 1
+#define set_pte(pteptr, pteval)	((*(pteptr)) = (pteval))
+#else
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+	unsigned long val = pte_val(pteval);
+	extern void xmon(void *);
+
+	if ((val & _PAGE_PRESENT) && ((val < 0x111000 || (val & 0x800)
+	    || ((val & _PAGE_HWWRITE) && (~val & (_PAGE_RW|_PAGE_DIRTY)))) {
+		printk("bad pte val %lx ptr=%p\n", val, pteptr);
+		xmon(0);
+	}
+	*pteptr = pteval;
+}
+#endif
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
 
-static pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
+static inline pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
 { pte_t pte; pte_val(pte) = (page) | pgprot_val(pgprot); return pte; }
-/*#define mk_pte_phys(physpage, pgprot) \
-({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })*/
 
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+{ pte_t pte; pte_val(pte) = __pa(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; }
+{ return (pte_val(pte) & PAGE_MASK) + KERNELBASE; }
 
 extern inline unsigned long pmd_page(pmd_t pmd)
-{ return pmd_val(pmd) & PAGE_MASK; }
+{ return pmd_val(pmd); }
 
 
 /* to find an entry in a kernel page-table-directory */
@@ -250,13 +268,14 @@
 
 /*
  * 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.
+ * used to allocate a kernel page table, but are actually identical
+ * to the xxx() versions.
  */
 extern inline void pte_free_kernel(pte_t * pte)
 {
 	free_page((unsigned long) pte);
 }
+
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -264,20 +283,17 @@
 		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
 		if (pmd_none(*pmd)) {
 			if (page) {
-/*                                pmd_set(pmd,page);*/
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				pmd_val(*pmd) = (unsigned long) page;
 				return page + address;
 			}
-/*			pmd_set(pmd, BAD_PAGETABLE);*/
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			pmd_val(*pmd) = (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_set(pmd, (pte_t *) BAD_PAGETABLE);		*/
-		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+		pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -308,17 +324,17 @@
 		pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
 		if (pmd_none(*pmd)) {
 			if (page) {
-				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+				pmd_val(*pmd) = (unsigned long) page;
 				return page + address;
 			}
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+			pmd_val(*pmd) = (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;
+		pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -350,18 +366,17 @@
 extern pgd_t swapper_pg_dir[1024];
 
 /*
- * Software maintained MMU tables may have changed -- update the
- * hardware [aka cache]
+ * Page tables may have changed.  We don't need to do anything here
+ * as entries are faulted into the hash table by the low-level
+ * data/instruction access exception handlers.
  */
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t _pte);
+#define update_mmu_cache(vma,address,pte) while(0){}
 
 
 #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
-#define module_map      vmalloc
-#define module_unmap    vfree
+
 
 #endif /* _PPC_PAGE_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/poll.h linux/include/asm-ppc/poll.h
--- v2.1.47/linux/include/asm-ppc/poll.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/poll.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,25 @@
+#ifndef __i386_POLL_H
+#define __i386_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN		0x0001
+#define POLLPRI		0x0002
+#define POLLOUT		0x0004
+#define POLLERR		0x0008
+#define POLLHUP		0x0010
+#define POLLNVAL	0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM	0x0040
+#define POLLRDBAND	0x0080
+#define POLLWRNORM	0x0100
+#define POLLWRBAND	0x0200
+#define POLLMSG		0x0400
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/ppc_machine.h linux/include/asm-ppc/ppc_machine.h
--- v2.1.47/linux/include/asm-ppc/ppc_machine.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/ppc_machine.h	Wed Dec 31 16:00:00 1969
@@ -1,56 +0,0 @@
-/*
- * PowerPC machine specifics
- */
-
-#ifndef _PPC_MACHINE_H_
-#define _PPC_MACHINE_H_ 
-
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
-
-/* Bit encodings for Machine State Register (MSR) */
-#define MSR_POW		(1<<18)		/* Enable Power Management */
-#define MSR_TGPR	(1<<17)		/* TLB Update registers in use */
-#define MSR_ILE		(1<<16)		/* Interrupt Little-Endian enable */
-#define MSR_EE		(1<<15)		/* External Interrupt enable */
-#define MSR_PR		(1<<14)		/* Supervisor/User privilege */
-#define MSR_FP		(1<<13)		/* Floating Point enable */
-#define MSR_ME		(1<<12)		/* Machine Check enable */
-#define MSR_FE0		(1<<11)		/* Floating Exception mode 0 */
-#define MSR_SE		(1<<10)		/* Single Step */
-#define MSR_BE		(1<<9)		/* Branch Trace */
-#define MSR_FE1		(1<<8)		/* Floating Exception mode 1 */
-#define MSR_IP		(1<<6)		/* Exception prefix 0x000/0xFFF */
-#define MSR_IR		(1<<5)		/* Instruction MMU enable */
-#define MSR_DR		(1<<4)		/* Data MMU enable */
-#define MSR_RI		(1<<1)		/* Recoverable Exception */
-#define MSR_LE		(1<<0)		/* Little-Endian enable */
-
-#define MSR_		MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
-#define MSR_USER	MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
-
-/* Bit encodings for Hardware Implementation Register (HID0) */
-#define HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
-#define HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
-#define HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
-#define HID0_SBCLK	(1<<27)
-#define HID0_EICE	(1<<26)
-#define HID0_ECLK	(1<<25)
-#define HID0_PAR	(1<<24)
-#define HID0_DOZE	(1<<23)
-#define HID0_NAP	(1<<22)
-#define HID0_SLEEP	(1<<21)
-#define HID0_DPM	(1<<20)
-#define HID0_ICE	(1<<15)		/* Instruction Cache Enable */
-#define HID0_DCE	(1<<14)		/* Data Cache Enable */
-#define HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
-#define HID0_DLOCK	(1<<12)		/* Data Cache Lock */
-#define HID0_ICFI	(1<<11)		/* Instruction Cache Flash Invalidate */
-#define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
-#define HID0_SIED	(1<<7)		/* Serial Instruction Execution [Disable] */
-#define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
-
-/* fpscr settings */
-#define FPSCR_FX        (1<<31)
-#define FPSCR_FEX       (1<<30)
-#endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.1.47/linux/include/asm-ppc/processor.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-ppc/processor.h	Thu Jul 31 13:09:18 1997
@@ -1,12 +1,8 @@
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
 
-/*
- * PowerPC machine specifics
- */
+#include <linux/config.h>
 
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
 
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_POW		(1<<18)		/* Enable Power Management */
@@ -26,7 +22,8 @@
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
 #define MSR_LE		(1<<0)		/* Little-Endian enable */
 
-#define MSR_		MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
+#define MSR_		MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
 #define MSR_USER	MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
 
 /* Bit encodings for Hardware Implementation Register (HID0) */
@@ -49,20 +46,16 @@
 #define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
 #define HID0_SIED	(1<<7)		/* Serial Instruction Execution [Disable] */
 #define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
-
 /* fpscr settings */
 #define FPSCR_FX        (1<<31)
 #define FPSCR_FEX       (1<<30)
 
-
-
 #ifndef __ASSEMBLY__
 /*
  * PowerPC machine specifics
  */
 extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
 
-
 /*
  * Bus types
  */
@@ -77,79 +70,83 @@
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space process size: 2GB. 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
- */
 #define TASK_SIZE	(0x80000000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
-
 struct thread_struct 
 {
-  unsigned long	ksp;		/* Kernel stack pointer */
-  unsigned long	*pg_tables;	/* MMU information */
-  unsigned long	segs[16];	/* MMU Segment registers */
-  unsigned long	last_pc;	/* PC when last entered system */
-  unsigned long	user_stack;	/* [User] Stack when entered kernel */
-  double       	fpr[32];	/* Complete floating point set */
-  unsigned long	wchan;		/* Event task is sleeping on */
-  unsigned long	*regs;		/* Pointer to saved register state */
-  unsigned long fp_used;	/* number of quantums fp was used */
-  unsigned long fs;		/* for get_fs() validation */
-  unsigned long expc;		/* exception handler addr (see fault.c) */
-  unsigned long excount;	/* exception handler count */
+	unsigned long	ksp;		/* Kernel stack pointer */
+	unsigned long	*pg_tables;	/* MMU information */
+#ifdef CONFIG_PMAC
+	unsigned long	last_pc;	/* PC when last entered system */
+	unsigned long	user_stack;	/* [User] Stack when entered kernel */
+#endif  
+	unsigned long	fpscr_pad;	/* (so we can save fpscr with stfd) */
+	unsigned long   fpscr;		/* fp status reg */
+	double       	fpr[32];	/* Complete floating point set */
+	unsigned long   fp_used;
+	unsigned long	wchan;		/* Event task is sleeping on */
+	struct pt_regs  *regs;		/* Pointer to saved register state */
+	unsigned long   fs;		/* for get_fs() validation */
+	signed long     last_syscall;
+	unsigned long   pad[2];	/* pad to 16-byte boundry */
 };
 
+/* Points to the thread_struct of the thread (if any) which
+   currently owns the FPU. */
+#define fpu_tss (&(last_task_used_math->tss))
+
+#ifdef CONFIG_PMAC
+#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
+#endif
+#ifdef CONFIG_PREP
+#define LAZY_TSS_FPR_INIT 0,0,{0},
+#endif
 
 #define INIT_TSS  { \
-	sizeof(init_kernel_stack) + (long) &init_kernel_stack,\
-	(long *)swapper_pg_dir, {0}, \
-	0, 0, {0}, \
-	0, 0, 0, \
-	KERNEL_DS, 0, 0 \
+	sizeof(init_stack) + (long) &init_stack, /* ksp */ \
+	(long *)swapper_pg_dir, /* pg_tables */ \
+	LAZY_TSS_FPR_INIT \
+	0, /*fp_used*/ 0, /*wchan*/ \
+	sizeof(init_stack) + (long)&init_stack - \
+		sizeof(struct pt_regs), /* regs */ \
+	KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
 }
 
-#define INIT_MMAP { &init_mm, 0, 0x40000000, \
-		      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-/* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
+#define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
+		      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
 /*
  * Return saved PC of a blocked thread. For now, this is the "user" PC
  */
 static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	return (t->last_pc);
+	return (t->regs) ? t->regs->nip : 0;
+	/*return (t->last_pc);*/
 }
 
-#define _PROC_Motorola 0
-#define _PROC_IBM      1
-#define _PROC_Be       2
-
-int _Processor;
-
-/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct()	kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define free_task_struct(p)	kfree(p)
-
-#ifdef KERNEL_STACK_BUFFER
-/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
-#define alloc_kernel_stack()  \
-          (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
-#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
-#else
-#define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-#endif
+extern int _machine;
+#define _MACH_Motorola 0
+#define _MACH_IBM      1
+#define _MACH_Be       2
+#define _MACH_Pmac     3
 
-#endif /* ASSEMBLY*/
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+	((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p)	free_pages((unsigned long)(p),1)
 
-#endif
+/* in process.c - for early bootup debug -- Cort */
+int ll_printk(const char *, ...);
+void ll_puts(const char *);
+
+#endif /* ndef ASSEMBLY*/
 
+#define init_task	(init_task_union.task)
+#define init_stack	(init_task_union.stack)
+  
+#endif /* __ASM_PPC_PROCESSOR_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/ptrace.h linux/include/asm-ppc/ptrace.h
--- v2.1.47/linux/include/asm-ppc/ptrace.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/ptrace.h	Thu Jul 31 13:09:18 1997
@@ -2,54 +2,61 @@
 #define _PPC_PTRACE_H
 
 /*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- * Note: the "_overhead" and "_underhead" spaces are stack locations
- * used by called routines.  Because of the way the PowerPC ABI
- * specifies the function prologue/epilogue, registers can be
- * saved in stack locations which are below the current stack
- * pointer (_underhead).  If an interrupt occurs during this
- * [albeit] small time interval, registers which were saved on
- * the stack could be trashed by the interrupt save code.  The
- * "_underhead" leaves a hole just in case this happens.  It also
- * wastes 80 bytes of stack if it doesn't!  Similarly, the called
- * routine stores some information "above" the stack pointer before
- * if gets adjusted.  This is covered by the "_overhead" field
- * and [thankfully] is not totally wasted.
+ * this should only contain volatile regs
+ * since we can keep non-volatile in the tss
+ * should set this up when only volatiles are saved
+ * by intr code.
  *
+ * I can't find any reference to the above comment (from Gary Thomas)
+ * about _underhead/_overhead in the sys V abi for the ppc
+ * dated july 25, 1994.
+ *
+ * the stack must be kept to a size that is a multiple of 16
+ * so this includes the stack frame overhead 
+ * -- Cort.
+ */
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't.  To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
  */
+#define STACK_FRAME_OVERHEAD 16
+#define STACK_UNDERHEAD	64
 
+#ifndef __ASSEMBLY__
 struct pt_regs {
-  unsigned long _overhead[14]; /* Callee's SP,LR,params */
-  unsigned long gpr[32];
-  unsigned long nip;
-  unsigned long msr;
-  unsigned long ctr;
-  unsigned long link;
-  unsigned long ccr;
-  unsigned long xer;
-  unsigned long dar;	/* Fault registers */
-  unsigned long dsisr;
-  unsigned long srr1;
-  unsigned long srr0;
-  unsigned long hash1, hash2;
-  unsigned long imiss, dmiss;
-  unsigned long icmp, dcmp;
-  unsigned long orig_gpr3; /* Used for restarting system calls */
-  unsigned long result;    /* Result of a system call */
-  double        fpcsr;
-  unsigned long trap;	/* Reason for being here */
-  unsigned long marker;	/* Should have DEADDEAD */
-  /*unsigned long _underhead[20]; *//* Callee's register save area */
-  unsigned long edx;	/* for binfmt_elf.c which wants edx */
+	unsigned long gpr[32];
+	unsigned long nip;	
+	unsigned long msr;	
+	unsigned long ctr;	
+	unsigned long link;	
+	unsigned long ccr;	
+	unsigned long xer;	
+	unsigned long dar;	/* Fault registers */
+	unsigned long dsisr;
+#if 0  
+	unsigned long srr1;
+	unsigned long srr0;
+	unsigned long hash1, hash2;
+	unsigned long imiss, dmiss;
+	unsigned long icmp, dcmp;
+#endif  
+	unsigned long orig_gpr3; /* Used for restarting system calls */
+	unsigned long result;	/* Result of a system call */
+	unsigned long trap;	/* Reason for being here */
+	unsigned long marker;	/* Should have DEADDEAD */
 };
 
+
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_mode(regs) ((regs)->msr & 0x4000)
 #ifdef KERNEL
 extern void show_regs(struct pt_regs *);
 #endif
 
+/* should include and generate these in ppc_defs.h -- Cort */
 /* Offsets used by 'ptrace' system call interface */
 /* Note: these should correspond to gpr[x]        */
 #define PT_R0	0
@@ -94,6 +101,7 @@
 #define PT_CCR	38
 
 #define PT_FPR0	48
+#endif /* __ASSEMBLY__ */
 
-#endif
+#endif /* _PPC_PTRACE_H */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.1.47/linux/include/asm-ppc/semaphore.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-ppc/semaphore.h	Thu Jul 31 13:09:18 1997
@@ -1,11 +1,18 @@
 #ifndef _PPC_SEMAPHORE_H
 #define _PPC_SEMAPHORE_H
 
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * Adapted for PowerPC by Gary Thomas and Paul Mackerras
+ */
+
 #include <asm/atomic.h>
 
 struct semaphore {
 	atomic_t count;
-	atomic_t waiting;
+	atomic_t waking;
 	struct wait_queue * wait;
 };
 
@@ -13,44 +20,61 @@
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
 extern void __down(struct semaphore * sem);
+extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-extern void atomic_add(int c, int *v);
-extern void atomic_sub(int c, int *v);
+#define sema_init(sem, val)	atomic_set(&((sem)->count), (val))
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * i.e. load with reservation and store conditional on the ppc.
+ */
 
-#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
+static inline void wake_one_more(struct semaphore * sem)
+{
+	atomic_inc(&sem->waking);
+}
 
 static inline int waking_non_zero(struct semaphore *sem)
 {
-	unsigned long flags;
-	int ret = 0;
+	int ret, tmp;
+
+	__asm__ __volatile__(
+		"1:	lwarx %1,0,%2\n"
+		"	cmpwi 0,%1,0\n"
+		"	addi %1,%1,-1\n"
+		"	ble- 2f\n"
+		"	stwcx. %1,0,%2\n"
+		"	bne- 1b\n"
+		"	mr %0,%1\n"
+		"2:"
+		: "=r" (ret), "=r" (tmp)
+		: "r" (&sem->waking), "0" (0)
+		: "cr0", "memory");
 
-	save_flags(flags);
-	cli();
-	if (atomic_read(&sem->waking) > 0) {
-		atomic_dec(&sem->waking);
-		ret = 1;
-	}
-	restore_flags(flags);
 	return ret;
 }
 
 extern inline void down(struct semaphore * sem)
 {
-  for (;;)
-  {
-    atomic_dec_return(&sem->count);
-    if ( sem->count >= 0)
-      break;
-    __down(sem);
-  }
+	if (atomic_dec_return(&sem->count) < 0)
+		__down(sem);
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	return ret;
 }
 
 extern inline void up(struct semaphore * sem)
 {
-  atomic_inc_return(&sem->count);
-  if ( sem->count <= 0)
-    __up(sem);
+	if (atomic_inc_return(&sem->count) <= 0)
+		__up(sem);
 }	
 
 #endif /* !(_PPC_SEMAPHORE_H) */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.1.47/linux/include/asm-ppc/smp.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/smp.h	Thu Jul 31 13:09:18 1997
@@ -19,7 +19,7 @@
 };
 
 extern struct cpuinfo_PPC cpu_data[NR_CPUS];
-
+#endif /* __ASSEMBLY__ */
 
 #endif /* !(__SMP__) */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/smp_lock.h linux/include/asm-ppc/smp_lock.h
--- v2.1.47/linux/include/asm-ppc/smp_lock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/smp_lock.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,16 @@
+#ifndef __PPC_SMPLOCK_H
+#define __PPC_SMPLOCK_H
+
+#ifndef __SMP__
+
+#define lock_kernel()		do { } while (0)
+#define unlock_kernel()		do { } while (0)
+#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
+#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
+
+#else
+
+#error need to defined lock_kernel and unlock_kernel, etc.
+
+#endif /* __SMP__ */
+#endif /* __PPC_SMPLOCK_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/socket.h linux/include/asm-ppc/socket.h
--- v2.1.47/linux/include/asm-ppc/socket.h	Thu Mar 27 14:40:07 1997
+++ linux/include/asm-ppc/socket.h	Thu Jul 31 13:09:18 1997
@@ -26,15 +26,12 @@
 #define SO_PRIORITY	12
 #define SO_LINGER	13
 #define SO_BSDCOMPAT	14
-/* To add :#define SO_REUSEPORT 14 */
+/* To add :#define SO_REUSEPORT 15 */
 #define SO_RCVLOWAT	16
 #define SO_SNDLOWAT	17
 #define SO_RCVTIMEO	18
 #define SO_SNDTIMEO	19
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION		20
-#define SO_SECURITY_ENCRYPTION_TRANSPORT	21
-#define SO_SECURITY_ENCRYPTION_NETWORK		22
+#define SO_PASSCRED	20
+#define SO_PEERCRED	21
 
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.1.47/linux/include/asm-ppc/softirq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/softirq.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,78 @@
+/*
+ * Software interrupts..
+ */
+
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#define get_active_bhs()	(bh_mask & bh_active)
+#define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+}
+
+extern inline void remove_bh(int nr)
+{
+	bh_base[nr] = NULL;
+	bh_mask &= ~(1 << nr);
+}
+
+extern inline void mark_bh(int nr)
+{
+	set_bit(nr, &bh_active);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
+}
+
+extern inline void enable_bh(int nr)
+{
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+}
+
+#ifndef __SMP__
+
+/*
+ * The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+
+extern int __ppc_bh_counter;
+
+extern inline void start_bh_atomic(void)
+{
+	__ppc_bh_counter++;
+	barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+	barrier();
+	__ppc_bh_counter--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock()	(__ppc_bh_counter? 0: ((__ppc_bh_counter=1),1))
+#define softirq_endlock()	(__ppc_bh_counter = 0)
+
+#else
+#error Nein, wir haben noch kein SMP
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h
--- v2.1.47/linux/include/asm-ppc/spinlock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/spinlock.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,107 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#ifndef __SMP__
+
+typedef struct { int blah; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock(lock)		do { } while(0)
+#define spin_trylock(lock)	do { } while(0)
+#define spin_unlock(lock)	do { } while(0)
+#define spin_lock_irq(lock)	cli()
+#define spin_unlock_irq(lock)	sti()
+
+#define spin_lock_irqsave(lock, flags) \
+	do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+	restore_flags(flags)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct { int fred; } rwlock_t;
+#define RW_LOCK_UNLOCKED { }
+
+#define read_lock(lock)		do { } while(0)
+#define read_unlock(lock)	do { } while(0)
+#define write_lock(lock)	do { } while(0)
+#define write_unlock(lock)	do { } while(0)
+#define read_lock_irq(lock)	cli()
+#define read_unlock_irq(lock)	sti()
+#define write_lock_irq(lock)	cli()
+#define write_unlock_irq(lock)	sti()
+
+#define read_lock_irqsave(lock, flags)	\
+	do { save_flags(flags); cli(); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+	restore_flags(flags)
+#define write_lock_irqsave(lock, flags)	\
+	do { save_flags(flags); cli(); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+	restore_flags(flags)
+
+#else
+
+/* Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+typedef struct {
+	volatile unsigned int lock;
+	unsigned long previous;
+} spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED { 0, 0 }
+
+#define spin_unlock(lock)	((lock)->lock = 0)
+
+static inline void spin_lock(spinlock_t * lock)
+{
+	int stuck = 10000000;
+	int tmp, val;
+	__label__ l1;
+
+l1:	__asm__ __volatile__(
+		"	mtctr %2\n"
+		"1:	lwarx %0,0,%3\n"
+		"	andi. %1,%0,1\n\t"
+		"	ori %0,%0,1\n\t"
+		"	bne- 2f\n\t"
+		"	stwcx. %0,0,%3\n\t"
+		"2:	bdnzf- 2,1b"
+		: "=r" (tmp), "=r" (val)
+		: "r" (stuck), "r" (lock)
+		: "ctr");
+	if (!val) {
+		printk("spinlock stuck at %p (%lx)\n", &&l1, lock->previous);
+	} else
+		lock->previous = (unsigned long) &&l1;
+}
+
+#define spin_trylock(lock) (!set_bit(0,(lock)))
+
+#define spin_lock_irq(lock) \
+	do { __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irq(lock) \
+	do { spin_unlock(lock); __sti(); } while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+	do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags) \
+	do { spin_unlock(lock); __restore_flags(flags); } while (0)
+
+#endif /* SMP */
+#endif /* __ASM_SPINLOCK_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/string.h linux/include/asm-ppc/string.h
--- v2.1.47/linux/include/asm-ppc/string.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/string.h	Thu Jul 31 13:09:18 1997
@@ -1,26 +1,27 @@
 #ifndef _PPC_STRING_H_
 #define _PPC_STRING_H_
 
-
-
-/*
- * keep things happy, the compile became unhappy since memset is
- * in include/linux/string.h and lib/string.c with different prototypes
- *                          -- Cort
- */
-#if 1
-#define  __HAVE_ARCH_MEMSET
-extern __inline__ void * memset(void * s,int c,__kernel_size_t count)
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRNCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCHR
+/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
+extern inline void * memchr(const void * cs,int c,size_t count)
 {
-	char *xs = (char *) s;
-
-	while (count--)
-		*xs++ = c;
-
-	return s;
+	unsigned long i = 0;
+	while ( count != i )
+	{
+		if ( (char)c == *(char *)(cs + i) )
+			return (void *)(cs + i);
+		i--;
+	}
+	return NULL;
 }
-#endif
-#define bzero(addr,size) memset((addr),(int)(0),(size))
-
-
 #endif
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.1.47/linux/include/asm-ppc/system.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/system.h	Thu Jul 31 13:09:18 1997
@@ -1,27 +1,66 @@
 #ifndef __PPC_SYSTEM_H
 #define __PPC_SYSTEM_H
 
-#if 0
-#define mb() \
-__asm__ __volatile__("mb": : :"memory")
-#endif
-#define mb()  __asm__ __volatile__ (""   : : :"memory")
+#include <linux/delay.h>
+
+#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
 
+#define __save_flags(flags)	({\
+	__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
+/* using Paul's in misc.S now -- Cort */
+extern void __restore_flags(unsigned long flags);
 
-extern void __save_flags(long *flags);
-extern void __restore_flags(long flags);
-extern void sti(void);
-extern void cli(void);
+/*
+  #define __sti() _soft_sti(void)
+  #define __cli() _soft_cli(void)
+ */
+extern void __sti(void);
+extern void __cli(void);
+
+extern void _hard_sti(void);
+extern void _hard_cli(void);
+extern void _soft_sti(void);
+extern void _soft_cli(void);
 extern int _disable_interrupts(void);
 extern void _enable_interrupts(int);
 
-/*extern void memcpy(void *, void *, int);*/
+extern void flush_instruction_cache(void);
+extern void hard_reset_now(void);
+extern void poweroff_now(void);
+extern void find_scsi_boot(void);
+extern int sd_find_target(void *, int);
+extern int _get_PVR(void);
+extern void via_cuda_init(void);
+extern void read_rtc_time(void);
+extern void pmac_find_display(void);
+extern void giveup_fpu(void);
+extern void store_cache_range(unsigned long, unsigned long);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
+
+struct device_node;
+extern void note_scsi_host(struct device_node *, void *);
 
 struct task_struct;
 extern void switch_to(struct task_struct *prev, struct task_struct *next);
 
-#define save_flags(flags) __save_flags(&(flags))
-#define restore_flags(flags) __restore_flags(flags)
+struct thread_struct;
+extern void _switch(struct thread_struct *prev, struct thread_struct *next,
+		    unsigned long context);
+
+struct pt_regs;
+extern int do_signal(unsigned long oldmask, struct pt_regs *regs);
+extern void dump_regs(struct pt_regs *);
+
+#ifndef __SMP__
+#define cli()	__cli()
+#define sti()	__sti()
+#define save_flags(flags)	__save_flags(flags)
+#define restore_flags(flags)	__restore_flags(flags)
+
+#else
+#error need global cli/sti etc. defined for SMP
+#endif
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/termbits.h linux/include/asm-ppc/termbits.h
--- v2.1.47/linux/include/asm-ppc/termbits.h	Mon May 27 02:00:59 1996
+++ linux/include/asm-ppc/termbits.h	Thu Jul 31 13:09:18 1997
@@ -7,7 +7,6 @@
 typedef unsigned int	speed_t;
 typedef unsigned int	tcflag_t;
 
-#if 0 /* This is how it's done on Alpha - maybe later. */
 /*
  * termios type and macro definitions.  Be careful about adding stuff
  * to this file since it's used in GNU libc and there are strict rules
@@ -27,23 +26,24 @@
 };
 
 /* c_cc characters */
-#define VEOF 0
-#define VEOL 1
-#define VEOL2 2
-#define VERASE 3
-#define VWERASE 4
-#define VKILL 5
-#define VREPRINT 6
-#define VSWTC 7
-#define VINTR 8
-#define VQUIT 9
-#define VSUSP 10
-#define VSTART 12
-#define VSTOP 13
-#define VLNEXT 14
-#define VDISCARD 15
-#define VMIN 16
-#define VTIME 17
+#define VINTR 	0
+#define VQUIT 	1
+#define VERASE 	2
+#define VKILL	3
+#define VEOF	4
+#define VMIN	5
+#define VEOL	6
+#define VTIME	7
+#define VEOL2	8
+#define VSWTC	9
+
+#define VWERASE 	10
+#define VREPRINT	11
+#define VSUSP 		12
+#define VSTART		13
+#define VSTOP		14
+#define VLNEXT		15
+#define VDISCARD	16
 
 /* c_iflag bits */
 #define IGNBRK	0000001
@@ -57,7 +57,7 @@
 #define ICRNL	0000400
 #define IXON	0001000
 #define IXOFF	0002000
-#if !defined(KERNEL) || defined(__USE_BSD)
+#if defined(__KERNEL__) || defined(__USE_BSD)
   /* POSIX.1 doesn't want these... */
 # define IXANY		0004000
 # define IUCLC		0010000
@@ -102,7 +102,7 @@
 #define XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
 
 /* c_cflag bit meaning */
-#define CBAUD	0000017
+#define CBAUD	0000377
 #define  B0	0000000		/* hang up */
 #define  B50	0000001
 #define  B75	0000002
@@ -173,6 +173,5 @@
 #define	TCSANOW		0
 #define	TCSADRAIN	1
 #define	TCSAFLUSH	2
-#endif
 
 #endif /* _PPC_TERMBITS_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/termios.h linux/include/asm-ppc/termios.h
--- v2.1.47/linux/include/asm-ppc/termios.h	Mon Dec 30 02:53:48 1996
+++ linux/include/asm-ppc/termios.h	Thu Jul 31 13:09:18 1997
@@ -137,18 +137,6 @@
 	unsigned char c_cc[NCC];	/* control characters */
 };
 
-#define NCCS 19
-struct termios {
-	tcflag_t c_iflag;		/* input mode flags */
-	tcflag_t c_oflag;		/* output mode flags */
-	tcflag_t c_cflag;		/* control mode flags */
-	tcflag_t c_lflag;		/* local mode flags */
-	cc_t c_cc[NCCS];		/* control characters */
-	cc_t c_line;			/* line discipline (== c_cc[19]) */
-	int c_ispeed;			/* input speed */
-	int c_ospeed;			/* output speed */
-};
-
 /* c_cc characters */
 #define _VINTR	0
 #define _VQUIT	1
@@ -161,150 +149,11 @@
 #define _VEOL2	8
 #define _VSWTC	9
 
-#define VINTR 	0
-#define VQUIT 	1
-#define VERASE 	2
-#define VKILL	3
-#define VEOF	4
-#define VMIN	5
-#define VEOL	6
-#define VTIME	7
-#define VEOL2	8
-#define VSWTC	9
-
-#define VWERASE 	10
-#define VREPRINT	11
-#define VSUSP 		12
-#define VSTART		13
-#define VSTOP		14
-#define VLNEXT		15
-#define VDISCARD	16
-
-
 #ifdef __KERNEL__
-/*	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\001\000"
-*/
-
 /*                   ^C  ^\ del  ^U  ^D   1   0   0   0   0  ^W  ^R  ^Z  ^Q  ^S  ^V  ^U  */
 #define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025" 
 #endif
 
-/* c_iflag bits */
-#define IGNBRK	0000001
-#define BRKINT	0000002
-#define IGNPAR	0000004
-#define PARMRK	0000010
-#define INPCK	0000020
-#define ISTRIP	0000040
-#define INLCR	0000100
-#define IGNCR	0000200
-#define ICRNL	0000400
-#define IXON	0001000
-#define IXOFF	0002000
-#define IXANY	0004000
-#define IUCLC	0010000
-#define IMAXBEL	0020000
-
-/* c_oflag bits */
-#define OPOST	0000001
-#define ONLCR	0000002
-#define OLCUC	0000004
-
-#define OCRNL	0000010
-#define ONOCR	0000020
-#define ONLRET	0000040
-
-#define OFILL	00000100
-#define OFDEL	00000200
-#define NLDLY	00001400
-#define   NL0	00000000
-#define   NL1	00000400
-#define   NL2	00001000
-#define   NL3	00001400
-#define TABDLY	00006000
-#define   TAB0	00000000
-#define   TAB1	00002000
-#define   TAB2	00004000
-#define   TAB3	00006000
-#define CRDLY	00030000
-#define   CR0	00000000
-#define   CR1	00010000
-#define   CR2	00020000
-#define   CR3	00030000
-#define FFDLY	00040000
-#define   FF0	00000000
-#define   FF1	00040000
-#define BSDLY	00100000
-#define   BS0	00000000
-#define   BS1	00100000
-#define VTDLY	00200000
-#define   VT0	00000000
-#define   VT1	00200000
-#define XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
-
-/* c_cflag bit meaning */
-#define CBAUD	0000377
-#define  B0	0000000		/* hang up */
-#define  B50	0000001
-#define  B75	0000002
-#define  B110	0000003
-#define  B134	0000004
-#define  B150	0000005
-#define  B200	0000006
-#define  B300	0000007
-#define  B600	0000010
-#define  B1200	0000011
-#define  B1800	0000012
-#define  B2400	0000013
-#define  B4800	0000014
-#define  B9600	0000015
-#define  B19200	0000016
-#define  B38400	0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CBAUDEX 0000020
-#define  B57600   00020
-#define  B115200  00021
-#define  B230400  00022
-#define  B460800  00023
-
-#define CSIZE	00001400
-#define   CS5	00000000
-#define   CS6	00000400
-#define   CS7	00001000
-#define   CS8	00001400
-
-#define CSTOPB	00002000
-#define CREAD	00004000
-#define PARENB	00010000
-#define PARODD	00020000
-#define HUPCL	00040000
-
-#define CLOCAL	00100000
-#define CRTSCTS	  020000000000		/* flow control */
-
-/* c_lflag bits */
-#define ISIG	0x00000080
-#define ICANON	0x00000100
-#define XCASE	0x00004000
-#define ECHO	0x00000008
-#define ECHOE	0x00000002
-#define ECHOK	0x00000004
-#define ECHONL	0x00000010
-#define NOFLSH	0x80000000
-#define TOSTOP	0x00400000
-#define ECHOCTL	0x00000040
-#define ECHOPRT	0x00000020
-#define ECHOKE	0x00000001
-#define FLUSHO	0x00800000
-#define PENDIN	0x20000000
-#define IEXTEN	0x00000400
-
 /* modem lines */
 #define TIOCM_LE	0x001
 #define TIOCM_DTR	0x002
@@ -321,23 +170,6 @@
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
-
-/* tcflow() and TCXONC use these */
-#define	TCOOFF		0
-#define	TCOON		1
-#define	TCIOFF		2
-#define	TCION		3
-
-/* tcflush() and TCFLSH use these */
-#define	TCIFLUSH	0
-#define	TCOFLUSH	1
-#define	TCIOFLUSH	2
-
-/* tcsetattr uses these */
-#define	TCSANOW		0
-#define	TCSADRAIN	1
-#define	TCSAFLUSH	2
-
 /* line disciplines */
 #define N_TTY		0
 #define N_SLIP		1
@@ -349,55 +181,33 @@
 /*
  * Translate a "termio" structure into a "termios". Ugh.
  */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+	unsigned short __tmp; \
+	get_user(__tmp,&(termio)->x); \
+	(termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
+}
+
 #define user_termio_to_kernel_termios(termios, termio) \
-do { \
-	unsigned short tmp; \
-	get_user(tmp, &(termio)->c_iflag); \
-	(termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
-	get_user(tmp, &(termio)->c_oflag); \
-	(termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
-	get_user(tmp, &(termio)->c_cflag); \
-	(termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
-	get_user(tmp, &(termio)->c_lflag); \
-	(termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
-	get_user((termios)->c_line, &(termio)->c_line); \
-	get_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
-	get_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
-	get_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
-	get_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
-	get_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
-	get_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
-	get_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
-	get_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
-	get_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
-	get_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
-} while(0)
+({ \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
 
 /*
  * Translate a "termios" structure into a "termio". Ugh.
- *
- * Note the "fun" _VMIN overloading.
  */
 #define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
 	put_user((termios)->c_iflag, &(termio)->c_iflag); \
 	put_user((termios)->c_oflag, &(termio)->c_oflag); \
 	put_user((termios)->c_cflag, &(termio)->c_cflag); \
 	put_user((termios)->c_lflag, &(termio)->c_lflag); \
 	put_user((termios)->c_line,  &(termio)->c_line); \
-	put_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
-	put_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
-	put_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
-	put_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
-	put_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
-	put_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
-	put_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
-	put_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
-	if (1/*!((termios)->c_lflag & ICANON)*/) { \
-		put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
-		put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
-	} \
-} while(0)
+	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
 
 #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h
--- v2.1.47/linux/include/asm-ppc/uaccess.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/uaccess.h	Thu Jul 31 13:09:18 1997
@@ -1,22 +1,30 @@
-#ifndef _ASM_UACCESS_H
-#define _ASM_UACCESS_H
+#ifndef _PPC_UACCESS_H
+#define _PPC_UACCESS_H
 
 #ifndef __ASSEMBLY__
 #include <linux/sched.h>
 #include <linux/errno.h>
 
-#define KERNEL_DS   (0)
-#define USER_DS		(1)
-
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
-#define get_fs() (current->tss.fs)
-#define get_ds() (KERNEL_DS)
-#define set_fs(val) ( current->tss.fs = (val))
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS	(0)
+#define USER_DS		(1)
+
+#define get_fs()	(current->tss.fs)
+#define get_ds()	(KERNEL_DS)
+#define set_fs(val)	(current->tss.fs = (val))
 
 #define __user_ok(addr,size) (((size) <= 0x80000000)&&((addr) <= 0x80000000-(size)))
-#define __kernel_ok (get_fs() == KERNEL_DS)
+#define __kernel_ok	(get_fs() == KERNEL_DS)
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
@@ -25,126 +33,227 @@
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
 
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+	unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
  *
- * As the powerpc uses the same address space for kernel and user
- * data, we can just do these as direct assignments.  (Of course, the
- * exception handling means that it's no longer "just"...)
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
  *
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof/typeof is ok)
- * (b) require any knowledge of processes at this stage
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ *
+ * As we use the same address space for kernel and user data on the
+ * PowerPC, we can just do these as direct assignments.  (Of course, the
+ * exception handling means that it's no longer "just"...)
  */
+#define get_user(x,ptr) \
+  __get_user_check((x),(ptr),sizeof(*(ptr)))
+#define put_user(x,ptr) \
+  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
 /*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the programmer has to do the
- * checks by hand with "access_ok()")
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
  */
-#define put_user(x,ptr) ({ \
-unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
 
-#define get_user(x,ptr) ({ \
-unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
+#define put_user_ret(x,ptr,ret) ({ \
+if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ \
+if (get_user(x,ptr)) return ret; })
+
+#define __put_user_ret(x,ptr,ret) ({ \
+if (__put_user(x,ptr)) return ret; })
+
+#define __get_user_ret(x,ptr,ret) ({ \
+if (__get_user(x,ptr)) return ret; })
+
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size)			\
+({							\
+	long __pu_err;					\
+	__put_user_size((x),(ptr),(size),__pu_err);	\
+	__pu_err;					\
+})
+
+#define __put_user_check(x,ptr,size)				\
+({								\
+	long __pu_err = -EFAULT;				\
+	__typeof__(*(ptr)) *__pu_addr = (ptr);			\
+	if (access_ok(VERIFY_WRITE,__pu_addr,size))		\
+		__put_user_size((x),__pu_addr,(size),__pu_err);	\
+	__pu_err;						\
+})
+
+#define __put_user_size(x,ptr,size,retval)			\
+do {								\
+	retval = 0;						\
+	switch (size) {						\
+	  case 1: __put_user_asm(x,ptr,retval,"stb"); break;	\
+	  case 2: __put_user_asm(x,ptr,retval,"sth"); break;	\
+	  case 4: __put_user_asm(x,ptr,retval,"stw"); break;	\
+	  default: __put_user_bad();				\
+	}							\
+} while (0)
 
-#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
-#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
 struct __large_struct { unsigned long buf[100]; };
-#define __m(x) ((struct __large_struct *)(x))
+#define __m(x) (*(struct __large_struct *)(x))
 
-#define __put_user_check(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} } __pu_ret; })
-
-#define __put_user_nocheck(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} __pu_ret; })
-
-extern int __put_user_bad(void);
-
-#define __get_user_check(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __gu_val = __get_user_8(__gu_val,addr); break; \
-case 2: __gu_val = __get_user_16(__gu_val,addr); break; \
-case 4: __gu_val = __get_user_32(__gu_val,addr); break; \
-default: __get_user_bad(); break; \
-} } (x) = (type) __gu_val; __gu_ret; })
-
-#define __get_user_nocheck(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-switch (size) { \
-case 1: __gu_val =__get_user_8(__gu_val,addr); break; \
-case 2: __gu_val =__get_user_16(__gu_val,addr); break; \
-case 4: __gu_val =__get_user_32(__gu_val,addr); break; \
-default: __gu_val = __get_user_bad(); break; \
-} (x) = (type) __gu_val; __gu_ret;  })
-     
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, op)			\
+	__asm__ __volatile__(					\
+		"1:	"op" %1,0(%2)\n"			\
+		"2:\n"						\
+		".section .fixup,\"ax\"\n"			\
+		"3:	li %0,%3\n"				\
+		"	b 2b\n"					\
+		".section __ex_table,\"a\"\n"			\
+		"	.align 2\n"				\
+		"	.long 1b,3b\n"				\
+		".text"						\
+		: "=r"(err)					\
+		: "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size)				\
+({								\
+	long __gu_err, __gu_val;				\
+	__get_user_size(__gu_val,(ptr),(size),__gu_err);	\
+	(x) = (__typeof__(*(ptr)))__gu_val;			\
+	__gu_err;						\
+})
+
+#define __get_user_check(x,ptr,size)					\
+({									\
+	long __gu_err = -EFAULT, __gu_val = 0;				\
+	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
+	if (access_ok(VERIFY_READ,__gu_addr,size))			\
+		__get_user_size(__gu_val,__gu_addr,(size),__gu_err);	\
+	(x) = (__typeof__(*(ptr)))__gu_val;				\
+	__gu_err;							\
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)			\
+do {								\
+	retval = 0;						\
+	switch (size) {						\
+	  case 1: __get_user_asm(x,ptr,retval,"lbz"); break;	\
+	  case 2: __get_user_asm(x,ptr,retval,"lhz"); break;	\
+	  case 4: __get_user_asm(x,ptr,retval,"lwz"); break;	\
+	  default: (x) = __get_user_bad();			\
+	}							\
+} while (0)
+
+#define __get_user_asm(x, addr, err, op)		\
+	__asm__ __volatile__(				\
+		"1:	"op" %1,0(%2)\n"		\
+		"2:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"3:	li %0,%3\n"			\
+		"	li %1,0\n"			\
+		"	b 2b\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 2\n"			\
+		"	.long 1b,3b\n"			\
+		".text"					\
+		: "=r"(err), "=r"(x)			\
+		: "b"(addr), "i"(-EFAULT), "0"(err))
 
 /* more complex routines */
 
-extern int __copy_tofrom_user(unsigned long to, unsigned long from, int size);
+extern int __copy_tofrom_user(void *to, const void *from, unsigned long size);
+
+extern inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+	if (access_ok(VERIFY_READ, from, n))
+		return __copy_tofrom_user(to, from, n);
+	return n? -EFAULT: 0;
+}
+
+extern inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+	if (access_ok(VERIFY_WRITE, to, n))
+		return __copy_tofrom_user(to, from, n);
+	return n? -EFAULT: 0;
+}
+
+#define __copy_from_user(to, from, size) \
+	__copy_tofrom_user((to), (from), (size))
+#define __copy_to_user(to, from, size) \
+	__copy_tofrom_user((to), (from), (size))
+
+extern unsigned long __clear_user(void *addr, unsigned long size);
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+	if (access_ok(VERIFY_WRITE, addr, size))
+		return __clear_user(addr, size);
+	return size? -EFAULT: 0;
+}
+
+extern int __strncpy_from_user(char *dst, const char *src, long count);
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+	if (access_ok(VERIFY_READ, src, 1))
+		return __strncpy_from_user(dst, src, count);
+	return -EFAULT;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
 
-#define copy_to_user(to,from,n) ({ \
-unsigned long __copy_to = (unsigned long) (to); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
-__copy_res = __copy_tofrom_user(__copy_to, (unsigned long) (from), __copy_size); \
-}  \
-__copy_res; })
-
-#define copy_from_user(to,from,n) ({ \
-unsigned long __copy_from = (unsigned long) (from); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
-__copy_res = __copy_tofrom_user((unsigned long) (to), __copy_from, __copy_size); \
-} \
-__copy_res; })
-
-extern int __clear_user(unsigned long addr, int size);
-
-#define clear_user(addr,n) ({ \
-unsigned long __clear_addr = (unsigned long) (addr); \
-int __clear_size = (int) (n); \
-int __clear_res = -EFAULT; \
-if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
-__clear_res = __clear_user(__clear_addr, __clear_size); \
-} \
-__clear_res; })
-
-extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
-
-#define strncpy_from_user(dest,src,count) ({ \
-unsigned long __sfu_src = (unsigned long) (src); \
-int __sfu_count = (int) (count); \
-long __sfu_res = -EFAULT; \
-if(__access_ok(__sfu_src, __sfu_count)) { \
-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
-} __sfu_res; })
+extern long strlen_user(const char *);
 
 #endif  /* __ASSEMBLY__ */
 
-#endif /* _ASM_UACCESS_H */
+#endif	/* _PPC_UACCESS_H */
diff -u --recursive --new-file v2.1.47/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h
--- v2.1.47/linux/include/asm-ppc/unistd.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-ppc/unistd.h	Thu Jul 31 13:09:18 1997
@@ -1,10 +1,6 @@
-/* * Last edited: Nov 17 16:28 1995 (cort) */
 #ifndef _ASM_PPC_UNISTD_H_
 #define _ASM_PPC_UNISTD_H_
 
-#define _NR(n) #n
-#define _lisc(n) "li 0," _NR(n)
-
 /*
  * This file contains the system call numbers.
  */
@@ -175,180 +171,79 @@
 #define __NR_mremap		163
 #define __NR_setresuid		164
 #define __NR_getresuid		165
-#define __NR_nfsservctl		166
+#define __NR_query_module	166
+#define __NR_poll		167
+#define __NR_nfsservctl		168
+
+#define __NR(n)	#n
+#define __do_syscall(n) \
+	asm volatile ("li 0,%0\n\
+	sc\n\
+	bns 1f\n\
+	mr 0,3\n\
+	lis 3,errno@ha\n\
+	stw 0,errno@l(3)\n\
+	li 3,-1\n\
+1:" : : "i" (n) : "r0", "r3")
 
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
 type name(void) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall2(type,name,type1,arg1,type2,arg2) \
 type name(type1 arg1,type2 arg2) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
 type name(type1 arg1,type2 arg2,type3 arg3) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-} 
-
+{ __do_syscall(__NR_##name); }
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
 	  type5,arg5) \
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
+{ __do_syscall(__NR_##name); }
 
 #ifdef __KERNEL_SYSCALLS__
 
 /*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
+ * Forking from kernel space will result in NO COPY ON WRITE (!!!),
+ * until an execve is executed. This is no problem, but for the stack.
+ * This is handled by not letting main() use the stack at all after
+ * fork().  On the PowerPC, this means we can only call leaf functions.
  */
 
-
-#if 0
 /*
-   This is the mechanism for creating a new kernel thread.
-   For the time being it only behaves the same as clone().
-   It should be changed very soon to work properly and cleanly.  This
-   gets us going for now, though.
-
-   some versions of gcc hate this -- complains about constraints being
-   incorrect.  not sure why so it's in arch/ppc/kernel/misc.S now.
-     -- Cort
+ * Create a new kernel thread.
  */
-static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-  long retval;
-  __asm__  (
-	"li 0, 120 \n\t"        /* __NR_clone */
-	"li 3, %5 \n\t"         /* load flags as arg to clone */
-	/*"mr 1,7 \n\t"*/		/* save kernel stack */
-	"sc \n\t"		/* syscall */
-	/*"cmp 0,1,7 \n\t"*/	/* if kernel stack changes -- child */
-	"cmpi	0,3,0 \n\t"
-	"bne 1f \n\t"		/* return if parent */
-	/* this is in child */
-	"li 3, %3 \n\t"		/* child -- load args and call fn */
-	"mtlr %4 \n\t"		
-	"blrl \n\t"
-	"li 0, %2 \n\t"		/* exit after child exits */
-        "li 3, 0 \n\t"
-	"sc \n\t"
-	/* parent */
-	"1: \n\t"
-	:"=3" (retval)
-	:"i" (__NR_clone), "i" (__NR_exit),
-	 "r" (arg), "r" (fn), "g" (CLONE_VM|flags) 
-	:"cc", "1", "0", "3", "7", "31", "memory" );
-  return retval;
-}
-#else
 extern long __kernel_thread(unsigned long, int (*)(void *), void *);
 
 static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	return __kernel_thread(flags | CLONE_VM, fn, arg);
 }
-#endif
 
-#define __NR__exit __NR_exit
-static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */
-static inline _syscall0(int,fork) /* needs to be inline */
-static inline _syscall0(int,pause) /* needs to be inline */
-static inline _syscall1(int,setup,int,magic) /* called in init before execve */
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static /*inline*/ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static /*inline*/ _syscall1(int,dup,int,fd)
-static /*inline*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static /*inline*/ _syscall3(int,open,const char *,file,int,flag,int,mode)
-static /*inline*/ _syscall1(int,close,int,fd)
-static /*inline*/ _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+/*
+ * System call prototypes.
+ */
+int idle(void);
+int setup(int);
+int sync(void);
+pid_t setsid(void);
+int write(int, const char *, off_t);
+int dup(int);
+int execve(const char *, char **, char **);
+int open(const char *, int, int);
+int close(int);
+pid_t waitpid(pid_t, int *, int);
 
-/* called from init before execve -- need to be inline? -- Cort */
 static inline pid_t wait(int * wait_stat) 
 {
 	return waitpid(-1,wait_stat,0);
 }
 
-#endif
+#endif /* __KERNEL_SYSCALLS__ */
 
 #endif /* _ASM_PPC_UNISTD_H_ */
-
-
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc/fbio.h linux/include/asm-sparc/fbio.h
--- v2.1.47/linux/include/asm-sparc/fbio.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/fbio.h	Thu Jul 31 13:09:18 1997
@@ -48,7 +48,6 @@
 };
 #define FBIOGTYPE _IOR('F', 0, struct fbtype)
 
-/* Used by FBIOPUTCMAP */
 struct  fbcmap {
         int             index;          /* first element (0 origin) */
         int             count;
@@ -150,6 +149,21 @@
 #define FBIO_WID_PUT	_IOW('F', 32, struct fb_wid_list)
 #define FBIO_WID_GET	_IOWR('F', 33, struct fb_wid_list)
 
+/* Creator ioctls */
+#define FFB_IOCTL	('F'<<8)
+#define FFB_SYS_INFO		(FFB_IOCTL|80)
+#define FFB_CLUTREAD		(FFB_IOCTL|81)
+#define FFB_CLUTPOST		(FFB_IOCTL|82)
+#define FFB_SETDIAGMODE		(FFB_IOCTL|83)
+#define FFB_GETMONITORID	(FFB_IOCTL|84)
+#define FFB_GETVIDEOMODE	(FFB_IOCTL|85)
+#define FFB_SETVIDEOMODE	(FFB_IOCTL|86)
+#define FFB_SETSERVER		(FFB_IOCTL|87)
+#define FFB_SETOVCTL		(FFB_IOCTL|88)
+#define FFB_GETOVCTL		(FFB_IOCTL|89)
+#define FFB_GETSAXNUM		(FFB_IOCTL|90)
+#define FFB_FBDEBUG		(FFB_IOCTL|91)
+
 /* Cg14 ioctls */
 #define MDI_IOCTL          ('M'<<8)
 #define MDI_RESET          (MDI_IOCTL|1)
@@ -174,15 +188,15 @@
  */
 #define MDI_CLEAR_XLUT       (MDI_IOCTL|9)
 
-/* leo ioctls */
-struct leo_clut_alloc {
+/* leo & ffb ioctls */
+struct fb_clut_alloc {
 	__u32	clutid;	/* Set on return */
  	__u32	flag;
  	__u32	index;
 };
 
-struct leo_clut {
-#define LEO_CLUT_WAIT	0x00000001	/* Not yet implemented */
+struct fb_clut {
+#define FB_CLUT_WAIT	0x00000001	/* Not yet implemented */
  	__u32	flag;
  	__u32	clutid;
  	__u32	offset;
@@ -191,10 +205,21 @@
  	char *	green;
  	char *	blue;
 };
-#define LEO_CLUTALLOC	_IOWR('L', 53, struct leo_clut_alloc)
-#define LEO_CLUTFREE	_IOW('L', 54, struct leo_clut_alloc)
-#define LEO_CLUTREAD	_IOW('L', 55, struct leo_clut)
-#define LEO_CLUTPOST	_IOW('L', 56, struct leo_clut)
+
+struct fb_clut32 {
+ 	__u32	flag;
+ 	__u32	clutid;
+ 	__u32	offset;
+ 	__u32	count;
+ 	__u32	red;
+ 	__u32	green;
+ 	__u32	blue;
+};
+
+#define LEO_CLUTALLOC	_IOWR('L', 53, struct fb_clut_alloc)
+#define LEO_CLUTFREE	_IOW('L', 54, struct fb_clut_alloc)
+#define LEO_CLUTREAD	_IOW('L', 55, struct fb_clut)
+#define LEO_CLUTPOST	_IOW('L', 56, struct fb_clut)
 #define LEO_SETGAMMA	_IOW('L', 68, int) /* Not yet implemented */
 #define LEO_GETGAMMA	_IOR('L', 69, int) /* Not yet implemented */
 
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.1.47/linux/include/asm-sparc/smp.h	Tue May 13 22:41:18 1997
+++ linux/include/asm-sparc/smp.h	Thu Jul 31 13:09:18 1997
@@ -6,6 +6,8 @@
 #ifndef _SPARC_SMP_H
 #define _SPARC_SMP_H
 
+#include <asm/head.h>
+
 #ifndef __ASSEMBLY__
 /* PROM provided per-processor information we need
  * to start them all up.
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h
--- v2.1.47/linux/include/asm-sparc64/oplib.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/oplib.h	Thu Jul 31 13:09:18 1997
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.7 1997/04/03 09:29:25 davem Exp $
+/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -179,8 +179,7 @@
 /* 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);
+extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0);
 
 /* Stop the CPU with the passed device tree node. */
 extern int prom_stopcpu(int cpunode);
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.47/linux/include/asm-sparc64/pgtable.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/pgtable.h	Thu Jul 31 13:09:18 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.49 1997/06/30 09:24:12 jj Exp $
+/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -158,33 +158,33 @@
 
 /* Cache and TLB flush operations. */
 
-#define flush_cache_all()	\
-do {	unsigned long va;	\
-	flushw_all();		\
-	for(va = 0;		\
-	    va<(PAGE_SIZE<<1);	\
-	    va += 32)		\
-spitfire_put_icache_tag(va,0x0);\
-} while(0)
-
+/* These are the same regardless of whether this is an SMP kernel or not. */
 #define flush_cache_mm(mm)			do { } while(0)
 #define flush_cache_range(mm, start, end)	do { } while(0)
 #define flush_cache_page(vma, page)		do { } while(0)
 
 /* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
 
-extern void flush_tlb_all(void);
+extern void __flush_cache_all(void);
 
+extern void __flush_tlb_all(void);
 extern void __flush_tlb_mm(unsigned long context);
+extern void __flush_tlb_range(unsigned long context, unsigned long start,
+			      unsigned long end);
+extern void __flush_tlb_page(unsigned long context, unsigned long page);
+
+#ifndef __SMP__
+
+#define flush_cache_all()	__flush_cache_all()
+#define flush_tlb_all()		__flush_tlb_all()
+
 extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
 {
 	if(mm->context != NO_CONTEXT)
 		__flush_tlb_mm(mm->context & 0x1fff);
 }
 
-extern void __flush_tlb_range(unsigned long context, unsigned long start,
-			      unsigned long end);
 extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
 				       unsigned long end)
 {
@@ -192,7 +192,6 @@
 		__flush_tlb_range(mm->context & 0x1fff, start, end);
 }
 
-extern void __flush_tlb_page(unsigned long context, unsigned long page);
 extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
@@ -200,6 +199,41 @@
 	if(mm->context != NO_CONTEXT)
 		__flush_tlb_page(mm->context & 0x1fff, page & PAGE_MASK);
 }
+
+#else /* __SMP__ */
+
+extern void smp_flush_cache_all(void);
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *mm);
+extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				unsigned long end);
+extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+
+#define flush_cache_all()	smp_flush_cache_all()
+#define flush_tlb_all()		smp_flush_tlb_all()
+
+extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
+{
+	if(mm->context != NO_CONTEXT)
+		smp_flush_tlb_mm(mm);
+}
+
+extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				       unsigned long end)
+{
+	if(mm->context != NO_CONTEXT)
+		smp_flush_tlb_range(mm, start, end);
+}
+
+extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+
+	if(mm->context != NO_CONTEXT)
+		smp_flush_tlb_page(vma, page);
+}
+
+#endif
 
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
 { return __pte(__pa(page) | pgprot_val(pgprot)); }
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- v2.1.47/linux/include/asm-sparc64/semaphore.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc64/semaphore.h	Thu Jul 31 13:09:18 1997
@@ -24,20 +24,17 @@
 
 #define wake_one_more(sem)      atomic_inc(&sem->waking);
 
-extern __inline__ int waking_non_zero(struct semaphore *sem)
-{
-        unsigned long flags;
-        int ret = 0;
-
-        save_flags(flags);
-        cli();
-        if (atomic_read(&sem->waking) > 0) {
-                atomic_dec(&sem->waking);
-                ret = 1;
-        }
-        restore_flags(flags);
-        return ret;
-}
+#define waking_non_zero(sem) \
+({	unsigned long flags; \
+	int ret = 0; \
+	save_and_cli(flags); \
+	if (atomic_read(&sem->waking) > 0) { \
+		atomic_dec(&sem->waking); \
+		ret = 1; \
+	} \
+	restore_flags(flags); \
+	ret; \
+})
 
 extern __inline__ void down(struct semaphore * sem)
 {
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.1.47/linux/include/asm-sparc64/smp.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc64/smp.h	Thu Jul 31 13:09:18 1997
@@ -19,7 +19,7 @@
 };
 
 extern int linux_num_cpus;	/* number of CPUs probed  */
-extern struct prom_cpuinfo linux_cpus[NCPUS];
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 
 #endif /* !(__ASSEMBLY__) */
 
@@ -35,8 +35,12 @@
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
 
-typedef __volatile__ unsigned char klock_t;
-extern klock_t kernel_flag;
+struct klock_info {
+	unsigned char kernel_flag;
+	unsigned char akp;
+};
+
+extern struct klock_info klock_info;
 
 #define KLOCK_HELD       0xff
 #define KLOCK_CLEAR      0x00
@@ -47,7 +51,7 @@
  
 extern int smp_found_cpus;
 extern unsigned char boot_cpu_id;
-extern unsigned int cpu_present_map;
+extern unsigned long cpu_present_map;
 extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
 extern __volatile__ unsigned long kernel_counter;
 extern __volatile__ unsigned char active_kernel_processor;
@@ -68,42 +72,21 @@
 extern void smp_callin(void);
 extern void smp_boot_cpus(void);
 extern void smp_store_cpu_info(int id);
-extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-			   unsigned long arg3, unsigned long arg4, unsigned long arg5);
-
-extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
-extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
-{ smp_cross_call(func, arg1, 0, 0, 0, 0); }
-extern __inline__ void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2)
-{ smp_cross_call(func, arg1, arg2, 0, 0, 0); }
-extern __inline__ void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-			   unsigned long arg3)
-{ smp_cross_call(func, arg1, arg2, arg3, 0, 0); }
-extern __inline__ void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-			   unsigned long arg3, unsigned long arg4)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, 0); }
-extern __inline__ void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg2,
-			   unsigned long arg3, unsigned long arg4, unsigned long arg5)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); }
 
 extern __volatile__ int cpu_number_map[NR_CPUS];
 extern __volatile__ int cpu_logical_map[NR_CPUS];
 
-extern __inline__ int smp_processor_id(void)
+extern __inline__ int hard_smp_processor_id(void)
 {
-	int cpuid;
+	unsigned long upaconfig;
 
-	/* Get MID from UPA Config register, and use that. */
-	__asm__ __volatile__("
-		ldxa	[%g0] %1, %0
-		srlx	%0, 17, %0
-		and	%0, 0x1f, %0
-	" : "=r" cpuid
-	  : "i" (ASI_UPA_CONFIG));
-
-	return cpuid;
+	__asm__ __volatile__("ldxa	[%%g0] %1, %0"
+			     : "=r" (upaconfig)
+			     : "i" (ASI_UPA_CONFIG));
+	return ((upaconfig >> 17) & 0x1f);
 }
 
+#define smp_processor_id() (current->processor)
 
 extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
 #endif /* !(__ASSEMBLY__) */
@@ -122,14 +105,13 @@
 #define MBOX_IDLECPU2         0xFD
 #define MBOX_STOPCPU2         0xFE
 
-
-#define NO_PROC_ID            0xFF
-
 #define PROC_CHANGE_PENALTY     20
 
 #define SMP_FROM_INT		1
 #define SMP_FROM_SYSCALL	2
 
 #endif /* !(__SMP__) */
+
+#define NO_PROC_ID            0xFF
 
 #endif /* !(_SPARC64_SMP_H) */
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/smp_lock.h linux/include/asm-sparc64/smp_lock.h
--- v2.1.47/linux/include/asm-sparc64/smp_lock.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc64/smp_lock.h	Thu Jul 31 13:09:18 1997
@@ -18,7 +18,69 @@
 #define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
 
 #else
-#error SMP on sparc64 not supported yet
+
+#include <asm/hardirq.h>
+
+/* Release global kernel lock and global interrupt lock */
+#define release_kernel_lock(task, cpu, depth)		\
+do {							\
+	if((depth = (task)->lock_depth) != 0) {		\
+		__cli();				\
+		(task)->lock_depth = 0;			\
+		klock_info.akp = NO_PROC_ID;		\
+		klock_info.kernel_flag = 0;		\
+	}						\
+	release_irqlock(cpu);				\
+	__sti();					\
+} while(0)
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+#define reacquire_kernel_lock(task, cpu, depth)					\
+do {										\
+	if(depth) {								\
+		register struct klock_info *klip asm("g1");			\
+		klip = &klock_info;						\
+		__asm__ __volatile__("mov	%%o7, %%g5\n\t"			\
+				     "call	___lock_reacquire_kernel\n\t"	\
+				     " mov	%1, %%g2"			\
+				     : /* No outputs. */			\
+				     : "r" (klip), "r" (depth)			\
+				     : "g2", "g3", "g5", "g7", "memory", "cc");	\
+	}									\
+} while(0)
+
+/* The following acquire and release the master kernel global lock,
+ * the idea is that the usage of this mechanmism becomes less and less
+ * as time goes on, to the point where they are no longer needed at all
+ * and can thus disappear.
+ */
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+extern __inline__ void lock_kernel(void)
+{
+	register struct klock_info *klip asm("g1");
+	klip = &klock_info;
+	__asm__ __volatile__("
+	mov	%%o7, %%g5
+	call	___lock_kernel
+	 ld	[%%g6 + %0], %%g2
+"	: : "i" (AOFF_task_lock_depth), "r" (klip)
+	: "g2", "g3", "g5", "g7", "memory", "cc");
+}
+
+/* Release kernel global lock. */
+extern __inline__ void unlock_kernel(void)
+{
+	register struct klock_info *klip asm("g1");
+	klip = &klock_info;
+	__asm__ __volatile__("
+	mov	%%o7, %%g5
+	call	___unlock_kernel
+	 ld	[%%g6 + %0], %%g2
+"	: : "i" (AOFF_task_lock_depth), "r" (klip)
+	: "g2", "g3", "g5", "memory", "cc");
+}
+
 #endif /* (__SMP__) */
 
 #endif /* !(__SPARC64_SMPLOCK_H) */
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h
--- v2.1.47/linux/include/asm-sparc64/softirq.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/softirq.h	Thu Jul 31 13:09:18 1997
@@ -68,6 +68,8 @@
 
 #include <asm/spinlock.h>
 
+extern spinlock_t global_bh_lock;
+
 #define init_bh(nr, routine)				\
 do {	unsigned long flags;				\
 	int ent = nr;					\
@@ -115,13 +117,13 @@
 #define softirq_trylock()					\
 ({								\
 	int ret = 1;						\
-	if(atomic_add_return(1, &__sparc_bh_counter) != 1) {	\
-		atomic_dec(&__sparc_bh_counter);		\
+	if(atomic_add_return(1, &__sparc64_bh_counter) != 1) {	\
+		atomic_dec(&__sparc64_bh_counter);		\
 		ret = 0;					\
 	}							\
 	ret;							\
 })
-#define softirq_endlock()	atomic_dec(&__sparc_bh_counter)
+#define softirq_endlock()	atomic_dec(&__sparc64_bh_counter)
 #define clear_active_bhs(mask)				\
 do {	unsigned long flags;				\
 	spin_lock_irqsave(&global_bh_lock, flags);	\
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.1.47/linux/include/asm-sparc64/spinlock.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/spinlock.h	Thu Jul 31 13:09:18 1997
@@ -56,6 +56,14 @@
 /* All of these locking primitives are expected to work properly
  * even in an RMO memory model, which currently is what the kernel
  * runs in.
+ *
+ * There is another issue.  Because we play games to save cycles
+ * in the non-contention case, we need to be extra careful about
+ * branch targets into the "spinning" code.  They live in their
+ * own section, but the newer V9 branches have a shorter range
+ * than the traditional 32-bit sparc branch variants.  The rule
+ * is that the branches that go into and out of the spinner sections
+ * must be pre-V9 branches.
  */
 
 typedef unsigned char spinlock_t;
@@ -67,13 +75,15 @@
 {
 	__asm__ __volatile__("
 1:	ldstub		[%0], %%g2
-	brnz,a,pn	%%g2, 2f
-	 ldub		[%0], %%g2
-	membar		#LoadLoad | #LoadStore
+	brz,pt		%%g2, 2f
+	 membar		#LoadLoad | #LoadStore
+	b,a		%%xcc, 3f
+2:
 	.text		2
-2:	brnz,a,pt	2b
+3:	ldub		[%0], %%g2
+4:	brnz,a,pt	%%g2, 4b
 	 ldub		[%0], %%g2
-	b,a,pt		%%xcc, 1b
+	b,a		1b
 	.previous
 "	: /* no outputs */
 	: "r" (lock)
@@ -104,14 +114,16 @@
 {
 	__asm__ __volatile__("
 	wrpr		%%g0, 15, %%pil
-	ldstub		[%0], %%g2
-	brnz,a,pn	%%g2, 2f
-	 ldub		[%0], %%g2
-	membar		#LoadLoad | #LoadStore
+1:	ldstub		[%0], %%g2
+	brz,pt		%%g2, 2f
+	 membar		#LoadLoad | #LoadStore
+	b,a		3f
+2:
 	.text		2
-2:	brnz,a,pt	2b
+3:	ldub		[%0], %%g2
+4:	brnz,a,pt	%%g2, 4b
 	 ldub		[%0], %%g2
-	b,a,pt		%%xcc, 1b
+	b,a		1b
 	.previous
 "	: /* no outputs */
 	: "r" (lock)
@@ -133,18 +145,20 @@
 do {	register spinlock_t *lp asm("g1");			\
 	lp = lock;						\
 	__asm__ __volatile__(					\
-	"	rdpr		%%pil, %0\n\t"			\
-	"	wrpr		%%g0, 15, %%pil\n\t"		\
-	"1:	ldstub		[%1], %%g2\n\t"			\
-	"	brnz,a,pnt	%%g2, 2f\n\t"			\
-	"	 ldub		[%1], %%g2\n\t"			\
-	"	membar		#LoadLoad | #LoadStore\n\t"	\
-	"	.text		2\n\t"				\
-	"2:	brnz,a,pt	%%g2, 2b\n\t"			\
-	"	 ldub		[%1], %%g2\n\t"			\
-	"	b,a,pt		%%xcc, 1b\n\t"			\
+	"\n	rdpr		%%pil, %0\n"			\
+	"	wrpr		%%g0, 15, %%pil\n"		\
+	"1:	ldstub		[%1], %%g2\n"			\
+	"	brz,pt		%%g2, 2f\n"			\
+	"	 membar		#LoadLoad | #LoadStore\n"	\
+	"	b,a		3f\n"				\
+	"2:\n"							\
+	"	.text		2\n"				\
+	"3:	ldub		[%1], %%g2\n"			\
+	"4:	brnz,a,pt	%%g2, 4b\n"			\
+	"	 ldub		[%1], %%g2\n"			\
+	"	b,a		1b\n"				\
 	"	.previous\n"					\
-	: "=r" (flags)						\
+	: "=&r" (flags)						\
 	: "r" (lp)						\
 	: "g2", "memory");					\
 } while(0)
@@ -169,19 +183,20 @@
 {
 	__asm__ __volatile__("
 	ldx		[%0], %%g2
-1:
-	brlz,pn		%%g2, 2f
-4:	 add		%%g2, 1, %%g3
-	casx		[%0], %%g2, %%g3
+1:	brgez,pt	%%g2, 4f
+	 add		%%g2, 1, %%g3
+	b,a		2f
+4:	casx		[%0], %%g2, %%g3
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 1b
-	 ldx		[%0],%%g2
+	 ldx		[%0], %%g2
 	membar		#LoadLoad | #LoadStore
 	.text		2
 2:	ldx		[%0], %%g2
-3:	brlz,pt		%%g2, 3b
+3:	brlz,a,pt	%%g2, 3b
 	 ldx		[%0], %%g2
-	b,a,pt		%%xcc, 4b
+	b		4b
+	 add		%%g2, 1, %%g3
 	.previous
 "	: /* no outputs */
 	: "r" (rw)
@@ -193,8 +208,7 @@
 	__asm__ __volatile__("
 	membar		#StoreStore | #LoadStore
 	ldx		[%0], %%g2
-1:
-	sub		%%g2, 1, %%g3
+1:	sub		%%g2, 1, %%g3
 	casx		[%0], %%g2, %%g3
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 1b
@@ -208,31 +222,34 @@
 {
 	__asm__ __volatile__("
 	sethi		%%uhi(0x8000000000000000), %%g5
-	ldx		[%0] %%g2
+	ldx		[%0], %%g2
 	sllx		%%g5, 32, %%g5
-1:
-	brlz,pn		%%g2, 5f
-4:	 or		%%g2, %%g5, %%g3
-	casx		[%0], %%g2, %%g3
+1:	brgez,pt	%%g2, 4f
+	 or		%%g2, %%g5, %%g3
+	b,a		5f
+4:	casx		[%0], %%g2, %%g3
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 1b
 	 ldx		[%0], %%g2
 	andncc		%%g3, %%g5, %%g0
-	bne,a,pn	%%xcc, 3f
-	 ldx		[%0], %%g2
-	membar		#LoadLoad | #LoadStore
+	be,pt		%%xcc, 2f
+	 membar		#LoadLoad | #LoadStore
+	b,a		7f
+2:
 	.text		2
-3:
-	andn		%%g2, %%g5, %%g3
+7:	ldx		[%0], %%g2
+3:	andn		%%g2, %%g5, %%g3
 	casx		[%0], %%g2, %%g3
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 3b
 	 ldx		[%0], %%g2
 	membar		#LoadLoad | #LoadStore
 5:	ldx		[%0], %%g2
-6:	brlz,pt		%%g2, 6b
+6:	brlz,a,pt	%%g2, 6b
 	 ldx		[%0], %%g2
-	b,a,pt		%%xcc, 4b
+	b		4b
+	 or		%%g2, %%g5, %%g3
+	.previous
 "	: /* no outputs */
 	: "r" (rw)
 	: "g2", "g3", "g5", "memory", "cc");
@@ -245,8 +262,7 @@
 	sethi		%%uhi(0x8000000000000000), %%g5
 	ldx		[%0], %%g2
 	sllx		%%g5, 32, %%g5
-1:
-	andn		%%g2, %%g5, %%g3
+1:	andn		%%g2, %%g5, %%g3
 	casx		[%0], %%g2, %%g3
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 1b
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.47/linux/include/asm-sparc64/system.h	Mon Jul  7 08:18:56 1997
+++ linux/include/asm-sparc64/system.h	Thu Jul 31 13:09:18 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.26 1997/06/28 10:04:03 davem Exp $ */
+/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -74,7 +74,27 @@
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
 #else
-#error SMP not supported on sparc64
+
+#ifndef __ASSEMBLY__
+extern unsigned char global_irq_holder;
+#endif
+
+#define save_flags(x) \
+do {	((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
+		((getipl() != 0) ? 2 : 0))); } while(0)
+
+#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+
+#ifndef __ASSEMBLY__
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern void __global_restore_flags(unsigned long flags);
+#endif
+
+#define cli()			__global_cli()
+#define sti()			__global_sti()
+#define restore_flags(flags)	__global_restore_flags(flags)
+
 #endif
 
 #define mb()  		__asm__ __volatile__ ("stbar" : : : "memory")
@@ -112,48 +132,48 @@
 	 * when modifying this code inspect output of sched.s very
 	 * carefully to make sure things still work.  -DaveM
 	 */
-#define switch_to(prev, next)								\
-do {											\
-	__label__ switch_continue;							\
-	register unsigned long task_pc asm("o7");					\
-	(prev)->tss.kregs->fprs = 0;							\
-	task_pc = ((unsigned long) &&switch_continue) - 0x8;				\
-	__asm__ __volatile__(								\
-	"rdpr	%%pstate, %%g2\n\t"							\
-	"wrpr	%%g2, 0x3, %%pstate\n\t"						\
-	"flushw\n\t"									\
-/*XXX*/	"wr	%%g0, 0, %%fprs\n\t"							\
-	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"						\
-	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"						\
-	"rdpr	%%wstate, %%o5\n\t"							\
-	"stx	%%o6, [%%g6 + %3]\n\t"							\
-	"stx	%%o5, [%%g6 + %2]\n\t"							\
-	"rdpr	%%cwp, %%o5\n\t"							\
-	"stx	%%o7, [%%g6 + %4]\n\t"							\
-	"st	%%o5, [%%g6 + %5]\n\t"							\
-	"mov	%0, %%g6\n\t"								\
-	"ld	[%0 + %5], %%g1\n\t"							\
-	"wrpr	%%g1, %%cwp\n\t"							\
-	"ldx	[%%g6 + %2], %%o5\n\t"							\
-	"ldx	[%%g6 + %3], %%o6\n\t"							\
-	"ldx	[%%g6 + %4], %%o7\n\t"							\
-	"mov	%%g6, %0\n\t"								\
-	"wrpr	%%o5, 0x0, %%wstate\n\t"						\
-	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"						\
-	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"						\
-	"wrpr	%%g0, 0x96, %%pstate\n\t"						\
-	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
-	" mov	%0, %%g6\n\t"								\
-	: /* No outputs */								\
-	: "r" (next), "r" (task_pc),							\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),		\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)),		\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))		\
-	: "cc", "g1", "g2", "g3", "g5", "g7",						\
-	  "l1", "l2", "l3", "l4", "l5", "l6", "l7",					\
-	  "i0", "i1", "i2", "i3", "i4", "i5",						\
-	  "o0", "o1", "o2", "o3", "o4", "o5");						\
+#define switch_to(prev, next)							\
+do {	__label__ switch_continue;						\
+	register unsigned long task_pc asm("o7");				\
+	(prev)->tss.kregs->fprs = 0;						\
+	task_pc = ((unsigned long) &&switch_continue) - 0x8;			\
+	(next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());			\
+	__asm__ __volatile__(							\
+	"rdpr	%%pstate, %%g2\n\t"						\
+	"wrpr	%%g2, 0x3, %%pstate\n\t"					\
+	"flushw\n\t"								\
+/*XXX*/	"wr	%%g0, 0, %%fprs\n\t"						\
+	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"					\
+	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"					\
+	"rdpr	%%wstate, %%o5\n\t"						\
+	"stx	%%o6, [%%g6 + %3]\n\t"						\
+	"stx	%%o5, [%%g6 + %2]\n\t"						\
+	"rdpr	%%cwp, %%o5\n\t"						\
+	"stx	%%o7, [%%g6 + %4]\n\t"						\
+	"st	%%o5, [%%g6 + %5]\n\t"						\
+	"mov	%0, %%g6\n\t"							\
+	"ld	[%0 + %5], %%g1\n\t"						\
+	"wrpr	%%g1, %%cwp\n\t"						\
+	"ldx	[%%g6 + %2], %%o5\n\t"						\
+	"ldx	[%%g6 + %3], %%o6\n\t"						\
+	"ldx	[%%g6 + %4], %%o7\n\t"						\
+	"mov	%%g6, %0\n\t"							\
+	"wrpr	%%o5, 0x0, %%wstate\n\t"					\
+	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"					\
+	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"					\
+	"wrpr	%%g0, 0x96, %%pstate\n\t"					\
+	"jmpl	%%o7 + 0x8, %%g0\n\t"						\
+	" mov	%0, %%g6\n\t"							\
+	: /* No outputs */							\
+	: "r" (next), "r" (task_pc),						\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),	\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),	\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)),	\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))	\
+	: "cc", "g1", "g2", "g3", "g5", "g7",					\
+	  "l1", "l2", "l3", "l4", "l5", "l6", "l7",				\
+	  "i0", "i1", "i2", "i3", "i4", "i5",					\
+	  "o0", "o1", "o2", "o3", "o4", "o5");					\
 switch_continue: } while(0)
 
 /* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
diff -u --recursive --new-file v2.1.47/linux/include/asm-sparc64/timer.h linux/include/asm-sparc64/timer.h
--- v2.1.47/linux/include/asm-sparc64/timer.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/timer.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,51 @@
+/* $Id: timer.h,v 1.1 1997/07/23 10:38:00 davem Exp $
+ * timer.h: System timer definitions for sun5.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_TIMER_H
+#define _SPARC64_TIMER_H
+
+/* How timers work:
+ *
+ * On uniprocessors we just use counter zero for the system wide
+ * ticker, this performs thread scheduling, clock book keeping,
+ * and runs timer based events.  Previously we used the Ultra
+ * %tick interrupt for this purpose.
+ *
+ * On multiprocessors we pick one cpu as the master level 10 tick
+ * processor.  Here this counter zero tick handles clock book
+ * keeping and timer events only.  Each Ultra has it's level
+ * 14 %tick interrupt set to fire off as well, even the master
+ * tick cpu runs this locally.  This ticker performs thread
+ * scheduling, system/user tick counting for the current thread,
+ * and also profiling if enabled.
+ */
+
+/* Two timers, traditionally steered to PIL's 10 and 14 respectively.
+ * But since INO packets are used on sun5, we could use any PIL level
+ * we like, however for now we use the normal ones.
+ *
+ * The 'reg' and 'interrupts' properties for these live in nodes named
+ * 'counter-timer'.  The first of three 'reg' properties describe where
+ * the sun5_timer registers are.  The other two I have no idea. (XXX)
+ */
+struct sun5_timer {
+	u64	count0;
+	u64	limit0;
+	u64	count1;
+	u64	limit1;
+};
+
+#define SUN5_LIMIT_ENABLE	0x80000000
+#define SUN5_LIMIT_TOZERO	0x40000000
+#define SUN5_LIMIT_ZRESTART	0x20000000
+#define SUN5_LIMIT_CMASK	0x1fffffff
+
+/* Given a HZ value, set the limit register to so that the timer IRQ
+ * gets delivered that often.
+ */
+#define SUN5_HZ_TO_LIMIT(__hz)  (1000000/(__hz))
+
+#endif /* _SPARC64_TIMER_H */
diff -u --recursive --new-file v2.1.47/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.1.47/linux/include/linux/dcache.h	Sun Jul 27 12:11:01 1997
+++ linux/include/linux/dcache.h	Wed Jul 30 20:53:50 1997
@@ -49,9 +49,13 @@
 	struct list_head d_alias;	/* inode alias list */
 	struct list_head d_lru;		/* d_count = 0 LRU list */
 	struct qstr d_name;
-	struct dentry * (*d_revalidate)(struct dentry *);
+	unsigned long d_time;		/* used by d_revalidate */
+	int (*d_revalidate)(struct dentry *);
 };
 
+/* d_flags entries */
+#define DCACHE_AUTOFS_PENDING 0x0001    /* autofs: "under construction" */
+
 /*
  * d_drop() unhashes the entry from the parent
  * dentry hashes, so that it won't be found through
@@ -102,8 +106,8 @@
 extern int d_validate(struct dentry *dentry, struct dentry *dparent,
 		      unsigned int hash, unsigned int len);
 
-/* write full pathname into buffer and return length */
-extern int d_path(struct dentry * entry, struct dentry * chroot, char * buf);
+/* write full pathname into buffer and return start of pathname */
+extern char * d_path(struct dentry * entry, char * buf, int buflen);
 
 /* Allocation counts.. */
 static inline struct dentry * dget(struct dentry *dentry)
diff -u --recursive --new-file v2.1.47/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.47/linux/include/linux/fs.h	Sun Jul 27 12:11:01 1997
+++ linux/include/linux/fs.h	Mon Aug  4 13:59:23 1997
@@ -672,7 +672,7 @@
 }
 
 extern int check_disk_change(kdev_t dev);
-extern void invalidate_inodes(kdev_t dev);
+extern int invalidate_inodes(kdev_t dev);
 extern void invalidate_inode_pages(struct inode *);
 extern void invalidate_buffers(kdev_t dev);
 extern int floppy_is_wp(int minor);
diff -u --recursive --new-file v2.1.47/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v2.1.47/linux/include/linux/miscdevice.h	Thu Jul 17 10:06:08 1997
+++ linux/include/linux/miscdevice.h	Thu Jul 31 13:09:18 1997
@@ -11,6 +11,7 @@
 #define PC110PAD_MINOR 9
 #define RTC_MINOR 135
 #define SUN_OPENPROM_MINOR 139
+#define NVRAM_MINOR 144
 #define MISC_DYNAMIC_MINOR 255
 
 extern int misc_init(void);
diff -u --recursive --new-file v2.1.47/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.47/linux/include/linux/mm.h	Thu Jul 17 10:06:08 1997
+++ linux/include/linux/mm.h	Mon Aug  4 13:59:23 1997
@@ -118,9 +118,8 @@
 	unsigned long offset;
 	struct page *next_hash;
 	atomic_t count;
+	unsigned int age;
 	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */
-	unsigned dirty:16,
-		 age:8;
 	struct wait_queue *wait;
 	struct page **pprev_hash;
 	struct buffer_head * buffers;
diff -u --recursive --new-file v2.1.47/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.1.47/linux/include/linux/msdos_fs.h	Sun Jul 27 12:11:01 1997
+++ linux/include/linux/msdos_fs.h	Mon Aug  4 14:02:25 1997
@@ -7,7 +7,6 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/fd.h>
-#include <linux/config.h>
 
 #include <asm/byteorder.h>
 
@@ -72,13 +71,9 @@
 
 #define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
 
-#ifdef CONFIG_ATARI
-#define EOF_FAT12 0xFFF		/* Atari GEMDOS fs uses a different EOF */
-#define EOF_FAT16 0xFFFF
-#else
 #define EOF_FAT12 0xFF8		/* standard EOF */
 #define EOF_FAT16 0xFFF8
-#endif
+#define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 16 ? 0xFFF8 : 0xFF8)
 
 /*
  * Inode flags
diff -u --recursive --new-file v2.1.47/linux/include/linux/msdos_fs_sb.h linux/include/linux/msdos_fs_sb.h
--- v2.1.47/linux/include/linux/msdos_fs_sb.h	Mon Mar 11 01:25:58 1996
+++ linux/include/linux/msdos_fs_sb.h	Thu Jul 31 13:09:18 1997
@@ -18,7 +18,8 @@
 		 isvfat:1,        /* 0=no vfat long filename support, 1=vfat support */
 		 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
 		 posixfs:1,       /* Allow names like makefile and Makefile to coexist */
-		 numtail:1;       /* Does first alias have a numeric '~1' type tail? */
+		 numtail:1,       /* Does first alias have a numeric '~1' type tail? */
+		 atari:1;         /* Use Atari GEMDOS variation of MS-DOS fs */
 };
 
 
diff -u --recursive --new-file v2.1.47/linux/include/linux/nvram.h linux/include/linux/nvram.h
--- v2.1.47/linux/include/linux/nvram.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/nvram.h	Thu Jul 31 13:09:18 1997
@@ -0,0 +1,18 @@
+#ifndef _LINUX_NVRAM_H
+#define _LINUX_NVRAM_H
+
+#include <linux/ioctl.h>
+
+/* /dev/nvram ioctls */
+#define NVRAM_INIT		_IO('p', 0x40) /* initialize NVRAM and set checksum */
+#define	NVRAM_SETCKS	_IO('p', 0x41) /* recalculate checksum */
+
+#ifdef __KERNEL__
+extern unsigned char nvram_read_byte( int i );
+extern void nvram_write_byte( unsigned char c, int i );
+extern int nvram_check_checksum( void );
+extern void nvram_set_checksum( void );
+extern int nvram_init( void );
+#endif
+
+#endif  /* _LINUX_NVRAM_H */
diff -u --recursive --new-file v2.1.47/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.1.47/linux/include/linux/parport.h	Sun Jul 27 12:11:01 1997
+++ linux/include/linux/parport.h	Mon Aug  4 14:00:47 1997
@@ -130,8 +130,7 @@
  *
  *  2) a wake-up function, called by the resource manager to tell drivers
  *     that the port is available to be claimed.  If a driver wants to use
- *     the port, it should call parport_claim() here.  The return value from
- *     this function is ignored.
+ *     the port, it should call parport_claim() here.
  */
 
 /* A parallel port device */
@@ -187,6 +186,9 @@
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
 				      struct parport_operations *ops);
 
+/* Unregister a port. */
+void parport_unregister_port(struct parport *port);
+
 /* parport_in_use returns nonzero if there are devices attached to a port. */
 #define parport_in_use(x)  ((x)->devices != NULL)
 
@@ -209,7 +211,7 @@
  */
 struct pardevice *parport_register_device(struct parport *port, 
 			  const char *name,
-			  int (*pf)(void *), int (*kf)(void *),
+			  int (*pf)(void *), void (*kf)(void *),
 			  void (*irq_func)(int, void *, struct pt_regs *), 
 			  int flags, void *handle);
 
diff -u --recursive --new-file v2.1.47/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.47/linux/include/linux/proc_fs.h	Thu Jul 17 10:06:08 1997
+++ linux/include/linux/proc_fs.h	Mon Aug  4 13:59:23 1997
@@ -335,7 +335,7 @@
 };
 extern struct inode_operations *
 proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
-		       int (*lookup)(struct inode *, struct qstr *, struct inode **),
+		       int (*lookup)(struct inode *, struct dentry *),
 		       void (*use)(struct inode *, int),
 		       struct openpromfs_dev ***);
 extern void proc_openprom_deregister(void);
diff -u --recursive --new-file v2.1.47/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.47/linux/include/linux/sched.h	Mon Jul  7 16:02:03 1997
+++ linux/include/linux/sched.h	Mon Aug  4 13:59:23 1997
@@ -384,33 +384,36 @@
 extern __inline__ void hash_pid(struct task_struct *p)
 {
 	struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
+	unsigned long flags;
 
-	spin_lock(&pidhash_lock);
+	spin_lock_irqsave(&pidhash_lock, flags);
 	if((p->pidhash_next = *htable) != NULL)
 		(*htable)->pidhash_pprev = &p->pidhash_next;
 	*htable = p;
 	p->pidhash_pprev = htable;
-	spin_unlock(&pidhash_lock);
+	spin_unlock_irqrestore(&pidhash_lock, flags);
 }
 
 extern __inline__ void unhash_pid(struct task_struct *p)
 {
-	spin_lock(&pidhash_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&pidhash_lock, flags);
 	if(p->pidhash_next)
 		p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
 	*p->pidhash_pprev = p->pidhash_next;
-	spin_unlock(&pidhash_lock);
+	spin_unlock_irqrestore(&pidhash_lock, flags);
 }
 
 extern __inline__ struct task_struct *find_task_by_pid(int pid)
 {
-	struct task_struct **htable = &pidhash[pid_hashfn(pid)];
-	struct task_struct *p;
+	struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
+	unsigned long flags;
 
-	spin_lock(&pidhash_lock);
+	spin_lock_irqsave(&pidhash_lock, flags);
 	for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
 		;
-	spin_unlock(&pidhash_lock);
+	spin_unlock_irqrestore(&pidhash_lock, flags);
 
 	return p;
 }
@@ -441,7 +444,7 @@
 extern void wake_up_interruptible(struct wait_queue ** p);
 extern void wake_up_process(struct task_struct * tsk);
 
-extern void notify_parent(struct task_struct * tsk);
+extern void notify_parent(struct task_struct * tsk, int signal);
 extern void force_sig(unsigned long sig,struct task_struct * p);
 extern int send_sig(unsigned long sig,struct task_struct * p,int priv);
 extern int in_group_p(gid_t grp);
diff -u --recursive --new-file v2.1.47/linux/include/linux/selection.h linux/include/linux/selection.h
--- v2.1.47/linux/include/linux/selection.h	Mon Jul  7 16:02:27 1997
+++ linux/include/linux/selection.h	Mon Aug  4 14:00:12 1997
@@ -23,11 +23,11 @@
 #define get_video_num_columns(dummy) video_num_columns
 #define get_video_num_lines(dummy) video_num_lines
 #define get_video_size_row(dummy) video_size_row
+#endif
+
 extern unsigned long video_num_columns;
 extern unsigned long video_num_lines;
 extern unsigned long video_size_row;
-#endif
-
 extern unsigned char video_type;
 extern unsigned long video_mem_base;
 extern unsigned long video_mem_term;
@@ -73,8 +73,6 @@
 
 /* how to access screen memory */
 
-#include <linux/config.h>
-
 #if defined(CONFIG_TGA_CONSOLE)
 
 extern int tga_blitc(unsigned int, unsigned long);
@@ -171,17 +169,25 @@
 
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
+#ifdef __powerpc__
+	st_le16(addr, val);
+#else
 	if ((long) addr < 0)
 		*addr = val;
 	else
 		writew(val, (unsigned long) addr);
+#endif /* !__powerpc__ */
 }
 
 static inline unsigned short scr_readw(unsigned short * addr)
 {
+#ifdef __powerpc__
+	return ld_le16(addr);
+#else
 	if ((long) addr < 0)
 		return *addr;
 	return readw((unsigned long) addr);
+#endif /* !__powerpc__ */	
 }
 
 #endif /* CONFIG_TGA_CONSOLE */
diff -u --recursive --new-file v2.1.47/linux/include/linux/sysrq.h linux/include/linux/sysrq.h
--- v2.1.47/linux/include/linux/sysrq.h	Mon Jul  7 16:02:01 1997
+++ linux/include/linux/sysrq.h	Mon Aug  4 13:59:34 1997
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *	$Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $
+ *	$Id: sysrq.h,v 1.3 1997/07/17 11:54:33 mj Exp $
  *
  *	Linux Magic System Request Key Hacks
  *
@@ -9,12 +9,25 @@
 
 #include <linux/config.h>
 
+struct pt_regs;
+struct kbd_struct;
+struct tty_struct;
+
+/* Generic SysRq interface -- you may call it from any device driver, supplying
+ * ASCII code of the key, pointer to registers and kbd/tty structs (if they
+ * are available -- else NULL's).
+ */
+
+void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+
+/* Deferred actions */
+
 extern int emergency_sync_scheduled;
 
 #define EMERG_SYNC 1
 #define EMERG_REMOUNT 2
 
-extern void do_emergency_sync(void);
+void do_emergency_sync(void);
 
 #ifdef CONFIG_MAGIC_SYSRQ
 #define CHECK_EMERGENCY_SYNC			\
diff -u --recursive --new-file v2.1.47/linux/init/main.c linux/init/main.c
--- v2.1.47/linux/init/main.c	Sun Jul 27 12:11:01 1997
+++ linux/init/main.c	Sun Jul 27 12:17:32 1997
@@ -215,7 +215,7 @@
 #ifdef CONFIG_WDT
 extern void wdt_setup(char *str, int *ints);
 #endif
-#ifdef CONFIG_PNP_PARPORT
+#ifdef CONFIG_PARPORT
 extern void parport_setup(char *str, int *ints);
 #endif
 #ifdef CONFIG_PLIP
@@ -511,7 +511,7 @@
 #ifdef CONFIG_WDT
 	{ "wdt=", wdt_setup },
 #endif
-#ifdef CONFIG_PNP_PARPORT
+#ifdef CONFIG_PARPORT
 	{ "parport=", parport_setup },
 #endif
 #ifdef CONFIG_PLIP
diff -u --recursive --new-file v2.1.47/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.47/linux/kernel/exit.c	Thu Jul 17 10:06:09 1997
+++ linux/kernel/exit.c	Mon Aug  4 14:50:04 1997
@@ -119,12 +119,12 @@
 	return 0;
 }
 
-void notify_parent(struct task_struct * tsk)
+void notify_parent(struct task_struct * tsk, int signal)
 {
-	if (tsk->p_pptr == task[smp_num_cpus])		/* Init */
-		tsk->exit_signal = SIGCHLD;
-	send_sig(tsk->exit_signal, tsk->p_pptr, 1);
-	wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
+	struct task_struct * parent = tsk->p_pptr;
+
+	send_sig(signal, parent, 1);
+	wake_up_interruptible(&parent->wait_chldexit);
 }
 
 static void release(struct task_struct * p)
@@ -346,11 +346,10 @@
 
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
-		if (p->p_opptr == father)
-			if (task[smp_num_cpus])	/* init */
-				p->p_opptr = task[smp_num_cpus];
-			else
-				p->p_opptr = task[0];
+		if (p->p_opptr == father) {
+			p->exit_signal = SIGCHLD;
+			p->p_opptr = task[smp_num_cpus] ? : task[0];	/* init */
+		}
 	}
 	read_unlock(&tasklist_lock);
 }
@@ -488,7 +487,7 @@
 		kill_pg(current->pgrp,SIGCONT,1);
 	}
 	/* Let father know we died */
-	notify_parent(current);
+	notify_parent(current, current->exit_signal);
 
 	/*
 	 * This loop does two things:
@@ -502,15 +501,13 @@
 		current->p_cptr = p->p_osptr;
 		p->p_ysptr = NULL;
 		p->flags &= ~(PF_PTRACED|PF_TRACESYS);
-		if (task[smp_num_cpus] && task[smp_num_cpus] != current) /* init */
-			p->p_pptr = task[smp_num_cpus];
-		else
-			p->p_pptr = task[0];
+
+		p->p_pptr = p->p_opptr;
 		p->p_osptr = p->p_pptr->p_cptr;
 		p->p_osptr->p_ysptr = p;
 		p->p_pptr->p_cptr = p;
 		if (p->state == TASK_ZOMBIE)
-			notify_parent(p);
+			notify_parent(p, p->exit_signal);
 		/*
 		 * process group orphan check
 		 * Case ii: Our child is in a different pgrp
@@ -651,7 +648,7 @@
 					REMOVE_LINKS(p);
 					p->p_pptr = p->p_opptr;
 					SET_LINKS(p);
-					notify_parent(p);
+					notify_parent(p, SIGCHLD);
 				} else
 					release(p);
 #ifdef DEBUG_PROC_TREE
diff -u --recursive --new-file v2.1.47/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.47/linux/kernel/ksyms.c	Sun Jul 27 12:11:01 1997
+++ linux/kernel/ksyms.c	Sun Jul 27 12:24:18 1997
@@ -156,6 +156,7 @@
 EXPORT_SYMBOL(d_move);
 EXPORT_SYMBOL(d_instantiate);
 EXPORT_SYMBOL(__mark_inode_dirty);
+EXPORT_SYMBOL(init_private_file);
 EXPORT_SYMBOL(insert_file_free);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
diff -u --recursive --new-file v2.1.47/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.47/linux/kernel/sched.c	Mon Jun 16 16:36:01 1997
+++ linux/kernel/sched.c	Mon Jul 28 13:44:44 1997
@@ -1379,6 +1379,11 @@
 
 asmlinkage int sys_sched_yield(void)
 {
+	/*
+	 * This is not really right. We'd like to reschedule
+	 * just _once_ with this process having a zero count.
+	 */
+	current->counter = 0;
 	spin_lock(&scheduler_lock);
 	spin_lock_irq(&runqueue_lock);
 	move_last_runqueue(current);
diff -u --recursive --new-file v2.1.47/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.1.47/linux/lib/vsprintf.c	Sun Dec  1 01:05:28 1996
+++ linux/lib/vsprintf.c	Thu Jul 31 13:09:18 1997
@@ -131,6 +131,9 @@
 	return str;
 }
 
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
 	int len;
@@ -247,6 +250,41 @@
 			} else {
 				int * ip = va_arg(args, int *);
 				*ip = (str - buf);
+			}
+			continue;
+
+		case 'I': /* IPv4 / IPv6 printout */
+			{
+			  __u8 *ip4;
+			  char sbuf[6];
+			  if (qualifier == 'l') {
+			    __u16 *ip6 = va_arg(args, __u16 *);
+			    i = 6;
+			    for ( ; i > 0; --i, ++ip6)
+			      if (*ip6 != 0)
+				break;
+			    if (i < 6)
+			      *str++ = ':';
+			    for ( ; i > 0; --i, ++ip6) {
+			      sprintf(sbuf,":%04x",(int)(*ip6));
+			      s = sbuf;
+			      while (*s)
+				*str++ = *s++;
+			    }
+			    *str++ = ':';
+			    ip4 = (__u8*) ip6;
+			  } else {
+			    ip4 = va_arg(args, __u8 *);
+			  }
+			  for (i = 0; i < 4; ++i, ++ip4) {
+			    if (i == 3)
+			      sprintf(sbuf,"%d", 0xFF & (*ip4));
+			    else
+			      sprintf(sbuf,"%d.", 0xFF & (*ip4));
+			    s = sbuf;
+			    while (*s)
+			      *str++ = *s++;
+			  }
 			}
 			continue;
 
diff -u --recursive --new-file v2.1.47/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.47/linux/mm/filemap.c	Sun Jul 27 12:11:01 1997
+++ linux/mm/filemap.c	Thu Jul 31 13:09:18 1997
@@ -64,7 +64,6 @@
 		inode->i_nrpages--;
 		if ((*p = page->next) != NULL)
 			(*p)->prev = page->prev;
-		page->dirty = 0;
 		page->next = NULL;
 		page->prev = NULL;
 		remove_page_from_hash_queue(page);
@@ -97,7 +96,6 @@
 			inode->i_nrpages--;
 			if ((*p = page->next) != NULL)
 				(*p)->prev = page->prev;
-			page->dirty = 0;
 			page->next = NULL;
 			page->prev = NULL;
 			remove_page_from_hash_queue(page);
diff -u --recursive --new-file v2.1.47/linux/mm/simp.c linux/mm/simp.c
--- v2.1.47/linux/mm/simp.c	Thu Jul 17 10:06:09 1997
+++ linux/mm/simp.c	Thu Jul 31 13:09:18 1997
@@ -6,6 +6,7 @@
  */
 
 #include <linux/simp.h>
+#include <linux/tasks.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
 #include <asm/spinlock.h>
@@ -206,7 +207,6 @@
 	hdr->next = simp->usable_list;
 	simp->usable_list = hdr;
 }
-
 
 /* current x86 memcpy() is horribly moving around registers for nothing,
  * is doing unnecessary work if the size is dividable by a power-of-two,
diff -u --recursive --new-file v2.1.47/linux/net/Changes linux/net/Changes
--- v2.1.47/linux/net/Changes	Sat May 11 00:08:34 1996
+++ linux/net/Changes	Thu Jul 31 13:09:18 1997
@@ -413,18 +413,20 @@
 because a single frame in the data stream has been lost). Given a 
 mathematician with some queue theory you can show this allows you to 
 lose one frame per window full of data without measurable speed loss.
+[done]
 
 4.	RFC1323. These are the extensions for very fast nets.
 RFC1323 will be useful for Linux talking to systems over 100Mb/sec
 ethernet and over ATM as it allows large windows and protects from some
 potential high speed TCP problems.
+[In progress]
 
 6.	Delayed ack. This is mostly supported but not actually set up and
 used yet. Basically ack frames are held back 1/10th of a second in the hope
 that two acks can be merged into one or for interactive use the ack can
 piggyback on the next character typed (great improvement on 2400 baud
 modems). Johannes Stille did some work on this about 0.99.13 but it never
-got merged in. [Pedro Roque]
+got merged in. [Pedro Roque] [Done, but needs fixing]
 
 7.	One on my tempting project list. Add an extra (unofficial - but so
 is SLIP6) SLIP mode that does packet data compression [maybe use the code
@@ -439,7 +441,7 @@
 a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
 Mike McLagan][Fritz Elfert is doing the isdn4linux kit].
  
-11.	IP over SCSI.
+11.	IP over SCSI. [worked on]
 
 14.	Bidirectional PLIP. Also PLIP for the newer style parallel ports.
 
diff -u --recursive --new-file v2.1.47/linux/net/ax25/ax25_ip.c linux/net/ax25/ax25_ip.c
--- v2.1.47/linux/net/ax25/ax25_ip.c	Mon Jul  7 08:19:59 1997
+++ linux/net/ax25/ax25_ip.c	Thu Jul 31 13:09:18 1997
@@ -165,6 +165,8 @@
   	bp[14] |= AX25_EBIT;
   	bp[14] |= AX25_SSSID_SPARE;
 
+	skb_pull(skb, AX25_KISS_HEADER_LEN);
+
 	if (route->digipeat != NULL) {
 		if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
 			kfree_skb(skb, FREE_WRITE);
diff -u --recursive --new-file v2.1.47/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
--- v2.1.47/linux/net/ax25/ax25_route.c	Mon Jul  7 08:19:59 1997
+++ linux/net/ax25/ax25_route.c	Thu Jul 31 13:09:18 1997
@@ -410,8 +410,6 @@
 	unsigned char *bp;
 	int len;
 
-	skb_pull(skb, 1);	/* skip KISS command */
-
 	len = digi->ndigi * AX25_ADDR_LEN;
 
 	if (skb_headroom(skb) < len) {
diff -u --recursive --new-file v2.1.47/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.47/linux/net/core/dev.c	Mon Jun 16 16:36:01 1997
+++ linux/net/core/dev.c	Thu Jul 31 13:09:18 1997
@@ -1082,8 +1082,9 @@
 	struct device *dev;
 
 
-	size = sprintf(buffer, "Inter-|   Receive                  |  Transmit\n"
-			    " face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n");
+	size = sprintf(buffer, 
+		"Inter-|   Receive                           |  Transmit\n"
+		" face |bytes    packets errs drop fifo frame|bytes    packets errs drop fifo colls carrier\n");
 	
 	pos+=size;
 	len+=size;
diff -u --recursive --new-file v2.1.47/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.47/linux/net/ipv4/ip_fragment.c	Mon Jun 16 16:36:01 1997
+++ linux/net/ipv4/ip_fragment.c	Sun Aug  3 14:05:44 1997
@@ -358,6 +358,9 @@
 		fp = fp->next;
 	}
 
+	skb->pkt_type = qp->fragments->skb->pkt_type;
+	skb->protocol = qp->fragments->skb->protocol;
+
 	/* We glued together all fragments, so remove the queue entry. */
 	ip_free(qp);
 
diff -u --recursive --new-file v2.1.47/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v2.1.47/linux/net/ipv4/ipip.c	Thu Mar 27 14:40:15 1997
+++ linux/net/ipv4/ipip.c	Sun Aug  3 14:04:43 1997
@@ -65,7 +65,8 @@
 	/*
 	 *	Discard the original IP header
 	 */
-	 
+
+	skb->mac.raw = skb->data;	 
 	skb_pull(skb, skb->h.raw - skb->nh.raw);
 	
 	/*
diff -u --recursive --new-file v2.1.47/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.1.47/linux/net/ipv4/proc.c	Wed Apr 23 19:01:29 1997
+++ linux/net/ipv4/proc.c	Thu Jul 31 13:09:18 1997
@@ -77,7 +77,7 @@
  *	This was very pretty but didn't work when a socket is destroyed
  *	at the wrong moment (eg a syn recv socket getting a reset), or
  *	a memory timer destroy. Instead of playing with timers we just
- *	concede defeat and cli().
+ *	concede defeat and do a start_bh_atomic().
  */
 	SOCKHASH_LOCK();
 	sp = pro->sklist_next;
diff -u --recursive --new-file v2.1.47/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.47/linux/net/ipv4/tcp.c	Mon Jun 16 16:36:01 1997
+++ linux/net/ipv4/tcp.c	Thu Jul 31 13:09:18 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $
+ * Version:	$Id: tcp.c,v 1.67 1997/07/20 12:46:07 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -201,26 +201,6 @@
  *		Eric Schenk	:	Fix fast close down bug with
  *					shutdown() followed by close().
  *					
- * To Fix:
- *		Fast path the code. Two things here - fix the window calculation
- *		so it doesn't iterate over the queue, also spot packets with no funny
- *		options arriving in order and process directly.
- *
- *		Rewrite output state machine to use a single queue.
- *		Speed up input assembly algorithm.
- *		RFC1323 - PAWS and window scaling.[Required for IPv6]
- *		User settable/learned rtt/max window/mtu
- *
- *		Change the fundamental structure to a single send queue maintained
- *		by TCP (removing the bogus ip stuff [thus fixing mtu drops on
- *		active routes too]). Cut the queue off in tcp_retransmit/
- *		tcp_transmit.
- *		Change the receive queue to assemble as it goes. This lets us
- *		dispose of most of tcp_sequence, half of tcp_ack and chunks of
- *		tcp_data/tcp_read as well as the window shrink crud.
- *		Separate out duplicated code - tcp_alloc_skb, tcp_build_ack
- *		tcp_queue_skb seem obvious routines to extract.
- *
  *		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
@@ -267,6 +247,9 @@
  * for violations and the like.  tcp.c is just too big... If I say something
  * "does?" or "doesn't?", it means I'm not sure, and will have to hash it out
  * with Alan. -- MS 950903
+ * [Note: Most of the TCP code has been rewriten/redesigned since this 
+ *  RFC1122 check. It is probably not correct anymore. It should be redone 
+ *  before 2.2. -AK]
  *
  * Use of PSH (4.2.2.2)
  *   MAY aggregate data sent without the PSH flag. (does)
diff -u --recursive --new-file v2.1.47/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.47/linux/net/ipv4/tcp_ipv4.c	Mon Jul  7 08:19:59 1997
+++ linux/net/ipv4/tcp_ipv4.c	Thu Jul 31 13:09:18 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.51 1997/07/04 23:35:02 freitag Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.52 1997/07/23 15:19:10 freitag Exp $
  *
  *		IPv4 specific functions
  *
@@ -1205,7 +1205,7 @@
 
 			/* Check for syn retransmission */
 			flg = *(((u32 *)skb->h.th) + 3);
-			flg &= __constant_htonl(0x002f0000);
+			flg &= __constant_htonl(0x001f0000);
 			if ((flg == __constant_htonl(0x00020000)) &&
 			    (!after(skb->seq, req->rcv_isn))) {
 				/*	retransmited syn
diff -u --recursive --new-file v2.1.47/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.1.47/linux/net/ipv6/route.c	Tue May 13 22:41:24 1997
+++ linux/net/ipv6/route.c	Thu Jul 31 13:09:18 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.12 1997/04/29 09:38:50 mj Exp $
+ *	$Id: route.c,v 1.13 1997/07/19 11:11:35 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1427,8 +1427,8 @@
 		}
 		arg->len += sprintf(arg->buffer + arg->len,
 				    " %08lx %08x %08x %08lx %8s\n",
-				    rt->rt6i_metric, rt->rt6i_use,
-				    rt->rt6i_ref, rt->rt6i_flags, 
+				    rt->rt6i_metric, atomic_read(&rt->rt6i_use),
+				    atomic_read(&rt->rt6i_ref), rt->rt6i_flags, 
 				    rt->rt6i_dev ? rt->rt6i_dev->name : "");
 	}
 }
diff -u --recursive --new-file v2.1.47/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.47/linux/net/ipv6/tcp_ipv6.c	Thu Jun 26 12:33:41 1997
+++ linux/net/ipv6/tcp_ipv6.c	Thu Jul 31 13:09:18 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.33 1997/06/06 20:38:10 freitag Exp $
+ *	$Id: tcp_ipv6.c,v 1.35 1997/07/23 15:18:04 freitag Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -699,7 +699,6 @@
 {
 	struct tcp_opt tp;
 	struct open_request *req;
-	__u16 req_mss;
 	
 	/* If the socket is dead, don't accept the connection.	*/
 	if (sk->dead) {
@@ -1048,7 +1047,7 @@
 
 			/* Check for syn retransmission */
 			flg = *(((u32 *)skb->h.th) + 3);
-			flg &= __constant_htonl(0x002f0000);
+			flg &= __constant_htonl(0x001f0000);
 
 			if ((flg == __constant_htonl(0x00020000)) &&
 			    (!after(skb->seq, req->rcv_isn))) {
