diff -u --recursive --new-file v2.1.95/linux/CREDITS linux/CREDITS
--- v2.1.95/linux/CREDITS	Wed Apr  8 19:36:24 1998
+++ linux/CREDITS	Mon Apr 13 17:09:13 1998
@@ -647,11 +647,11 @@
 S: USA
 
 N: Angelo Haritsis
-E: ah@doc.ic.ac.uk
+E: ah@computer.org
 D: kernel patches (serial, watchdog)
 D: xringd, vuzkern, greekXfonts
-S: 58 Henfield Close
-S: London N19 3UL
+S: 77 Clarence Mews
+S: London SE16 1GD
 S: United Kingdom
 
 N: Kai Harrekilde-Petersen
diff -u --recursive --new-file v2.1.95/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.95/linux/Documentation/Configure.help	Wed Apr  8 19:36:24 1998
+++ linux/Documentation/Configure.help	Sat Apr 11 11:19:34 1998
@@ -2398,74 +2398,64 @@
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
-Adaptec AIC7xxx support (includes 274x/284x/294x)
+Adaptec AIC7xxx chipset SCSI controller support
 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. 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 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.
-
-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.
+  This is support for the various aic7xxx based Adaptec SCSI controllers.
+  These include the 274x EISA cards, 284x VLB cards, 294x PCI cards,
+  394x PCI cards, 3985 PCI card, and several versions of the Adaptec
+  built-in SCSI controllers on various PC motherboards.  Information on
+  the configuration options for this controller can be found by checking
+  the README.aic7xxx file, usually in /usr/src/linux/drivers/scsi.
 
 Override driver defaults for commands per LUN
 CONFIG_OVERRIDE_CMDS
-  This option allows you to set the maximum number of SCSI commands
-  queued per LUN (Logical Unit Number - some physical SCSI devices,
-  e.g. CD jukeboxes, act logically as several logical units).  If you
-  say N here, the driver will attempt to set the commands per LUN
-  using its own reasonable heuristic. If you say Y, you can specify
-  your preference in the next question.  If unsure, say N.
+  Use this option to allow you to override the default maximum number of
+  commands that a single device on the aic7xxx controller is allowed to have
+  active at one time.  This option only effects tagged queueing capable
+  devices.  The driver uses a "failsafe" value of 8 by default.  This is
+  much lower than many devices can handle, but left in place for safety sake.
+  NOTE: This does not actually enabled tagged queueing on any particular
+  device.  The driver has changed in this respect.  Please see the file
+  README.aic7xxx in /usr/src/linux/drivers/scsi for more information on how
+  to get particular devices to use tagged command queueing.
+  Default: N
 
 Maximum number of commands per LUN
 CONFIG_AIC7XXX_CMDS_PER_LUN
-  By default, we limit the commands per LUN to 2 with or without
-  tagged queueing enabled.  If tagged queueing is enabled, the
-  sequencer in the host adapter will attempt to send the 2nd command
-  block to the device while the first command block is still executing
-  and the device is disconnected. If the devices don't complain, you
-  can thus try to increase the number of SCSI commands per LUN to more
-  than 2 in this case. If tagged queueing is disabled, the sequencer
-  in the host adapter will keep the 2nd command in its input queue
-  until the first one completes - so it is OK to have more than 1
-  command queued. However, for host adapters limited to 4 command
-  blocks (SCB's), 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 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).  If unsure, go with the default for now.
-
-Enable SCB paging
-CONFIG_AIC7XXX_PAGE_ENABLE
-  This option enables SCB paging.  This will increase performance when
-  tagged queueing is enabled.  Note that, if you say Y here, you
-  should increase the "Maximum number of commands per LUN"
-  (AIC7XXX_CMDS_PER_LUN) above 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.
+  Specify the maximum number of commands per lun you would like to allocate
+  per device.  Reasonable figures are in the range of 14 to 32 commands per
+  device, but depending on hardware could be increased or decreased from
+  that figure.  If the number is too high for any particular device, the
+  driver will automatically compensate usually after only 10 minutes of
+  uptime and will issue a message to alert you to the fact that the number
+  of commands for that device has been reduced.  It will not hinder
+  performance if a portion of your devices eventually have their commands
+  per lun reduced, but is a waste of memory if all of your devices end
+  up reducing this number down to a more reasonable figure.  Default: 24
 
 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. The statistics will appear under
-  /proc/scsi/aic7xxx. This will only work if you also enable the "proc
-  filesystem", below.
+  This option tells the driver to keep track of how many commands have been
+  sent to each particular device and report that information to the user
+  via the /proc/scsi/aic7xxx/x file, where x is the number of the aic7xxx
+  controller you want the information on.  This adds a small amount of
+  overhead to each and every SCSI command the aic7xxx driver handles, so if
+  you aren't really interested in this information, it is best to leave it
+  disabled.  Default: N
 
 Delay in seconds after SCSI bus reset
 CONFIG_AIC7XXX_RESET_DELAY
-  This option sets the delay in seconds after a SCSI bus reset. If you
-  don't know what you are doing, go with the default.
+  This sets how long the driver will wait after resetting the SCSI bus before
+  attempting to communicate with the devices on the SCSI bus again.  This
+  delay will be used during the reset phase at bootup time as well as after
+  any reset that might occur during normal operation.  Reasonable numbers
+  range anywhere from 5 to 15 seconds depending on your devices.  DAT tape
+  drives are notorious for needing more time after a bus reset to be
+  ready for the next command, but most hard drives and CD-ROM devices are
+  ready in only a few seconds.  This option has a maximum upper limit of
+  20 seconds to avoid bad interactions between the aic7xxx driver and the
+  rest of the linux kernel.  The default value has been reduced.  If this
+  doesn't work with your hardware, try increasing this value.  Default: 5
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
diff -u --recursive --new-file v2.1.95/linux/Documentation/parport.txt linux/Documentation/parport.txt
--- v2.1.95/linux/Documentation/parport.txt	Sat Nov 29 10:33:18 1997
+++ linux/Documentation/parport.txt	Sun Apr 12 11:39:20 1998
@@ -5,11 +5,15 @@
 You can pass parameters to the parport code to override its automatic
 detection of your hardware.  This is particularly useful if you want
 to use IRQs, since in general these can't be autoprobed successfully.
+By default IRQs are not used even if they _can_ be probed.  This is
+because there are a lot of people using the same IRQ for their
+parallel port and a sound card or network card.
 
 The parport code is split into two parts: generic (which deals with
 port-sharing) and architecture-dependent (which deals with actually
 using the port).
 
+
 Parport as modules
 ==================
 
@@ -20,31 +24,33 @@
 to load the generic parport code.  You then must load the
 architecture-dependent code with (for example):
 
-	# insmod parport_pc.o io=0x378,0x278 irq=7,5
+	# insmod parport_pc.o io=0x3bc,0x378,0x278 irq=none,7,auto
+
+to tell the parport code that you want three PC-style ports, one at
+0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an
+auto-detected IRQ.  Currently, PC-style (parport_pc) and Sun Ultra/AX
+(parport_ax) hardware is supported; more is in the works.
 
-to tell the parport code that you want two PC-style ports, one at
-0x378 using IRQ 7, and one at 0x278 using IRQ 5.  Currently, PC-style
-(parport_pc) and ARC onboard (parport_arc) parallel ports are
-supported.
 
-Kerneld
--------
+KMod
+----
 
-If you use kerneld, you will find it useful to edit /etc/conf.modules.
+If you use kmod, you will find it useful to edit /etc/conf.modules.
 Here is an example of the lines that need to be added:
 
 	alias parport_lowlevel parport_pc
-	options parport_pc io=0x378,0x278 irq=7,5
+	options parport_pc io=0x378,0x278 irq=7,auto
+
+KMod will then automatically load parport_pc (with the options
+"io=0x378,0x278 irq=7,auto") whenever a parallel port device driver
+(such as lp) is loaded.
 
-Kerneld, in conjunction with parport, will automatically load
-parport_pc whenever a parallel port device driver (such as lp) is
-loaded.
 
 Parport probe [optional]
 -------------
 
 Once the architecture-dependent part of the parport code is loaded
-into the kernel, you insert the parport_probe module with:
+into the kernel, you can insert the parport_probe module with:
 
 	# insmod parport_probe.o
 
@@ -53,22 +59,25 @@
 
 	parport0: Printer, BJC-210 (Canon)
 
-(If you are using kerneld and have configured parport_probe as a 
-module, this will just happen.)
+(If you are using kmod and have configured parport_probe as a module,
+this will just happen.)
 
 
-Parport, but not as modules
-===========================
+Parport linked into the kernel statically
+=========================================
 
 If you compile the parport code into the kernel, then you can use
 kernel boot parameters to get the same effect.  Add something like the
 following to your LILO command line:
 
-	parport=0x378,7 parport=0x278,5
+	parport=0x3bc parport=0x378,7 parport=0x278,auto
 
 You can have many `parport=...' statements, one for each port you want
 to add.  Adding `parport=0' to the kernel command-line will disable
-parport support entirely.
+parport support entirely.  Adding `parport=auto' to the kernel
+command-line will make parport use any IRQ lines or DMA channels that
+it auto-detects.
+
 
 Files in /proc
 ==============
@@ -90,10 +99,10 @@
 				and DMA channel.
 
 /proc/parport/0/irq		The IRQ that parport is using for that
-				port (as above).  This is in a
-				separate file to allow you to alter it
-				by writing a new value in (IRQ number
-				or "none").
+				port.  This is in a separate file to
+                                allow you to alter it by writing a new
+				value in (IRQ number or "none").
+
 
 Device drivers
 ==============
@@ -121,7 +130,7 @@
 
 Also:
 
- * If you selected the device autoprobe at compile time, you can say
+ * If you selected the IEEE-1284 autoprobe at compile time, you can say
    `lp=auto' on the kernel command line, and lp will create devices
    only for those ports that seem to have printers attached.
 
@@ -129,10 +138,7 @@
    the command line, or with `insmod plip timid=1' when using modules,
    it will avoid any ports that seem to be in use by other devices.
 
- * If your BIOS allows you to engage "ECP mode", you may find that
-   your port's IRQ can be autoprobed, without having to specify any 
-   parameters.
-
+ * IRQ autoprobing works only for a few port types at the moment.
 
 --
 Philip.Blundell@pobox.com
diff -u --recursive --new-file v2.1.95/linux/Documentation/sound/ultrasound linux/Documentation/sound/ultrasound
--- v2.1.95/linux/Documentation/sound/ultrasound	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/ultrasound	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,31 @@
+
+insmod sound
+insmod ad1848
+insmod gus io=* irq=* dma=* ...
+
+This loads the driver for the Gravis Ultrasound familily of soundcards.
+
+The gus modules takes the following arguments
+
+io		I/O address of the ultrasound card (eg. io=0x220)
+irq		IRQ of the soundblaster card 
+dma     	DMA channel for the soundblaster
+dma16   	2nd DMA channel, only needed for full duplex operation
+type		1 for PnP card
+gus16		1 for using 16 bit sampling daughter board
+no_wave_dma	Set to disable dma usage for wavetable (see note)
+db16		???
+
+
+no_wave_dma option
+
+This option defaults to a value of 0, which allows the Ultrasound wavetable
+DSP to use DMA for for playback and downloading samples. This is the same
+as the old behaviour. If set to 1, no DMA is needed for downloading samples,
+and allows owners of a GUS MAX to make use of simultanious digital audio
+(/dev/dsp), MIDI, and wavetable playback.
+
+
+If you have problems in recording with GUS MAX, you could try to use
+just one 8 bit DMA channel. Recording will not work with one DMA
+channel if it's a 16 bit one.
diff -u --recursive --new-file v2.1.95/linux/Makefile linux/Makefile
--- v2.1.95/linux/Makefile	Fri Apr 10 13:03:48 1998
+++ linux/Makefile	Fri Apr 10 13:03:35 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 95
+SUBLEVEL = 96
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.95/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.1.95/linux/arch/alpha/kernel/bios32.c	Fri Apr 10 13:03:48 1998
+++ linux/arch/alpha/kernel/bios32.c	Fri Apr 10 13:44:09 1998
@@ -410,7 +410,7 @@
 			pcibios_write_config_dword(bus->number, dev->devfn,
 						   off, base);
 			handle = HANDLE(bus->number) | base;
-			dev->base_address[PCI_BASE_INDEX(off)] = handle;
+			dev->base_address[idx] = handle;
 			DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n",
 				  dev->device, handle, size));
 		}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.1.95/linux/arch/arm/Makefile	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/Makefile	Sun Apr 12 11:42:15 1998
@@ -12,6 +12,9 @@
 #
 # Copyright (C) 1995, 1996 by Russell King
 
+CFLAGS_PROC	:=
+ASFLAGS_PROC	:=
+
 ifeq ($(CONFIG_CPU_ARM2),y)
 PROCESSOR	 = armo
 ASFLAGS_PROC	+= -m2
@@ -65,7 +68,6 @@
 # ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded).
 #
 
-HEAD		:= arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o
 COMPRESSED_HEAD	 = head.o
 
 ifeq ($(PROCESSOR),armo)
@@ -79,11 +81,13 @@
 
 ifeq ($(CONFIG_ARCH_A5K),y)
 MACHINE		 = a5k
+ARCHDIR		 = arc
 COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 endif
 
 ifeq ($(CONFIG_ARCH_ARC),y)
 MACHINE		 = arc
+ARCHDIR		 = arc
 COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 endif
 
@@ -96,6 +100,7 @@
 
 ifeq ($(CONFIG_ARCH_RPC),y)
 MACHINE		 = rpc
+ARCHDIR		 = rpc
 COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o
 ZTEXTADDR	 = 0x10008000
 ZRELADDR	 = 0x10008000
@@ -103,6 +108,14 @@
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 MACHINE		 = ebsa110
+ARCHDIR		 = ebsa110
+ZTEXTADDR	 = 0x00008000
+ZRELADDR	 = 0x00008000
+endif
+
+ifeq ($(CONFIG_ARCH_EBSA285),y)
+MACHINE		 = ebsa285
+ARCHDIR		 = ebsa285
 ZTEXTADDR	 = 0x00008000
 ZRELADDR	 = 0x00008000
 endif
@@ -129,35 +142,55 @@
 CFLAGS		:= $(CFLAGS:-fomit-frame-pointer=)
 endif
 CFLAGS		:= $(CFLAGS_PROC) $(CFLAGS) -pipe
-ASFLAGS		:= $(ASFLAGS_PROC) $(ASFLAGS) -D__ASSEMBLY__
+ASFLAGS		:= $(ASFLAGS_PROC) $(ASFLAGS)
 LINKFLAGS	 = -T $(TOPDIR)/arch/arm/vmlinux.lds -e stext -Ttext $(TEXTADDR)
 ZLINKFLAGS	 = -Ttext $(ZTEXTADDR)
 
 SUBDIRS		:= $(SUBDIRS:drivers=) arch/arm/lib arch/arm/kernel arch/arm/mm arch/arm/drivers
+HEAD		:= arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o
 CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
 LIBS		:= arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
 
-DRIVERS		:= arch/arm/drivers/block/block.a \
-		   arch/arm/drivers/char/char.a \
-		   drivers/misc/misc.a \
-		   arch/arm/drivers/net/net.a
+BLOCK_DRIVERS	:= arch/arm/drivers/block/block.a
+CDROM_DRIVERS	:= drivers/cdrom/cdrom.a
+CHAR_DRIVERS	:= arch/arm/drivers/char/char.a
+MISC_DRIVERS	:= drivers/misc/misc.a
+NET_DRIVERS	:= drivers/net/net.a
+PARIDE_DRIVERS	:= drivers/block/paride/paride.a
+PCI_DRIVERS	:= drivers/pci/pci.a
+SCSI_DRIVERS	:= drivers/scsi/scsi.a
+SOUND_DRIVERS	:= drivers/sound/sound.a
+
+ifeq ($(CONFIG_ARCH_ACORN),y)
+BLOCK_DRIVERS	+= drivers/acorn/block/acorn-block.a
+CHAR_DRIVERS	+= drivers/acorn/char/acorn-char.a
+NET_DRIVERS	+= drivers/acorn/net/acorn-net.a drivers/net/net.a
+SCSI_DRIVERS	+= drivers/acorn/scsi/acorn-scsi.a
+endif
+
+DRIVERS		:= $(BLOCK_DRIVERS) $(CHAR_DRIVERS) $(MISC_DRIVERS) $(NET_DRIVERS)
 
 ifeq ($(CONFIG_SCSI),y)
-DRIVERS		:= $(DRIVERS) arch/arm/drivers/scsi/scsi.a
+DRIVERS		:= $(DRIVERS) $(SCSI_DRIVERS)
 endif
-
 ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),)
-DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a
+DRIVERS		:= $(DRIVERS) $(CDROM_DRIVERS)
+endif
+ifdef CONFIG_PCI
+DRIVERS		:= $(DRIVERS) $(PCI_DRIVERS)
 endif
-
 ifeq ($(CONFIG_SOUND),y)
-DRIVERS		:= $(DRIVERS) arch/arm/drivers/sound/sound.a
+DRIVERS		:= $(DRIVERS) $(SOUND_DRIVERS)
+endif
+ifeq ($(CONFIG_PARIDE),y)
+DRIVERS		:= $(DRIVERS) $(PARIDE_DRIVERS)
 endif
 
 symlinks::
 	$(RM) include/asm-arm/arch include/asm-arm/proc
-	(cd include/asm-arm; ln -sf arch-$(MACHINE) arch; ln -sf proc-$(PROCESSOR) proc)
+	(cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc)
 
+# Once we've finished integrating the sources, the @$(MAKE) will disappear
 mrproper::
 	rm -f include/asm-arm/arch include/asm-arm/proc
 	@$(MAKE) -C arch/$(ARCH)/drivers mrproper
@@ -183,7 +216,6 @@
 	@$(MAKEBOOT) install
 
 # My testing targets (that short circuit a few dependencies)
-#
 zImg:;	@$(MAKEBOOT) zImage
 Img:;	@$(MAKEBOOT) Image
 i:;	@$(MAKEBOOT) install
@@ -191,8 +223,7 @@
 
 archclean:
 	@$(MAKEBOOT) clean
-	@$(MAKE) -C arch/arm/lib clean
+	$(RM) arch/arm/lib/constants.h
 
 archdep:
 	@$(MAKEBOOT) dep
-sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal
diff -u --recursive --new-file v2.1.95/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile
--- v2.1.95/linux/arch/arm/boot/Makefile	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/boot/Makefile	Sun Apr 12 11:42:15 1998
@@ -25,11 +25,8 @@
 zinstall: $(CONFIGURE) zImage
 	sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-tools/build: tools/build.c
-	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
-
 clean:
-	rm -f Image zImage tools/build
+	rm -f Image zImage
 	@$(MAKE) -C compressed clean
 
 dep:
diff -u --recursive --new-file v2.1.95/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
--- v2.1.95/linux/arch/arm/boot/compressed/Makefile	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/boot/compressed/Makefile	Sun Apr 12 11:42:15 1998
@@ -26,7 +26,7 @@
 		$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
 		gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
 		echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-		$(LD) -m elf_arm -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \
+		$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \
 		rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk;
 
 clean:;		rm -f vmlinux core
diff -u --recursive --new-file v2.1.95/linux/arch/arm/boot/tools/build.c linux/arch/arm/boot/tools/build.c
--- v2.1.95/linux/arch/arm/boot/tools/build.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/boot/tools/build.c	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <a.out.h>
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
-
-void die(const char * str, ...)
-{
-	va_list args;
-	va_start(args, str);
-	vfprintf(stderr, str, args);
-	fputc('\n', stderr);
-	exit (1);
-}
-
-int main(int argc, char **argv)
-{
-	void *data;
-	struct exec ex;
-	FILE *f;
-	int totlen;
-
-	if (argc < 2) {
-		fprintf(stderr, "Usage: build kernel-name\n");
-		exit(1);
-	}
-
-	f = fopen(argv[1], "rb");
-	if (!f)
-		die("Unable to open `%s': %m", argv[1]);
-
-	fread(&ex, 1, sizeof(ex), f);
-
-	if(N_MAGIC(ex) == ZMAGIC) {
-		fseek(f, 4096, SEEK_SET);
-		totlen = ex.a_text + ex.a_data;
-	} else
-	if(N_MAGIC(ex) == QMAGIC) {
-		unsigned long my_header;
-		
-		fseek(f, 4, SEEK_SET);
-
-		my_header = 0xea000006;
-
-		fwrite(&my_header, 4, 1, stdout);
-
-		totlen = ex.a_text + ex.a_data - 4;
-	} else {
-		fprintf(stderr, "Unacceptable a.out header on kernel\n");
-		fclose(f);
-		exit(1);
-	}
-
-	fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n",
-		(ex.a_text + ex.a_data + ex.a_bss)/1024,
-		 ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024);
-
-	data = malloc(totlen);
-	fread(data, 1, totlen, f);
-	fwrite(data, 1, totlen, stdout);
-
-	free(data);
-	fclose(f);
-	fflush(stdout);
-	return 0;
-}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.1.95/linux/arch/arm/config.in	Wed Apr  8 19:36:24 1998
+++ linux/arch/arm/config.in	Sun Apr 12 11:42:15 1998
@@ -7,38 +7,25 @@
 define_bool CONFIG_ARM y
 
 mainmenu_option next_comment
-comment 'Code maturity level options'
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
-
-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 module loader' CONFIG_KMOD
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'General setup'
+comment 'System type and processor type'
 choice 'ARM system type'	\
 	"Archimedes		CONFIG_ARCH_ARC \
 	 A5000			CONFIG_ARCH_A5K \
 	 RiscPC			CONFIG_ARCH_RPC \
 	 EBSA-110		CONFIG_ARCH_EBSA110 \
+	 EBSA-285		CONFIG_ARCH_EBSA285 \
 	 NexusPCI		CONFIG_ARCH_NEXUSPCI" RiscPC
 if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" -o "$CONFIG_ARCH_RPC" = "y" ]; then
   define_bool CONFIG_ARCH_ACORN y
 else
   define_bool CONFIG_ARCH_ACORN n
 fi
-if [ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
+if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA285" = "y" ]; then
   define_bool CONFIG_PCI y
 else
   define_bool CONFIG_PCI n
 fi
-if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA110" = "y" ]; then
+if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_ARCH_EBSA285" = "y" ]; then
   define_bool CONFIG_CPU_SA110 y
 else
   if [ "$CONFIG_ARCH_A5K" = "y" ]; then
@@ -51,11 +38,31 @@
 	 StrongARM		CONFIG_CPU_SA110" StrongARM
   fi
 fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+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 module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
 bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER
 bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW
 bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
+# This needs kernel/acct.c to be updated
+#bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
@@ -70,6 +77,7 @@
 endmenu
 
 source arch/arm/drivers/block/Config.in
+source drivers/acorn/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
@@ -81,7 +89,7 @@
 tristate 'SCSI support?' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-  source arch/arm/drivers/scsi/Config.in
+  source drivers/scsi/Config.in
 fi
 endmenu
 
@@ -91,7 +99,7 @@
 
   bool 'Network device support?' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    source arch/arm/drivers/net/Config.in
+    source drivers/net/Config.in
   fi
   endmenu
 fi
@@ -128,7 +136,7 @@
 
   tristate 'Sound support' CONFIG_SOUND
   if [ "$CONFIG_SOUND" != "n" ]; then
-    source arch/arm/drivers/sound/Config.in
+    source drivers/sound/Config.in
   fi
   endmenu
 fi
diff -u --recursive --new-file v2.1.95/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.1.95/linux/arch/arm/defconfig	Wed Apr  8 19:36:24 1998
+++ linux/arch/arm/defconfig	Sun Apr 12 11:42:15 1998
@@ -31,6 +31,7 @@
 CONFIG_CPU_SA110=y
 CONFIG_FRAME_POINTER=y
 # CONFIG_BINUTILS_NEW is not set
+CONFIG_DEBUG_ERRORS=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
@@ -76,7 +77,7 @@
 #
 # Networking options
 #
-CONFIG_PACKET=m
+# CONFIG_PACKET is not set
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
@@ -112,8 +113,11 @@
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
 
 #
 # SCSI support
@@ -149,7 +153,6 @@
 # The following drives are not fully supported
 #
 CONFIG_SCSI_CUMANA_1=m
-CONFIG_SCSI_ECOSCSI=m
 CONFIG_SCSI_OAK1=m
 CONFIG_SCSI_PPA=m
 CONFIG_SCSI_PPA_HAVE_PEDANTIC=2
@@ -199,6 +202,7 @@
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_ADFS_FS=y
+CONFIG_ADFS_FS=y
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
@@ -252,10 +256,10 @@
 #
 # Sound
 #
-# CONFIG_SOUND is not set
-# CONFIG_VIDC is not set
-# CONFIG_AUDIO is not set
-# DSP_BUFFSIZE is not set
+CONFIG_SOUND=m
+CONFIG_VIDC=y
+CONFIG_AUDIO=y
+DSP_BUFFSIZE=65536
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.1.95/linux/arch/arm/kernel/Makefile	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/Makefile	Sun Apr 12 11:42:15 1998
@@ -19,15 +19,24 @@
 O_OBJS += armksyms.o
 endif
 
+ifdef CONFIG_PCI
+  O_OBJS += bios32.o
+endif
+
 ifdef CONFIG_ARCH_ACORN
   O_OBJS += setup.o ecard.o iic.o dma.o
   ifdef CONFIG_ARCH_ARC
     O_OBJS += oldlatches.o
   endif
+  O_OBJS += dma-$(MACHINE).o
 endif
 
 ifeq ($(MACHINE),ebsa110)
-  O_OBJS += setup-ebsa110.o dma.o
+  O_OBJS += setup-ebsa110.o dma.o dma-dummy.o
+endif
+
+ifeq ($(MACHINE),ebsa285)
+  O_OBJS += dma.o dma-dummy.o leds-ebsa285.o setup-ebsa110.o
 endif
 
 ifeq ($(MACHINE),nexuspci)
@@ -37,9 +46,12 @@
 $(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
 	$(CC) -D__ASSEMBLY__ -traditional -c $(HEAD_OBJ:.o=.S) -o $@
 
+$(ENTRY_OBJ): $(ENTRY_OBJ:.o=.S)
+	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $(ENTRY_OBJ:.o=.S) -o $@
+
 include $(TOPDIR)/Rules.make
 
-$(ENTRY_OBJ:.o=.S): ../lib/constants.h
+$(ENTRY_OBJ): ../lib/constants.h
 
 .PHONY: ../lib/constants.h
 
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.1.95/linux/arch/arm/kernel/armksyms.c	Wed Apr  8 19:36:24 1998
+++ linux/arch/arm/kernel/armksyms.c	Sun Apr 12 11:42:15 1998
@@ -12,7 +12,6 @@
 #include <asm/dma.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
-#include <asm/irq.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
@@ -64,7 +63,6 @@
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(udelay);
-EXPORT_SYMBOL(dma_str);
 EXPORT_SYMBOL(xchg_str);
 
 /* expansion card support */
@@ -78,26 +76,39 @@
 /* processor dependencies */
 EXPORT_SYMBOL(processor);
 
-/* irq */
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-
 /* io */
 EXPORT_SYMBOL(outswb);
 EXPORT_SYMBOL(outsw);
 EXPORT_SYMBOL(inswb);
 EXPORT_SYMBOL(insw);
 
-#ifdef CONFIG_ARCH_RPC
-EXPORT_SYMBOL(drambank);
+/* address translation */
+#ifndef __virt_to_phys__is_a_macro
+EXPORT_SYMBOL(__virt_to_phys);
+#endif
+#ifndef __phys_to_virt__is_a_macro
+EXPORT_SYMBOL(__phys_to_virt);
 #endif
+#ifndef __virt_to_bus__is_a_macro
+EXPORT_SYMBOL(__virt_to_bus);
+#endif
+#ifndef __bus_to_virt__is_a_macro
+EXPORT_SYMBOL(__bus_to_virt);
+#endif
+
+EXPORT_SYMBOL(quicklists);
+EXPORT_SYMBOL(__bad_pmd);
+EXPORT_SYMBOL(__bad_pmd_kernel);
 
 /* dma */
+EXPORT_SYMBOL(dma_str);
 EXPORT_SYMBOL(enable_dma);
-EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(disable_dma);
 EXPORT_SYMBOL(set_dma_addr);
 EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(set_dma_mode);
 EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(set_dma_sg);
 
 /*
  * floating point math emulator support.
@@ -182,7 +193,3 @@
 EXPORT_SYMBOL(test_and_change_bit);
 EXPORT_SYMBOL(find_first_zero_bit);
 EXPORT_SYMBOL(find_next_zero_bit);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.1.95/linux/arch/arm/kernel/bios32.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/bios32.c	Mon Apr 13 17:03:04 1998
@@ -0,0 +1,144 @@
+/*
+ * arch/arm/kernel/bios32.c: PCI functions for ARM
+ *
+ * Copyright (C) 1998 Russell King
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+int pcibios_present(void)
+{
+	return 1;
+}
+
+static unsigned long pcibios_base_address(unsigned char dev_fn)
+{
+	int slot = PCI_SLOT(dev_fn);
+
+	if (slot < 4)
+		return 0xf8000000 + (1 << (19 - slot));
+	else
+		return 0;
+}
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char where, unsigned char *val)
+{
+	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned char v;
+
+	if (addr) {
+		__asm__("ldr%?b	%0, [%1, %2]"
+			: "=r" (v)
+			: "r" (addr), "r" (where));
+		*val = v;
+	} else
+		*val = 0xff;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char where, unsigned short *val)
+{
+	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned short v;
+
+	if (addr) {
+		__asm__("ldrh%?	%0, [%1, %2]"
+			: "=r" (v)
+			: "r" (addr), "r" (where));
+		*val = v;
+	} else
+		*val = 0xffff;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			      unsigned char where, unsigned int *val)
+{
+	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned int v;
+
+	if (addr) {
+		__asm__("ldr%?	%0, [%1, %2]"
+			: "=r" (v)
+			: "r" (addr), "r" (where));
+		*val = v;
+	} else
+		*val = 0xffffffff;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char where, unsigned char val)
+{
+	unsigned long addr = pcibios_base_address(dev_fn);
+
+	if (addr)
+		__asm__("str%?b	%0, [%1, %2]"
+			: : "r" (val), "r" (addr), "r" (where));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			      unsigned char where, unsigned short val)
+{
+	unsigned long addr = pcibios_base_address(dev_fn);
+
+	if (addr)
+		__asm__("strh%?	%0, [%1, %2]"
+			: : "r" (val), "r" (addr), "r" (where));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			       unsigned char where, unsigned int val)
+{
+	unsigned long addr = pcibios_base_address(dev_fn);
+
+	if (addr)
+		__asm__("str%?	%0, [%1, %2]"
+			: : "r" (val), "r" (addr), "r" (where));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int irq[] = { 18, 8, 9, 11 };
+
+__initfunc(void pcibios_fixup(void))
+{
+	struct pci_dev *dev;
+	unsigned char pin;
+
+	for (dev = pci_devices; dev; dev = dev->next) {
+		pcibios_read_config_byte(dev->bus->number,
+					 dev->devfn,
+					 PCI_INTERRUPT_PIN,
+					 &pin);
+
+		dev->irq = irq[(PCI_SLOT(dev->devfn) + pin) & 3];
+
+		pcibios_write_config_byte(dev->bus->number,
+					  dev->devfn,
+					  PCI_INTERRUPT_LINE,
+					  dev->irq);
+
+		printk("PCI: %02x:%02x [%04x/%04x] pin %d irq %d\n",
+			dev->bus->number, dev->devfn,
+			dev->vendor, dev->device,
+			pin, dev->irq);
+	}
+}
+
+__initfunc(void pcibios_init(void))
+{
+	int rev;
+
+	rev = *(unsigned char *)0xfe000008;
+	printk("DEC21285 PCI revision %02X\n", rev);
+}
+
+__initfunc(char *pcibios_setup(char *str))
+{
+	return str;
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-a5k.c linux/arch/arm/kernel/dma-a5k.c
--- v2.1.95/linux/arch/arm/kernel/dma-a5k.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/dma-a5k.c	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,79 @@
+/*
+ * arch/arm/kernel/dma-a5k.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * DMA functions specific to A5000 architecture
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel == DMA_VIRTUAL_FLOPPY0)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel != DMA_VIRTUAL_FLOPPY0)
+		printk ("arch_free_dma: invalid channel %d\n", channel);
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+	if (channel != DMA_VIRTUAL_FLOPPY0)
+		printk ("arch_dma_count: invalid channel %d\n", dmanr);
+	else {
+		extern int floppy_fiqresidual(void);
+		return floppy_fiqresidual();
+	}
+	return 0;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel != DMA_VIRTUAL_FLOPPY0)
+		printk ("arch_enable_dma: invalid channel %d\n", channel);
+	else {
+		void *fiqhandler_start;
+		unsigned int fiqhandler_length;
+		extern void floppy_fiqsetup (unsigned long len, unsigned long addr,
+					     unsigned long port);
+
+		if (dma->dma_mode == DMA_MODE_READ) {
+			extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
+			fiqhandler_start = &floppy_fiqin_start;
+			fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
+		} else {
+			extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
+			fiqhandler_start = &floppy_fiqout_start;
+			fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
+		}
+		memcpy ((void *)0x1c, fiqhandler_start, fiqhandler_length);
+		flush_page_to_ram(0);
+		floppy_fiqsetup (dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+		enable_irq (dma->dma_irq);
+	}
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel != DMA_VIRTUAL_FLOPPY0)
+		printk ("arch_disable_dma: invalid channel %d\n", channel);
+	else
+		disable_irq (dma->dma_irq);
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+	dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c
--- v2.1.95/linux/arch/arm/kernel/dma-arc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/dma-arc.c	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,115 @@
+/*
+ * arch/arm/kernel/dma-arc.c
+ *
+ * Copyright (C) 1998 Dave Gilbert / Russell King
+ *
+ * DMA functions specific to Archimedes architecture
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel == DMA_VIRTUAL_FLOPPY0 ||
+	    channel == DMA_VIRTUAL_FLOPPY1)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel != DMA_VIRTUAL_FLOPPY0 &&
+	    channel != DMA_VIRTUAL_FLOPPY1)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+	switch (channel) {
+	case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
+		switch (dma->dma_mode) {
+		case DMA_MODE_READ: /* read */
+    	    	{
+			extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end;
+			extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
+			unsigned long flags;
+#ifdef DEBUG
+			printk("enable_dma fdc1772 data read\n");
+#endif
+			save_flags(flags);
+			cliIF();
+			
+			memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
+				&fdc1772_dma_read_end - &fdc1772_dma_read);
+			fdc1772_setupdma(dma->buf.length, __bus_to_virt(dma->buf.address)); /* Sets data pointer up */
+			enable_irq (64);
+			restore_flags(flags);
+		}
+		break;
+
+		case DMA_MODE_WRITE: /* write */
+	        {
+			extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end;
+			extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
+			unsigned long flags;
+
+#ifdef DEBUG
+			printk("enable_dma fdc1772 data write\n");
+#endif
+			save_flags(flags);
+			cliIF();
+			memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
+				&fdc1772_dma_write_end - &fdc1772_dma_write);
+			fdc1772_setupdma(dma->buf.length, __bus_to_virt(dma->buf.address)); /* Sets data pointer up */
+			enable_irq (64);
+
+			restore_flags(flags);
+		}
+		break;
+    		default:
+			printk ("enable_dma: dma%d not initialised\n", channel);
+			return;
+		}
+	}
+	break;
+
+	case DMA_VIRTUAL_FLOPPY1: { /* Command end FIQ - actually just sets a flag */
+		/* Need to build a branch at the FIQ address */
+		extern void fdc1772_comendhandler(void);
+		unsigned long flags;
+
+		/*printk("enable_dma fdc1772 command end FIQ\n");*/
+		save_flags(flags);
+		cliIF();
+	
+		*((unsigned int *)0x1c)=0xea000000 | (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); /* B fdc1772_comendhandler */
+
+		restore_flags(flags);
+	}
+	break;
+	}
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+	if (channel != DMA_VIRTUAL_FLOPPY0 &&
+	    channel != DMA_VIRTUAL_FLOPPY1)
+		printk("arch_disable_dma: invalid channel %d\n", channel);
+	else
+		disable_irq(dma->dma_irq);
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+	dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
+	dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65;
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c
--- v2.1.95/linux/arch/arm/kernel/dma-dummy.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/dma-dummy.c	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,45 @@
+/*
+ * arch/arm/kernel/dma-dummy.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * Dummy DMA functions
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *devname)
+{
+	return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+	printk ("arch_free_dma: invalid channel %d\n", channel);
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+	printk ("arch_enable_dma: invalid channel %d\n", channel);
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+	printk ("arch_disable_dma: invalid channel %d\n", channel);
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+	printk ("arch_get_dma_residue: invalid channel %d\n", channel);
+	return 0;
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c
--- v2.1.95/linux/arch/arm/kernel/dma-rpc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/dma-rpc.c	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,342 @@
+/*
+ * arch/arm/kernel/dma-rpc.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * DMA functions specific to RiscPC architecture
+ */
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+
+#include "dma.h"
+
+#if 0
+typedef enum {
+	dma_size_8	= 1,
+	dma_size_16	= 2,
+	dma_size_32	= 4,
+	dma_size_128	= 16
+} dma_size_t;
+
+typedef struct {
+	dma_size_t	transfersize;
+} dma_t;
+#endif
+
+#define TRANSFER_SIZE	2
+
+#define CURA	(0)
+#define ENDA	((IOMD_IO0ENDA - IOMD_IO0CURA) << 2)
+#define CURB	((IOMD_IO0CURB - IOMD_IO0CURA) << 2)
+#define ENDB	((IOMD_IO0ENDB - IOMD_IO0CURA) << 2)
+#define CR	((IOMD_IO0CR - IOMD_IO0CURA) << 2)
+#define ST	((IOMD_IO0ST - IOMD_IO0CURA) << 2)
+
+#define state_prog_a	0
+#define state_wait_a	1
+#define state_wait_b	2
+
+static void arch_get_next_sg(dmasg_t *sg, dma_t *dma)
+{
+	unsigned long end, offset, flags = 0;
+
+	if (dma->sg) {
+		sg->address = dma->sg->address;
+		offset = sg->address & ~PAGE_MASK;
+
+		end = offset + dma->sg->length;
+
+		if (end > PAGE_SIZE)
+			end = PAGE_SIZE;
+
+		if (offset + (int) TRANSFER_SIZE > end)
+			flags |= DMA_END_L;
+
+		sg->length = end - TRANSFER_SIZE;
+
+		dma->sg->length -= end - offset;
+		dma->sg->address += end - offset;
+
+		if (dma->sg->length == 0) {
+			if (dma->sgcount > 1) {
+				dma->sg++;
+				dma->sgcount--;
+			} else {
+				dma->sg = NULL;
+				flags |= DMA_END_S;
+			}
+		}
+	} else {
+		flags = DMA_END_S | DMA_END_L;
+		sg->address = 0;
+		sg->length = 0;
+	}
+
+	sg->length |= flags;
+}
+
+static inline void arch_setup_dma_a(dmasg_t *sg, dma_t *dma)
+{
+	outl_t(sg->address, dma->dma_base + CURA);
+	outl_t(sg->length, dma->dma_base + ENDA);
+}
+
+static inline void arch_setup_dma_b(dmasg_t *sg, dma_t *dma)
+{
+	outl_t(sg->address, dma->dma_base + CURB);
+	outl_t(sg->length, dma->dma_base + ENDB);
+}
+
+static void arch_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+	dma_t *dma = (dma_t *)dev_id;
+	unsigned int status = 0, no_buffer = dma->sg == NULL;
+
+	do {
+		switch (dma->state) {
+		case state_prog_a:
+			arch_get_next_sg(&dma->cur_sg, dma);
+			arch_setup_dma_a(&dma->cur_sg, dma);
+			dma->state = state_wait_a;
+
+		case state_wait_a:
+			status = inb_t(dma->dma_base + ST);
+			switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
+			case DMA_ST_OFL|DMA_ST_INT:
+				arch_get_next_sg(&dma->cur_sg, dma);
+				arch_setup_dma_a(&dma->cur_sg, dma);
+				break;
+
+			case DMA_ST_INT:
+				arch_get_next_sg(&dma->cur_sg, dma);
+				arch_setup_dma_b(&dma->cur_sg, dma);
+				dma->state = state_wait_b;
+				break;
+
+			case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
+				arch_setup_dma_b(&dma->cur_sg, dma);
+				dma->state = state_wait_b;
+				break;
+			}
+			break;
+
+		case state_wait_b:
+			status = inb_t(dma->dma_base + ST);
+			switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
+			case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
+				arch_get_next_sg(&dma->cur_sg, dma);
+				arch_setup_dma_b(&dma->cur_sg, dma);
+				break;
+
+			case DMA_ST_INT|DMA_ST_AB:
+				arch_get_next_sg(&dma->cur_sg, dma);
+				arch_setup_dma_a(&dma->cur_sg, dma);
+				dma->state = state_wait_a;
+				break;
+
+			case DMA_ST_OFL|DMA_ST_INT:
+				arch_setup_dma_a(&dma->cur_sg, dma);
+				dma->state = state_wait_a;
+				break;
+			}
+			break;
+		}
+	} while (dma->sg && (status & DMA_ST_INT));
+
+	if (!no_buffer)
+		enable_irq(irq);
+}
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
+{
+	unsigned long flags;
+	int ret;
+
+	switch (channel) {
+	case DMA_0:
+	case DMA_1:
+	case DMA_2:
+	case DMA_3:
+	case DMA_S0:
+	case DMA_S1:
+		save_flags_cli(flags);
+		ret = request_irq(dma->dma_irq, arch_dma_handle, SA_INTERRUPT, dev_name, dma);
+		if (!ret)
+			disable_irq(dma->dma_irq);
+		restore_flags(flags);
+		break;
+
+	case DMA_VIRTUAL_FLOPPY:
+	case DMA_VIRTUAL_SOUND:
+		ret = 0;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+	switch (channel) {
+	case DMA_0:
+	case DMA_1:
+	case DMA_2:
+	case DMA_3:
+	case DMA_S0:
+	case DMA_S1:
+		free_irq(dma->dma_irq, dma);
+		break;
+
+	default:
+		break;
+	}
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+	int residue = 0;
+
+	switch (channel) {
+	case DMA_0:	/* Physical DMA channels */
+	case DMA_1:
+	case DMA_2:
+	case DMA_3:
+	case DMA_S0:
+	case DMA_S1:
+		break;
+
+	case DMA_VIRTUAL_FLOPPY: {
+		extern int floppy_fiqresidual(void);
+		residue = floppy_fiqresidual();
+		}
+		break;
+	}
+	return residue;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+	unsigned long dma_base = dma->dma_base;
+	unsigned int ctrl;
+
+	switch (channel) {
+	case DMA_0:	/* Physical DMA channels */
+	case DMA_1:
+	case DMA_2:
+	case DMA_3:
+	case DMA_S0:
+	case DMA_S1:
+		ctrl = TRANSFER_SIZE | DMA_CR_E;
+
+		if (dma->invalid) {
+			dma->invalid = 0;
+
+			outb_t(DMA_CR_C, dma_base + CR);
+			dma->state = state_prog_a;
+		}
+		
+		if (dma->dma_mode == DMA_MODE_READ)
+			ctrl |= DMA_CR_D;
+
+		outb_t(ctrl, dma_base + CR);
+		enable_irq(dma->dma_irq);
+		break;
+
+	case DMA_VIRTUAL_FLOPPY: {
+		void *fiqhandler_start;
+		unsigned int fiqhandler_length;
+		extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
+					     unsigned long port);
+
+		if (dma->dma_mode == DMA_MODE_READ) {
+			extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
+			fiqhandler_start = &floppy_fiqin_start;
+			fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
+		} else {
+			extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
+			fiqhandler_start = &floppy_fiqout_start;
+			fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
+		}
+		/* Allow access to page 0 via domains */
+		__asm__ __volatile__("mcr	p15, 0, %0, c3, c0" :
+					: "r" (DOMAIN_USER_MANAGER |
+					       DOMAIN_KERNEL_CLIENT |
+					       DOMAIN_IO_CLIENT));
+		memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
+		/* set domain register to normal */
+		set_fs(get_fs());
+		flush_page_to_ram(0);
+		floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+		enable_irq(dma->dma_irq);
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+	unsigned long dma_base = dma->dma_base;
+	unsigned int ctrl;
+
+	switch (channel) {
+	case DMA_0:	/* Physical DMA channels */
+	case DMA_1:
+	case DMA_2:
+	case DMA_3:
+	case DMA_S0:
+	case DMA_S1:
+		disable_irq(dma->dma_irq);
+		ctrl = inb_t(dma_base + CR);
+		outb_t(ctrl & ~DMA_CR_E, dma_base + CR);
+		break;
+
+	case DMA_VIRTUAL_FLOPPY:
+		disable_irq(dma->dma_irq);
+		break;
+	}
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+	outb(0, IOMD_IO0CR);
+	outb(0, IOMD_IO1CR);
+	outb(0, IOMD_IO2CR);
+	outb(0, IOMD_IO3CR);
+
+//	outb(0xf0, IOMD_DMATCR);
+
+	dma[0].dma_base = ioaddr(IOMD_IO0CURA);
+	dma[0].dma_irq  = IRQ_DMA0;
+	dma[1].dma_base = ioaddr(IOMD_IO1CURA);
+	dma[1].dma_irq  = IRQ_DMA1;
+	dma[2].dma_base = ioaddr(IOMD_IO2CURA);
+	dma[2].dma_irq  = IRQ_DMA2;
+	dma[3].dma_base = ioaddr(IOMD_IO3CURA);
+	dma[3].dma_irq  = IRQ_DMA3;
+	dma[4].dma_base = ioaddr(IOMD_SD0CURA);
+	dma[4].dma_irq  = IRQ_DMAS0;
+	dma[5].dma_base = ioaddr(IOMD_SD1CURA);
+	dma[5].dma_irq  = IRQ_DMAS1;
+	dma[6].dma_irq  = 64;
+
+	/* Setup DMA channels 2,3 to be for podules
+	 * and channels 0,1 for internal devices
+	 */
+	outb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c
--- v2.1.95/linux/arch/arm/kernel/dma.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/dma.c	Sun Apr 12 11:42:15 1998
@@ -1,199 +1,189 @@
 /*
  * linux/arch/arm/kernel/dma.c
  *
- * Copyright (C) 1995, 1996 Russell King
+ * Copyright (C) 1995-1998 Russell King
+ *
+ * Front-end to the DMA handling.  You must provide the following
+ * architecture-specific routines:
+ *
+ *  int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id);
+ *  void arch_free_dma(dmach_t channel, dma_t *dma);
+ *  void arch_enable_dma(dmach_t channel, dma_t *dma);
+ *  void arch_disable_dma(dmach_t channel, dma_t *dma);
+ *  int arch_get_dma_residue(dmach_t channel, dma_t *dma);
+ *
+ * Moved DMA resource allocation here...
  */
-
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
 #include <linux/mman.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
-#define KERNEL_ARCH_DMA
 #include <asm/dma.h>
 
-static unsigned long dma_address[8];
-static unsigned long dma_count[8];
-static char dma_direction[8] = { -1, -1, -1, -1, -1, -1, -1};
-
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC)
-#define DMA_PCIO
-#endif
-#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD)
-#define DMA_OLD
-#endif
-
-void enable_dma (unsigned int dmanr)
-{
-	switch (dmanr) {
-#ifdef DMA_PCIO
-		case 2: {
-			void *fiqhandler_start;
-			unsigned int fiqhandler_length;
-			extern void floppy_fiqsetup (unsigned long len, unsigned long addr,
-					unsigned long port);
-		    	switch (dma_direction[dmanr]) {
-	    		case 1: {
-				extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
-				fiqhandler_start = &floppy_fiqin_start;
-				fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
-				break;
-			}
-			case 0: {
-				extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
-				fiqhandler_start = &floppy_fiqout_start;
-				fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
-				break;
-			}
-		    	default:
-				printk ("enable_dma: dma%d not initialised\n", dmanr);
-				return;
-			}
-			memcpy ((void *)0x1c, fiqhandler_start, fiqhandler_length);
-			flush_page_to_ram(0);
-			floppy_fiqsetup (dma_count[dmanr], dma_address[dmanr], (int)PCIO_FLOPPYDMABASE);
-			enable_irq (64);
-			return;
-		}
-#endif
-#ifdef DMA_OLD
-		case 0: { /* Data DMA */
-			switch (dma_direction[dmanr]) {
-			case 1: /* read */
-	    	    	{
-				extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end;
-				extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
-				unsigned long flags;
-#ifdef DEBUG
-				printk("enable_dma fdc1772 data read\n");
-#endif
-				save_flags(flags);
-				cliIF();
-			
-				memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
-					&fdc1772_dma_read_end - &fdc1772_dma_read);
-				fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */
-				enable_irq (64);
-				restore_flags(flags);
-			}
-			break;
-
-			case 0: /* write */
-		        {
-				extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end;
-				extern void fdc1772_setupdma(unsigned int count,unsigned int addr);
-				unsigned long flags;
-
-#ifdef DEBUG
-				printk("enable_dma fdc1772 data write\n");
-#endif
-				save_flags(flags);
-				cliIF();
-				memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
-					&fdc1772_dma_write_end - &fdc1772_dma_write);
-				fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */
-				enable_irq (64);
-
-				restore_flags(flags);
-			}
-			break;
-	    		default:
-				printk ("enable_dma: dma%d not initialised\n", dmanr);
-				return;
-			}
-		}
-		break;
+#include "dma.h"
 
-		case 1: { /* Command end FIQ - actually just sets a flag */
-			/* Need to build a branch at the FIQ address */
-			extern void fdc1772_comendhandler(void);
-			unsigned long flags;
-
-			/*printk("enable_dma fdc1772 command end FIQ\n");*/
-			save_flags(flags);
-			cliIF();
-	
-			*((unsigned int *)0x1c)=0xea000000 | (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); /* B fdc1772_comendhandler */
+static dma_t dma_chan[MAX_DMA_CHANNELS];
 
-			restore_flags(flags);
-		}
-		break;
-#endif
-		case DMA_0:
-		case DMA_1:
-		case DMA_2:
-		case DMA_3:
-		case DMA_S0:
-		case DMA_S1:
-			arch_enable_dma (dmanr - DMA_0);
-			break;
+/* Get dma list
+ * for /proc/dma
+ */
+int get_dma_list(char *buf)
+{
+	int i, len = 0;
 
-		default:
-			printk ("enable_dma: dma %d not supported\n", dmanr);
+	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+		if (dma_chan[i].lock)
+			len += sprintf(buf + len, "%2d: %s\n",
+				       i, dma_chan[i].device_id);
 	}
+	return len;
 }
 
-void set_dma_mode (unsigned int dmanr, char mode)
+/* Request DMA channel
+ *
+ * On certain platforms, we have to allocate an interrupt as well...
+ */
+int request_dma(dmach_t channel, const char *device_id)
 {
-	if (dmanr < 8) {
-		if (mode == DMA_MODE_READ)
-			dma_direction[dmanr] = 1;
-		else if (mode == DMA_MODE_WRITE)
-			dma_direction[dmanr] = 0;
-		else
-			printk ("set_dma_mode: dma%d: invalid mode %02X not supported\n",
-				dmanr, mode);
-	} else if (dmanr < MAX_DMA_CHANNELS)
-		arch_set_dma_mode (dmanr - DMA_0, mode);
-	else
-		printk ("set_dma_mode: dma %d not supported\n", dmanr);
-}
-
-void set_dma_addr (unsigned int dmanr, unsigned int addr)
-{
-	if (dmanr < 8)
-		dma_address[dmanr] = (unsigned long)addr;
-	else if (dmanr < MAX_DMA_CHANNELS)
-		arch_set_dma_addr (dmanr - DMA_0, addr);
-	else
-		printk ("set_dma_addr: dma %d not supported\n", dmanr);
-}
-
-void set_dma_count (unsigned int dmanr, unsigned int count)
-{
-	if (dmanr < 8)
-		dma_count[dmanr] = (unsigned long)count;
-	else if (dmanr < MAX_DMA_CHANNELS)
-		arch_set_dma_count (dmanr - DMA_0, count);
-	else
-	    	printk ("set_dma_count: dma %d not supported\n", dmanr);
-}
-
-int get_dma_residue (unsigned int dmanr)
-{
-	if (dmanr < 8) {
-		switch (dmanr) {
-#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC)
-		case 2: {
-			extern int floppy_fiqresidual (void);
-			return floppy_fiqresidual ();
+	if (channel < MAX_DMA_CHANNELS) {
+		int ret;
+
+		if (xchg(&dma_chan[channel].lock, 1) != 0)
+			return -EBUSY;
+
+		ret = arch_request_dma(channel, &dma_chan[channel], device_id);
+		if (!ret) {
+			dma_chan[channel].device_id = device_id;
+			dma_chan[channel].active    = 0;
+			dma_chan[channel].invalid   = 1;
+		} else
+			xchg(&dma_chan[channel].lock, 0);
+
+		return ret;
+	} else {
+		printk (KERN_ERR "Trying to allocate DMA%d\n", channel);
+		return -EINVAL;
+	}
+}
+
+/* Free DMA channel
+ *
+ * On certain platforms, we have to free interrupt as well...
+ */
+void free_dma(dmach_t channel)
+{
+	if (channel >= MAX_DMA_CHANNELS) {
+		printk (KERN_ERR "Trying to free DMA%d\n", channel);
+		return;
+	}
+
+	if (xchg(&dma_chan[channel].lock, 0) == 0) {
+		if (dma_chan[channel].active) {
+			printk (KERN_ERR "Freeing active DMA%d\n", channel);
+			arch_disable_dma(channel, &dma_chan[channel]);
+			dma_chan[channel].active = 0;
 		}
-#endif
-#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD)
-		case 0: {
-			extern unsigned int fdc1772_bytestogo;
-			return fdc1772_bytestogo;
+
+		printk (KERN_ERR "Trying to free free DMA%d\n", channel);
+		return;
+	}
+	arch_free_dma(channel, &dma_chan[channel]);
+}
+
+/* Set DMA Scatter-Gather list
+ */
+void set_dma_sg (dmach_t channel, dmasg_t *sg, int nr_sg)
+{
+	dma_chan[channel].sg = sg;
+	dma_chan[channel].sgcount = nr_sg;
+	dma_chan[channel].invalid = 1;
+}
+
+/* Set DMA address
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_addr (dmach_t channel, unsigned long physaddr)
+{
+	if (dma_chan[channel].active)
+		printk(KERN_ERR "set_dma_addr: altering DMA%d"
+		       " address while DMA active\n",
+		       channel);
+
+	dma_chan[channel].sg = &dma_chan[channel].buf;
+	dma_chan[channel].sgcount = 1;
+	dma_chan[channel].buf.address = physaddr;
+	dma_chan[channel].invalid = 1;
+}
+
+/* Set DMA byte count
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_count (dmach_t channel, unsigned long count)
+{
+	if (dma_chan[channel].active)
+		printk(KERN_ERR "set_dma_count: altering DMA%d"
+		       " count while DMA active\n",
+		       channel);
+
+	dma_chan[channel].sg = &dma_chan[channel].buf;
+	dma_chan[channel].sgcount = 1;
+	dma_chan[channel].buf.length = count;
+	dma_chan[channel].invalid = 1;
+}
+
+/* Set DMA direction mode
+ */
+void set_dma_mode (dmach_t channel, dmamode_t mode)
+{
+	if (dma_chan[channel].active)
+		printk(KERN_ERR "set_dma_mode: altering DMA%d"
+		       " mode while DMA active\n",
+		       channel);
+
+	dma_chan[channel].dma_mode = mode;
+	dma_chan[channel].invalid = 1;
+}
+
+/* Enable DMA channel
+ */
+void enable_dma (dmach_t channel)
+{
+	if (dma_chan[channel].lock) {
+		if (dma_chan[channel].active == 0) {
+			dma_chan[channel].active = 1;
+			arch_enable_dma(channel, &dma_chan[channel]);
 		}
-#endif
-		default:
-			return -1;
+	} else
+		printk (KERN_ERR "Trying to enable free DMA%d\n", channel);
+}
+
+/* Disable DMA channel
+ */
+void disable_dma (dmach_t channel)
+{
+	if (dma_chan[channel].lock) {
+		if (dma_chan[channel].active == 1) {
+			dma_chan[channel].active = 0;
+			arch_disable_dma(channel, &dma_chan[channel]);
 		}
-	} else if (dmanr < MAX_DMA_CHANNELS)
-		return arch_dma_count (dmanr - DMA_0);
-	return -1;
+	} else
+		printk (KERN_ERR "Trying to disable free DMA%d\n", channel);
+}
+
+int get_dma_residue(dmach_t channel)
+{
+	return arch_get_dma_residue(channel, &dma_chan[channel]);
+}
+
+__initfunc(void init_dma(void))
+{
+	arch_dma_init(dma_chan);
 }
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/dma.h linux/arch/arm/kernel/dma.h
--- v2.1.95/linux/arch/arm/kernel/dma.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/dma.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/kernel/dma.h
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * This header file describes the interface between the generic DMA handler
+ * (dma.c) and the architecture-specific DMA backends (dma-*.c)
+ */
+
+typedef struct {
+	dmasg_t		buf;		/* single DMA			*/
+	int		sgcount;	/* number of DMA SG		*/
+	dmasg_t		*sg;		/* DMA Scatter-Gather List	*/
+
+	unsigned int	active:1;	/* Transfer active		*/
+	unsigned int	invalid:1;	/* Address/Count changed	*/
+	dmamode_t	dma_mode;	/* DMA mode			*/
+
+	unsigned int	lock;		/* Device is allocated		*/
+	const char	*device_id;	/* Device name			*/
+
+	unsigned int	dma_base;	/* Controller base address	*/
+	int		dma_irq;	/* Controller IRQ		*/
+	int		state;		/* Controller state		*/
+	dmasg_t		cur_sg;		/* Current controller buffer	*/
+} dma_t;
+
+/* Prototype: int arch_request_dma(channel, dma, dev_id)
+ * Purpose  : Perform architecture specific claiming of a DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure (above) for channel
+ *          : dev_id  - device ID string passed with request
+ * Returns  : 0 on success, E????? number on error
+ */ 
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id);
+
+/* Prototype: int arch_free_dma(channel, dma)
+ * Purpose  : Perform architecture specific freeing of a DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ */
+void arch_free_dma(dmach_t channel, dma_t *dma);
+
+/* Prototype: void arch_enable_dma(channel, dma)
+ * Purpose  : Enable a claimed DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ */
+void arch_enable_dma(dmach_t channel, dma_t *dma);
+
+/* Prototype: void arch_disable_dma(channel, dma)
+ * Purpose  : Disable a claimed DMA channel
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ */
+void arch_disable_dma(dmach_t channel, dma_t *dma);
+
+/* Prototype: int arch_get_dma_residue(channel, dma)
+ * Purpose  : Return number of bytes left to DMA
+ * Params   : channel - DMA channel number
+ *          : dma     - DMA structure for channel
+ * Returns  : Number of bytes left to DMA
+ */
+int arch_get_dma_residue(dmach_t channel, dma_t *dma);
+
+/* Prototype: void arch_dma_init(dma)
+ * Purpose  : Initialise architecture specific DMA
+ * Params   : dma - pointer to array of DMA structures
+ */
+void arch_dma_init(dma_t *dma);
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.1.95/linux/arch/arm/kernel/ecard.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/ecard.c	Sun Apr 12 11:42:15 1998
@@ -13,6 +13,7 @@
  *			now register their own routine to control interrupts (recommended).
  * 29-Sep-1997	RMK	Expansion card interrupt hardware not being re-enabled on reset from
  *			Linux. (Caused cards not to respond under RiscOS without hard reset).
+ * 15-Feb-1998	RMK	Added DMA support
  */
 
 #define ECARD_C
@@ -24,13 +25,14 @@
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
-#include <asm/irq-no.h>
-#include <asm/ecard.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/arch/irq.h>
+#include <asm/ecard.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
 
 #ifdef CONFIG_ARCH_ARC
 #include <asm/arch/oldlatches.h>
@@ -59,9 +61,11 @@
   BLACKLIST_LOADER(MANU_ATOMWIDE,	PROD_ATOMWIDE_3PSERIAL,	atomwide_serial_loader),
   BLACKLIST_LOADER(MANU_OAK,		PROD_OAK_SCSI,		oak_scsi_loader),
 
+/* Supported cards with broken loader */
+  { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI (loader blacklisted)" },
+
 /* Unsupported cards with no loader */
-BLACKLIST_NOLOADER(MANU_ALSYSTEMS,	PROD_ALSYS_SCSIATAPI),
-BLACKLIST_NOLOADER(MANU_MCS,		PROD_MCS_CONNECT32)
+  BLACKLIST_NOLOADER(MANU_MCS,		PROD_MCS_CONNECT32)
 };
 
 extern int setup_arm_irq(int, struct irqaction *);
@@ -75,7 +79,6 @@
 static signed char irqno_to_expcard[16];
 static unsigned int ecard_numcards, ecard_numirqcards;
 static unsigned int have_expmask;
-static unsigned long kmem;
 
 static void ecard_def_irq_enable (ecard_t *ec, int irqnr)
 {
@@ -178,20 +181,6 @@
 	}
 }
 
-static void *ecard_malloc(int len)
-{
-	int r;
-
-	len = (len + 3) & ~3;
-
-	if (kmem) {
-		r = kmem;
-		kmem += len;
-		return (void *)r;
-	} else
-		return kmalloc(len, GFP_KERNEL);
-}
-
 static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
 {
 	const int num_cards = ecard_numirqcards;
@@ -301,13 +290,13 @@
 			lowaddress = 0;
 		}
 		while (lowaddress <= laddr) {
-			byte = inb (ec->podaddr + haddr);
+			byte = inb(ec->podaddr + haddr);
 			lowaddress += 1;
 		}
 		while (len--) {
 			*a++ = byte;
 			if (len) {
-				byte = inb (ec->podaddr + haddr);
+				byte = inb(ec->podaddr + haddr);
 				lowaddress += 1;
 			}
 		}
@@ -417,7 +406,7 @@
 		}
 		if (c_id(&excd) == 0x80) { /* loader */
 			if (!ec->loader) {
-				ec->loader = (loader_t)ecard_malloc(c_len(&excd));
+				ec->loader = (loader_t)kmalloc(c_len(&excd), GFP_KERNEL);
 				ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld);
 			}
 			continue;
@@ -441,20 +430,39 @@
 	return 1;
 }
 
-unsigned int ecard_address (ecard_t *ec, card_type_t memc, card_speed_t speed)
+unsigned int ecard_address (ecard_t *ec, card_type_t type, card_speed_t speed)
 {
 	switch (ec->slot_no) {
 	case 0:
 	case 1:
 	case 2:
 	case 3:
-		return (memc ? MEMCECIO_BASE : IOCECIO_BASE + (speed << 17)) + (ec->slot_no << 12);
+		switch (type) {
+		case ECARD_MEMC:
+			return MEMCECIO_BASE + (ec->slot_no << 12);
+
+		case ECARD_IOC:
+			return IOCECIO_BASE + (speed << 17) + (ec->slot_no << 12);
+
+		default:
+			return 0;
+		}
+
 #ifdef IOCEC4IO_BASE
 	case 4:
 	case 5:
 	case 6:
 	case 7:
-		return (memc ? 0 : IOCEC4IO_BASE + (speed << 17)) + ((ec->slot_no - 4) << 12);
+		switch (type) {
+		case ECARD_MEMC:
+			return 0;
+
+		case ECARD_IOC:
+			return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
+
+		default:
+			return 0;
+		}
 #endif
 #ifdef MEMCEC8IO_BASE
 	case 8:
@@ -470,7 +478,7 @@
  * If bit 1 of the first byte of the card is set,
  * then the card does not exist.
  */
-static int ecard_probe (int card, int freeslot)
+__initfunc(static int ecard_probe (int card, int freeslot))
 {
 	ecard_t *ec = expcard + freeslot;
 	struct ex_ecld excld;
@@ -480,7 +488,7 @@
 	irqno_to_expcard[card] = -1;
 
 	ec->slot_no = card;
-	if ((ec->podaddr = ecard_address (ec, 0, ECARD_SYNC)) == 0)
+	if ((ec->podaddr = ecard_address (ec, ECARD_IOC, ECARD_SYNC)) == 0)
 		return 0;
 
 	excld.r_ecld = 2;
@@ -490,8 +498,9 @@
 
 	irqno_to_expcard[card] = freeslot;
 
-	ec->irq = -1;
-	ec->fiq = -1;
+	ec->irq = NO_IRQ;
+	ec->fiq = NO_IRQ;
+	ec->dma = NO_DMA;
 	ec->cld.ecld = e_ecld(&excld);
 	ec->cld.manufacturer = e_manu(&excld);
 	ec->cld.product = e_prod(&excld);
@@ -514,15 +523,20 @@
 			break;
 		}
 
-	if (card != 8) {
-		ec->irq = 32 + card;
+	ec->irq = 32 + card;
 #if 0
-		ec->fiq = 96 + card;
+	/* We don't support FIQs on expansion cards at the moment */
+	ec->fiq = 96 + card;
 #endif
-	} else {
+#ifdef CONFIG_ARCH_RPC
+	if (card != 8) {
+		/* On RiscPC, only first two slots have DMA capability
+		 */
+		if (card < 2)
+			ec->dma = 2 + card;
+	} else
 		ec->irq = 11;
-		ec->fiq = -1;
-	}
+#endif
 
 	if ((ec->cld.ecld & 0x78) == 0) {
 		struct in_chunk_dir incd;
@@ -551,11 +565,10 @@
  * Locate all hardware - interrupt management and
  * actual cards.
  */
-unsigned long ecard_init(unsigned long start_mem)
+__initfunc(void ecard_init(void))
 {
 	int i, nc = 0;
 
-	kmem = (start_mem | 3) & ~3;
 	memset (expcard, 0, sizeof (expcard));
 
 #ifdef HAS_EXPMASK
@@ -565,6 +578,7 @@
 		have_expmask = -1;
 	}
 #endif
+
 	printk("Installed expansion cards:");
 
 	/*
@@ -578,27 +592,25 @@
 
 	ecard_numirqcards = nc;
 
-	/*
-	 * Now probe other cards with different interrupt lines
+	/* Now probe other cards with different interrupt lines
 	 */
 #ifdef MEMCEC8IO_BASE
 	if (ecard_probe (8, nc))
 		nc += 1;
 #endif
+
 	printk("\n");
 	ecard_numcards = nc;
 
 	if (nc && setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
 		printk ("Could not allocate interrupt for expansion cards\n");
-		return kmem;
+		return;
 	}
 	
 #ifdef HAS_EXPMASK
 	if (nc && have_expmask)
 		EXPMASK_ENABLE = have_expmask;
 #endif
+
 	oldlatch_init ();
-	start_mem = kmem;
-	kmem = 0;
-	return start_mem;	
 }
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.1.95/linux/arch/arm/kernel/entry-armv.S	Mon Feb 23 18:12:01 1998
+++ linux/arch/arm/kernel/entry-armv.S	Sun Apr 12 11:42:15 1998
@@ -9,7 +9,7 @@
  * Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
  * it to save wrong values...  Be aware!
  */
-#include <linux/config.h> /* for CONFIG_ARCH_EBSA110 /*
+#include <linux/config.h> /* for CONFIG_ARCH_EBSA110 */
 #include <linux/autoconf.h>
 #include <linux/linkage.h>
 
@@ -21,15 +21,6 @@
 
 		.text
 
-@ Offsets into task structure
-@ ---------------------------
-@
-#define STATE		0
-#define COUNTER		4
-#define PRIORITY	8
-#define FLAGS		12
-#define SIGPENDING	16
-
 #define PF_TRACESYS	0x20
 
 @ Bad Abort numbers
@@ -82,21 +73,24 @@
 		strb	r12, [r12, #0x38]	@ Disable FIQ register
 		.endm
 
-		.macro	get_irqnr_and_base, irqnr, base
+		.macro	get_irqnr_and_base, irqnr, irqstat, base
 		mov	r4, #ioc_base_high		@ point at IOC
 		.if	ioc_base_low
 		orr	r4, r4, #ioc_base_low
 		.endif
-		ldrb	\irqnr, [r4, #0x24]		@ get high priority first
+		ldrb	\irqstat, [r4, #0x24]		@ get high priority first
 		adr	\base, irq_prio_h
-		teq	\irqnr, #0
+		teq	\irqstat, #0
 #ifdef IOMD_BASE
-		ldreqb	\irqnr, [r4, #0x1f4]		@ get dma
+		ldreqb	\irqstat, [r4, #0x1f4]		@ get dma
 		adreq	\base, irq_prio_d
-		teqeq	\irqnr, #0
+		teqeq	\irqstat, #0
 #endif
-		ldreqb	\irqnr, [r4, #0x14]		@ get low priority
+		ldreqb	\irqstat, [r4, #0x14]		@ get low priority
 		adreq	\base, irq_prio_l
+
+		teq	\irqstat, #0
+		ldrneb	\irqnr, [r5, \irqstat]		@ get IRQ number
 		.endm
 
 /*
@@ -160,10 +154,13 @@
 		.macro	disable_fiq
 		.endm
 
-		.macro	get_irqnr_and_base, irqnr, base
+		.macro	get_irqnr_and_base, irqnr, irqstat, base
 		mov	r4, #0xf3000000
-		ldrb	\irqnr, [r4]			@ get interrupts
+		ldrb	\irqstat, [r4]			@ get interrupts
 		adr	\base, irq_prio_ebsa110
+
+		teq	\irqstat, #0
+		ldrneb	\irqnr, [r5, \irqstat]		@ get IRQ number
 		.endm
 
 		.macro	irq_prio_table
@@ -189,6 +186,26 @@
 		.byte	 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2
 		.endm
 
+#elif defined(CONFIG_ARCH_EBSA285)
+
+		.macro	disable_fiq
+		.endm
+
+		.macro	get_irqnr_and_base, irqnr, irqstat, base
+		mov	r4, #0xfe000000
+		ldr	\irqstat, [r4, #0x180]		@ get interrupts
+		mov	\irqnr, #0
+1001:		tst	\irqstat, #1
+		addeq	\irqnr, \irqnr, #1
+		moveq	\irqstat, \irqstat, lsr #1
+		tsteq	\irqnr, #32
+		beq	1001b
+		teq	\irqnr, #32
+		.endm
+
+		.macro	irq_prio_table
+		.endm
+
 #else
 #error Unknown architecture
 #endif
@@ -267,6 +284,16 @@
 		.endm
 
 /*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit mode).
+ */
+
+vector_addrexcptn:
+		b	vector_addrexcptn
+
+/*=============================================================================
  * Undefined FIQs
  *-----------------------------------------------------------------------------
  * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
@@ -400,86 +427,6 @@
 		b	__dabt_svc			@  3  (SVC_26 / SVC_32)
 
 /*=============================================================================
- * Undefined instruction handler
- *-----------------------------------------------------------------------------
- * Handles floating point instructions
- */
-__und_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
-		stmia	sp, {r0 - r12}			@ Save r0 - r12
-		add	r8, sp, #S_PC
-		stmdb	r8, {sp, lr}^			@ Save user r0 - r12
-		ldr	r4, .LCund
-		ldmia	r4, {r5 - r7}
-		stmia	r8, {r5 - r7}			@ Save USR pc, cpsr, old_r0
-		mov	fp, #0
-
-		adr	r1, .LC2
-		ldmia	r1, {r1, r4}
-		ldr	r1, [r1]
-		get_current_task r2
-		teq	r1, r2
-		blne	SYMBOL_NAME(math_state_restore)
-		adrsvc,	al, r9, SYMBOL_NAME(fpreturn)
-		adrsvc	al, lr, SYMBOL_NAME(fpundefinstr)
-		ldr	pc, [r4]			@ Call FP module USR entry point
-
-		.globl	SYMBOL_NAME(fpundefinstr)
-SYMBOL_NAME(fpundefinstr):				@ Called by FP module on undefined instr
-		mov	r0, lr
-		mov	r1, sp
-		mrs	r4, cpsr			@ Enable interrupts
-		bic	r4, r4, #I_BIT
-		msr	cpsr, r4
-		bl	SYMBOL_NAME(do_undefinstr)
-		b	ret_from_exception		@ Normal FP exit
-
-__und_svc:	sub	sp, sp, #S_FRAME_SIZE
-		stmia	sp, {r0 - r12}			@ save r0 - r12
-		mov	r6, lr
-		ldr	r7, .LCund
-		ldmia	r7, {r7 - r9}
-		add	r5, sp, #S_FRAME_SIZE
-		add	r4, sp, #S_SP
-		stmia	r4, {r5 - r9}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-
-		adr	r1, .LC2
-		ldmia	r1, {r1, r4}
-		ldr	r1, [r1]
-		mov	r2, sp, lsr #13
-		mov	r2, r2, lsl #13
-		teq	r1, r2
-		blne	SYMBOL_NAME(math_state_restore)
-		adrsvc	al, r9, SYMBOL_NAME(fpreturnsvc)
-		adrsvc	al, lr, SYMBOL_NAME(fpundefinstrsvc)
-		ldr	pc, [r4]			@ Call FP module SVC entry point
-
-		.globl	SYMBOL_NAME(fpundefinstrsvc)
-SYMBOL_NAME(fpundefinstrsvc):
-		mov	r0, r5				@ unsigned long pc
-		mov	r1, sp				@ struct pt_regs *regs
-		bl	SYMBOL_NAME(do_undefinstr)
-
-		.globl	SYMBOL_NAME(fpreturnsvc)
-SYMBOL_NAME(fpreturnsvc):
-		ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
-		msr	spsr, lr
-		ldmia	sp, {r0 - pc}^			@ Restore SVC registers
-
-.LC2:		.word	SYMBOL_NAME(last_task_used_math)
-		.word	SYMBOL_NAME(fp_enter)
-
-__und_invalid:	sub	sp, sp, #S_FRAME_SIZE
-		stmia	sp, {r0 - lr}
-		mov	r7, r0
-		ldr	r4, .LCund
-		ldmia	r4, {r5, r6}			@ Get UND/IRQ/FIQ/ABT pc, cpsr
-		add	r4, sp, #S_PC
-		stmia	r4, {r5, r6, r7}		@ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0
-		mov	r0, sp				@ struct pt_regs *regs
-		mov	r1, #BAD_UNDEFINSTR		@ int reason
-		and	r2, r6, #31			@ int mode
-		b	SYMBOL_NAME(bad_mode)		@ Does not ever return...
-/*=============================================================================
  * Prefetch abort handler
  *-----------------------------------------------------------------------------
  */
@@ -531,14 +478,62 @@
 #endif
 
 /*=============================================================================
- * Address exception handler
+ * Data abort handler code
  *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit mode).
  */
+.LCprocfns:	.word	SYMBOL_NAME(processor)
 
-vector_addrexcptn:
-		b	vector_addrexcptn
+__dabt_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
+		stmia	sp, {r0 - r12}			@ save r0 - r12
+		add	r3, sp, #S_PC
+		stmdb	r3, {sp, lr}^
+		ldr	r0, .LCabt
+		ldmia	r0, {r0 - r2}			@ Get USR pc, cpsr
+		stmia	r3, {r0 - r2}			@ Save USR pc, cpsr, old_r0
+		mov	fp, #0
+		mrs	r2, cpsr			@ Enable interrupts if they were
+		bic	r2, r2, #I_BIT			@ previously
+		msr	cpsr, r2
+		ldr	r2, .LCprocfns
+		mov	lr, pc
+		ldr	pc, [r2, #8]			@ call processor specific code
+		mov	r3, sp
+		bl	SYMBOL_NAME(do_DataAbort)
+		b	ret_from_sys_call
+
+__dabt_svc:	sub	sp, sp, #S_FRAME_SIZE
+		stmia	sp, {r0 - r12}			@ save r0 - r12
+		ldr	r2, .LCabt
+		add	r0, sp, #S_FRAME_SIZE
+		add	r5, sp, #S_SP
+		mov	r1, lr
+		ldmia	r2, {r2 - r4}			@ get pc, cpsr
+		stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+		tst	r3, #I_BIT
+		mrseq	r0, cpsr			@ Enable interrupts if they were
+		biceq	r0, r0, #I_BIT			@ previously
+		msreq	cpsr, r0
+		mov	r0, r2
+		ldr	r2, .LCprocfns
+		mov	lr, pc
+		ldr	pc, [r2, #8]			@ call processor specific code
+		mov	r3, sp
+		bl	SYMBOL_NAME(do_DataAbort)
+		ldr	r0, [sp, #S_PSR]
+		msr	spsr, r0
+		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+
+__dabt_invalid:	sub	sp, sp, #S_FRAME_SIZE
+		stmia	sp, {r0 - lr}			@ Save SVC r0 - lr [lr *should* be intact]
+		mov	r7, r0
+		ldr	r4, .LCabt
+		ldmia	r4, {r5, r6}			@ Get SVC pc, cpsr
+		add	r4, sp, #S_PC
+		stmia	r4, {r5, r6, r7}		@ Save SVC pc, cpsr, old_r0
+		mov	r0, sp
+		mov	r1, #BAD_DATA
+		and	r2, r6, #31
+		b	SYMBOL_NAME(bad_mode)
 
 /*=============================================================================
  * Interrupt (IRQ) handler
@@ -551,9 +546,7 @@
 		ldr	r4, .LCirq
 		ldmia	r4, {r5 - r7}			@ get saved PC, SPSR
 		stmia	r8, {r5 - r7}			@ save pc, psr, old_r0
-1:		get_irqnr_and_base r6, r5
-		teq	r6, #0
-		ldrneb	r0, [r5, r6]			@ get IRQ number
+1:		get_irqnr_and_base r0, r6, r5
 		movne	r1, sp
 		@
 		@ routine called with r0 = irq number, r1 = struct pt_regs *
@@ -572,9 +565,7 @@
 		add	r5, sp, #S_FRAME_SIZE
 		add	r4, sp, #S_SP
 		stmia	r4, {r5, r6, r7, r8, r9}	@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-1:		get_irqnr_and_base r6, r5
-		teq	r6, #0
-		ldrneb	r0, [r5, r6]			@ get IRQ number
+1:		get_irqnr_and_base r0, r6, r5
 		movne	r1, sp
 		@
 		@ routine called with r0 = irq number, r1 = struct pt_regs *
@@ -598,63 +589,85 @@
 		b	SYMBOL_NAME(bad_mode)
 
 /*=============================================================================
- * Data abort handler code
+ * Undefined instruction handler
  *-----------------------------------------------------------------------------
+ * Handles floating point instructions
  */
-.LCprocfns:	.word	SYMBOL_NAME(processor)
-
-__dabt_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
-		stmia	sp, {r0 - r12}			@ save r0 - r12
-		add	r3, sp, #S_PC
-		stmdb	r3, {sp, lr}^
-		ldr	r0, .LCabt
-		ldmia	r0, {r0 - r2}			@ Get USR pc, cpsr
-		stmia	r3, {r0 - r2}			@ Save USR pc, cpsr, old_r0
+__und_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
+		stmia	sp, {r0 - r12}			@ Save r0 - r12
+		add	r8, sp, #S_PC
+		stmdb	r8, {sp, lr}^			@ Save user r0 - r12
+		ldr	r4, .LCund
+		ldmia	r4, {r5 - r7}
+		stmia	r8, {r5 - r7}			@ Save USR pc, cpsr, old_r0
 		mov	fp, #0
-		mrs	r2, cpsr			@ Enable interrupts if they were
-		bic	r2, r2, #I_BIT			@ previously
-		msr	cpsr, r2
-		ldr	r2, .LCprocfns
-		mov	lr, pc
-		ldr	pc, [r2, #8]			@ call processor specific code
-		mov	r3, sp
-		bl	SYMBOL_NAME(do_DataAbort)
-		b	ret_from_sys_call
 
-__dabt_svc:	sub	sp, sp, #S_FRAME_SIZE
+		adr	r1, .LC2
+		ldmia	r1, {r1, r4}
+		ldr	r1, [r1]
+		get_current_task r2
+		teq	r1, r2
+		blne	SYMBOL_NAME(math_state_restore)
+		adrsvc	al, r9, SYMBOL_NAME(fpreturn)
+		adrsvc	al, lr, SYMBOL_NAME(fpundefinstr)
+		ldr	pc, [r4]			@ Call FP module USR entry point
+
+		.globl	SYMBOL_NAME(fpundefinstr)
+SYMBOL_NAME(fpundefinstr):				@ Called by FP module on undefined instr
+		mov	r0, lr
+		mov	r1, sp
+		mrs	r4, cpsr			@ Enable interrupts
+		bic	r4, r4, #I_BIT
+		msr	cpsr, r4
+		bl	SYMBOL_NAME(do_undefinstr)
+		b	ret_from_exception		@ Normal FP exit
+
+__und_svc:	sub	sp, sp, #S_FRAME_SIZE
 		stmia	sp, {r0 - r12}			@ save r0 - r12
-		ldr	r2, .LCabt
-		add	r0, sp, #S_FRAME_SIZE
-		add	r5, sp, #S_SP
-		mov	r1, lr
-		ldmia	r2, {r2 - r4}			@ get pc, cpsr
-		stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-		tst	r3, #I_BIT
-		mrseq	r0, cpsr			@ Enable interrupts if they were
-		biceq	r0, r0, #I_BIT			@ previously
-		msreq	cpsr, r0
-		mov	r0, r2
-		ldr	r2, .LCprocfns
-		mov	lr, pc
-		ldr	pc, [r2, #8]			@ call processor specific code
-		mov	r3, sp
-		bl	SYMBOL_NAME(do_DataAbort)
-		ldr	r0, [sp, #S_PSR]
-		msr	spsr, r0
-		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+		mov	r6, lr
+		ldr	r7, .LCund
+		ldmia	r7, {r7 - r9}
+		add	r5, sp, #S_FRAME_SIZE
+		add	r4, sp, #S_SP
+		stmia	r4, {r5 - r9}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
 
-__dabt_invalid:	sub	sp, sp, #S_FRAME_SIZE
-		stmia	sp, {r0 - lr}			@ Save SVC r0 - lr [lr *should* be intact]
+		adr	r1, .LC2
+		ldmia	r1, {r1, r4}
+		ldr	r1, [r1]
+		mov	r2, sp, lsr #13
+		mov	r2, r2, lsl #13
+		teq	r1, r2
+		blne	SYMBOL_NAME(math_state_restore)
+		adrsvc	al, r9, SYMBOL_NAME(fpreturnsvc)
+		adrsvc	al, lr, SYMBOL_NAME(fpundefinstrsvc)
+		ldr	pc, [r4]			@ Call FP module SVC entry point
+
+		.globl	SYMBOL_NAME(fpundefinstrsvc)
+SYMBOL_NAME(fpundefinstrsvc):
+		mov	r0, r5				@ unsigned long pc
+		mov	r1, sp				@ struct pt_regs *regs
+		bl	SYMBOL_NAME(do_undefinstr)
+
+		.globl	SYMBOL_NAME(fpreturnsvc)
+SYMBOL_NAME(fpreturnsvc):
+		ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
+		msr	spsr, lr
+		ldmia	sp, {r0 - pc}^			@ Restore SVC registers
+
+.LC2:		.word	SYMBOL_NAME(last_task_used_math)
+		.word	SYMBOL_NAME(fp_enter)
+
+__und_invalid:	sub	sp, sp, #S_FRAME_SIZE
+		stmia	sp, {r0 - lr}
 		mov	r7, r0
-		ldr	r4, .LCabt
-		ldmia	r4, {r5, r6}			@ Get SVC pc, cpsr
+		ldr	r4, .LCund
+		ldmia	r4, {r5, r6}			@ Get UND/IRQ/FIQ/ABT pc, cpsr
 		add	r4, sp, #S_PC
-		stmia	r4, {r5, r6, r7}		@ Save SVC pc, cpsr, old_r0
-		mov	r0, sp
-		mov	r1, #BAD_DATA
-		and	r2, r6, #31
-		b	SYMBOL_NAME(bad_mode)
-
+		stmia	r4, {r5, r6, r7}		@ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0
+		mov	r0, sp				@ struct pt_regs *regs
+		mov	r1, #BAD_UNDEFINSTR		@ int reason
+		and	r2, r6, #31			@ int mode
+		b	SYMBOL_NAME(bad_mode)		@ Does not ever return...
 
 #include "entry-common.S"
 
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.1.95/linux/arch/arm/kernel/entry-common.S	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/entry-common.S	Sun Apr 12 11:42:15 1998
@@ -1,56 +1,54 @@
-/*
- *=============================================================================
- *		Low-level interface code
- *-----------------------------------------------------------------------------
- *		Trap initialisation
- *-----------------------------------------------------------------------------
- *
- * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
- * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
- * some excess cycles).
- *
- * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
- * (the kernel).
- * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
- * the actuall address to jump to.
- */
-/*
- * these go into 0x00
- */
-.Lbranches:	swi	SYS_ERROR0
-		ldr	pc, .Lbranches + 0xe4
-		ldr	pc, .Lbranches + 0xe8
-		ldr	pc, .Lbranches + 0xec
-		ldr	pc, .Lbranches + 0xf0
-		ldr	pc, .Lbranches + 0xf4
-		ldr	pc, .Lbranches + 0xf8
-		ldr	pc, .Lbranches + 0xfc
-/*
- * this is put into 0xe4 and above
- */
-.Ljump_addresses:
-		.word	vector_undefinstr	@ 0xe4
-		.word	vector_swi		@ 0xe8
-		.word	vector_prefetch		@ 0xec
-		.word	vector_data		@ 0xf0
-		.word	vector_addrexcptn	@ 0xf4
-		.word	vector_IRQ		@ 0xf8
-		.word	_unexp_fiq		@ 0xfc
-/*
- * initialise the trap system
+/*============================================================================
+ * All exits to user mode from the kernel go through this code.
  */
-ENTRY(trap_init)
-		stmfd	sp!, {r4 - r7, lr}
-		initialise_traps_extra
-		mov	r0, #0xe4
-		adr	r1, .Ljump_addresses
-		ldmia	r1, {r1 - r6}
-		stmia	r0, {r1 - r6}
-		mov	r0, #0
-		adr	r1, .Lbranches
-		ldmia	r1, {r1 - r7}
-		stmia	r0, {r1 - r7}
-		LOADREGS(fd, sp!, {r4 - r7, pc})
+
+		.globl	ret_from_sys_call
+
+		.globl	SYMBOL_NAME(fpreturn)
+SYMBOL_NAME(fpreturn):
+ret_from_exception:
+		adr	r0, 1f
+		ldmia	r0, {r0, r1}
+		ldr	r0, [r0]
+		ldr	r1, [r1]
+		tst	r0, r1
+		blne	SYMBOL_NAME(do_bottom_half)
+ret_from_intr:	ldr	r0, [sp, #S_PSR]
+		tst	r0, #3
+		beq	ret_with_reschedule
+		b	ret_from_all
+
+ret_signal:	mov	r1, sp
+		adrsvc	al, lr, ret_from_all
+		b	SYMBOL_NAME(do_signal)
+
+2:		bl	SYMBOL_NAME(schedule)
+
+ret_from_sys_call:
+		adr	r0, 1f
+		ldmia	r0, {r0, r1}
+		ldr	r0, [r0]
+		ldr	r1, [r1]
+		tst	r0, r1
+		adrsvc	ne, lr, ret_from_intr
+		bne	SYMBOL_NAME(do_bottom_half)
+
+ret_with_reschedule:
+		ldr	r0, 1f + 8
+		ldr	r0, [r0]
+		teq	r0, #0
+		bne	2b
+
+		get_current_task r1
+		ldr	r1, [r1, #TSK_SIGPENDING]
+		teq	r1, #0
+		bne	ret_signal
+
+ret_from_all:	restore_user_regs
+
+1:		.word	SYMBOL_NAME(bh_mask)
+		.word	SYMBOL_NAME(bh_active)
+		.word	SYMBOL_NAME(need_resched)
 
 /*=============================================================================
  * SWI handler
@@ -77,7 +75,7 @@
 		bcs	2f
 
 		get_current_task r5
-		ldr	ip, [r5, #FLAGS]	@ check for syscall tracing
+		ldr	ip, [r5, #TSK_FLAGS]	@ check for syscall tracing
 		tst	ip, #PF_TRACESYS
 		bne	1f
 
@@ -91,7 +89,7 @@
 
 1:		ldr	r7, [sp, #S_IP]		@ save old IP
 		mov	r0, #0
-		str	r7, [sp, #S_IP]		@ trace entry [IP = 0]
+		str	r0, [sp, #S_IP]		@ trace entry [IP = 0]
 		bl	SYMBOL_NAME(syscall_trace)
 		str	r7, [sp, #S_IP]
 		ldmia	sp, {r0 - r3}		@ have to reload r0 - r3
@@ -193,57 +191,59 @@
 		add	r0, sp, #4
 		b	SYMBOL_NAME(sys_rt_sigreturn)
 
-/*============================================================================
- * All exits to user mode from the kernel go through this code.
+/*
+ *=============================================================================
+ *		Low-level interface code
+ *-----------------------------------------------------------------------------
+ *		Trap initialisation
+ *-----------------------------------------------------------------------------
+ *
+ * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
+ * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
+ * some excess cycles).
+ *
+ * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
+ * (the kernel).
+ * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
+ * the actuall address to jump to.
  */
-
-		.globl	ret_from_sys_call
-
-		.globl	SYMBOL_NAME(fpreturn)
-SYMBOL_NAME(fpreturn):
-ret_from_exception:
-		adr	r0, 1f
-		ldmia	r0, {r0, r1}
-		ldr	r0, [r0]
-		ldr	r1, [r1]
-		tst	r0, r1
-		blne	SYMBOL_NAME(do_bottom_half)
-ret_from_intr:	ldr	r0, [sp, #S_PSR]
-		tst	r0, #3
-		beq	ret_with_reschedule
-		b	ret_from_all
-
-ret_signal:	mov	r1, sp
-		adrsvc	al, lr, ret_from_all
-		b	SYMBOL_NAME(do_signal)
-
-2:		bl	SYMBOL_NAME(schedule)
-
-ret_from_sys_call:
-		adr	r0, 1f
-		ldmia	r0, {r0, r1}
-		ldr	r0, [r0]
-		ldr	r1, [r1]
-		tst	r0, r1
-		adrsvc	ne, lr, ret_from_intr
-		bne	SYMBOL_NAME(do_bottom_half)
-
-ret_with_reschedule:
-		ldr	r0, 1f + 8
-		ldr	r0, [r0]
-		teq	r0, #0
-		bne	2b
-
-		get_current_task r1
-		ldr	r1, [r1, #SIGPENDING]
-		teq	r1, #0
-		bne	ret_signal
-
-ret_from_all:	restore_user_regs
-
-1:		.word	SYMBOL_NAME(bh_mask)
-		.word	SYMBOL_NAME(bh_active)
-		.word	SYMBOL_NAME(need_resched)
+/*
+ * these go into 0x00
+ */
+.Lbranches:	swi	SYS_ERROR0
+		ldr	pc, .Lbranches + 0xe4
+		ldr	pc, .Lbranches + 0xe8
+		ldr	pc, .Lbranches + 0xec
+		ldr	pc, .Lbranches + 0xf0
+		ldr	pc, .Lbranches + 0xf4
+		ldr	pc, .Lbranches + 0xf8
+		ldr	pc, .Lbranches + 0xfc
+/*
+ * this is put into 0xe4 and above
+ */
+.Ljump_addresses:
+		.word	vector_undefinstr	@ 0xe4
+		.word	vector_swi		@ 0xe8
+		.word	vector_prefetch		@ 0xec
+		.word	vector_data		@ 0xf0
+		.word	vector_addrexcptn	@ 0xf4
+		.word	vector_IRQ		@ 0xf8
+		.word	_unexp_fiq		@ 0xfc
+/*
+ * initialise the trap system
+ */
+ENTRY(trap_init)
+		stmfd	sp!, {r4 - r7, lr}
+		initialise_traps_extra
+		mov	r0, #0xe4
+		adr	r1, .Ljump_addresses
+		ldmia	r1, {r1 - r6}
+		stmia	r0, {r1 - r6}
+		mov	r0, #0
+		adr	r1, .Lbranches
+		ldmia	r1, {r1 - r7}
+		stmia	r0, {r1 - r7}
+		LOADREGS(fd, sp!, {r4 - r7, pc})
 
 /*============================================================================
  * FP support
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S
--- v2.1.95/linux/arch/arm/kernel/head-armo.S	Mon Feb 23 18:12:01 1998
+++ linux/arch/arm/kernel/head-armo.S	Sun Apr 12 11:42:15 1998
@@ -42,7 +42,7 @@
 		b	SYMBOL_NAME(start_kernel)
 
 LC1:		.word	SYMBOL_NAME(_stext)
-LC0:		.word	SYMBOL_NAME(_edata)
+LC0:		.word	SYMBOL_NAME(__bss_start)
 		.word	SYMBOL_NAME(arm_id)
 		.word	SYMBOL_NAME(_end)
 		.word	SYMBOL_NAME(init_task_union)+8192
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.1.95/linux/arch/arm/kernel/head-armv.S	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/head-armv.S	Sun Apr 12 11:42:15 1998
@@ -16,19 +16,21 @@
 		.globl	__stext
 /*
  * Entry point and restart point.  Entry *must* be called with r0 == 0,
- * MMU off.
+ * MMU off.  Note! These should be unique!!! Please read Documentation/ARM-README
+ * for more information.
  *
- *  r1 = 0 -> ebsa  (Ram @ 0x00000000)
- *  r1 = 1 -> RPC   (Ram @ 0x10000000)
- *  r1 = 2 -> ebsit (???)
+ *  r1 = 0 -> ebsa110  (Ram @ 0x00000000)
+ *  r1 = 1 -> RPC      (Ram @ 0x10000000)
+ *  r1 = 2 -> ebsit    (???)
  *  r1 = 3 -> nexuspci
+ *  r1 = 4 -> ebsa285  (Ram @ 0x00000000)
  */
 ENTRY(stext)
 ENTRY(_stext)
 __entry:
 		teq	r0, #0					@ check for illegal entry...
 		bne	.Lerror					@ loop indefinitely
-		cmp	r1, #4					@ Unknown machine architecture
+		cmp	r1, #5					@ Unknown machine architecture
 		bge	.Lerror
 @
 @ First thing to do is to get the page tables set up so that we can call the kernel
@@ -57,18 +59,23 @@
 
 		adr	r4, .LCMachTypes
 		add	r4, r4, r1, lsl #4
-		ldmia	r4, {r4, r5, r6}			@ r4 = page dir in physical ram
-
+		ldmia	r4, {r4, r5, r6}
+/*
+ * r4 = page dir in physical ram
+ * r5 = physical address of start of RAM
+ * r6 = I/O address
+ */
 		mov	r0, r4
 		mov	r1, #0
 		add	r2, r0, #0x4000
 1:		str	r1, [r0], #4				@ Clear page table
 		teq	r0, r2
 		bne	1b
-@
-@ Add enough entries to allow the kernel to be called.
-@ It will sort out the real mapping in paging_init
-@
+/*
+ * Add enough entries to allow the kernel to be called.
+ * It will sort out the real mapping in paging_init.
+ * We map in 2MB of memory into 0xC0000000 - 0xC0200000
+ */
 		add	r0, r4, #0x3000
 		mov	r1, #0x0000000c				@ SECT_CACHEABLE | SECT_BUFFERABLE
 		orr	r1, r1, r8
@@ -121,7 +128,7 @@
 
 .Lbranch:	.long	.Lalready_done_mmap			@ Real address of routine
 
-		@ EBSA (pg dir phys, phys ram start, phys i/o)
+		@ EBSA110 (pg dir phys, phys ram start, phys i/o)
 .LCMachTypes:	.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000	@ Address of page tables (physical)
 		.long	0					@ Address of RAM
 		.long	0xe0000000				@ I/O address
@@ -145,6 +152,14 @@
 		.long	0x10000000
 		.long	0
 
+		@ EBSA285
+		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000	@ Address of page tables (physical)
+		.long	0					@ Address of RAM
+		.long	0x24000000				@ I/O base address (0x42000000 -> 0xFE000000)
+		.long	0
+
+
+
 .LCProcTypes:	@ ARM6 / 610
 		.long	0x41560600
 		.long	0xffffff00
@@ -168,7 +183,7 @@
 
 		.long	0
 
-.LC0:		.long	SYMBOL_NAME(_edata)
+.LC0:		.long	SYMBOL_NAME(__bss_start)
 		.long	SYMBOL_NAME(arm_id)
 		.long	SYMBOL_NAME(_end)
 		.long	SYMBOL_NAME(init_task_union)+8192
@@ -231,19 +246,84 @@
 		b	SYMBOL_NAME(start_kernel)
 
 #if 1
+
+#if defined(CONFIG_ARCH_RPC)
+		.macro	addruart,rx
+		mov	\rx, #0xe0000000
+		orr	\rx, \rx, #0x00010000
+		orr	\rx, \rx, #0x00000fe0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldrb	\rd, [\rx, #0x14]
+		and	\rd, \rd, #0x60
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x18]
+		tst	\rd, #0x10
+		beq	1001b
+		.endm
+
+#elif defined(CONFIG_ARCH_EBSA110)
+		.macro	addruart,rx
+		mov	\rx, #0xf0000000
+		orr	\rx, \rx, #0x00000be0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	busyuart,rd,rx
+1002:		ldrb	\rd, [\rx, #0x14]
+		and	\rd, \rd, #0x60
+		bne	1002b
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldrb	\rd, [\rx, #0x18]
+		tst	\rd, #0x10
+		beq	1001b
+		.endm
+
+#elif defined(CONFIG_ARCH_EBSA285)
+		.macro	addruart,rx
+		mov	\rx, #0xfe000000
+		.endm
+
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #0x160]	@ UARTDR
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:		ldr	\rd, [\rx, #0x178]	@ UARTFLG
+		tst	\rd, #1 << 3
+		bne	1001b
+		.endm
+
+		.macro	waituart,rd,rx
+		.endm
+#endif
+
 /*
  * Useful debugging routines
  */
-		.globl	_printhex8
-_printhex8:	mov	r1, #8
+ENTRY(printhex8)
+		mov	r1, #8
 		b	printhex
 
-		.globl	_printhex4
-_printhex4:	mov	r1, #4
+ENTRY(printhex4)
+		mov	r1, #4
 		b	printhex
 
-		.globl	_printhex2
-_printhex2:	mov	r1, #2
+ENTRY(printhex2)
+		mov	r1, #2
 printhex:	ldr	r2, =hexbuf
 		add	r3, r2, r1
 		mov	r1, #0
@@ -258,46 +338,23 @@
 		bne	1b
 		mov	r0, r2
 
-		.globl	_printascii
-_printascii:
-#ifdef CONFIG_ARCH_RPC
-		mov	r3, #0xe0000000
-		orr	r3, r3, #0x00010000
-		orr	r3, r3, #0x00000fe0
-#else
-		mov	r3, #0xf0000000
-		orr	r3, r3, #0x0be0
-#endif
-		b	3f
-1:		ldrb	r2, [r3, #0x18]
-		tst	r2, #0x10
-		beq	1b
-		strb	r1, [r3]
-2:		ldrb	r2, [r3, #0x14]
-		and	r2, r2, #0x60
-		teq	r2, #0x60
-		bne	2b
+ENTRY(printascii)
+		addruart r3
+		b	2f
+1:		waituart r2, r3
+		senduart r1, r3
+		busyuart r2, r3
 		teq	r1, #'\n'
 		moveq	r1, #'\r'
 		beq	1b
-3:		teq	r0, #0
+2:		teq	r0, #0
 		ldrneb	r1, [r0], #1
 		teqne	r1, #0
 		bne	1b
 		mov	pc, lr
 
-		.ltorg
-
-		.globl	_printch
-_printch:
-#ifdef CONFIG_ARCH_RPC
-		mov	r3, #0xe0000000
-		orr	r3, r3, #0x00010000
-		orr	r3, r3, #0x00000fe0
-#else
-		mov	r3, #0xf0000000
-		orr	r3, r3, #0x0be0
-#endif
+ENTRY(printch)
+		addruart r3
 		mov	r1, r0
 		mov	r0, #0
 		b	1b
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.1.95/linux/arch/arm/kernel/irq.c	Wed Apr  8 19:36:24 1998
+++ linux/arch/arm/kernel/irq.c	Sun Apr 12 11:42:15 1998
@@ -33,16 +33,10 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/hardware.h>
-#include <asm/irq-no.h>
 #include <asm/arch/irq.h>
 
+unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-atomic_t __arm_bh_counter;
-#else
-int __arm_bh_counter;
-#endif
-
 spinlock_t irq_controller_lock;
 
 #ifndef SMP
@@ -80,13 +74,21 @@
 
 struct irqaction *irq_action[NR_IRQS];
 
-/*
- * Bitmask indicating valid interrupt numbers
+#ifdef CONFIG_ARCH_ACORN
+/* Bitmask indicating valid interrupt numbers
+ * (to be moved to include/asm-arm/arch-*)
  */
 unsigned long validirqs[NR_IRQS / 32] = {
-	0x003fffff,	0x000001ff,	0x000000ff,	0x00000000
+	0x003ffe7f,	0x000001ff,	0x000000ff,	0x00000000
 };
 
+#define valid_irq(x) ((x) < NR_IRQS && validirqs[(x) >> 5] & (1 << ((x) & 31)))
+#else
+
+#define valid_irq(x) ((x) < NR_IRQS)
+
+#endif
+
 int get_irq_list(char *buf)
 {
 	int i;
@@ -98,7 +100,7 @@
 		if (!action)
 			continue;
 		p += sprintf(p, "%3d: %10u   %s",
-			     i, kstat.irqs[0][i], action->name);
+			     i, kstat_irqs(i), action->name);
 		for (action = action->next; action; action = action->next) {
 			p += sprintf(p, ", %s", action->name);
 		}
@@ -126,7 +128,7 @@
 
 	cpu = smp_processor_id();
 	irq_enter(cpu, irq);
-	kstat.irqs[0][irq]++;
+	kstat.irqs[cpu][irq]++;
 
 	/* Return with this interrupt masked if no action */
 	status = 0;
@@ -143,13 +145,26 @@
 		if (status & SA_SAMPLE_RANDOM)
 			add_interrupt_randomness(irq);
 		__cli();
+
+		switch (irq) {
 #if defined(HAS_IOMD) || defined(HAS_IOC)
-		if (irq != IRQ_KEYBOARDTX && irq != IRQ_EXPANSIONCARD)
+		case IRQ_KEYBOARDTX:
+		case IRQ_EXPANSIONCARD:
+			break;
+#endif
+#ifdef HAS_IOMD
+		case IRQ_DMA0:
+		case IRQ_DMA1:
+		case IRQ_DMA2:
+		case IRQ_DMA3:
+			break;
 #endif
-		{
+
+		default:
 			spin_lock(&irq_controller_lock);
 			unmask_irq(irq);
 			spin_unlock(&irq_controller_lock);
+			break;
 		}
 	}
 
@@ -235,7 +250,7 @@
 	unsigned long retval;
 	struct irqaction *action;
         
-	if (irq >= NR_IRQS || !(validirqs[irq >> 5] & (1 << (irq & 31))))
+	if (!valid_irq(irq))
 		return -EINVAL;
 	if (!handler)
 		return -EINVAL;
@@ -263,7 +278,7 @@
 	struct irqaction * action, **p;
 	unsigned long flags;
 
-	if (irq >= NR_IRQS || !(validirqs[irq >> 5] & (1 << (irq & 31)))) {
+	if (!valid_irq(irq)) {
 		printk(KERN_ERR "Trying to free IRQ%d\n",irq);
 #ifdef CONFIG_DEBUG_ERRORS
 		__backtrace();
@@ -294,7 +309,7 @@
 
 	/* first snaffle up any unassigned irqs */
 	for (i = 15; i > 0; i--) {
-		if (!irq_action[i]) {
+		if (!irq_action[i] && valid_irq(i)) {
 			enable_irq(i);
 			irqs |= 1 << i;
 		}
@@ -323,5 +338,7 @@
 
 __initfunc(void init_IRQ(void))
 {
+	extern void init_dma(void);
 	irq_init_irq();
+	init_dma();
 }
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/leds-ebsa285.c linux/arch/arm/kernel/leds-ebsa285.c
--- v2.1.95/linux/arch/arm/kernel/leds-ebsa285.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/leds-ebsa285.c	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/kernel/leds-285.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * EBSA-285 LED control routines.  We use the leds as follows:
+ *
+ *  - Green - toggles state every 50 timer interrupts
+ *  - Amber - On if system is not idle
+ *  - Red   - currently unused
+ */
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+static char led_state = XBUS_LED_RED | XBUS_LED_GREEN;
+
+void leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+
+	save_flags_cli(flags);
+
+	switch(ledevt) {
+	case led_idle_start:
+		led_state |= XBUS_LED_AMBER;
+		break;
+
+	case led_idle_end:
+		led_state &= ~XBUS_LED_AMBER;
+		break;
+
+	case led_timer:
+		led_state ^= XBUS_LED_GREEN;
+		break;
+
+	default:
+		break;
+	}
+
+	restore_flags(flags);
+
+	*XBUS_LEDS = led_state;
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.1.95/linux/arch/arm/kernel/process.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/process.c	Sun Apr 12 11:42:15 1998
@@ -69,8 +69,10 @@
 	current->priority = -100;
 	for (;;)
 	{
+#if 0 //def ARCH_IDLE_OK
 		if (!hlt_counter && !need_resched)
 			proc_idle ();
+#endif
 		run_task_queue(&tq_scheduler);
 		schedule();
 	}
@@ -142,7 +144,7 @@
 "	mrc p15, 0, %1, c2, c0\n"
 "	mrc p15, 0, %2, c3, c0\n"
  : "=r" (ctrl), "=r" (transbase), "=r" (dac));
-  printk("Control: %04X  Table: %08X  DAC: %08X",
+  printk("Control: %04X  Table: %08X  DAC: %08X  ",
   	ctrl, transbase, dac);
   }
 #endif
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- v2.1.95/linux/arch/arm/kernel/ptrace.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/ptrace.c	Sun Apr 12 11:42:15 1998
@@ -27,18 +27,6 @@
  */
 #define BREAKINST	0xef9f0001
 
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
-	int i;
-
-	for (i = 1; i < NR_TASKS; i++) {
-		if (task[i] != NULL && (task[i]->pid == pid))
-			return task[i];
-	}
-	return NULL;
-}
-
 /*
  * this routine will get a word off of the processes privileged stack.
  * the offset is how far from the base addr as stored in the TSS.
@@ -581,7 +569,7 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	ret = -ESRCH;
-	if (!(child = get_task(pid)))
+	if (!(child = find_task_by_pid(pid)))
 		goto out;
 	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/setup-ebsa110.c linux/arch/arm/kernel/setup-ebsa110.c
--- v2.1.95/linux/arch/arm/kernel/setup-ebsa110.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/setup-ebsa110.c	Sun Apr 12 11:42:15 1998
@@ -26,62 +26,95 @@
 #include <linux/delay.h>
 #include <linux/major.h>
 #include <linux/utsname.h>
+#include <linux/init.h>
 
-#include <asm/segment.h>
-#include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/setup.h>
+#include <asm/system.h>
 
 #ifndef CONFIG_CMDLINE
 #define CONFIG_CMDLINE	"root=nfs rw console=ttyS1,38400n8"
 #endif
+#define COMMAND_LINE_SIZE 256
+
 #define MEM_SIZE	(16*1024*1024)
 
-#define COMMAND_LINE_SIZE 256
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+       char saved_command_line[COMMAND_LINE_SIZE];
 
+struct processor processor;
+struct screen_info screen_info;
 unsigned char aux_device_present;
 unsigned long arm_id;
+
 extern int root_mountflags;
 extern int _etext, _edata, _end;
+extern const struct processor sa110_processor_functions;
 
 #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 */
 
-static inline void setup_ramdisk (void)
+static inline void setup_ramdisk(int start, int prompt, int load)
 {
-    rd_image_start	= 0;
-    rd_prompt		= 1;
-    rd_doload		= 1;
+	rd_image_start	= start;
+	rd_prompt	= prompt;
+	rd_doload	= load;
 }
 #else
-#define setup_ramdisk()	
+#define setup_ramdisk(start,prompt,load)
 #endif
 
+#ifdef PARAMS_BASE
+static struct param_struct *params = (struct param_struct *)PARAMS_BASE;
+
+static inline char *setup_params(unsigned long *mem_end_p)
+{
+	ROOT_DEV	  = to_kdev_t(params->u1.s.rootdev);
+	ORIG_X		  = params->u1.s.video_x;
+	ORIG_Y		  = params->u1.s.video_y;
+	ORIG_VIDEO_COLS	  = params->u1.s.video_num_cols;
+	ORIG_VIDEO_LINES  = params->u1.s.video_num_rows;
+
+	setup_ramdisk(params->u1.s.rd_start,
+		      (params->u1.s.flags & FLAG_RDPROMPT) == 0,
+		      (params->u1.s.flags & FLAG_RDLOAD) == 0);
+
+	*mem_end_p = 0xc0000000 + MEM_SIZE;
+
+	return params->commandline;
+}
+#else
 static char default_command_line[] = CONFIG_CMDLINE;
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
-struct processor processor;
-extern const struct processor sa110_processor_functions;
+static inline char *setup_params(unsigned long *mem_end_p)
+{
+	ROOT_DEV	  = 0x00ff;
+
+	setup_ramdisk(0, 1, 1);
+
+	*mem_end_p = 0xc0000000 + MEM_SIZE;
+
+	return default_command_line;
+}
+#endif
 
-void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p)
+__initfunc(void setup_arch(char **cmdline_p,
+	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	unsigned long memory_start, memory_end;
 	char c = ' ', *to = command_line, *from;
 	int len = 0;
 
 	memory_start = (unsigned long)&_end;
-	memory_end = 0xc0000000 + MEM_SIZE;
-	from = default_command_line;
 
 	processor = sa110_processor_functions;
-	processor._proc_init ();
+	processor._proc_init();
 
-	ROOT_DEV		= 0x00ff;
-	setup_ramdisk();
+	from = setup_params(&memory_end);
 
 	init_task.mm->start_code = TASK_SIZE;
 	init_task.mm->end_code	 = TASK_SIZE + (unsigned long) &_etext;
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.1.95/linux/arch/arm/kernel/setup.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/setup.c	Sun Apr 12 11:42:15 1998
@@ -26,15 +26,16 @@
 #include <linux/major.h>
 #include <linux/utsname.h>
 #include <linux/blk.h>
+#include <linux/init.h>
 
-#include <asm/segment.h>
-#include <asm/system.h>
 #include <asm/hardware.h>
+#include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/arch/mmu.h>
 #include <asm/procinfo.h>
-#include <asm/io.h>
+#include <asm/segment.h>
 #include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/arch/mmu.h>
 
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info;
@@ -153,13 +154,17 @@
 #define setup_initrd(p,m)
 #endif
 
+#ifdef IOEB_BASE
 static inline void check_ioeb_present(void)
 {
 	if (((*IOEB_BASE) & 15) == 5)
 		armidlist[armidindex].features |= F_IOEB;
 }
+#else
+#define check_ioeb_present()
+#endif
 
-static void get_processor_type (void)
+static inline void get_processor_type (void)
 {
 	for (armidindex = 0; ; armidindex ++)
 		if (!((armidlist[armidindex].id ^ arm_id) &
@@ -179,11 +184,14 @@
 
 #define COMMAND_LINE_SIZE 256
 
+/* Can this be initdata?  --pb
+ *  command_line can be, saved_command_line can't though
+ */
 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)
+__initfunc(void setup_arch(char **cmdline_p,
+	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	static unsigned char smptrap;
 	unsigned long memory_start, memory_end;
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c
--- v2.1.95/linux/arch/arm/kernel/time.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/time.c	Sun Apr 12 11:42:15 1998
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -30,7 +31,6 @@
 #include <asm/delay.h>
 
 #include <linux/timex.h>
-#include <asm/irq-no.h>
 #include <asm/hardware.h>
 
 extern int setup_arm_irq(int, struct irqaction *);
@@ -143,12 +143,12 @@
 	update_rtc ();
 }
 
-static struct irqaction irqtimer0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+static struct irqaction irqtimer = { timer_interrupt, 0, 0, "timer", NULL, NULL};
 
-void time_init(void)
+__initfunc(void time_init(void))
 {
 	xtime.tv_sec = setup_timer();
 	xtime.tv_usec = 0;
 
-	setup_arm_irq(IRQ_TIMER0, &irqtimer0);
+	setup_arm_irq(IRQ_TIMER, &irqtimer);
 }
diff -u --recursive --new-file v2.1.95/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.1.95/linux/arch/arm/kernel/traps.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/kernel/traps.c	Sun Apr 12 11:42:15 1998
@@ -59,17 +59,27 @@
 		return 0;
 }
 
-static void dump_stack (unsigned long *start, unsigned long *end, int offset, int max)
+/*
+ * Dump out the contents of some memory nicely...
+ */
+void dump_mem(unsigned long bottom, unsigned long top)
 {
-	unsigned long *p;
+	unsigned long p = bottom & ~31;
 	int i;
 
-	for (p = start + offset, i = 0; i < max && p < end; i++, p++) {
-		if (i && (i & 7) == 0)
-			printk ("\n       ");
-		printk ("%08lx ", *p);
+	for (p = bottom & ~31; p < top;) {
+		printk("%08lx: ", p);
+
+		for (i = 0; i < 8; i++, p += 4) {
+			if (p < bottom || p >= top)
+				printk("         ");
+			else
+				printk("%08lx ", *(unsigned long *)p);
+			if (i == 3)
+				printk(" ");
+		}
+		printk ("\n");
 	}
-	printk ("\n");
 }
 
 /*
@@ -139,28 +149,26 @@
 		break;
 	}
 
-	console_verbose ();
-	printk ("Internal error: %s: %x\n", str, err);
-	printk ("CPU: %d", smp_processor_id());
-	show_regs (regs);
-	printk ("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
+	console_verbose();
+	printk("Internal error: %s: %x\n", str, err);
+	printk("CPU: %d", smp_processor_id());
+	show_regs(regs);
+	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 		current->comm, current->pid, 4096+(unsigned long)current);
 
 	cstack = (unsigned long)(regs + 1);
 	sstack = 4096+(unsigned long)current;
 
-	if (*(unsigned long *)sstack != STACK_MAGIC)
-		printk ("*** corrupted stack page\n       ");
-
-	if (verify_stack_pointer (cstack, 4))
-		printk ("%08lx invalid kernel stack pointer\n", cstack);
+	printk("Stack: ");
+	if (verify_stack_pointer(cstack, 4))
+		printk("invalid kernel stack pointer %08lx", cstack);
 	else if(cstack > sstack + 4096)
-		printk("(sp overflow)\n");
+		printk("(sp overflow)");
 	else if(cstack < sstack)
-		printk("(sp underflow)\n");
-	else
-		dump_stack ((unsigned long *)sstack, (unsigned long *)sstack + 1024,
-			cstack - sstack, kstack_depth_to_print);
+		printk("(sp underflow)");
+	printk("\n");
+
+	dump_mem(cstack, sstack + 4096);
 
 	frameptr = regs->ARM_fp;
 	if (frameptr) {
@@ -172,7 +180,7 @@
 		}
 	}
 
-	dump_instr (instruction_pointer(regs));
+	dump_instr(instruction_pointer(regs));
 	died = 0;
 	if (ret != -1)
 		do_exit (ret);
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.1.95/linux/arch/arm/lib/Makefile	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/lib/Makefile	Sun Apr 12 11:42:15 1998
@@ -5,17 +5,13 @@
 #
 
 L_TARGET := lib.a
-L_OBJS   := backtrace.o bitops.o delay.o fp_support.o \
+L_OBJS   := backtrace.o bitops.o checksum.o delay.o fp_support.o \
 	    loaders.o memcpy.o memfastset.o system.o string.o uaccess.o
 
 ifeq ($(PROCESSOR),armo)
   L_OBJS += uaccess-armo.o
 endif
 
-ifdef CONFIG_INET
-  L_OBJS += checksum.o
-endif
-
 ifdef CONFIG_ARCH_ACORN
   L_OBJS += ll_char_wr.o io-acorn.o
   ifdef CONFIG_ARCH_A5K
@@ -26,30 +22,27 @@
   endif
 endif
 
-ifdef CONFIG_ARCH_EBSA110
+ifeq ($(MACHINE),ebsa110)
   L_OBJS += io-ebsa110.o
 endif
 
-include $(TOPDIR)/Rules.make
+ifeq ($(MACHINE),ebsa285)
+  L_OBJS += io-ebsa285.o
+endif
 
-constants.h: getconstants
-	./getconstants > constants.h
+include $(TOPDIR)/Rules.make
 
-getconstants: getconstants.c getconstants.h
-	$(HOSTCC) -D__KERNEL__ -o getconstants getconstants.c
+constants.h: getconsdata.o extractconstants.pl
+	$(PERL) extractconstants.pl $(OBJDUMP) > $@
 
-getconstants.h: getconsdata.c
+getconsdata.o: getconsdata.c
 	$(CC) $(CFLAGS) -c getconsdata.c
-	$(PERL) extractinfo.perl $(OBJDUMP) > $@
 
 %.o: %.S
-ifndef $(CONFIG_BINUTILS_NEW)
+ifneq ($(CONFIG_BINUTILS_NEW),y)
 	$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s
 	$(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s
 	$(RM) ..tmp.$<.s
 else
 	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
 endif
-
-clean:
-	$(RM) getconstants constants.h getconstants.h
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/extractconstants.pl linux/arch/arm/lib/extractconstants.pl
--- v2.1.95/linux/arch/arm/lib/extractconstants.pl	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/extractconstants.pl	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+
+$OBJDUMP=$ARGV[0];
+
+sub swapdata {
+	local ($num) = @_;
+
+	return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2);
+}
+
+open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') ||
+	die ('Cant objdump!');
+while (<DATA>) {
+	($addr, $data0, $data1, $data2, $data3) = split (' ');
+	$dat[hex($addr)] = hex(&swapdata($data0));
+	$dat[hex($addr)+4] = hex(&swapdata($data1));
+	$dat[hex($addr)+8] = hex(&swapdata($data2));
+	$dat[hex($addr)+12] = hex(&swapdata($data3));
+}
+close (DATA);
+
+open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!');
+while (<DATA>) {
+	/elf32/ && ( $elf = 1 );
+	/a.out/ && ( $aout = 1 );
+	next if ($aout && ! / 07 /);
+	next if ($elf && ! (/^00...... g/ && /.data/));
+	next if (!$aout && !$elf);
+
+	if ($aout) {
+		($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ');
+		$nam[hex($addr)] = substr($name, 1);
+	}
+	if ($elf) {
+		chomp;
+		$addr = substr ($_, 0, 8);
+		$name = substr ($_, 32);
+		$nam[hex($addr)] = $name;
+	}
+}
+close (DATA);
+
+print "/*\n * *** This file is automatically generated from getconsdata.c.  Do not edit! ***\n */\n";
+for ($i = 0; $i < hex($addr)+4; $i += 4) {
+	print "#define $nam[$i] $dat[$i]\n";
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/extractinfo.perl linux/arch/arm/lib/extractinfo.perl
--- v2.1.95/linux/arch/arm/lib/extractinfo.perl	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/lib/extractinfo.perl	Wed Dec 31 16:00:00 1969
@@ -1,45 +0,0 @@
-#!/usr/bin/perl
-
-$OBJDUMP=$ARGV[0];
-
-sub swapdata {
-	local ($num) = @_;
-
-	return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2);
-}
-
-open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') ||
-	die ('Cant objdump!');
-while (<DATA>) {
-	($addr, $data0, $data1, $data2, $data3) = split (' ');
-	$dat[hex($addr)] = hex(&swapdata($data0));
-	$dat[hex($addr)+4] = hex(&swapdata($data1));
-	$dat[hex($addr)+8] = hex(&swapdata($data2));
-	$dat[hex($addr)+12] = hex(&swapdata($data3));
-}
-close (DATA);
-
-open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!');
-while (<DATA>) {
-	/elf32/ && ( $elf = 1 );
-	/a.out/ && ( $aout = 1 );
-	next if ($aout && ! / 07 /);
-	next if ($elf && ! (/^00...... g/ && /.data/));
-	next if (!$aout && !$elf);
-
-	($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ') if $aout;
-	$nam[hex($addr)] = substr($name, 1) if $aout;
-	if ($elf) {
-		chomp;
-		$addr = substr ($_, 0, 8);
-		$name = substr ($_, 32);
-		$nam[hex($addr)] = $name;
-	}
-}
-close (DATA);
-
-print "/*\n * *** THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT! ***\n */\n";
-for ($i = 0; $i < hex($addr)+12; $i ++) {
-	print "unsigned long $nam[$i] = $dat[$i];\n" if $dat[$i];
-	print "#define __HAS_$nam[$i]\n" if $dat[$i];
-}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c
--- v2.1.95/linux/arch/arm/lib/getconsdata.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/lib/getconsdata.c	Sun Apr 12 11:42:15 1998
@@ -1,9 +1,8 @@
 /*
  * linux/arch/arm/lib/getconsdata.c
  *
- * Copyright (C) 1995, 1996 Russell King
+ * Copyright (C) 1995-1998 Russell King
  */
-
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -15,17 +14,55 @@
 #define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n)
 
 #ifdef KERNEL_DOMAIN
-unsigned long kernel_domain = KERNEL_DOMAIN;
+unsigned long DOM_KERNELDOMAIN = KERNEL_DOMAIN;
 #endif
 #ifdef USER_DOMAIN
-unsigned long user_domain = USER_DOMAIN;
+unsigned long DOM_USERDOMAIN = USER_DOMAIN;
 #endif
-unsigned long addr_limit = OFF_TSK(addr_limit);
-unsigned long tss_memmap = OFF_TSK(tss.memmap);
-unsigned long mm = OFF_TSK(mm);
-unsigned long pgd = OFF_MM(pgd);
-unsigned long tss_save = OFF_TSK(tss.save);
-unsigned long tss_fpesave = OFF_TSK(tss.fpstate.soft.save);
+
+unsigned long TSK_STATE = OFF_TSK(state);
+unsigned long TSK_FLAGS = OFF_TSK(flags);
+unsigned long TSK_SIGPENDING = OFF_TSK(sigpending);
+unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit);
+
+unsigned long MM = OFF_TSK(mm);
+unsigned long PGD = OFF_MM(pgd);
+
+unsigned long TSS_MEMMAP = OFF_TSK(tss.memmap);
+unsigned long TSS_SAVE = OFF_TSK(tss.save);
+unsigned long TSS_FPESAVE = OFF_TSK(tss.fpstate.soft.save);
 #if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3)
-unsigned long tss_memcmap = OFF_TSK(tss.memcmap);
+unsigned long TSS_MEMCMAP = OFF_TSK(tss.memcmap);
+#endif
+
+#ifdef _PAGE_PRESENT
+unsigned long PAGE_PRESENT = _PAGE_PRESENT;
+#endif
+#ifdef _PAGE_RW
+unsigned long PAGE_RW = _PAGE_RW;
+#endif
+#ifdef _PAGE_USER
+unsigned long PAGE_USER = _PAGE_USER;
 #endif
+#ifdef _PAGE_ACCESSED
+unsigned long PAGE_ACCESSED = _PAGE_ACCESSED;
+#endif
+#ifdef _PAGE_DIRTY
+unsigned long PAGE_DIRTY = _PAGE_DIRTY;
+#endif
+#ifdef _PAGE_READONLY
+unsigned long PAGE_READONLY = _PAGE_READONLY;
+#endif
+#ifdef _PAGE_NOT_USER
+unsigned long PAGE_NOT_USER = _PAGE_NOT_USER;
+#endif
+#ifdef _PAGE_OLD
+unsigned long PAGE_OLD = _PAGE_OLD;
+#endif
+#ifdef _PAGE_CLEAN
+unsigned long PAGE_CLEAN = _PAGE_CLEAN;
+#endif
+
+unsigned long KSWI_BASE = 0x900000;
+unsigned long KSWI_SYS_BASE = 0x9f0000;
+unsigned long SYS_ERROR0 = 0x9f0000;
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/getconstants.c linux/arch/arm/lib/getconstants.c
--- v2.1.95/linux/arch/arm/lib/getconstants.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/lib/getconstants.c	Wed Dec 31 16:00:00 1969
@@ -1,74 +0,0 @@
-/*
- * linux/arch/arm/lib/getconstants.c
- *
- * Copyright (C) 1995, 1996 Russell King
- */
-
-#include <linux/mm.h>
-#include <asm/pgtable.h>
-#include <stdio.h>
-#include <linux/unistd.h>
-
-void printdef(char *def, int no)
-{
-	printf("#define %s\t%d\n", def, no);
-}
-
-#include "getconstants.h"
-
-int main()
-{
-	printf("/*\n *  contants.h generated by getconstants\n * DO NOT EDIT!\n */\n");
-
-	printf("#define _current\t_%s\n", "current_set");
-
-#ifdef _PAGE_PRESENT
-	printdef("PAGE_PRESENT",	_PAGE_PRESENT);
-#endif
-#ifdef _PAGE_RW
-	printdef("PAGE_RW",		_PAGE_RW);
-#endif
-#ifdef _PAGE_USER
-	printdef("PAGE_USER",		_PAGE_USER);
-#endif
-#ifdef _PAGE_ACCESSED
-	printdef("PAGE_ACCESSED",	_PAGE_ACCESSED);
-#endif
-#ifdef _PAGE_DIRTY
-	printdef("PAGE_DIRTY",		_PAGE_DIRTY);
-#endif
-#ifdef _PAGE_READONLY
-	printdef("PAGE_READONLY",	_PAGE_READONLY);
-#endif
-#ifdef _PAGE_NOT_USER
-	printdef("PAGE_NOT_USER",	_PAGE_NOT_USER);
-#endif
-#ifdef _PAGE_OLD
-	printdef("PAGE_OLD",		_PAGE_OLD);
-#endif
-#ifdef _PAGE_CLEAN
-	printdef("PAGE_CLEAN",		_PAGE_CLEAN);
-#endif
-	printdef("TSS_MEMMAP",		(int)tss_memmap);
-	printdef("TSS_SAVE",		(int)tss_save);
-#ifdef __HAS_tss_memcmap
-	printdef("TSS_MEMCMAP",		(int)tss_memcmap);
-#endif
-#ifdef __HAS_addr_limit
-	printdef("ADDR_LIMIT",		(int)addr_limit);
-#endif
-#ifdef __HAS_kernel_domain
-	printdef("KERNEL_DOMAIN",	kernel_domain);
-#endif
-#ifdef __HAS_user_domain
-	printdef("USER_DOMAIN",		user_domain);
-#endif
-	printdef("TSS_FPESAVE",		(int)tss_fpesave);
-	printdef("MM",			(int)mm);
-	printdef("PGD",			(int)pgd);
-
-	printf("#define KSWI_BASE	0x900000\n");
-	printf("#define KSWI_SYS_BASE	0x9F0000\n");
-	printf("#define SYS_ERROR0	0x9F0000\n");
-	return 0;
-}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/getconstants.h linux/arch/arm/lib/getconstants.h
--- v2.1.95/linux/arch/arm/lib/getconstants.h	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/lib/getconstants.h	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-/*
- * *** THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT! ***
- */
-unsigned long addr_limit = 56;
-#define __HAS_addr_limit
-unsigned long tss_memmap = 640;
-#define __HAS_tss_memmap
-unsigned long mm = 1676;
-#define __HAS_mm
-unsigned long pgd = 8;
-#define __HAS_pgd
-unsigned long tss_save = 636;
-#define __HAS_tss_save
-unsigned long tss_fpesave = 492;
-#define __HAS_tss_fpesave
-unsigned long tss_memcmap = 644;
-#define __HAS_tss_memcmap
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S
--- v2.1.95/linux/arch/arm/lib/io-acorn.S	Mon Feb 23 18:12:02 1998
+++ linux/arch/arm/lib/io-acorn.S	Sun Apr 12 11:42:15 1998
@@ -57,7 +57,7 @@
 		mov	r2, r2, lsl#1
 ENTRY(inswb)
 		mov	ip, sp
-		stmfd	sp!, {r4 - r10 ,fp ,ip ,lr ,pc}
+		stmfd	sp!, {r4 - r10, fp, ip, lr, pc}
 		sub	fp, ip, #4
 		addr	r3, r0
 		add	r0, r3, r0, lsl #2
@@ -70,7 +70,7 @@
 		strgeb	r4, [r1], #1
 		movgt	r4, r4, LSR#8
 		strgtb	r4, [r1], #1
-		ldmleea	fp, {r4 - r10, fp, sp, pc}^
+		LOADREGS(leea, fp, {r4 - r10, fp, sp, pc})
 		sub	r2, r2, #2
 Linswok:	mov	ip, #0xFF
 		orr	ip, ip, ip, lsl #8
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/io-ebsa285.S linux/arch/arm/lib/io-ebsa285.S
--- v2.1.95/linux/arch/arm/lib/io-ebsa285.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/lib/io-ebsa285.S	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,109 @@
+#define __ASSEMBLER__
+#include <linux/linkage.h>
+
+ENTRY(insl)
+		add	r0, r0, #0xff000000
+		add	r0, r0, #0x00e00000
+		ands	ip, r1, #3
+		bne	2f
+
+1:		ldr	r3, [r0]
+		str	r3, [r1], #4
+		subs	r2, r2, #1
+		bne	1b
+		mov	pc, lr
+
+2:		cmp	ip, #2
+		ldr	ip, [r0]
+		blt	3f
+		bgt	4f
+
+		strh	ip, [r1], #2
+		mov	ip, ip, lsr #16
+1:		subs	r2, r2, #1
+		ldrne	r3, [r0]
+		orrne	ip, ip, r3, lsl #16
+		strne	ip, [r1], #4
+		movne	ip, r3, lsr #16
+		bne	1b
+		strh	ip, [r1], #2
+		mov	pc, lr
+
+3:		strb	ip, [r1], #1
+		mov	ip, ip, lsr #8
+		strh	ip, [r1], #2
+		mov	ip, ip, lsr #16
+1:		subs	r2, r2, #1
+		ldrne	r3, [r0]
+		orrne	ip, ip, r3, lsl #8
+		strne	ip, [r1], #4
+		movne	ip, r3, lsr #24
+		bne	1b
+		strb	ip, [r1], #1
+		mov	pc, lr
+
+4:		strb	ip, [r1], #1
+		mov	ip, ip, lsr #8
+1:		subs	r2, r2, #1
+		ldrne	r3, [r0]
+		orrne	ip, ip, r3, lsl #24
+		strne	ip, [r1], #4
+		movne	ip, r3, lsr #8
+		bne	1b
+		strb	ip, [r1], #1
+		mov	ip, ip, lsr #8
+		strh	ip, [r1], #2
+		mov	pc, lr
+
+ENTRY(outsl)
+		add	r0, r0, #0xff000000
+		add	r0, r0, #0x00e00000
+		ands	ip, r1, #3
+		bne	2f
+
+1:		ldr	r3, [r1], #4
+		str	r3, [r0]
+		subs	r2, r2, #1
+		bne	1b
+		mov	pc, lr
+
+2:		bic	r1, r1, #3
+		cmp	ip, #2
+		ldr	ip, [r1], #4
+		mov	ip, ip, lsr #16
+		blt	3f
+		bgt	4f
+
+1:		ldr	r3, [r1], #4
+		orr	ip, ip, r3, lsl #16
+		str	ip, [r0]
+		mov	ip, r3, lsr #16
+		subs	r2, r2, #1
+		bne	1b
+		mov	pc, lr
+
+3:		ldr	r3, [r1], #4
+		orr	ip, ip, r3, lsl #8
+		str	ip, [r0]
+		mov	ip, r3, lsr #24
+		subs	r2, r2, #1
+		bne	3b
+		mov	pc, lr
+
+4:		ldr	r3, [r1], #4
+		orr	ip, ip, r3, lsl #24
+		str	ip, [r0]
+		mov	ip, r3, lsr #8
+		subs	r2, r2, #1
+		bne	4b
+		mov	pc, lr
+
+
+ENTRY(outsw)
+ENTRY(outswb)
+		mov	pc, lr
+
+ENTRY(insw)
+ENTRY(inswb)
+		mov	pc, lr
+
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/ll_char_wr.S linux/arch/arm/lib/ll_char_wr.S
--- v2.1.95/linux/arch/arm/lib/ll_char_wr.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/lib/ll_char_wr.S	Sun Apr 12 11:42:15 1998
@@ -3,9 +3,10 @@
  *
  * Copyright (C) 1995, 1996 Russell King.
  *
- * Speedups & 1bpp code (C) 1996 Philip Blundel & Russell King.
+ * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King.
  *
  * 10-04-96	RMK	Various cleanups & reduced register usage.
+ * 08-04-98	RMK	Shifts re-ordered
  */
 
 @ Regs: [] = corruptable
@@ -32,22 +33,22 @@
 @
 @ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
 @
-		eor	ip, r1, #UNDERLINE << 24
+		eor	ip, r1, #UNDERLINE << 9
 /*
  * calculate colours
  */
-		tst	r1, #INVERSE << 24
-		moveq	r2, r1, lsr #8
-		moveq	r3, r1, lsr #16
-		movne	r2, r1, lsr #16
-		movne	r3, r1, lsr #8
+		tst	r1, #INVERSE << 9
+		moveq	r2, r1, lsr #16
+		moveq	r3, r1, lsr #24
+		movne	r2, r1, lsr #24
+		movne	r3, r1, lsr #16
 		and	r3, r3, #255
 		and	r2, r2, #255
 /*
  * calculate offset into character table
  */
-		and	r1, r1, #255
-		mov	r1, r1, lsl #3
+		mov	r1, r1, lsl #23
+		mov	r1, r1, lsr #20
 /*
  * calculate offset required for each row [maybe I should make this an argument to this fn.
  * Have to see what the register usage is like in the calling routines.
@@ -67,7 +68,7 @@
 		add	r0, r0, r5, lsl #3		@ Move to bottom of character
 		add	r1, r1, #7
 		ldrb	r7, [r6, r1]
-		tst	ip, #UNDERLINE << 24
+		tst	ip, #UNDERLINE << 9
 		eoreq	r7, r7, #255
 		teq	r4, #8
 		beq	Lrow8bpplp
@@ -131,7 +132,7 @@
 @
 Lrow1bpp:	add	r6, r6, r1
 		ldmia	r6, {r4, r7}
-		tst	ip, #INVERSE << 24
+		tst	ip, #INVERSE << 9
 		mvnne	r4, r4
 		mvnne	r7, r7
 		strb	r4, [r0], r5
@@ -147,7 +148,7 @@
 		mov	r7, r7, lsr #8
 		strb	r7, [r0], r5
 		mov	r7, r7, lsr #8
-		tst	ip, #UNDERLINE << 24
+		tst	ip, #UNDERLINE << 9
 		mvneq	r7, r7
 		strb	r7, [r0], r5
 		LOADREGS(fd, sp!, {r4 - r7, pc})
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S
--- v2.1.95/linux/arch/arm/lib/memcpy.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/lib/memcpy.S	Sun Apr 12 11:42:15 1998
@@ -8,6 +8,12 @@
 #include <asm/assembler.h>
 #include <linux/linkage.h>
 
+#ifndef ENTRY
+#define ENTRY(x...)				\
+		.globl	_##x;			\
+_##x:
+#endif
+
 		.text
 #define ENTER	\
 		mov	ip,sp	;\
@@ -84,6 +90,7 @@
 		blt	6b
 		ands	ip, r1, #3
 		beq	1b
+
 8:		bic	r1, r1, #3
 		ldr	r7, [r1], #4
 		cmp	ip, #2
@@ -105,14 +112,14 @@
 		subs	r2, r2, #16
 		bge	9b
 		adds	r2, r2, #12
-		blt	1b
+		blt	100f
 10:		mov	r3, r7, lsr #8
 		ldr	r7, [r1], #4
 		orr	r3, r3, r7, lsl #24
 		str	r3, [r0], #4
 		subs	r2, r2, #4
 		bge	10b
-		sub	r1, r1, #3
+100:		sub	r1, r1, #3
 		b	6b
 
 11:		cmp	r2, #12
diff -u --recursive --new-file v2.1.95/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S
--- v2.1.95/linux/arch/arm/lib/uaccess.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/lib/uaccess.S	Sun Apr 12 11:42:15 1998
@@ -13,13 +13,21 @@
 #include <asm/errno.h>
 
 		.text
-
+#ifdef ENTRY
 #define USER(x...)					\
 9999:		x;					\
 		.section __ex_table,"a";		\
 		.align	3;				\
 		.long	9999b,9001f;			\
 		.previous
+#else
+#define USER(x...)					\
+		x
+#define ENTRY(x...)					\
+		.globl	_##x;				\
+_##x:
+#define TESTING
+#endif
 
 #define PAGE_SHIFT 12
 
@@ -278,12 +286,12 @@
 USER(		strgtbt	r3, [r0], #1)			// May fault
 		b	.c2u_finished
 
+#ifndef TESTING
 		.section .fixup,"ax"
 		.align	0
 9001:		LOADREGS(fd,sp!, {r0, r4 - r7, pc})
 		.previous
-
-
+#endif
 
 /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
  * Purpose  : copy a block from user memory to kernel memory
@@ -538,10 +546,12 @@
 		strgtb	r3, [r0], #1
 		b	.cfu_finished
 
+#ifndef TESTING
 		.section .fixup,"ax"
 		.align	0
 9001:		LOADREGS(fd,sp!, {r0, r4 - r7, pc})
 		.previous
+#endif
 
 /* Prototype: int __arch_clear_user(void *addr, size_t sz)
  * Purpose  : clear some user memory
@@ -556,7 +566,7 @@
 		blt	2f
 		ands	ip, r0, #3
 		beq	1f
-		cmp	ip, #1
+		cmp	ip, #2
 USER(		strbt	r2, [r0], #1)
 USER(		strlebt	r2, [r0], #1)
 USER(		strltbt	r2, [r0], #1)
@@ -566,9 +576,9 @@
 USER(		strplt	r2, [r0], #4)
 USER(		strplt	r2, [r0], #4)
 		bpl	1b
-2:		adds	r1, r1, #4		@  3  2  1  0 -1 -2 -3
+		adds	r1, r1, #4		@  3  2  1  0 -1 -2 -3
 USER(		strplt	r2, [r0], #4)
-		tst	r1, #2			@ 1x 1x 0x 0x 1x 1x 0x
+2:		tst	r1, #2			@ 1x 1x 0x 0x 1x 1x 0x
 USER(		strnebt	r2, [r0], #1)
 USER(		strnebt	r2, [r0], #1)
 		tst	r1, #1			@ x1 x0 x1 x0 x1 x0 x1
@@ -576,6 +586,7 @@
 		mov	r0, #0
 		LOADREGS(fd,sp!, {r1, pc})
 
+#ifndef TESTING
 		.section .fixup,"ax"
 		.align	0
 9001:		LOADREGS(fd,sp!, {r0, pc})
@@ -611,21 +622,25 @@
  */
 ENTRY(__arch_strncpy_from_user)
 		stmfd	sp!, {lr}
-		mov	ip, r2
+		add	ip, r1, #1
 1:		subs	r2, r2, #1
 		bmi	2f
 USER(		ldrbt	r3, [r1], #1)
 		strb	r3, [r0], #1
 		teq	r3, #0
 		bne	1b
-2:		subs	r0, ip, r2
-		LOADREGS(fd,sp!, {pc})
+		sub	r0, r1, ip
+		LOADREGS(fd, sp!, {pc})
+2:		sub	ip, ip, #1
+		sub	r0, r1, ip
+		LOADREGS(fd, sp!, {pc})
 
 		.section .fixup,"ax"
 		.align	0
 9001:		mov	r0, #-EFAULT
-		LOADREGS(fd,sp!, {pc})
+		LOADREGS(fd, sp!, {pc})
 		.previous
 
 		.align
+#endif
 
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile
--- v2.1.95/linux/arch/arm/mm/Makefile	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/Makefile	Sun Apr 12 11:42:15 1998
@@ -7,8 +7,14 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
+ifeq ($(MACHINE),a5k)
+MMARCH=arc
+else
+MMARCH=$(MACHINE)
+endif
+
 O_TARGET := mm.o
-O_OBJS   := init.o extable.o fault-$(PROCESSOR).o mm-$(MACHINE).o
+O_OBJS   := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o
 
 ifeq ($(PROCESSOR),armo)
  O_OBJS += proc-arm2,3.o
@@ -28,9 +34,9 @@
 ../lib/constants.h:
 	@$(MAKE) -C ../lib constants.h
 
+ifneq ($(CONFIG_BINUTILS_NEW),y)
 %.o: %.S
-ifndef $(CONFIG_BINUTILS_NEW)
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s
-	$(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.s
-	$(RM) ..tmp.s
+	$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s
+	$(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s
+	$(RM) ..$@.tmp.s
 endif
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.1.95/linux/arch/arm/mm/fault-armv.c	Wed Apr  8 19:36:24 1998
+++ linux/arch/arm/mm/fault-armv.c	Sun Apr 12 11:42:15 1998
@@ -27,13 +27,13 @@
 
 struct pgtable_cache_struct quicklists;
 
-void __bad_pte(pmd_t *pmd)
+void __bad_pmd(pmd_t *pmd)
 {
 	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
 	set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
 }
 
-void __bad_pte_kernel(pmd_t *pmd)
+void __bad_pmd_kernel(pmd_t *pmd)
 {
 	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
 	set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
@@ -72,7 +72,7 @@
 	}
 	free_small_page ((unsigned long) pte);
 	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
+		__bad_pmd(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + offset;
@@ -94,7 +94,7 @@
 	}
 	free_small_page ((unsigned long) pte);
 	if (pmd_bad(*pmd)) {
-		__bad_pte_kernel(pmd);
+		__bad_pmd_kernel(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + offset;
@@ -102,6 +102,19 @@
 
 extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
 
+#ifdef DEBUG
+static int sp_valid (unsigned long *sp)
+{
+	unsigned long addr = (unsigned long) sp;
+
+	if (addr >= 0xb0000000 && addr < 0xd0000000)
+		return 1;
+	if (addr >= 0x03ff0000 && addr < 0x04000000)
+		return 1;
+	return 0;
+}
+#endif
+
 static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
 			       struct task_struct *tsk, struct mm_struct *mm)
 {
@@ -178,6 +191,16 @@
 		printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
 			tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
 #ifdef DEBUG
+		{
+			unsigned int i, j;
+			unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128);
+			for (j = 0; j < 20 && sp_valid (sp); j++) {
+				printk ("%p: ", sp);
+				for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
+					printk ("%08lx ", *sp);
+				printk ("\n");
+			}
+		}
 		show_regs (regs);
 		c_backtrace (regs->ARM_fp, regs->ARM_cpsr);
 #endif
@@ -208,7 +231,6 @@
 {
 	if (user_mode(regs))
 		error_code |= FAULT_CODE_USER;
-
 #define DIE(signr,nam)\
 		force_sig(signr, current);\
 		die_if_kernel(nam, regs, fsr, signr);\
@@ -229,18 +251,22 @@
 	case 11:
 		DIE(SIGSEGV, "Domain fault")
 	case 13:/* permission fault on section */
-#ifndef DEBUG
+#ifdef DEBUG
 		{
-			unsigned int i, j, a;
-static int count=2;
-if (count-- == 0) while (1);
-			a = regs->ARM_sp;
-			for (j = 0; j < 10; j++) {
-				printk ("%08x: ", a);
-				for (i = 0; i < 8; i += 1, a += 4)
-					printk ("%08lx ", *(unsigned long *)a);
+			unsigned int i, j;
+			unsigned long *sp;
+
+			printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n",
+				current->comm, addr, error_code);
+			sp = (unsigned long *) (regs->ARM_sp - 128);
+			for (j = 0; j < 20 && sp_valid (sp); j++) {
+				printk ("%p: ", sp);
+				for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
+					printk ("%08lx ", *sp);
 				printk ("\n");
 			}
+			show_regs (regs);
+			c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
 		}
 #endif
 		DIE(SIGSEGV, "Permission fault")
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.1.95/linux/arch/arm/mm/init.c	Wed Apr  8 19:36:24 1998
+++ linux/arch/arm/mm/init.c	Sun Apr 12 11:42:15 1998
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/smp.h>
+#include <linux/init.h>
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
@@ -102,7 +103,7 @@
 /*
  * paging_init() sets up the page tables...
  */
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
 {
 	extern unsigned long free_area_init(unsigned long, unsigned long);
 
@@ -129,7 +130,7 @@
  * memory is free.  This is done after various parts of the system have
  * claimed their memory after the kernel image.
  */
-void mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
 	extern void sound_init(void);
 	int codepages = 0;
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-a5k.c linux/arch/arm/mm/mm-a5k.c
--- v2.1.95/linux/arch/arm/mm/mm-a5k.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/mm-a5k.c	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-/*
- * arch/arm/mm/mm-a5k.c
- *
- * Extra MM routines for the Archimedes architecture
- *
- * Copyright (C) 1998 Russell King
- */
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-arc.c linux/arch/arm/mm/mm-arc.c
--- v2.1.95/linux/arch/arm/mm/mm-arc.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/mm-arc.c	Sun Apr 12 11:42:15 1998
@@ -5,3 +5,4 @@
  *
  * Copyright (C) 1998 Russell King
  */
+#include <asm/arch/mm-init.h>
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c
--- v2.1.95/linux/arch/arm/mm/mm-ebsa110.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/mm-ebsa110.c	Sun Apr 12 11:42:15 1998
@@ -5,3 +5,22 @@
  *
  * Copyright (C) 1998 Russell King
  */
+
+#include <asm/io.h>
+ 
+/* map in IO */
+void setup_io_pagetables(void)
+{
+	unsigned long address = IO_START;
+	int spi = IO_BASE >> PGDIR_SHIFT;
+
+	pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT |
+					 PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
+
+	while (address < IO_START + IO_SIZE && address) {
+		pgd_val(swapper_pg_dir[spi++]) = address | PMD_TYPE_SECT |
+						PMD_DOMAIN(DOMAIN_IO) |
+						PMD_SECT_AP_WRITE;
+		address += PGDIR_SIZE;
+	}
+}
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-ebsa285.c linux/arch/arm/mm/mm-ebsa285.c
--- v2.1.95/linux/arch/arm/mm/mm-ebsa285.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/mm-ebsa285.c	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,97 @@
+/*
+ * arch/arm/mm/mm-ebsa285.c
+ *
+ * Extra MM routines for the EBSA285 architecture
+ *
+ * Copyright (C) 1998 Russell King
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+ 
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/proc/mm-init.h>
+ 
+/*    Logical    Physical
+ * 0xfff00000	0x40000000	X-Bus
+ * 0xffe00000	0x7c000000	PCI I/O space
+ * 0xfe000000	0x42000000	CSR
+ * 0xfd000000	0x78000000	Outbound write flush
+ * 0xfc000000	0x79000000	PCI IACK/special space
+ * 0xf9000000	0x7a000000	PCI Config type 1
+ * 0xf8000000	0x7b000000	PCI Config type 0
+ */
+
+static struct mapping {
+	unsigned long virtual;
+	unsigned long physical;
+	unsigned long length;
+} io_mapping[] = {
+	/*
+	 * This is to allow us to fiddle with the EEPROM
+	 *  This entry will go away in time
+	 */
+	{ 0xd8000000, 0x41000000, 0x00400000 },
+
+	/*
+	 * These ones are so that we can fiddle
+	 *  with the various cards (eg VGA)
+	 *  until we're happy with them...
+	 */
+	{ 0xdc000000, 0x7c000000, 0x00100000 },
+	{ 0xe0000000, 0x80000000, 0x10000000 },
+
+	{ 0xf8000000, 0x7b000000, 0x01000000 },	/* Type 0 Config */
+
+	{ 0xf9000000, 0x7a000000, 0x01000000 },	/* Type 1 Config */
+
+	{ 0xfc000000, 0x79000000, 0x01000000 },	/* PCI IACK	 */
+	{ 0xfd000000, 0x78000000, 0x01000000 },	/* Outbound wflsh*/
+	{ 0xfe000000, 0x42000000, 0x01000000 },	/* CSR		 */
+	{ 0xffe00000, 0x7c000000, 0x00100000 },	/* PCI I/O	 */
+	{ 0xfff00000, 0x40000000, 0x00100000 },	/* X-Bus	 */
+};
+
+#define SIZEOFIO (sizeof(io_mapping) / sizeof(io_mapping[0]))
+
+/* map in IO */
+unsigned long setup_io_pagetables(unsigned long start_mem)
+{
+	struct mapping *mp;
+	int i;
+
+	for (i = 0, mp = io_mapping; i < SIZEOFIO; i++, mp++) {
+		while ((mp->virtual & 1048575 || mp->physical & 1048575) && mp->length >= PAGE_SIZE) {
+			alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+					PTE_AP_WRITE);
+
+			mp->length -= PAGE_SIZE;
+			mp->virtual += PAGE_SIZE;
+			mp->physical += PAGE_SIZE;
+		}
+
+		while (mp->length >= 1048576) {
+if (mp->virtual > 0xf0000000)
+			alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+					   PMD_SECT_AP_WRITE);
+else
+alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_USER, PMD_SECT_AP_WRITE | PMD_SECT_AP_READ);
+
+			mp->length -= 1048576;
+			mp->virtual += 1048576;
+			mp->physical += 1048576;
+		}
+
+		while (mp->length >= PAGE_SIZE) {
+			alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+					PTE_AP_WRITE);
+
+			mp->length -= PAGE_SIZE;
+			mp->virtual += PAGE_SIZE;
+			mp->physical += PAGE_SIZE;
+		}
+	}
+	return start_mem;
+}
+
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-nexuspci.c linux/arch/arm/mm/mm-nexuspci.c
--- v2.1.95/linux/arch/arm/mm/mm-nexuspci.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/mm-nexuspci.c	Sun Apr 12 11:42:15 1998
@@ -1,7 +1,28 @@
 /*
  * arch/arm/mm/mm-nexuspci.c
+ *  from arch/arm/mm/mm-ebsa110.c
  *
- * Extra MM routines for the Archimedes architecture
+ * Extra MM routines for the NexusPCI architecture
  *
  * Copyright (C) 1998 Russell King
  */
+
+#include <asm/io.h>
+ 
+/* map in IO */
+void setup_io_pagetables(void)
+{
+	unsigned long address = IO_START;
+	int spi = IO_BASE >> PGDIR_SHIFT;
+
+	pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT |
+					 PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
+
+	while (address < IO_START + IO_SIZE && address) {
+		pgd_val(swapper_pg_dir[spi++]) = address | PMD_TYPE_SECT |
+						PMD_DOMAIN(DOMAIN_IO) |
+						PMD_SECT_AP_WRITE;
+		address += PGDIR_SIZE;
+	}
+}
+
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c
--- v2.1.95/linux/arch/arm/mm/mm-rpc.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/mm-rpc.c	Sun Apr 12 11:42:15 1998
@@ -6,7 +6,14 @@
  * Copyright (C) 1998 Russell King
  */
 
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
 #include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/proc/mm-init.h>
+#include <asm/arch/mm-init.h>
 
 #define NR_DRAM_BANKS	4
 #define NR_VRAM_BANKS	1
@@ -21,8 +28,8 @@
 #define FIRST_DRAM_ADDR	0x10000000
 
 #define PHYS_TO_BANK(x)	(((x) >> BANK_SHIFT) & (NR_DRAM_BANKS - 1))
-#define BANK_TO_PHYS(x)	((FIRST_DRAM_ADDR) +
-			    (((x) - FIRST_DRAM_BANK) << BANK_SHIFT)
+#define BANK_TO_PHYS(x)	((FIRST_DRAM_ADDR) + \
+			    (((x) - FIRST_DRAM_BANK) << BANK_SHIFT))
 
 struct ram_bank {
 	unsigned int virt_addr;		/* virtual address of the *end* of this bank + 1 */
@@ -75,6 +82,56 @@
 		rambank[bank].virt_addr   = PAGE_OFFSET + bytes;
 	}
 
-	drambank[4].phys_offset = 0xd6000000;
-	drambank[4].virt_addr   = 0xd8000000;
+	rambank[FIRST_VRAM_BANK].phys_offset = 0xd6000000;
+	rambank[FIRST_VRAM_BANK].virt_addr   = 0xd8000000;
+
+	current->tss.memmap = __virt_to_phys((unsigned long)swapper_pg_dir);
+}
+
+static struct mapping {
+	unsigned long virtual;
+	unsigned long physical;
+	unsigned long length;
+} io_mapping[] = {
+	{ SCREEN2_BASE,	SCREEN_START,	2*1048576	},	/* VRAM		*/
+	{ IO_BASE,	IO_START,	IO_SIZE		}	/* IO space	*/
+};
+
+#define SIZEOFIO (sizeof(io_mapping) / sizeof(io_mapping[0]))
+
+/* map in IO */
+unsigned long setup_io_pagetables(unsigned long start_mem)
+{
+	struct mapping *mp;
+	int i;
+
+	for (i = 0, mp = io_mapping; i < SIZEOFIO; i++, mp++) {
+		while ((mp->virtual & 1048575 || mp->physical & 1048575) && mp->length >= PAGE_SIZE) {
+			alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+					PTE_AP_WRITE);
+
+			mp->length -= PAGE_SIZE;
+			mp->virtual += PAGE_SIZE;
+			mp->physical += PAGE_SIZE;
+		}
+
+		while (mp->length >= 1048576) {
+			alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+					   PMD_SECT_AP_WRITE);
+			mp->length -= 1048576;
+			mp->virtual += 1048576;
+			mp->physical += 1048576;
+		}
+
+		while (mp->length >= PAGE_SIZE) {
+			alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO,
+					PTE_AP_WRITE);
+
+			mp->length -= PAGE_SIZE;
+			mp->virtual += PAGE_SIZE;
+			mp->physical += PAGE_SIZE;
+		}
+	}
+
+	return start_mem;
 }
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.1.95/linux/arch/arm/mm/proc-arm6,7.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/proc-arm6,7.S	Sun Apr 12 11:42:15 1998
@@ -72,10 +72,10 @@
 		stmfd	sp!, {ip}			@ Save cpsr_SVC
 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r0, [r1, #ADDR_LIMIT]
+		ldr	r0, [r1, #TSK_ADDR_LIMIT]
 		teq	r0, #0
-		moveq	r0, #KERNEL_DOMAIN
-		movne	r0, #USER_DOMAIN
+		moveq	r0, #DOM_KERNELDOMAIN
+		movne	r0, #DOM_USERDOMAIN
 		mcr	p15, 0, r0, c3, c0		@ Set domain reg
 		ldr	r0, [r1, #TSS_MEMMAP]		@ Page table pointer
 		mov	r1, #0
diff -u --recursive --new-file v2.1.95/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.1.95/linux/arch/arm/mm/proc-sa110.S	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/proc-sa110.S	Sun Apr 12 11:42:15 1998
@@ -161,8 +161,6 @@
 		blt	1b
 		mcr	p15, 0, r0, c7, c5, 0		@ flush I cache
 		mov	pc, lr
-
-@LC0:		.word	_current
 /*
  * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
  *
@@ -183,10 +181,10 @@
 		stmfd	sp!, {ip}			@ Save cpsr_SVC
 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r0, [r1, #ADDR_LIMIT]
+		ldr	r0, [r1, #TSK_ADDR_LIMIT]
 		teq	r0, #0
-		moveq	r0, #KERNEL_DOMAIN
-		movne	r0, #USER_DOMAIN
+		moveq	r0, #DOM_KERNELDOMAIN
+		movne	r0, #DOM_USERDOMAIN
 		mcr	p15, 0, r0, c3, c0		@ Set segment
 		ldr	r0, [r1, #TSS_MEMMAP]		@ Page table pointer
 		ldr	r3, =Lclean_switch
@@ -227,8 +225,6 @@
 		mov	r2, r2, lsr #19			@ b1 = L
 		and	r3, r2, #0x69 << 2
 		and	r2, r2, #2
-//		teq	r3, #0x21 << 2
-//		orreq	r2, r2, #1			@ b0 = {LD,ST}RT
 		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 		and	r1, r1, #255
 		mov	pc, lr
diff -u --recursive --new-file v2.1.95/linux/arch/arm/vmlinux.lds linux/arch/arm/vmlinux.lds
--- v2.1.95/linux/arch/arm/vmlinux.lds	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/vmlinux.lds	Sun Apr 12 11:42:15 1998
@@ -1,4 +1,5 @@
-/* ld script to make i386 Linux kernel
+/* ld script to make ARM Linux kernel
+ * taken from the i386 version
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")
@@ -34,11 +35,15 @@
 
   _edata = .;			/* End of data section */
 
-  . = ALIGN(4096);		/* Init code and data */
+  /* This has to be aligned to a page boundary to do us any good.  This
+     alignment is overkill for ARM6 up but needed for ARM3.  Since all this
+     data will be thrown away I don't think the extra padding will hurt.
+       -- pb */
+  . = ALIGN(32768);		/* Init code and data */
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
+  . = ALIGN(32768);
   __init_end = .;
 
   __bss_start = .;		/* BSS */
diff -u --recursive --new-file v2.1.95/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.1.95/linux/arch/i386/kernel/ldt.c	Tue Mar 10 10:03:30 1998
+++ linux/arch/i386/kernel/ldt.c	Tue Apr 14 13:05:25 1998
@@ -18,7 +18,7 @@
 
 static int read_ldt(void * ptr, unsigned long bytecount)
 {
-	void * address = current->ldt;
+	void * address = current->mm->segments;
 	unsigned long size;
 
 	if (!ptr)
@@ -37,6 +37,7 @@
 {
 	struct modify_ldt_ldt_s ldt_info;
 	unsigned long *lp;
+	struct mm_struct * mm;
 	int error, i;
 
 	if (bytecount != sizeof(ldt_info))
@@ -48,19 +49,32 @@
 	if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES)
 		return -EINVAL;
 
-	if (!current->ldt) {
+	mm = current->mm;
+
+	/*
+	 * Horrible dependencies! Try to get rid of this. This is wrong,
+	 * as it only reloads the ldt for the first process with this
+	 * mm. The implications are that you should really make sure that
+	 * you have a ldt before you do the first clone(), otherwise
+	 * you get strange behaviour (the kernel is safe, it's just user
+	 * space strangeness).
+	 *
+	 * For no good reason except historical, the GDT index of the LDT
+	 * is chosen to follow the index number in the task[] array.
+	 */
+	if (!mm->segments) {
 		for (i=1 ; i<NR_TASKS ; i++) {
-			if (task[i] == current) {
-				if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
+			if (task[i]->mm == mm) {
+				if (!(mm->segments = (void *) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
 					return -ENOMEM;
-				memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
-				set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
+				memset(mm->segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+				set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, mm->segments, LDT_ENTRIES);
 				load_ldt(i);
 			}
 		}
 	}
 	
-	lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
+	lp = (unsigned long *) (LDT_ENTRY_SIZE * ldt_info.entry_number + (unsigned long) mm->segments);
    	/* Allow LDTs to be cleared by the user. */
    	if (ldt_info.base_addr == 0 && ldt_info.limit == 0
 		&& (oldmode ||
diff -u --recursive --new-file v2.1.95/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.95/linux/arch/i386/kernel/process.c	Wed Apr  1 20:11:47 1998
+++ linux/arch/i386/kernel/process.c	Tue Apr 14 12:24:06 1998
@@ -418,43 +418,37 @@
 		0xffff & regs->xds,0xffff & regs->xes);
 }
 
-/*
- * Free current thread data structures etc..
- */
-
-void exit_thread(void)
+void release_segments(struct mm_struct *mm)
 {
-	/* forget lazy i387 state */
-	if (last_task_used_math == current)
-		last_task_used_math = NULL;
+	void * ldt;
+
 	/* forget local segments */
 	__asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs ; lldt %w0"
 		: /* no outputs */
 		: "r" (0));
 	current->tss.ldt = 0;
-	if (current->ldt) {
-		void * ldt = current->ldt;
-		current->ldt = NULL;
+
+	ldt = mm->segments;
+	if (ldt) {
+		mm->segments = NULL;
 		vfree(ldt);
 	}
 }
 
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+	/* forget lazy i387 state */
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
+}
+
 void flush_thread(void)
 {
 	int i;
 
-	if (current->ldt) {
-		free_page((unsigned long) current->ldt);
-		current->ldt = NULL;
-		for (i=1 ; i<NR_TASKS ; i++) {
-			if (task[i] == current)  {
-				set_ldt_desc(gdt+(i<<1)+
-					     FIRST_LDT_ENTRY,&default_ldt, 1);
-				load_ldt(i);
-			}
-		}	
-	}
-
 	for (i=0 ; i<8 ; i++)
 		current->debugreg[i] = 0;
 
@@ -479,13 +473,30 @@
 {
 }
 
+void copy_segments(int nr, struct task_struct *p, struct mm_struct *new_mm)
+{
+	int ldt_size = 1;
+	void * ldt = &default_ldt;
+	struct mm_struct * old_mm = current->mm;
+
+	p->tss.ldt = _LDT(nr);
+	if (old_mm->segments) {
+		new_mm->segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+		if (new_mm->segments) {
+			ldt = new_mm->segments;
+			ldt_size = LDT_ENTRIES;
+			memcpy(ldt, old_mm->segments, LDT_ENTRIES*LDT_ENTRY_SIZE);
+		}
+	}
+	set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, ldt, LDT_ENTRIES);
+}
+
 int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
 	struct task_struct * p, struct pt_regs * regs)
 {
 	struct pt_regs * childregs;
 
 	p->tss.tr = _TSS(nr);
-	p->tss.ldt = _LDT(nr);
 	p->tss.es = __KERNEL_DS;
 	p->tss.cs = __KERNEL_CS;
 	p->tss.ss = __KERNEL_DS;
@@ -508,16 +519,8 @@
 	childregs->eax = 0;
 	childregs->esp = esp;
 	p->tss.back_link = 0;
-	if (p->ldt) {
-		p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-		if (p->ldt != NULL)
-			memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
-	}
 	set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
-	if (p->ldt)
-		set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
-	else
-		set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
+
 	/*
 	 * a bitmap offset pointing outside of the TSS limit causes a nicely
 	 * controllable SIGSEGV. The first sys_ioperm() call sets up the
diff -u --recursive --new-file v2.1.95/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c
--- v2.1.95/linux/arch/i386/lib/checksum.c	Fri Jan 30 15:50:56 1998
+++ linux/arch/i386/lib/checksum.c	Mon Apr 13 14:42:33 1998
@@ -123,6 +123,8 @@
 unsigned int csum_partial_copy_generic (const char *src, char *dst,
 				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
 {
+    __u32 tmp_var;
+
     __asm__ __volatile__ ( "
 		testl $2, %%edi		# Check alignment. 
 		jz 2f			# Jump if alignment is ok.
@@ -137,7 +139,7 @@
 		addw %%bx, %%ax	
 		adcl $0, %%eax
 	2:
-		pushl %%ecx
+		movl %%ecx, %8
 		shrl $5, %%ecx
 		jz 2f
 		testl %%esi, %%esi
@@ -174,7 +176,7 @@
 		dec %%ecx
 		jne 1b
 		adcl $0, %%eax
-	2:	popl %%edx
+	2:	movl %8, %%edx
 		movl %%edx, %%ecx
 		andl $0x1c, %%edx
 		je 4f
@@ -231,9 +233,10 @@
 ################################################
 
 "
-	: "=a" (sum), "=m" (src_err_ptr), "=m" (dst_err_ptr)
-	:  "0" (sum), "c" (len), "S" (src), "D" (dst),
-		"i" (-EFAULT)
+	: "=a" (sum)
+	: "m" (src_err_ptr), "m" (dst_err_ptr),
+	  "0" (sum), "c" (len), "S" (src), "D" (dst),
+		"i" (-EFAULT), "m"(tmp_var)
 	: "bx", "cx", "dx", "si", "di" );
 
     return(sum);
diff -u --recursive --new-file v2.1.95/linux/arch/i386/math-emu/fpu_system.h linux/arch/i386/math-emu/fpu_system.h
--- v2.1.95/linux/arch/i386/math-emu/fpu_system.h	Tue Dec  9 17:57:09 1997
+++ linux/arch/i386/math-emu/fpu_system.h	Tue Apr 14 12:16:29 1998
@@ -20,7 +20,7 @@
    of the stack frame of math_emulate() */
 #define SETUP_DATA_AREA(arg)	FPU_info = (struct info *) &arg
 
-#define LDT_DESCRIPTOR(s)	(current->ldt[(s) >> 3])
+#define LDT_DESCRIPTOR(s)	(((struct ldt_struct *)current->mm->segments)[(s) >> 3])
 #define SEG_D_SIZE(x)		((x).b & (3 << 21))
 #define SEG_G_BIT(x)		((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)	(((x).b & (1 << 23)) ? 4096 : 1)
diff -u --recursive --new-file v2.1.95/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.1.95/linux/drivers/block/ide-disk.c	Fri Apr 10 13:03:48 1998
+++ linux/drivers/block/ide-disk.c	Fri Apr 10 16:05:01 1998
@@ -112,7 +112,6 @@
 	int i;
 	unsigned int msect, nsect;
 	struct request *rq;
-	unsigned long flags;
 
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
 		ide_error(drive, "read_intr", stat);
@@ -162,7 +161,6 @@
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = hwgroup->rq;
-	unsigned long flags;
 	int error = 0;
 
 	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
@@ -239,7 +237,6 @@
 	int i;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = &hwgroup->wrq;
-	unsigned long flags;
 	int error = 0;
 
 	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
diff -u --recursive --new-file v2.1.95/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.95/linux/drivers/block/ide.c	Fri Apr 10 13:03:48 1998
+++ linux/drivers/block/ide.c	Fri Apr 10 16:04:41 1998
@@ -1267,7 +1267,6 @@
 
 static void do_ide_intr (int irq, void *dev_id, struct pt_regs *regs)
 {
-	unsigned long flags;
 	ide_hwgroup_t *hwgroup = dev_id;
 	ide_hwif_t *hwif = hwgroup->hwif;
 	ide_handler_t *handler;
diff -u --recursive --new-file v2.1.95/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.95/linux/drivers/block/ll_rw_blk.c	Fri Apr 10 13:03:48 1998
+++ linux/drivers/block/ll_rw_blk.c	Mon Apr 13 13:35:10 1998
@@ -149,11 +149,6 @@
 		}
 	}
 	if (queue_new_request)
-		/*
-		 * request functions are smart enough to notice a change
-		 * in the request queue, calling them without the spinlock
-		 * is OK, i think. <-- FIXME: [is this true? --mingo]
-		 */
 		(dev->request_fn)();
 
 	spin_unlock_irqrestore(&io_request_lock,flags);
@@ -348,10 +343,6 @@
 	if (scsi_blk_major(MAJOR(req->rq_dev)))
 		queue_new_request = 1;
 out:
-	/*
-	 * request_fn() is usually a quite complex and slow function,
-	 * we want to call it with no spinlocks held
-	 */
 	if (queue_new_request)
 		(dev->request_fn)();
 	spin_unlock_irqrestore(&io_request_lock,flags);
diff -u --recursive --new-file v2.1.95/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c
--- v2.1.95/linux/drivers/block/rz1000.c	Mon Apr  6 17:40:59 1998
+++ linux/drivers/block/rz1000.c	Fri Apr 10 22:08:08 1998
@@ -84,9 +84,9 @@
 {
 	struct pci_dev *dev = NULL;
 
-	while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_PD_PCTECH_RZ1000, dev))
+	while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))
 		init_rz1000 (dev, "RZ1000");
-	while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_PD_PCTECH_RZ1001, dev))
+	while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))
 		init_rz1000 (dev, "RZ1001");
 }
 
diff -u --recursive --new-file v2.1.95/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.1.95/linux/drivers/char/bttv.c	Wed Apr  8 19:36:25 1998
+++ linux/drivers/char/bttv.c	Mon Apr 13 17:03:04 1998
@@ -34,7 +34,6 @@
 
 #include <linux/module.h>
 #include <linux/bios32.h>
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
diff -u --recursive --new-file v2.1.95/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.95/linux/drivers/char/cyclades.c	Mon Apr  6 17:40:59 1998
+++ linux/drivers/char/cyclades.c	Fri Apr 10 15:35:36 1998
@@ -1,6 +1,9 @@
 #define BLOCKMOVE
+#define	NEW_INTR_FLOW
+#define	Z_WAKE
+#define	NEW_PCI
 static char rcsid[] =
-"$Revision: 2.1.1.1 $$Date: 1997/12/03 17:31:19 $";
+"$Revision: 2.2.1.1 $$Date: 1998/03/19 16:43:12 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -30,11 +33,28 @@
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.1.1  1998/03/19 16:43:12 ivan
+ * added conditional compilation for new/old PCI structure support;
+ * removed kernel series (2.0.x / 2.1.x) conditional compilation.
+ *
+ * Revision 2.1.1.3  1998/03/16 18:01:12 ivan
+ * cleaned up the data loss fix;
+ * fixed XON/XOFF handling once more (Cyclades-Z);
+ * general revision in the driver routines;
+ * introduction of a mechanism to prevent data loss with slow 
+ * printers, by forcing a delay before closing the port.
+ *
+ * Revision 2.1.1.2  1998/02/17 16:50:00 ivan
+ * fixed detection/handling of new CD1400 in Ye boards;
+ * fixed XON/XOFF handling (Cyclades-Z);
+ * fixed data loss caused by a premature port close;
+ * introduction of a flag that holds the CD1400 version ID per port
+ * (used by the CYGETCD1400VER new ioctl).
+ *
  * Revision 2.1.1.1  1997/12/03 17:31:19 ivan
- * Code review for the module cleanup routine (fixed memory leak);
+ * Code review for the module cleanup routine;
  * fixed RTS and DTR status report for new CD1400's in get_modem_info;
- * purged conditional code for older kernels;
- * includes anonymous changes regarding signal_pending
+ * includes anonymous changes regarding signal_pending.
  * 
  * Revision 2.1  1997/11/01 17:42:41 ivan
  * Changes in the driver to support Alpha systems (except 8Zo V_1);
@@ -461,17 +481,16 @@
 #define ZO_V2	1
 #define ZE_V1	2
 
-#define SERIAL_PARANOIA_CHECK
-#undef  SERIAL_DEBUG_OPEN
-#undef  SERIAL_DEBUG_THROTTLE
-#undef  SERIAL_DEBUG_OTHER
-#undef  SERIAL_DEBUG_IO
-#undef  SERIAL_DEBUG_COUNT
-#undef  SERIAL_DEBUG_DTR
-#undef  CYCLOM_16Y_HACK
-#undef  CYCLOM_ENABLE_MONITORING
-#undef  CY_PCI_DEBUG
-
+#define	SERIAL_PARANOIA_CHECK
+#undef	SERIAL_DEBUG_OPEN
+#undef	SERIAL_DEBUG_THROTTLE
+#undef	SERIAL_DEBUG_OTHER
+#undef	SERIAL_DEBUG_IO
+#undef	SERIAL_DEBUG_COUNT
+#undef	SERIAL_DEBUG_DTR
+#undef	CYCLOM_16Y_HACK
+#undef	CYCLOM_ENABLE_MONITORING
+#undef	CY_PCI_DEBUG
 
 #if 0
 #define PAUSE __asm__("nop");
@@ -525,6 +544,9 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#ifndef NEW_PCI
+#include <linux/bios32.h>
+#endif
 #include <linux/pci.h>
 
 #include <linux/version.h>
@@ -566,10 +588,9 @@
 #define SERIAL_TYPE_NORMAL  1
 #define SERIAL_TYPE_CALLOUT 2
 
+static DECLARE_TASK_QUEUE(tq_cyclades);
 
-DECLARE_TASK_QUEUE(tq_cyclades);
-
-struct tty_driver cy_serial_driver, cy_callout_driver;
+static struct tty_driver cy_serial_driver, cy_callout_driver;
 
 static volatile int cy_irq_triggered;
 static volatile int cy_triggered;
@@ -856,7 +877,6 @@
     run_task_queue(&tq_cyclades);
 } /* do_cyclades_bh */
 
-
 static void
 do_softint(void *private_)
 {
@@ -883,6 +903,11 @@
         }
         wake_up_interruptible(&tty->write_wait);
     }
+#ifdef Z_WAKE
+    if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->shutdown_wait);
+    }
+#endif
 } /* do_softint */
 
 
@@ -1014,6 +1039,7 @@
   unsigned long   	timeout;
   volatile ucchar 	*base_addr;
   int           	index;
+  unsigned long		flags;
 
     index = 0;  /* IRQ probing is only for ISA */
     base_addr = address;
@@ -1023,13 +1049,13 @@
      * Enable interrupts and see who answers
      */
     cy_irq_triggered = 0;
-    cli();
+    save_flags(flags); cli();
         cy_writeb((u_long)base_addr+(CyCAR<<index), 0);
         cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
         cy_writeb((u_long)base_addr+(CySRER<<index), 
              cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
         probe_ready = 1;
-    sti();
+    restore_flags(flags);
     
     timeout = jiffies+(HZ/50);
     while (timeout >= jiffies) {
@@ -1050,7 +1076,7 @@
   int                   irq_lines = 0;
   int                   irq_try_1 = 0, irq_try_2 = 0;
   int                   retries;
-  unsigned long flags;
+  unsigned long		flags;
 
     /* Turn on interrupts (they may be off) */
     save_flags(flags); sti();
@@ -1346,7 +1372,7 @@
 			/* delay a bit */
                         cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
                         cy_writeb((u_long)base_addr + (CyTDR<<index), 0x82);
-                        if (cy_readb(base_addr + (CyGFRCR<<index)) >= 0x48 ) {
+                        if (info->chip_rev >= CD1400_REV_J ) {
 			    /* It is a CD1400 rev. J or later */
                             cy_writeb((u_long)base_addr + (CyTDR<<index), 
 				      info->x_break*500/HZ);
@@ -1361,7 +1387,30 @@
                         info->x_break = 0;
                     }
 
+#ifdef NEW_INTR_FLOW
+                    if (!info->xmit_cnt){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+                        goto txdone;
+                    }
+                    if (info->xmit_buf == 0){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
+                    if (info->tty->stopped || info->tty->hw_stopped){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
+#endif
                     while (char_count-- > 0){
+#ifdef NEW_INTR_FLOW
+                        if (!info->xmit_cnt){
+                            goto txdone;
+                        }
+#else
                         if (!info->xmit_cnt){
                             cy_writeb((u_long)base_addr+(CySRER<<index),
                                cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
@@ -1375,8 +1424,8 @@
                         if (info->tty->stopped || info->tty->hw_stopped){
                             cy_writeb((u_long)base_addr+(CySRER<<index),
                                cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
-                            goto txdone;
-                        }
+			}
+#endif
                         /* Because the Embedded Transmit Commands have
                            been enabled, we must check to see if the
 			   escape character, NULL, is being sent.  If it
@@ -1412,7 +1461,6 @@
                     if (info->xmit_cnt < WAKEUP_CHARS) {
                         cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
                     }
-
         txend:
                     /* end of service */
                     cy_writeb((u_long)base_addr+(CyTIR<<index), 
@@ -1491,7 +1539,6 @@
    /* clear interrupts */
    cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0);
                                 /* Cy_ClrIntr is 0x1800 */
-
 } /* cyy_interrupt */
 
 /***********************************************************/
@@ -1714,6 +1761,11 @@
 	        break;
 	    case C_CM_MDSR:
 	        break;
+#ifdef Z_WAKE
+	    case C_CM_IOCTLW:
+		cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+	        break;
+#endif
 	    case C_CM_FATAL:
 		/* should do something with this !!! */
 	        break;
@@ -1994,7 +2046,13 @@
 #endif
 
 	cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
-	cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD|C_IN_MCTS);
+#ifdef Z_WAKE
+	cy_writel(&ch_ctrl[channel].intr_enable, 
+		  C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW);
+#else
+	cy_writel(&ch_ctrl[channel].intr_enable, 
+		  C_IN_MDCD|C_IN_MCTS);
+#endif
 	retval = cyz_issue_cmd( &cy_card[card],
 	    channel, C_CM_IOCTL, 0L);	/* was C_CM_RESET */
 	if (retval != 0){
@@ -2089,20 +2147,14 @@
 		card, chip, channel, (long)base_addr);
 #endif
 
-	/* REALLY SHOULD WAIT FOR LAST CHARACTER TO BE
-	   SENT BEFORE DROPPING THE LINE !!!  (Perhaps
-	   set some flag that is read when XMTY happens.)
-	   Other choices are to delay some fixed interval
-	   or schedule some later processing.
-	 */
 	save_flags(flags); cli();
+
 	    if (info->xmit_buf){
 		unsigned char * temp;
 		temp = info->xmit_buf;
 		info->xmit_buf = 0;
 		free_page((unsigned long) temp);
 	    }
-
 	    cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 	    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 		cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -2147,14 +2199,15 @@
 	board_ctrl = &(zfw_ctrl->board_ctrl);
 	ch_ctrl = zfw_ctrl->ch_ctrl;
 
-
 	save_flags(flags); cli();
+
 	    if (info->xmit_buf){
 		unsigned char * temp;
 		temp = info->xmit_buf;
 		info->xmit_buf = 0;
 		free_page((unsigned long) temp);
 	    }
+	    
 	    if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 		cy_writel((u_long)&ch_ctrl[channel].rs_control,
                    (uclong)(cy_readl(&ch_ctrl[channel].rs_control) & 
@@ -2162,14 +2215,13 @@
 		retval = cyz_issue_cmd(&cy_card[info->card],
 			channel, C_CM_IOCTLM, 0L);
 		if (retval != 0){
-		    printk("cyc:shutdown retval was %x\n",
-		        retval);
+		    printk("cyc:shutdown retval (2) was %x\n", retval);
 		}
 #ifdef SERIAL_DEBUG_DTR
 		printk("cyc:shutdown dropping Z DTR\n");
 #endif
 	    }
-
+	    
 	    if (info->tty){
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
 	    }
@@ -2206,8 +2258,10 @@
      * If the device is in the middle of being closed, then block
      * until it's done, and then try again.
      */
-    if (info->flags & ASYNC_CLOSING) {
-        interruptible_sleep_on(&info->close_wait);
+    if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+	if (info->flags & ASYNC_CLOSING) {
+            interruptible_sleep_on(&info->close_wait);
+	}
         if (info->flags & ASYNC_HUP_NOTIFY){
             return -EAGAIN;
         }else{
@@ -2241,7 +2295,8 @@
      * If non-blocking mode is set, then make the check up front
      * and then exit.
      */
-    if (filp->f_flags & O_NONBLOCK) {
+    if ((filp->f_flags & O_NONBLOCK) ||
+	(tty->flags & (1 << TTY_IO_ERROR))) {
         if (info->flags & ASYNC_CALLOUT_ACTIVE){
             return -EBUSY;
         }
@@ -2262,7 +2317,10 @@
     printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
            info->line, info->count);/**/
 #endif
-    info->count--;
+    save_flags(flags); cli();
+    if (!tty_hung_up_p(filp))
+	info->count--;
+    restore_flags(flags);
 #ifdef SERIAL_DEBUG_COUNT
     printk("cyc block_til_ready: (%d): decrementing count to %d\n",
         current->pid, info->count);
@@ -2568,8 +2626,54 @@
         info->normal_termios = *tty->termios;
     if (info->flags & ASYNC_CALLOUT_ACTIVE)
         info->callout_termios = *tty->termios;
-    if (info->flags & ASYNC_INITIALIZED)
-        tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */
+
+    /*
+    * Now we wait for the transmit buffer to clear; and we notify
+    * the line discipline to only process XON/XOFF characters.
+    */
+    tty->closing = 1;
+    if (info->closing_wait2 != 0) { /* The port's being forced to wait, 
+				       independent on the port settings */
+	tty_wait_until_sent(tty, info->closing_wait2*HZ);
+    } else {
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+	    tty_wait_until_sent(tty, info->closing_wait*HZ);
+    }
+
+    /* Waiting for on-board buffers to be empty before closing the port */
+    if (!IS_CYC_Z(cy_card[info->card])) {
+#ifdef NEW_INTR_FLOW
+	unsigned char *base_addr = (unsigned char *) 
+					cy_card[info->card].base_addr;
+	int index = cy_card[info->card].bus_index;
+
+	if (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
+	    /* Interrupts are enabled, so go to sleep */
+            interruptible_sleep_on(&info->shutdown_wait);
+	}
+#endif
+    } else {
+#ifdef Z_WAKE
+	unsigned char *base_addr = (unsigned char *) 
+					cy_card[info->card].base_addr;
+	struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+	struct ZFW_CTRL *zfw_ctrl = 
+	    (struct ZFW_CTRL *) (base_addr + cy_readl(&firm_id->zfwctrl_addr));
+	struct CH_CTRL *ch_ctrl = zfw_ctrl->ch_ctrl;
+	int channel = info->line - cy_card[info->card].first_line;
+	int retval;
+
+	if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+	    retval = cyz_issue_cmd(&cy_card[info->card], channel, 
+				   C_CM_IOCTLW, 0L);
+	    if (retval != 0){
+		printk("cyc:shutdown retval (1) was %x\n", retval);
+	    }
+	    interruptible_sleep_on(&info->shutdown_wait);
+	}
+#endif
+    }
+
     shutdown(info);
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
@@ -2634,14 +2738,13 @@
 
     if (from_user)
 	down(&tmp_buf_sem);
+    save_flags(flags);               
     while (1) {
-        save_flags(flags); cli();               
+        cli();               
         c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                            SERIAL_XMIT_SIZE - info->xmit_head));
-        if (c <= 0){
-            restore_flags(flags);
+        if (c <= 0)
             break;
-        }
 
         if (from_user) {
             copy_from_user(tmp_buf, buf, c);
@@ -2664,13 +2767,10 @@
     }
     if (from_user)
 	up(&tmp_buf_sem);
-
-
-    if (info->xmit_cnt
-    && !tty->stopped
-    && !tty->hw_stopped ) {
+    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
         start_xmit(info);
     }
+    restore_flags(flags);
     return total;
 } /* cy_write */
 
@@ -2788,16 +2888,47 @@
 cy_chars_in_buffer(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  int card, channel;
                                 
-#ifdef SERIAL_DEBUG_IO
-    printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
-        info->line, info->xmit_cnt); /* */
-#endif
-
     if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
         return 0;
 
-    return info->xmit_cnt;
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+
+    if (!IS_CYC_Z(cy_card[card])) {
+#ifdef SERIAL_DEBUG_IO
+	printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+		info->line, info->xmit_cnt); /* */
+#endif
+	return info->xmit_cnt;
+    } else {
+	static volatile struct FIRM_ID *firm_id;
+	static volatile struct ZFW_CTRL *zfw_ctrl;
+	static volatile struct CH_CTRL *ch_ctrl;
+	static volatile struct BUF_CTRL *buf_ctrl;
+	int char_count;
+	volatile uclong tx_put, tx_get, tx_bufsize;
+
+	firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+	zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+				cy_readl(&firm_id->zfwctrl_addr));
+	ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+	buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+	tx_get = cy_readl(&buf_ctrl->tx_get);
+	tx_put = cy_readl(&buf_ctrl->tx_put);
+	tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+	if (tx_put >= tx_get)
+	    char_count = tx_put - tx_get;
+	else
+	    char_count = tx_put - tx_get + tx_bufsize;
+#ifdef SERIAL_DEBUG_IO
+	printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+		info->line, info->xmit_cnt + char_count); /* */
+#endif
+	return (info->xmit_cnt + char_count);
+    }
 } /* cy_chars_in_buffer */
 
 
@@ -2818,7 +2949,8 @@
   unsigned long flags;
   unsigned char *base_addr;
   int card,chip,channel,index;
-  unsigned cflag;
+  unsigned cflag, iflag;
+  unsigned short chip_number;
   int   i;
 
 
@@ -2829,9 +2961,11 @@
         return;
     }
     cflag = info->tty->termios->c_cflag;
+    iflag = info->tty->termios->c_iflag;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
+    chip_number = channel / 4;
 
     if (!IS_CYC_Z(cy_card[card])) {
 
@@ -2843,17 +2977,16 @@
 	if (i & CBAUDEX) {
 	    if (i == B57600)
 		i = 16;
+#ifdef B76800
+	    else if(i == B76800) 
+		i = 17;
+#endif
 	    else if(i == B115200) 
 		i = 18;
-	    else if(i == B230400 && 
-                 cy_readb(cy_card[card].base_addr+(CyGFRCR<<index)) >= 0x48) {
+	    else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) {
 		/* It is a CD1400 rev. J or later */
 		i = 20;
 	    }
-#ifdef B76800
-	    else if(i == B76800) 
-		i = 17;
-#endif
 	    else
 		info->tty->termios->c_cflag &= ~CBAUDEX;
 	}
@@ -2867,6 +3000,10 @@
                 switch(info->baud) {
 		    case 57600:
 			i += 1; break;
+#ifdef B76800
+		    case 76800: 
+			i += 2; break;
+#endif
 		    case 115200:
 			i += 3; break;
 		    case 230400:
@@ -2876,7 +3013,7 @@
 	        }
             }
 	}
-        if(cy_readb(cy_card[card].base_addr+(CyGFRCR<<index)) >= 0x48) {
+	if(info->chip_rev >= CD1400_REV_J) {
 	    /* It is a CD1400 rev. J or later */
 	    info->tbpr = baud_bpr_60[i]; /* Tx BPR */
 	    info->tco = baud_co_60[i]; /* Tx CO */
@@ -3115,6 +3252,16 @@
         case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break;
 	}
 
+	if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) {
+	    info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+	    /* get it right for 134.5 baud */
+	} else if (i) {
+	    info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2;
+	    /* this needs to be propagated into the card info */
+	} else {
+	    info->timeout = 0;
+	}
+
 	/* byte size and parity */
 	switch(cflag & CSIZE){
 	case CS5: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS5); break;
@@ -3150,7 +3297,7 @@
                cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
 	}
 
-	retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L);
+	retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
 	if (retval != 0){
 	    printk("cyc:set_line_char retval at %d was %x\n",
 	        __LINE__, retval);
@@ -3163,6 +3310,14 @@
 	    info->flags |= ASYNC_CHECK_CD;
 	}
 
+	if (iflag & IXON){
+	    cy_writel(&ch_ctrl->sw_flow, 
+		cy_readl(&ch_ctrl->sw_flow) | C_FL_OXX);
+	} else {
+	    cy_writel(&ch_ctrl->sw_flow, 
+		cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
+	}
+
 	if(i == 0){ /* baud rate is zero, turn off line */
 	    cy_writel(&ch_ctrl->rs_control,
                cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
@@ -3182,7 +3337,6 @@
 	    printk("cyc:set_line_char retval at %d was %x\n",
 	        __LINE__, retval);
 	}
-	cy_readl(&ch_ctrl->comm_baud);
 
 	if (info->tty){
 	    clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -3230,8 +3384,9 @@
 
     if (!suser()) {
             if ((new_serial.close_delay != info->close_delay) ||
-                ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
-                 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+		(new_serial.baud_base != info->baud) ||
+		((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+		 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
                     return -EPERM;
             info->flags = ((info->flags & ~ASYNC_USR_MASK) |
                            (new_serial.flags & ASYNC_USR_MASK));
@@ -3245,11 +3400,12 @@
      * At this point, we start making changes.....
      */
 
+    info->baud = new_serial.baud_base;
     info->flags = ((info->flags & ~ASYNC_FLAGS) |
                     (new_serial.flags & ASYNC_FLAGS));
-    info->baud = new_serial.baud_base;
-    info->close_delay = new_serial.close_delay;
-
+    info->close_delay = new_serial.close_delay * HZ/100;
+    info->closing_wait = new_serial.closing_wait * HZ/100;
+ 
 
 check_and_exit:
     if (info->flags & ASYNC_INITIALIZED){
@@ -3806,25 +3962,44 @@
             ret_val = set_default_timeout(info, (unsigned long)arg);
             break;
 	case CYSETRFLOW:
-    	    info->rflow = 1;
+    	    info->rflow = (int)arg;
 	    ret_val = 0;
 	    break;
-	case CYRESETRFLOW:
-    	    info->rflow = 0;
-	    ret_val = 0;
+	case CYGETRFLOW:
+	    ret_val = info->rflow;
 	    break;
 	case CYSETRTSDTR_INV:
-    	    info->rtsdtr_inv = 1;
+    	    info->rtsdtr_inv = (int)arg;
 	    ret_val = 0;
 	    break;
-	case CYRESETRTSDTR_INV:
-    	    info->rtsdtr_inv = 0;
+	case CYGETRTSDTR_INV:
+	    ret_val = info->rtsdtr_inv;
+	    break;
+	case CYGETCARDINFO:
+            error = verify_area(VERIFY_WRITE, (void *) arg
+                                ,sizeof(struct cyclades_card));
+            if (error){
+                ret_val = error;
+                break;
+            }
+            copy_to_user((void *)arg, (void *)&cy_card[info->card], 
+			 sizeof (struct cyclades_card));
 	    ret_val = 0;
+            break;
+	case CYGETCD1400VER:
+	    ret_val = info->chip_rev;
 	    break;
 	case CYZPOLLCYCLE:
             cyz_polling_cycle = (HZ * arg) / 1000;
 	    ret_val = 0;
 	    break;
+	case CYSETWAIT:
+    	    info->closing_wait2 = (unsigned short)arg;
+	    ret_val = 0;
+	    break;
+	case CYGETWAIT:
+	    ret_val = info->closing_wait2;
+	    break;
         case TCSBRK:    /* SVID version: non-zero arg --> no break */
             ret_val = tty_check_change(tty);
             if (ret_val)
@@ -3968,12 +4143,13 @@
 
 #ifdef SERIAL_DEBUG_THROTTLE
   char buf[64];
-        
-    printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+
+    printk("cyc:throttle %s: %d....ttyC%d\n", 
+	   tty_name(tty, buf),
            tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+    if (serial_paranoia_check(info, tty->device, "cy_throttle")){
             return;
     }
 
@@ -4024,17 +4200,21 @@
 #ifdef SERIAL_DEBUG_THROTTLE
   char buf[64];
         
-    printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+    printk("cyc:unthrottle %s: %d....ttyC%d\n", 
+	   tty_name(tty, buf),
            tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+    if (serial_paranoia_check(info, tty->device, "cy_unthrottle")){
             return;
     }
 
     if (I_IXOFF(tty)) {
-        info->x_char = START_CHAR(tty);
-        /* Should use the "Send Special Character" feature!!! */
+	if (info->x_char)
+	    info->x_char = 0;
+	else
+	    info->x_char = START_CHAR(tty);
+            /* Should use the "Send Special Character" feature!!! */
     }
 
     card = info->card;
@@ -4146,6 +4326,49 @@
 } /* cy_start */
 
 
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  int card, channel;
+  unsigned long flags;
+                                
+#ifdef SERIAL_DEBUG_IO
+    printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+#endif
+
+    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+        return;
+    save_flags(flags); cli();
+    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+    restore_flags(flags);
+
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+
+    if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board 
+				      buffers as well */
+	static volatile struct FIRM_ID *firm_id;
+	static volatile struct ZFW_CTRL *zfw_ctrl;
+	static volatile struct CH_CTRL *ch_ctrl;
+	static volatile struct BUF_CTRL *buf_ctrl;
+
+	firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+	zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+				cy_readl(&firm_id->zfwctrl_addr));
+	ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+	buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+	while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put))
+		cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get));
+    }
+    wake_up_interruptible(&tty->write_wait);
+    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+	&& tty->ldisc.write_wakeup)
+	    (tty->ldisc.write_wakeup)(tty);
+} /* cy_flush_buffer */
+
+
 /*
  * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
  */
@@ -4160,7 +4383,8 @@
 
     if (serial_paranoia_check(info, tty->device, "cy_hangup"))
         return;
-    
+
+    cy_flush_buffer(tty);
     shutdown(info);
     info->event = 0;
     info->count = 0;
@@ -4173,28 +4397,6 @@
 } /* cy_hangup */
 
 
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-                                
-#ifdef SERIAL_DEBUG_IO
-    printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
-        return;
-    save_flags(flags); cli();
-        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-    restore_flags(flags);
-    wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-    && tty->ldisc.write_wakeup)
-        (tty->ldisc.write_wakeup)(tty);
-} /* cy_flush_buffer */
-
-
 /*
  * ---------------------------------------------------------------------
  * cy_init() and friends
@@ -4265,7 +4467,7 @@
             return chip_number;
         }
         cy_writeb((u_long)base_addr+(CyGCR<<index), CyCH0_SERIAL);
-        if (cy_readb(base_addr+(CyGFRCR<<index)) >= 0x48){
+        if (cy_readb(base_addr+(CyGFRCR<<index)) >= CD1400_REV_J){
 	    /* It is a CD1400 rev. J or later */
 	    /* Impossible to reach 5ms with this chip. 
 	       Changed to 2ms instead (f = 500 Hz). */
@@ -4275,11 +4477,11 @@
 	    cy_writeb((u_long)base_addr+(CyPPR<<index), CyCLOCK_25_5MS);
 	}
 
-        /*
+    /*
         printk(" chip #%d at %#6lx is rev 0x%2x\n",
                chip_number, (unsigned long)base_addr,
-	       base_addr[CyGFRCR<<index]);
-        */
+	       cy_readb(base_addr+(CyGFRCR<<index)));
+    */
     }
     return chip_number;
 } /* cyy_init_card */
@@ -4308,7 +4510,7 @@
 
                 /* probe for CD1400... */
 
-#if !defined(__alpha__) 
+#if !defined(__alpha__)
 		cy_isa_address = ioremap((unsigned int)cy_isa_address,
                                                        CyISA_Ywin);
 #endif
@@ -4390,45 +4592,89 @@
 cy_detect_pci(void))
 {
 #ifdef CONFIG_PCI
-  unsigned char         cyy_rev_id;
+
+#ifdef NEW_PCI
+  struct pci_dev	*pdev = NULL;
+  unsigned char		cyy_rev_id;
+#else
+  unsigned char         cyy_bus, cyy_dev_fn, cyy_rev_id;
+#endif
   unsigned long         pci_intr_ctrl;
   unsigned char         cy_pci_irq;
   uclong                cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan;
-  unsigned short        device_id,dev_index = 0,board_index = 0;
+  unsigned short        device_id,dev_index = 0;
+#ifndef NEW_PCI
+  unsigned short	board_index = 0;
+#endif
   uclong		mailbox;
   uclong		Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
-  struct pci_dev	*pdev = NULL;
 
+#ifdef NEW_PCI
         if(pci_present() == 0) {    /* PCI bus not present */
+#else
+        if(pcibios_present() == 0) {    /* PCI bus not present */
+#endif
                 return(0);
         }
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
                 while((device_id = cy_pci_dev_id[dev_index]) != 0) {
-			if ((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES, device_id, pdev)) == NULL)
+#ifdef NEW_PCI
+                        if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES,
+                                        device_id, pdev)) == NULL) {
                                 dev_index++;    /* try next device id */
-                        else {
+                        } else {
+                                break;          /* found a board */
+                        }
+#else
+                        if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
+                                        device_id,board_index,
+                                        &cyy_bus, &cyy_dev_fn) != 0) {
+                                dev_index++;    /* try next device id */
+                                board_index = 0;
+                        } else {
                                 board_index++;
                                 break;          /* found a board */
                         }
+#endif
                 }
 
 		if (device_id == 0)
 		    break;
 
                 /* read PCI configuration area */
+#ifdef NEW_PCI
 		cy_pci_irq = pdev->irq;
 		cy_pci_addr0 = pdev->base_address[0];
-		cy_pci_addr1 = pdev->base_address[1];
-		cy_pci_addr2 = pdev->base_address[2];
-		pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+		cy_pci_addr1 = pdev->base_address[1]; 
+		cy_pci_addr2 = pdev->base_address[2]; 
+                pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+#else
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                 PCI_INTERRUPT_LINE, &cy_pci_irq);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_0, 
+				  (unsigned int *) &cy_pci_addr0);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_1, 
+				  (unsigned int *) &cy_pci_addr1);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_2, 
+				  (unsigned int *) &cy_pci_addr2);
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                  PCI_REVISION_ID, &cyy_rev_id);
+#endif
 
     if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
 	   || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
 #ifdef CY_PCI_DEBUG
             printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+#ifdef NEW_PCI
 		pdev->bus->number, pdev->devfn);
+#else
+		cyy_bus, cyy_dev_fn);
+#endif
             printk("rev_id=%d) IRQ%d\n",
 		cyy_rev_id, (int)cy_pci_irq);
             printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
@@ -4440,7 +4686,11 @@
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
 		    printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-		        pdev->bus->number, pdev->devfn);
+#ifdef NEW_PCI
+			pdev->bus->number, pdev->devfn);
+#else
+			cyy_bus, cyy_dev_fn);
+#endif
 		    printk("rev_id=%d) IRQ%d\n",
 		        cyy_rev_id, (int)cy_pci_irq);
                     printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
@@ -4525,7 +4775,11 @@
     }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
 	    /* print message */
 		printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+#ifdef NEW_PCI
 		    pdev->bus->number, pdev->devfn);
+#else
+		    cyy_bus, cyy_dev_fn);
+#endif
 		printk("rev_id=%d) IRQ%d\n",
 		    cyy_rev_id, (int)cy_pci_irq);
 		printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4535,7 +4789,11 @@
     }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
 #ifdef CY_PCI_DEBUG
             printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-		pdev->bus->number, pdev->devfn);
+#ifdef NEW_PCI
+	        pdev->bus->number, pdev->devfn);
+#else
+	        cyy_bus, cyy_dev_fn);
+#endif
             printk("rev_id=%d) IRQ%d\n",
 		cyy_rev_id, (int)cy_pci_irq);
             printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4777,7 +5035,7 @@
     tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
     rcsdate = strchr(tmp, ' '); rcsdate++;
     tmp = strrchr(rcsdate, ' '); *tmp = '\0';
-    printk("Cyclom driver %s %s\n",
+    printk("Cyclades driver %s %s\n",
         rcsvers, rcsdate);
     printk("        built %s %s\n",
 	__DATE__, __TIME__);
@@ -4810,6 +5068,7 @@
   int number_z_boards = 0;
   int board,port,i,index;
   unsigned long mailbox;
+  unsigned short chip_number;
   int nports;
 
     show_version();
@@ -4858,9 +5117,9 @@
     cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
     if (tty_register_driver(&cy_serial_driver))
-            panic("Couldn't register Cyclom serial driver\n");
+            panic("Couldn't register Cyclades serial driver\n");
     if (tty_register_driver(&cy_callout_driver))
-            panic("Couldn't register Cyclom callout driver\n");
+            panic("Couldn't register Cyclades callout driver\n");
 
     init_bh(CYCLADES_BH, do_cyclades_bh);
 
@@ -4922,9 +5181,13 @@
                     info->type = PORT_STARTECH;
                     info->card = board;
                     info->line = port;
+		    info->chip_rev = 0;
                     info->flags = STD_COM_FLAGS;
                     info->tty = 0;
-                    info->xmit_fifo_size = 0;
+		    if (mailbox == ZO_V1)
+			info->xmit_fifo_size = CYZ_FIFO_SIZE;
+		    else
+			info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
                     info->cor1 = 0;
                     info->cor2 = 0;
                     info->cor3 = 0;
@@ -4934,7 +5197,9 @@
                     info->tco = 0;
                     info->rbpr = 0;
                     info->rco = 0;
-                    info->close_delay = 0;
+                    info->close_delay = 5*HZ/10;
+		    info->closing_wait = CLOSING_WAIT_DELAY;
+		    info->closing_wait2 = 0;
                     info->x_char = 0;
                     info->event = 0;
                     info->count = 0;
@@ -4952,6 +5217,7 @@
 		                cy_serial_driver.init_termios;
                     info->open_wait = 0;
                     info->close_wait = 0;
+                    info->shutdown_wait = 0;
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask = 0;
@@ -4976,14 +5242,19 @@
                     info->line = port;
                     info->flags = STD_COM_FLAGS;
                     info->tty = 0;
-                    info->xmit_fifo_size = 12;
+                    info->xmit_fifo_size = CyMAX_CHAR_FIFO;
                     info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
                     info->cor2 = CyETC;
                     info->cor3 = 0x08; /* _very_ small rcv threshold */
                     info->cor4 = 0;
                     info->cor5 = 0;
-                    info->close_delay = 0;
-                    if (cy_readb(cinfo->base_addr+(CyGFRCR<<index)) >= 0x48) {
+                    info->close_delay = 5*HZ/10;
+		    info->closing_wait = CLOSING_WAIT_DELAY;
+		    info->closing_wait2 = 0;
+		    chip_number = (port - cinfo->first_line) / 4;
+                    if ((info->chip_rev = cy_readb(cinfo->base_addr +
+	               		 (cy_chip_offset[chip_number]<<index) +
+				 (CyGFRCR<<index))) >= CD1400_REV_J) {
                         /* It is a CD1400 rev. J or later */
                         info->tbpr = baud_bpr_60[13]; /* Tx BPR */
                         info->tco = baud_co_60[13]; /* Tx CO */
@@ -5016,6 +5287,7 @@
 		               cy_serial_driver.init_termios;
                     info->open_wait = 0;
                     info->close_wait = 0;
+                    info->shutdown_wait = 0;
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask =
@@ -5054,21 +5326,19 @@
     int i;
     unsigned long flags;
 
-
     if (cyz_timeron){
 	cyz_timeron = 0;
 	del_timer(&cyz_timerlist);
     }
 
-    save_flags(flags);
-    cli();
+    save_flags(flags); cli();
     remove_bh(CYCLADES_BH);
 
     free_page((unsigned long)tmp_buf);
     if (tty_unregister_driver(&cy_callout_driver))
-            printk("Couldn't unregister Cyclom callout driver\n");
+            printk("Couldn't unregister Cyclades callout driver\n");
     if (tty_unregister_driver(&cy_serial_driver))
-            printk("Couldn't unregister Cyclom serial driver\n");
+            printk("Couldn't unregister Cyclades serial driver\n");
 
     restore_flags(flags);
 
diff -u --recursive --new-file v2.1.95/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.95/linux/drivers/char/lp.c	Wed Apr  8 19:36:26 1998
+++ linux/drivers/char/lp.c	Sun Apr 12 11:39:20 1998
@@ -239,23 +239,32 @@
 }
 
 static int lp_check_status(int minor) {
+	static unsigned char last = 0;
 	unsigned char status = r_str(minor);
 	if ((status & LP_POUTPA)) {
-		printk(KERN_INFO "lp%d out of paper\n", minor);
-		if (LP_F(minor) & LP_ABORT)
-			return 1;
-		lp_error(minor);
+		if (last != LP_POUTPA) {
+			last = LP_POUTPA;
+			printk(KERN_INFO "lp%d out of paper\n", minor);
+		}
 	} else if (!(status & LP_PSELECD)) {
-		printk(KERN_INFO "lp%d off-line\n", minor);
-		if (LP_F(minor) & LP_ABORT)
-			return 1;
-		lp_error(minor);
+		if (last != LP_PSELECD) {
+			last = LP_PSELECD;
+			printk(KERN_INFO "lp%d off-line\n", minor);
+		}
 	} else if (!(status & LP_PERRORP)) {
-		printk(KERN_ERR "lp%d printer error\n", minor);
+		if (last != LP_PERRORP) {
+			last = LP_PERRORP;
+			printk(KERN_ERR "lp%d on fire!\n", minor);
+		}
+	}
+	else last = 0;
+
+	if (last != 0) {
 		if (LP_F(minor) & LP_ABORT)
 			return 1;
 		lp_error(minor);
 	}
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.95/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.95/linux/drivers/char/pc_keyb.c	Mon Apr  6 17:40:59 1998
+++ linux/drivers/char/pc_keyb.c	Fri Apr 10 23:12:04 1998
@@ -145,12 +145,12 @@
 	 */
 
         do {
-	kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+		kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
                 status = kbd_wait_for_input();
                 if (status == KBD_REPLY_ACK)
 			break;
                 else if (status != KBD_REPLY_RESEND)
-		return "Keyboard reset failed, no ACK";
+			return "Keyboard reset failed, no ACK";
         } while (1);
 
 	if (kbd_wait_for_input() != KBD_REPLY_POR)
@@ -164,12 +164,12 @@
 	 */
 
 	do {
-	kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+		kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
 		status = kbd_wait_for_input();
 		if (status == KBD_REPLY_ACK)
 			break;
 		else if (status != KBD_REPLY_RESEND)
-		return "Disable keyboard: no ACK";
+			return "Disable keyboard: no ACK";
 	} while (1);
 
 	kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
diff -u --recursive --new-file v2.1.95/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h
--- v2.1.95/linux/drivers/char/pc_keyb.h	Sun Dec 21 17:27:18 1997
+++ linux/drivers/char/pc_keyb.h	Mon Apr 13 17:01:48 1998
@@ -17,7 +17,7 @@
 
 #define KBD_INIT_TIMEOUT HZ		/* Timeout in jiffies for initializing the keyboard */
 #define KBC_TIMEOUT 250			/* Timeout in ms for sending to keyboard controller */
-#define KBD_TIMEOUT 250			/* Timeout in ms for keyboard command acknowledge */
+#define KBD_TIMEOUT 1000		/* Timeout in ms for keyboard command acknowledge */
 
 /*
  *	Internal variables of the driver
diff -u --recursive --new-file v2.1.95/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.95/linux/drivers/char/serial.c	Wed Apr  1 20:11:49 1998
+++ linux/drivers/char/serial.c	Mon Apr 13 14:41:53 1998
@@ -3613,6 +3613,7 @@
 	 *	Disable UART interrupts, set DTR and RTS high
 	 *	and set speed.
 	 */
+	outb(cval, ser->port + UART_LCR);  /* don't assume that DLAB is clear */
 	outb(0, ser->port + UART_IER);
 	outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
 	outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);	/* set DLAB */
diff -u --recursive --new-file v2.1.95/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.1.95/linux/drivers/misc/parport_init.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/misc/parport_init.c	Sun Apr 12 11:39:20 1998
@@ -20,7 +20,7 @@
 
 #ifndef MODULE
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_NONE };
+static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
 static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
 
 extern int parport_pc_init(int *io, int *irq, int *dma);
@@ -30,26 +30,68 @@
 
 __initfunc(void parport_setup(char *str, int *ints))
 {
-	if (ints[0] == 0 || ints[1] == 0) {
-		/* Disable parport if "parport=" or "parport=0" in cmdline */
+	if (ints[0] == 0) {
+		if (str && !strncmp(str, "auto", 4)) {
+			irq[0] = PARPORT_IRQ_AUTO;
+			dma[0] = PARPORT_DMA_AUTO;
+		}
+		else if (str)
+			printk (KERN_ERR "parport: `%s': huh?\n", str);
+		else
+			printk (KERN_ERR "parport: parport=.. what?\n");
+		
+		return;
+	}
+	else if (ints[1] == 0) {
+		/* Disable parport if "parport=0" in cmdline */
 		io[0] = PARPORT_DISABLE; 
 		return;
 	}
+
 	if (parport_setup_ptr < PARPORT_MAX) {
+		char *sep;
 		io[parport_setup_ptr] = ints[1];
-		if (ints[0]>1) {
+		irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
+		dma[parport_setup_ptr] = PARPORT_DMA_NONE;
+		if (ints[0] > 1) {
 			irq[parport_setup_ptr] = ints[2];
-			if (ints[0]>2) dma[parport_setup_ptr] = ints[3];
+			if (ints[0] > 2) {
+				dma[parport_setup_ptr] = ints[3];
+				goto done;
+			}
+
+			if (str == NULL)
+				goto done;
+
+			goto dma_from_str;
 		}
-		parport_setup_ptr++;
-	} else {
-		printk(KERN_ERR "parport=0x%x", ints[1]);
-		if (ints[0]>1) {
-			printk(",%d", ints[2]);
-			if (ints[0]>2) printk(",%d", ints[3]);
+		else if (str == NULL)
+			goto done;
+		else if (!strncmp(str, "auto", 4))
+			irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
+		else if (strncmp(str, "none", 4) != 0) {
+			printk(KERN_ERR "parport: bad irq `%s'\n", str);
+			return;
 		}
-		printk(" ignored, too many ports.\n");
-	}
+
+		if ((sep = strchr(str, ',')) == NULL) goto done;
+		str = sep+1;
+	dma_from_str:
+		if (!strncmp(str, "auto", 4))
+			dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+		else if (strncmp(str, "none", 4) != 0) {
+			char *ep;
+			dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
+			if (ep == str) {
+				printk(KERN_ERR "parport: bad dma `%s'\n",
+				       str);
+				return;
+			}
+		}
+	done:
+		parport_setup_ptr++;
+	} else
+		printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
 }
 #endif
 
@@ -100,6 +142,7 @@
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
 EXPORT_SYMBOL(parport_probe_hook);
+EXPORT_SYMBOL(parport_parse_irqs);
 
 void inc_parport_count(void)
 {
diff -u --recursive --new-file v2.1.95/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.95/linux/drivers/misc/parport_pc.c	Fri Apr 10 13:03:48 1998
+++ linux/drivers/misc/parport_pc.c	Mon Apr 13 14:39:59 1998
@@ -36,7 +36,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -163,9 +162,9 @@
 
 int parport_pc_claim_resources(struct parport *p)
 {
-	/* FIXME check that resources are free */
+	int err;
 	if (p->irq != PARPORT_IRQ_NONE)
-		request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL);
+		if ((err = request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL)) != 0) return err;
 	request_region(p->base, p->size, p->name);
 	if (p->modes & PARPORT_MODE_PCECR)
 		request_region(p->base+0x400, 3, p->name);
@@ -276,159 +275,6 @@
 	parport_pc_dec_use_count
 };
 
-/* --- DMA detection -------------------------------------- */
-
-/*
- * Prepare DMA channels from 0-8 to transmit towards buffer
- */
-static int parport_prepare_dma(char *buff, int size)
-{
-	int tmp = 0;
-	int i,retv;
-	
-	for (i = 0; i < 8; i++) {
-		retv = request_dma(i, "probe");
-		if (retv)
-			continue;
-		tmp |= 1 << i;
-
-		cli();
-		disable_dma(i);
-		clear_dma_ff(i);
-		set_dma_addr(i, virt_to_bus(buff));
-		set_dma_count(i, size);
-		set_dma_mode(i, DMA_MODE_READ);
-		sti();
-	}
-
-	return tmp;
-}
-
-/*
- * Activate all DMA channels passed in dma
- */
-static int parport_enable_dma(int dma)
-{
-	int i;
-	
-	for (i = 0; i < 8; i++)
-		if (dma & (1 << i)) {
-			cli();
-			enable_dma(i);
-			sti();
-		}
-
-	return dma;
-}
-
-static int parport_detect_dma_transfer(int dma, int size)
-{
-	int i,n,retv;
-	int count=0;
-
-	retv = PARPORT_DMA_NONE;
-	for (i = 0; i < 8; i++)
-		if (dma & (1 << i)) {
-			disable_dma(i);
-			clear_dma_ff(i);
-			n = get_dma_residue(i);
-			if (n != size) {
-				retv = i;
-				if (count > 0) {
-					retv = PARPORT_DMA_NONE; /* Multiple DMA's */
-					printk(KERN_ERR "parport: multiple DMA detected.  Huh?\n");
-				}
-				count++;
-			}
-			free_dma(i);
-		}
-
-	return retv;	
-}
-
-/* Only if supports ECP mode */
-static int programmable_dma_support(struct parport *pb)
-{
-	unsigned char dma, oldstate = parport_pc_read_econtrol(pb);
-
-	parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */
-	
-	dma = parport_pc_read_configb(pb) & 0x07;
-
-	parport_pc_write_econtrol(pb, oldstate);
-	
-	if (dma == 0 || dma == 4) /* Jumper selection */
-		return PARPORT_DMA_NONE;
-	else
-		return dma;
-}
-
-/* Only called if port supports ECP mode.
- *
- * The only restriction on DMA channels is that it has to be
- * between 0 to 7 (inclusive). Used only in an ECP mode, DMAs are
- * considered a shared resource and hence they should be registered
- * when needed and then immediately unregistered.
- *
- * DMA autoprobes for ECP mode are known not to work for some
- * main board BIOS configs. I had to remove everything from the
- * port, set the mode to SPP, reboot to DOS, set the mode to ECP,
- * and reboot again, then I got IRQ probes and DMA probes to work.
- * [Is the BIOS doing a device detection?]
- *
- * A value of PARPORT_DMA_NONE is allowed indicating no DMA support.
- *
- * if( 0 < DMA < 4 )
- *    1Byte DMA transfer
- * else // 4 < DMA < 8
- *    2Byte DMA transfer
- *
- */
-static int parport_dma_probe(struct parport *pb)
-{
-	int dma,retv;
-	unsigned char dsr,dsr_read;
-	char *buff;
-
-	retv = programmable_dma_support(pb);
-	if (retv != PARPORT_DMA_NONE)
-		return retv;
-	
-	if (!(buff = kmalloc(2048, GFP_KERNEL | GFP_DMA))) {
-	    printk(KERN_ERR "parport: memory squeeze\n");
-	    return PARPORT_DMA_NONE;
-	}
-	
- 	dsr = pb->ops->read_control(pb);
-	dsr_read = (dsr & ~(0x20)) | 0x04;    /* Direction == read */
-
-	pb->ops->write_econtrol(pb, 0xc0);	   /* ECP MODE */
- 	pb->ops->write_control(pb, dsr_read );
-	dma = parport_prepare_dma(buff, 1000);
-	pb->ops->write_econtrol(pb, 0xd8);	   /* ECP FIFO + enable DMA */
-	parport_enable_dma(dma);
-	udelay(500);           /* Give some for DMA tranfer */
-	retv = parport_detect_dma_transfer(dma, 1000);
-	
-	/*
-	 * National Semiconductors only supports DMA tranfers
-	 * in ECP MODE
-	 */
-	if (retv == PARPORT_DMA_NONE) {
-		pb->ops->write_econtrol(pb, 0x60);	   /* ECP MODE */
-		pb->ops->write_control(pb, dsr_read );
-		dma=parport_prepare_dma(buff,1000);
-		pb->ops->write_econtrol(pb, 0x68);	   /* ECP FIFO + enable DMA */
-		parport_enable_dma(dma);
-		udelay(500);           /* Give some for DMA tranfer */
-		retv = parport_detect_dma_transfer(dma, 1000);
-	}
-	
-	kfree(buff);
-	
-	return retv;
-}
-
 /* --- Mode detection ------------------------------------- */
 
 /*
@@ -807,6 +653,7 @@
 static int probe_one_port(unsigned long int base, int irq, int dma)
 {
 	struct parport tmpport, *p;
+	int probedirq = PARPORT_IRQ_NONE;
 	if (check_region(base, 3)) return 0;
 	tmpport.base = base;
 	tmpport.ops = &parport_pc_ops;
@@ -830,12 +677,16 @@
 	if (p->irq == PARPORT_IRQ_AUTO) {
 		p->irq = PARPORT_IRQ_NONE;
 		parport_irq_probe(p);
+	} else if (p->irq == PARPORT_IRQ_PROBEONLY) {
+		p->irq = PARPORT_IRQ_NONE;
+		parport_irq_probe(p);
+		probedirq = p->irq;
+		p->irq = PARPORT_IRQ_NONE;
 	}
 	if (p->irq != PARPORT_IRQ_NONE)
 		printk(", irq %d", p->irq);
 	if (p->dma == PARPORT_DMA_AUTO)		
-		p->dma = (p->modes & PARPORT_MODE_PCECP)?
-			parport_dma_probe(p):PARPORT_DMA_NONE;
+		p->dma = PARPORT_DMA_NONE;
 	if (p->dma != PARPORT_DMA_NONE)
 		printk(", dma %d", p->dma);
 	printk(" [");
@@ -851,6 +702,8 @@
 	}
 #undef printmode
 	printk("]\n");
+	if (probedirq != PARPORT_IRQ_NONE) 
+		printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
 	parport_proc_register(p);
 	p->flags |= PARPORT_FLAG_COMA;
 
@@ -875,9 +728,9 @@
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
 	} else {
 		/* Probe all the likely ports. */
-		count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-		count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
-		count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
+		count += probe_one_port(0x3bc, irq[0], dma[0]);
+		count += probe_one_port(0x378, irq[0], dma[0]);
+		count += probe_one_port(0x278, irq[0], dma[0]);
 	}
 
 	/* Give any attached devices a chance to gather their thoughts */
@@ -890,15 +743,22 @@
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
-static int irq[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO };
+static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
+static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
+static char *irq = NULL;
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
 
 int init_module(void)
 {	
-	return (parport_pc_init(io, irq, dma)?0:1);
+	/* Work out how many ports we have, then get parport_share to parse
+	   the irq values. */
+	unsigned int i;
+	for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
+	parport_parse_irqs(i, irq, irqval);
+
+	return (parport_pc_init(io, irqval, dma)?0:1);
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v2.1.95/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.1.95/linux/drivers/misc/parport_share.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/misc/parport_share.c	Sun Apr 12 11:39:20 1998
@@ -441,3 +441,26 @@
 			pd->wakeup(pd->private);
 	}
 }
+
+void parport_parse_irqs(int nports, const char *irqstr, int irqval[])
+{
+	unsigned int i;
+	for (i = 0; i < nports && irqstr; i++) {
+		if (!strncmp(irqstr, "auto", 4))
+			irqval[i] = PARPORT_IRQ_AUTO;
+		else if (!strncmp(irqstr, "none", 4))
+			irqval[i] = PARPORT_IRQ_NONE;
+		else {
+			char *ep;
+			unsigned long r = simple_strtoul(irqstr, &ep, 0);
+			if (ep != irqstr)
+				irqval[i] = r;
+			else {
+				printk("parport: bad irq specifier `%s'\n", irqstr);
+				return;
+			}
+		}
+		irqstr = strchr(irqstr, ',');
+		if (irqstr) irqstr++;
+	}
+}
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.1.95/linux/drivers/scsi/53c7,8xx.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/53c7,8xx.c	Sat Apr 11 11:13:25 1998
@@ -253,6 +253,7 @@
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <linux/init.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -290,6 +291,7 @@
 static int NCR53c8xx_script_len;
 static int NCR53c8xx_dsa_len;
 static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
@@ -1134,9 +1136,9 @@
 
     if (!search) {
 #ifdef __powerpc__
-	if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
+	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL)) 
 #else
-	if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
 #endif
 	  {
 	  
@@ -4388,6 +4390,22 @@
 	    hostdata->dstat |= DSTAT_DFE;
     	}
     }
+}
+
+/*
+ * Function : do_NCR53c7x0_intr()
+ *
+ * Purpose : A quick wrapper function added to grab the io_request_lock
+ *      spin lock prior to entering the real interrupt handler.  Needed
+ *      for 2.1.95 and above.
+ */
+static void
+do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs) {
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR53c7x0_intr(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /*
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.1.95/linux/drivers/scsi/53c7xx.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/53c7xx.c	Sat Apr 11 11:13:25 1998
@@ -252,6 +252,7 @@
 #include <linux/ioport.h>
 #include <linux/time.h>
 #include <linux/blk.h>
+#include <asm/spinlock.h>
 
 #ifdef CONFIG_AMIGA
 #include <asm/pgtable.h>
@@ -313,7 +314,8 @@
 static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
 static int disable (struct Scsi_Host *host);
 static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
@@ -1069,10 +1071,10 @@
      */
 
 #ifdef CONFIG_MVME16x
-    if (request_irq(IRQ_MVME16x_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
+    if (request_irq(IRQ_MVME16x_SCSI, do_NCR53c7x0_intr, 0, "SCSI-script", NULL))
 	panic ("Couldn't get SCSI IRQ");
 #ifdef MVME16x_INTFLY
-    else if (request_irq(IRQ_MVME16x_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
+    else if (request_irq(IRQ_MVME16x_FLY, do_NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
 	panic ("Couldn't get INT_FLY IRQ");
 #endif
 #else
@@ -1081,9 +1083,9 @@
 
     if (!search) {
 #ifdef CONFIG_AMIGA
-	if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
+	if (request_irq(IRQ_AMIGA_PORTS, do_NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
 #else
-	if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
+	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
 #endif
 	    printk("scsi%d : IRQ%d not free, detaching\n"
 	           "         You have either a configuration problem, or a\n"
@@ -4068,6 +4070,20 @@
 }
 #endif
 
+/* Function : NCR53c7x0_intr
+ *
+ * Purpose : grab the global io_request_lock spin lock before entering the
+ *      real interrupt routine.
+ */
+static void
+do_NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR53c7x0_intr(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 /*
  * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
  *
@@ -4082,7 +4098,7 @@
  * script interrupt handler will call back to this function.
  */
 
-void 
+static void 
 NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
     NCR53c7x0_local_declare();
     struct Scsi_Host *host;			/* Host we are looking at */
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- v2.1.95/linux/drivers/scsi/AM53C974.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/AM53C974.c	Tue Apr 14 10:24:16 1998
@@ -10,6 +10,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -361,6 +362,7 @@
 static __inline__ void run_main(void);
 static void AM53C974_main (void);
 static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void AM53C974_intr_disconnect(struct Scsi_Host *instance); 
 static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg);
 static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target);
@@ -716,7 +718,7 @@
                  (search->irq != instance->irq) || (search == instance) );
      search = search->next);
 if (!search) {
-   if (request_irq(instance->irq, AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
+   if (request_irq(instance->irq, do_AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) {
       printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq);
       scsi_unregister(instance);
       return 0; } 
@@ -974,6 +976,24 @@
        } /* for instance */
    } while (!done);
 main_running = 0;
+}
+
+/************************************************************************
+* Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
+*                                                                       *
+* Purpose : interrupt handler                                           *
+*                                                                       *
+* Inputs : irq - interrupt line, regs - ?                               *
+*                                                                       *
+* Returns : nothing                                                     *
+************************************************************************/
+static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+unsigned long flags;
+
+spin_lock_irqsave(&io_request_lock, flags);
+AM53C974_intr(irq, dev_id, regs);
+spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /************************************************************************
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.95/linux/drivers/scsi/Config.in	Tue Mar 10 10:03:32 1998
+++ linux/drivers/scsi/Config.in	Sat Apr 11 11:19:34 1998
@@ -24,14 +24,12 @@
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $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
     bool '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
     if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
-      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
     fi
-    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
+    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.1.95/linux/drivers/scsi/NCR5380.c	Wed Apr  1 20:11:52 1998
+++ linux/drivers/scsi/NCR5380.c	Sat Apr 11 11:13:25 1998
@@ -1279,6 +1279,9 @@
 }
 
 #ifndef DONT_USE_INTR
+#include <linux/blk.h>
+#include <asm/spinlock.h>
+
 /*
  * Function : void NCR5380_intr (int irq)
  * 
@@ -1390,6 +1393,16 @@
 	    } /* if (instance->irq == irq) */
     } while (!done);
 }
+
+
+static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) {
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR5380_intr(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 #endif
 
 #ifdef NCR5380_STATS
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/NCR5380.h linux/drivers/scsi/NCR5380.h
--- v2.1.95/linux/drivers/scsi/NCR5380.h	Wed Apr  1 20:11:52 1998
+++ linux/drivers/scsi/NCR5380.h	Sat Apr 11 11:13:25 1998
@@ -286,6 +286,7 @@
 static void NCR5380_information_transfer (struct Scsi_Host *instance);
 #ifndef DONT_USE_INTR
 static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
+static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
 #endif
 static void NCR5380_main (void);
 static void NCR5380_print_options (struct Scsi_Host *instance);
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- v2.1.95/linux/drivers/scsi/NCR53c406a.c	Wed Apr  1 20:11:52 1998
+++ linux/drivers/scsi/NCR53c406a.c	Sat Apr 11 11:13:25 1998
@@ -52,6 +52,7 @@
 #include <asm/irq.h>
 
 #include <linux/blk.h>
+#include <asm/spinlock.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
@@ -171,6 +172,7 @@
 
 /* Static function prototypes */
 static  void NCR53c406a_intr(int, void *, struct pt_regs *);
+static  void do_NCR53c406a_intr(int, void *, struct pt_regs *);
 static  void internal_done(Scsi_Cmnd *);
 static  void wait_intr(void);
 static  void chip_init(void);
@@ -539,7 +541,7 @@
     request_region(port_base, 0x10, "NCR53c406a");
     
     if(irq_level > 0) {
-        if(request_irq(irq_level, NCR53c406a_intr, 0, "NCR53c406a", NULL)){
+        if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", NULL)){
             printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
             return 0;
         }
@@ -764,6 +766,15 @@
     return 0;
   }
      
+     static void
+do_NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    NCR53c406a_intr(0, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
      static void
 NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
     DEB(unsigned char fifo_size;)
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.1.95/linux/drivers/scsi/README.aic7xxx	Thu Jul 31 12:37:17 1997
+++ linux/drivers/scsi/README.aic7xxx	Sat Apr 11 11:19:34 1998
@@ -1,8 +1,7 @@
 			    AIC7xxx Driver for Linux
-				 July 20, 1997
 
 Introduction
-------------------------
+----------------------------
 The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
 SCSI controllers and chipsets. Major portions of the driver and driver
 development are shared between both Linux and FreeBSD. Support for the
@@ -11,32 +10,42 @@
 2.1.0 or later.
 
   Supported cards/chipsets
-  ------------------------
+  ----------------------------
     Adaptec Cards
-    -----------------------
-    AHA-274x               
-    AHA-2842               
+    ----------------------------
+    AHA-274x
+    AHA-274xT               
+    AHA-2842
+    AHA-2910B               
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
-    AHA-2940UW             
+    AHA-2940UW
+    AHA-2940AU             
     AHA-2944D              
     AHA-2944WD
+    AHA-2944UD
+    AHA-2944UWD
     AHA-3940
+    AHA-3940U
     AHA-3940W
+    AHA-3940UW
     AHA-3985
+    AHA-3985U
     AHA-3985W
+    AHA-3985UW
 
     Motherboard Chipsets
-    -----------------------
+    ----------------------------
     AIC-777x   
     AIC-785x
     AIC-786x
     AIC-787x
     AIC-788x
+    AIC-7895
 
     Bus Types
-    -----------------------
+    ----------------------------
     W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
         SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
     U - Ultra SCSI, transfer rates up to 40MB/s.
@@ -50,23 +59,28 @@
     AHA-398x - PCI RAID controllers with three separate SCSI controllers
                on-board.
 
-    NOTE: The AHA-2920 is NOT a AIC-7xxx based controller, and is not
+    NOTE: The AHA-2920 is NOT an AIC-7xxx based controller, and is not
           handled by this driver.
 
   People
-  ------------------------
-    Justin T Gibbs  gibbs@freefall.FreeBSD.org     (BSD Driver Author)
-    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)
-
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@dialnet.net
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+    
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
     again for all his work!
-
+    
   Mailing list
-  ------------------------
+  ------------------------------
     There is a mailing list available for users who want to track development
     and converse with other users and developers. This list is for both
     FreeBSD and Linux support of the AIC7xxx chipsets.
@@ -84,20 +98,150 @@
 
     Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
     
-  Command line options ("aic7xxx=option[,option...]")
-  ---------------------------------------------------
+  Boot Command line options
+  ------------------------------
     "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.
+    "aic7xxx=reverse_scan" - Have the driver register the SCSI cards in the
+        reverse of the normal order.  This may help those people who have more
+        than one PCI Adaptec controller force the correct controller to be
+        scsi0 under linux so that their boot hard drive is also sda under
+        linux
+    "aic7xxx=extended" - Force the driver to detect extended drive translation
+        on your controller.  This helps those people who have cards without
+        a SEEPROM make sure that linux and all other operating systems think
+        the same way about your hard drives.
+    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+        to use the correct IRQ type for your card.  This only applies to EISA
+        based controllers.  On these controllers, 0 is for Edge triggered
+        interrupts, and 1 is for Level triggered interrupts.  If you aren't
+        sure or don't know which IRQ trigger type your EISA card uses, then
+        let the kernel autodetect the trigger type.
+    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
+        simply specify aic7xxx=verbose, then the kernel will automatically pick
+        the default set of verbose messages for you to see.  Alternatively, you
+        can specify the command as "aic7xxx=verbose:0xXXXX" where the X entries
+        are replaced with hexadecimal digits.  This option is a bit field type
+        option.  For a full listing of the available options, search for the
+        #define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want verbose
+        messages, then it is recommended that you simply use the aic7xxx=verbose
+        variant of this command.
+    "aic7xxx=7895_irq_hack:x" - This option enables some work around code to
+        fix a bug in the Tyan Thunder II motherboard BIOS.  The BIOS
+        incorrectly sets the IRQs on the two channels of the 7895 to two
+        different values even though the motherboard hardware doesn't support
+        this mode of operation.  The valid values for x are: 0 to force
+        both channels to use the IRQ assigned to Channel A, 1 to force both
+        channels to use the IRQ assigned to Channel B, and -1 will disable
+        this horrible abomination of a hack.  The default is disabled (-1).
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to enable
+        tagged queueing on specific devices.  As of driver version 5.0.6, we
+        now globally enable tagged queueing by default, but we also disable
+        tagged queueing on all individual devices by default.  In order to
+        enable tagged queueing for certian devices at boot time, a user may
+        use this boot param.  The driver will then parse this message out
+        and enable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{{8,8},,{8,8}}
+          First adapter, scsi id 0 to 8, id 1 to 8, remainder stay at their
+          default.  Second adapter stays entirely at default.  Third
+          adapter, id 0 to 8, id 1 to 8, remainder at default (identical to
+          first adapter).
+
+        tag_info:{,,,{,,,64}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 to 64.  Notice that leading commas simply increment
+          what the first number effects, and there are no need for trailing
+          commas.  When you close out an adapter, or the entire entry,
+          anything not explicitly set stays at the default value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma on
+    the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the F1 key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button next
+    to the option you have questions about.  The help information from the
+    Configure.help file will then get automatically displayed.
 
   /proc support
-  ------------------------
+  ------------------------------
     The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
     directory. That directory contains a file for each SCSI controller in
     the system. Each file presents the current configuration and transfer
@@ -107,45 +251,19 @@
     Matthew Jacob for statistics support.
 
   FTP sites
-  ------------------------
-    ftp://ftp.teleport.com/users/deang/Linux/aic7xxx/
-      - Main Linux AIC7xxx driver release/pre-release site
-      - Experimental/development patches and bootdisks
+  ------------------------------
     ftp://ftp.dialnet.net/pub/linux/aic7xxx/
+      - Primary site for Doug Ledford developed driver releases
       - US Linux mirror of Teleport site
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
     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
 
-(Modified by D. Eischen, 7/20/97)
-
-$Revision: 3.1a $
+$Revision: 3.0 $
 
+Modified by Doug Ledford 1998
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c
--- v2.1.95/linux/drivers/scsi/a2091.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/scsi/a2091.c	Sat Apr 11 11:13:25 1998
@@ -12,6 +12,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -35,7 +36,6 @@
 {
     unsigned int status;
     struct Scsi_Host *instance;
-
     for (instance = first_instance; instance &&
 	 instance->hostt == a2091_template; instance = instance->next)
     {
@@ -54,6 +54,15 @@
     }
 }
 
+static void do_a2091_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    a2091_intr(irq, dummy, fp);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
 {
     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
@@ -220,7 +229,7 @@
 	if (num_a2091++ == 0) {
 	    first_instance = instance;
 	    a2091_template = instance->hostt;
-	    request_irq(IRQ_AMIGA_PORTS, a2091_intr, 0, "A2091 SCSI", a2091_intr);
+	    request_irq(IRQ_AMIGA_PORTS, do_a2091_intr, 0, "A2091 SCSI", a2091_intr);
 	}
 	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
 	zorro_config_board(key, 0);
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c
--- v2.1.95/linux/drivers/scsi/a3000.c	Tue May 13 22:41:13 1997
+++ linux/drivers/scsi/a3000.c	Sat Apr 11 11:13:25 1998
@@ -11,6 +11,7 @@
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -35,7 +36,6 @@
 
     if (!(status & ISTR_INT_P))
 	return;
-
     if (status & ISTR_INTS)
     {
 	/* disable PORTS interrupt */
@@ -48,6 +48,14 @@
     }
 }
 
+static void do_a3000_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    a3000_intr(irq, dummy, fp);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
 static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
 {
     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
@@ -186,7 +194,7 @@
     DMA(a3000_host)->DAWR = DAWR_A3000;
     wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR),
 		 dma_setup, dma_stop, WD33C93_FS_12_15);
-    request_irq(IRQ_AMIGA_PORTS, a3000_intr, 0, "A3000 SCSI", a3000_intr);
+    request_irq(IRQ_AMIGA_PORTS, do_a3000_intr, 0, "A3000 SCSI", a3000_intr);
     DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
     called = 1;
 
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.1.95/linux/drivers/scsi/advansys.c	Thu Feb 12 20:56:10 1998
+++ linux/drivers/scsi/advansys.c	Mon Apr 13 13:32:24 1998
@@ -668,6 +668,9 @@
 #include <linux/blk.h>
 #include <linux/stat.h>
 #endif /* version >= v1.3.0 */
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+#include <asm/spinlock.h>
+#endif
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
@@ -3841,8 +3844,11 @@
 #endif /* version >= v1.3.0 */
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
 STATIC void         advansys_interrupt(int, struct pt_regs *);
-#else /* version >= v1.3.70 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
+STATIC void         advansys_interrupt(int, void *, struct pt_regs *);
+#else /* version >= 2.1.95 */
 STATIC void         advansys_interrupt(int, void *, struct pt_regs *);
+STATIC void         do_advansys_interrupt(int, void *, struct pt_regs *);
 #endif /* version >= v1.3.70 */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 STATIC void         advansys_select_queue_depths(struct Scsi_Host *,
@@ -4880,10 +4886,14 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
             if ((ret = request_irq(shp->irq, advansys_interrupt,
                             SA_INTERRUPT, "advansys")) != 0)
-#else /* version >= v1.3.70 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,95)
             if ((ret = request_irq(shp->irq, advansys_interrupt,
                             SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
                             "advansys", boardp)) != 0)
+#else /* version >= 2.1.95 */
+            if ((ret = request_irq(shp->irq, do_advansys_interrupt,
+                            SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+                            "advansys", boardp)) != 0)
 #endif /* version >= v1.3.70 */
             {
                 ASC_PRINT2(
@@ -6204,6 +6214,18 @@
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
 }
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
+static void
+do_advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    advansys_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+#endif
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
 /*
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.1.95/linux/drivers/scsi/aha1542.c	Sun Jan  4 10:55:09 1998
+++ linux/drivers/scsi/aha1542.c	Sat Apr 11 11:13:25 1998
@@ -30,6 +30,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -129,6 +130,8 @@
 
 static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
 static int aha1542_restart(struct Scsi_Host * shost);
+static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
 
 #define aha1542_intr_reset(base)  outb(IRST, CONTROL(base))
 
@@ -363,6 +366,16 @@
     return 0;					/* 0 = not ok */
 }
 
+/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
+static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    aha1542_intr_handle(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 /* A "high" level interrupt handler */
 static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -1013,7 +1026,7 @@
 		    DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
 		    save_flags(flags);
 		    cli();
-		    if (request_irq(irq_level,aha1542_intr_handle, 0, "aha1542", NULL)) {
+		    if (request_irq(irq_level,do_aha1542_intr_handle, 0, "aha1542", NULL)) {
 			    printk("Unable to allocate IRQ for adaptec controller.\n");
 			    restore_flags(flags);
 			    goto unregister;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.reg	Tue Dec  2 20:41:21 1997
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Sat Apr 11 11:19:34 1998
@@ -10,10 +10,7 @@
  * 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
+ * 2. 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 
@@ -393,6 +390,27 @@
 }
 
 /*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+	address			0x01b
+	access_mode RW
+	bit	SOFT1		0x80
+	bit	SOFT0		0x40
+	bit	SOFTCMDEN	0x20	
+	bit	HAS_BRDCTL	0x10	/* External Board control */
+	bit	SEEPROM		0x08	/* External serial eeprom logic */
+	bit	EEPROM		0x04	/* Writable external BIOS ROM */
+	bit	ROM		0x02	/* Logic for accessing external ROM */
+	bit	SSPIOCPS	0x01	/* Termination and cable detection */
+}
+
+/*
  * 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
@@ -622,26 +640,19 @@
 	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	ABORT_REQUESTED 0x50|SEQINT	/* Reconect of aborted 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
+						 * a message to this target
+						 * (command was null), so tell
+						 * it that it can fill the
+						 * message buffer.
 						 */
+	mask	TRACEPOINT	0xb0|SEQINT
+	mask	TRACEPOINT2	0xc0|SEQINT
 	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
 						 * Target changed phase on us
 						 * when we were expecting
@@ -665,7 +676,10 @@
 register ERROR {
 	address			0x092
 	access_mode RO
-	bit	PARERR		0x08
+	bit	PCIERRSTAT	0x40	/* PCI only */
+	bit	MPARERR		0x20	/* PCI only */
+	bit	DPARERR		0x10	/* PCI only */
+	bit	SQPARERR	0x08
 	bit	ILLOPCODE	0x04
 	bit	ILLSADDR	0x02
 	bit	ILLHADDR	0x01
@@ -677,6 +691,7 @@
 register CLRINT {
 	address			0x092
 	access_mode WO
+	bit	CLRPARERR	0x10	/* PCI only */
 	bit	CLRBRKADRINT	0x08
 	bit	CLRSCSIINT      0x04
 	bit	CLRCMDINT 	0x02
@@ -771,8 +786,6 @@
 		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
 	}
@@ -801,10 +814,11 @@
 		size	4
 	}
 	SCB_DATACNT {
-		size	3
-	}
-	SCB_LINKED_NEXT {
-		size	1
+		/*
+		 * Really only 3 bytes, but padded to make
+		 * the kernel's job easier.
+		 */
+		size	4
 	}
 	SCB_CMDPTR {
 		size	4
@@ -924,6 +938,9 @@
 	TARG_SCRATCH {
 		size		16
 	}
+	/*
+	 * Bit vector of targets that have ULTRA enabled.
+	 */
 	ULTRA_ENB {
 		size		2
 	}
@@ -934,14 +951,11 @@
 		size		2
 	}
 	/*
-	 * Length of pending message
+	 * Single byte buffer used to designate the type or message
+	 * to send to a target.
 	 */
-	MSG_LEN	{
-		size		1
-	}
-	/* We reserve 8bytes to store outgoing messages */
 	MSG_OUT {
-		size		8
+		size		1
 	}
 	/* Parameters for DMA Logic */
 	DMAPARAMS {
@@ -956,35 +970,12 @@
 		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	IDENTIFY_SEEN	0x80
+		bit	SCBPTR_VALID	0x20
 		bit	DPHASE		0x10
-		bit	PAGESCBS	0x04
+		bit	AMTARGET	0x08
 		bit	WIDE_BUS	0x02
 		bit	TWIN_BUS	0x01
 	}
@@ -996,34 +987,15 @@
 	SAVED_TCL {
 		size		1
 	}
+	/* Working value of the number of SG segments left */
 	SG_COUNT {
 		size		1
 	}
-	/* working value of SG pointer */
+	/* 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 {
@@ -1040,23 +1012,12 @@
 		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.
+	 * head of list of SCBs awaiting
+	 * selection
 	 */
-	MSGIN_EXT_BYTES	{
-		size		3
+	WAITING_SCBH {
+		size		1
 	}
 	/*
 	 * head of list of SCBs that are
@@ -1073,10 +1034,40 @@
 	FREE_SCBH {
 		size		1
 	}
+	/*
+	 * Address of the hardware scb array in the host.
+	 */
 	HSCB_ADDR {
 		size		4
 	}
-	CUR_SCBID {
+	/*
+	 * Address of the 256 byte array storing the SCBID of outstanding
+	 * untagged SCBs indexed by TCL.
+	 */
+	SCBID_ADDR {
+		size		4
+	}
+	/*
+	 * Address of the array of command descriptors used to store
+	 * information about incoming selections.
+	 */
+	TMODE_CMDADDR {
+		size		4
+	}
+	KERNEL_QINPOS {
+		size		1
+	}
+	QINPOS {
+		size		1
+	}
+	QOUTPOS {
+		size		1
+	}
+	/*
+	 * Offset into the command descriptor array for the next
+	 * available desciptor to use.
+	 */
+	TMODE_CMDADDR_NEXT {
 		size		1
 	}
 	ARG_1 {
@@ -1084,30 +1075,13 @@
 		mask	SEND_MSG	0x80
 		mask	SEND_SENSE	0x40
 		mask	SEND_REJ	0x20
+		mask	MSGOUT_PHASEMIS	0x10
 		alias	RETURN_1
 	}
 	/*
-	 * Running count of commands placed in
-	 * the QOUTFIFO.  This is cleared by the
-	 * kernel driver every FIFODEPTH commands.
-	 *
-	 * NOTE: These scratch RAM registers are overlaying SCSICONF
-	 *       and SCSICONF2 and are only used on cards that are
-	 *       capable of SCB paging.   Currently, only the PCI
-	 *       controllers can do this, which is good because the
-	 *       AIC-7770 based controllers use the SCSICONF register
-	 *       to control termination.  In other words, do not
-	 *       destroy the contents of SCSICONF and SCSICONF2 for
-	 *       AIC-7770 based controllers.
+	 * Snapshot of MSG_OUT taken after each message is sent.
 	 */
-	CMDOUTCNT {
-		size		1
-	}
-	/*
-	 * Maximum number of entries allowed in
-	 * the QOUT/INFIFO.
-	 */
-	FIFODEPTH {
+	LAST_MSG {
 		size		1
 	}
 	/*
@@ -1118,12 +1092,10 @@
 	SCSICONF {
 		address		0x05a
 		size		1
+		bit	TERM_ENB	0x80
 		bit	RESET_SCSI	0x40
-	}
-        SCSICONF2 {
-		address		0x05b
-		size		1
-		bit	RESET_SCSI	0x40
+		mask	HSCSIID		0x07	/* our SCSI ID */
+		mask	HWSCSIID	0x0f	/* our SCSI ID if Wide Bus */
 	}
 	HOSTCONF {
 		address		0x05d
@@ -1140,6 +1112,10 @@
 
 const SCB_LIST_NULL	0xff
 
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET	0
+const QOUTFIFO_OFFSET		1
+const QINFIFO_OFFSET		2
 
 /* WDTR Message values */
 const BUS_8_BIT		0x00
@@ -1147,3 +1123,24 @@
 const BUS_32_BIT		0x02
 const MAX_OFFSET_8BIT		0x0f
 const MAX_OFFSET_16BIT	0x08
+const HOST_MSG		0xFF
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT	0x05
+const CMD_GROUP0_BYTE_DELTA	-4
+const CMD_GROUP2_BYTE_DELTA	-6
+const CMD_GROUP4_BYTE_DELTA	4
+const CMD_GROUP5_BYTE_DELTA	11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+/*
+ * Mask of bits to test against when looking at the Queue Count
+ * registers.  Works around a bug on aic7850 chips. 
+ */
+const QCNTMASK		download
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS	download
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- v2.1.95/linux/drivers/scsi/aic7xxx/aic7xxx.seq	Wed Aug 13 09:50:32 1997
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Sat Apr 11 11:19:34 1998
@@ -10,10 +10,7 @@
  * 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
+ * 2. 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 
@@ -38,8 +35,8 @@
  *	$Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
  */
 
-#include <aic7xxx.reg>
-#include <scsi_message.h>
+#include "aic7xxx.reg"
+#include "scsi_message.h"
 
 /*
  * A few words on the waiting SCB list:
@@ -59,18 +56,21 @@
  * 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 */
+.if ( TARGET_MODE )
+	mvi	SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+.else
 	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
+.endif
 	call	clear_target_state;
+	and	SXFRCTL0, ~SPIOEN;
 poll_for_work:
-	test	SSTAT0,SELDO	jnz select;
-	test	SSTAT0,SELDI	jnz reselect;
+	mov	A, QINPOS;
+poll_for_work_loop:
+	and	SEQCTL, ~PAUSEDIS;
+	test	SSTAT0, SELDO|SELDI	jnz selection;
 	test	SCSISEQ, ENSELO	jnz poll_for_work;
 .if ( TWIN_CHANNEL )
 	/*
@@ -80,16 +80,17 @@
 	 * 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	SSTAT0, SELDO|SELDI	jnz selection;
 	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;
+	or	SEQCTL, PAUSEDIS;
+	cmp	KERNEL_QINPOS, A je poll_for_work_loop;
+	inc	QINPOS;
+	and	SEQCTL, ~PAUSEDIS;
 
 /*
  * We have at least one queued SCB now and we don't have any 
@@ -99,76 +100,24 @@
  */
 .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;
+	add	A, -1, QINPOS;
+	mvi	QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+	call	dma_finish;
+	mov	SINDEX, DFDAT;
 .if !( SCB_PAGING )
 	/* In the non-paging case, the SCBID == hardware SCB index */
-	mov	SCBPTR, CUR_SCBID;
+	mov	SCBPTR, SINDEX;
 .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;
+	call	dma_scb;
 
 start_scb:
 	/*
@@ -179,9 +128,7 @@
 	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.
+	 * Pull the first entry off of the waiting SCB list.
 	 */
 	mov	SCBPTR, WAITING_SCBH;
 	call	start_selection;
@@ -199,17 +146,170 @@
 	and	SCSIID, OID;		/* Clear old target */
 	or	SCSIID, A;
 	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+	or	A, CLRSTCNT|CLRCHN, SINDEX;
+	or	SXFRCTL0, A;
+.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 ret;
+
+
+selection:
+	test	SSTAT0,SELDO	jnz select_out;
+select_in:
+.if ( TARGET_MODE )
+	test	SSTAT0, TARGET	jz initiator_reselect;
+	/*
+	 * We've just been selected.  Assert BSY and
+	 * setup the phase for receiving the messages
+	 * from the target.
+	 */
+	mvi	SCSISIGO, P_MESGOUT|BSYO;
+	mvi	CLRSINT0, CLRSELDO;
+
+	/*
+	 * If ATN isn't asserted, go directly to bus free.
+	 */
+	test	SCSISIGI, ATNI	jz	target_busfree;
+
+	/*
+	 * Setup the DMA for sending the identify and
+	 * command information.
+	 */
+	mov	A, TMODE_CMDADDR_NEXT;
+	mvi	TMODE_CMDADDR call set_32byte_haddr_and_clrcnt;
+	mvi	DFCNTRL, FIFORESET;
+
+	clr	SINDEX;
+	/* Watch ATN closely now */
+message_loop:
+	or	SXFRCTL0, SPIOEN;
+	test	SSTAT0, SPIORDY jz .;
+	and	SXFRCTL0, ~SPIOEN;
+	mov	DINDEX, SCSIDATL;
+	mov	DFDAT, DINDEX;
+	inc	SINDEX;
+
+	/* Message Testing... */
+	test	DINDEX, MSG_IDENTIFYFLAG jz . + 2;
+	mov	ARG_1, DINDEX;
+
+	test	SCSISIGI, ATNI	jnz	message_loop;
+	add	A, -4, SINDEX;
+	jc	target_cmdphase;
+	mvi	DFDAT, SCB_LIST_NULL;	/* Terminate the message list */
+
+target_cmdphase:
+	add	HCNT[0], 1, A;
+	mvi	SCSISIGO, P_COMMAND|BSYO;
+	or	SXFRCTL0, SPIOEN;
+	test	SSTAT0, SPIORDY jz .;
+	mov	A, SCSIDATL;
+	mov	DFDAT, A;	/* Store for host */
+
+	/*
+	 * Determine the number of bytes to read
+	 * based on the command group code.  Count is
+	 * one less than the total since we've already
+	 * fetched the first byte.
+	 */
+	clr	SINDEX;
+	shr	A, CMD_GROUP_CODE_SHIFT;
+	add	SEQADDR0, A;
+
+	add	SINDEX, CMD_GROUP0_BYTE_DELTA;
+	nop;	/* Group 1 and 2 are the same */
+	add	SINDEX, CMD_GROUP2_BYTE_DELTA;
+	nop;	/* Group 3 is reserved */
+	add	SINDEX, CMD_GROUP4_BYTE_DELTA;
+	add	SINDEX, CMD_GROUP5_BYTE_DELTA;
+		/* Group 6 and 7 are not handled yet */
+
+	mov	A, SINDEX;
+	add	HCNT[0], A;
+
+command_loop:
+	test	SSTAT0, SPIORDY jz .;
+	cmp	SINDEX, 1 jne . + 2;
+	and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
+	mov	DFDAT, SCSIDATL;
+	dec	SINDEX;
+	test	SINDEX, 0xFF jnz command_loop;
+
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+	
+	call	dma_finish;
+
+	test	ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+
+	mvi	SCSISIGO, P_MESGIN|BSYO;
+
+	or	SXFRCTL0, SPIOEN;
+
+	mvi	MSG_DISCONNECT call target_outb;
+	
+selectin_post:
+	inc	TMODE_CMDADDR_NEXT;
+	cmp	TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+	clr	TMODE_CMDADDR_NEXT;
+	mvi	QOUTFIFO, SCB_LIST_NULL;
+	mvi	INTSTAT,CMDCMPLT;
+
+	test	ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
+
+	/* Busy loop on something then go to data or status phase */
+
+target_busfree:
+	clr	SCSISIGO;
+	jmp	poll_for_work;
+
+.endif /* TARGET_MODE */
 /*
  * 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 */
+initiator_reselect:
 	mvi	CLRSINT0, CLRSELDI;
 	/* XXX test for and handle ONE BIT condition */
 	and	SAVED_TCL, SELID_MASK, SELID;
-	or	SEQ_FLAGS,RESELECTED;
-	jmp	select2;
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+	mvi	SPIOEN call	initialize_channel;
+	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */
+	jmp	ITloop;
 
 /*
  * After the selection, remove this SCB from the "waiting SCB"
@@ -217,7 +317,7 @@
  * 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:
+select_out:
 	/* Turn off the selection hardware */
 	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
 						 * ATN on parity errors
@@ -227,41 +327,6 @@
 	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
@@ -269,54 +334,24 @@
 						 * the kernel driver if it
 						 * happens.
 						 */
+	mvi	SPIOEN call	initialize_channel;
 /*
- * 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.
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
  */
-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;
-
+	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
+	or	SEQ_FLAGS, IDENTIFY_SEEN;
 
 /*
- * 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.
- *
+ * Main loop for information transfer phases.  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;
+	call	phase_lock;
 
-	and	A,PHASE_MASK,SCSISIGI;
-	mov	LASTPHASE,A;
-	mov	SCSISIGO,A;
+	mov	A, LASTPHASE;
 
-	cmp	ALLZEROS,A	je p_dataout;
-	cmp	A,P_DATAIN	je p_datain;
+	test	A, ~P_DATAIN	jz p_data;
 	cmp	A,P_COMMAND	je p_command;
 	cmp	A,P_MESGOUT	je p_mesgout;
 	cmp	A,P_STATUS	je p_status;
@@ -329,25 +364,27 @@
 	and	SIMODE1, ~ENBUSFREE;
 	call	clear_target_state;
 	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	and	SXFRCTL0, ~SPIOEN;
 	test	SSTAT1,REQINIT|BUSFREE	jz .;
 	test	SSTAT1, BUSFREE jnz poll_for_work;
 	mvi	INTSTAT, BAD_PHASE;
 	
 clear_target_state:
-	clr	DFCNTRL;
+	clr	DFCNTRL;		/*
+					 * We assume that the kernel driver
+					 * may reset us at any time, even
+					 * in the middle of a DMA, so clear
+					 * DFCNTRL too.
+					 */
 	clr	SCSIRATE;		/*
 					 * We don't know the target we will
 					 * connect to, so default to narrow
 					 * transfers to avoid parity problems.
 					 */
-	and	SXFRCTL0, ~FAST20;	
+	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;
+	and	SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
 
 /*
  * If we re-enter the data phase after going through another phase, the
@@ -358,9 +395,10 @@
 	mvi	SCB_RESID_DCNT	call bcopy_3;
 	jmp	data_phase_loop;
 
-p_datain:
+p_data:
 	mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-data_phase_init:
+	test	LASTPHASE, IOI jnz . + 2;
+	or	DMAPARAMS, DIRECTION;
 	call	assert;			/*
 					 * Ensure entering a data
 					 * phase is okay - seen identify, etc.
@@ -398,6 +436,7 @@
 	mvi	HCNT[1], 0xff;
 	mvi	HCNT[2], 0xff;
 	call	set_stcnt_from_hcnt;
+	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
 
 data_phase_inbounds:
 /* If we are the last SG block, ensure wideodd is off. */
@@ -512,54 +551,85 @@
 	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.
+ * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
  */
 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.
+	mov	SINDEX, MSG_OUT;
+	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+.if ( WIDE )
+	and	SINDEX,0xf,SCB_TCL;	/* lun */
+.else
+	and	SINDEX,0x7,SCB_TCL;	/* lun */
+.endif
+	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
+	or	SINDEX,A;		/* or in disconnect privledge */
+	or	SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+	test	SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
+	mov	SCSIDATL, SINDEX;	/* Send the last byte */
+	jmp	p_mesgout_from_host + 1;/* Skip HOST_MSG test */
+/*
+ * 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.
  */
-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;
+p_mesgout_tag:
+	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+	mov	SCSIDATL, SINDEX;	/* Send the identify message */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	mov	SCB_TAG	jmp p_mesgout_onebyte;
+/*
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
+ */
+p_mesgout_from_host:
+	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
+	mvi     INTSTAT,AWAITING_MSG;
+	/*
+	 * Did the host detect a phase change?
+	 */
+	cmp	RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+	mvi	CLRSINT1, CLRATNO;
+	mov	SCSIDATL, SINDEX;
+
 /*
  * 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;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+	jmp	p_mesgout;
 
 p_mesgout_done:
 	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
-	clr	MSG_LEN;		/* no active msg */
+	mov	LAST_MSG, MSG_OUT;
+	cmp	MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
 	jmp	ITloop;
 
 /*
@@ -567,7 +637,6 @@
  */
 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;
@@ -597,8 +666,8 @@
 /*
  * 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
+ * is a residual or the status byte is something other than STATUS_GOOD (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
@@ -616,60 +685,17 @@
  * First check for residuals
  */
 	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
-	test	SCB_TARGET_STATUS,0xff	jz status_ok;	/* Good Status? */
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* 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? */
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Just a residual? */
 	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
-	cmp	RETURN_1, SEND_SENSE	jne status_ok;
+	cmp	RETURN_1, SEND_SENSE	jne complete;
 	/* 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 */
-.if ( SCB_PAGING )
-	/*
-	 * Spin loop until there is space
-	 * in the QOUTFIFO.
-	 */
-	mov	A, FIFODEPTH;
-	cmp	CMDOUTCNT, A	je .;
-	inc	CMDOUTCNT;
-.endif
-	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;
+	mov	SCB_TAG		call dma_scb;
 add_to_waiting_list:
 	mov	SCB_NEXT,WAITING_SCBH;
 	mov	WAITING_SCBH, SCBPTR;
@@ -679,6 +705,28 @@
 	 */
 	call	start_selection;
 	jmp	await_busfree;
+
+complete:
+	/* If we are untagged, clear our address up in host ram */
+	test	SCB_CONTROL, TAG_ENB jnz complete_post;
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, FIFORESET;
+	mvi	DFDAT, SCB_LIST_NULL;
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+	call	dma_finish;
+
+complete_post:
+	/* Post the SCB and issue an interrupt */
+	mov	A, QOUTPOS;
+	mvi	QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, FIFORESET;
+	mov	DFDAT, SCB_TAG;
+	or	DFCNTRL, HDMAEN|FIFOFLUSH;
+	call	dma_finish;
+	inc 	QOUTPOS;
+	mvi	INTSTAT,CMDCMPLT;
+
 add_to_free_list:
 	call	add_scb_to_free_list;
 	jmp	await_busfree;
@@ -690,22 +738,8 @@
  * 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;
+	jmp	ITloop;
 
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -713,9 +747,7 @@
  */
 mesgin_disconnect:
 	or	SCB_CONTROL,DISCONNECTED;
-.if ( SCB_PAGING )
 	call	add_scb_to_disc_list;
-.endif
 	jmp	await_busfree;
 
 /*
@@ -764,24 +796,30 @@
  * clearing the "disconnected" bit so we don't "find" it by accident later.
  */
 mesgin_identify:
-	test	A,0x78	jnz rej_mesgin;	/*!DiscPriv|!LUNTAR|!Reserved*/
+.if ( WIDE )
+	and	A,0x0f;			/* lun in lower four bits */
+.else
 	and	A,0x07;			/* lun in lower three bits */
+.endif
 	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
-	mov	SAVED_TCL call index_untagged_scb;
-	mov	ARG_1, SINDIR;
+
+	call	get_untagged_SCBID;
+	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
 .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;
+	test	SEQ_FLAGS, SCBPTR_VALID	jz use_retrieveSCB;
 .endif
+	/*
+	 * If the SCB was found in the disconnected list (as is
+	 * always the case in non-paging scenarios), SCBPTR is already
+	 * set to the correct SCB.  So, simply setup the SCB and get
+	 * on with things.
+	 */
+	mov	SCBPTR	call rem_scb_from_disc_list;
+	jmp	setup_SCB;
 /*
  * 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
+ * SCB.  With SCB paging, this requires using search 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.
@@ -789,44 +827,42 @@
 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;
+	call	phase_lock;
 	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;
+	mov	SCBPTR	call rem_scb_from_disc_list;
 .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;
+use_retrieveSCB:
+	call	retrieveSCB;
 .endif
 setup_SCB:
+	mov	A, SAVED_TCL;
+	cmp	SCB_TCL, A	jne not_found_cleanup_scb;
+	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
 	and	SCB_CONTROL,~DISCONNECTED;
 	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
+	/* See if the host wants to send a message upon reconnection */
+	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	HOST_MSG	call mk_mesg;
 	jmp	mesgin_done;
 
+not_found_cleanup_scb:
+	test	SCB_CONTROL, DISCONNECTED jz . + 3;
+	call	add_scb_to_disc_list;
+	jmp	not_found;
+	call	add_scb_to_free_list;
 not_found:
 	mvi	INTSTAT, NO_MATCH;
 	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
@@ -851,23 +887,8 @@
  * 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;
+	mov	MSG_OUT,SINDEX ret;
 
 /*
  * Functions to read data in Automatic PIO mode.
@@ -903,6 +924,17 @@
 inb_last:
 	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
 
+.if ( TARGET_MODE )
+/*
+ * Send a byte to an initiator in Automatic PIO mode.
+ * SPIOEN must be on prior to calling this routine.
+ */
+target_outb:
+	mov	SCSIDATL, SINDEX;
+	test	SSTAT0, SPIORDY	jz .;
+	ret;
+.endif
+	
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -957,60 +989,114 @@
  * 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.
+ * or by the SCBID ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list.  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	SCBPTR,SINDEX;			/* Initialize SCBPTR */
+	cmp	ARG_1, SCB_LIST_NULL	jne findSCB_by_SCBID;
+	mov	A, SAVED_TCL;
+	mvi	SCB_TCL	jmp findSCB_loop;	/* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
 	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*/
+	mvi	SCB_TAG	jmp findSCB_loop;	/* &SCB_TAG -> SINDEX */
+findSCB_next:
+	cmp	SCB_NEXT, SCB_LIST_NULL je notFound;
+	mov	SCBPTR,SCB_NEXT;
+	dec	SINDEX;		/* Last comparison moved us too far */
 findSCB_loop:
-	inc	SINDEX;
-	mov	A,SCBCOUNT;
-	cmp	SINDEX,A	jne findSCB;
+	cmp	SINDIR, A	jne findSCB_next;
+	mov	SINDEX, SCBPTR 	ret;
+notFound:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+
+/*
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host.  This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+	test	SEQ_FLAGS, SCBPTR_VALID	jz retrieve_from_host;
+	mov	SCBPTR	call findSCB;	/* Continue the search */
+	cmp	SINDEX, SCB_LIST_NULL	je retrieve_from_host;
+
 /*
- * 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.
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed and SCBPTR to be pointing to that SCB.
  */
-	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	DINDEX, SCB_PREV;
 	mov	SCBPTR, SCB_NEXT;
-	mov	SCB_PREV, SAVED_LINKPTR;
+	mov	SCB_PREV, DINDEX;
 	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	DINDEX, SCB_NEXT;
 	mov	SCBPTR, SCB_PREV;
-	mov	SCB_NEXT, SAVED_LINKPTR;
+	mov	SCB_NEXT, DINDEX;
 	mov	SCBPTR, SINDEX ret;
 rHead:
 	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
-.else
-	ret;
-.endif
+
+retrieve_from_host:
+/*
+ * We didn't find it.  Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+	mov	ALLZEROS	call	get_free_or_disc_scb;
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	/* Jump instead of call as we want to return anyway */
+	mov	ARG_1	jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL.  The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+	mvi	ARG_1, SCB_LIST_NULL;
+	mov	DISCONNECTED_SCBH call findSCB;
+	cmp	SINDEX, SCB_LIST_NULL	je get_SCBID_from_host;
+	or	SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+	test	SCB_CONTROL, TAG_ENB	jnz . + 2;
+	mov	ARG_1, SCB_TAG	ret;
+	mvi	ARG_1, SCB_LIST_NULL ret;
+
+set_SCBID_host_addr_and_cnt:
+	mov	DINDEX, SINDEX;
+	mvi	SCBID_ADDR call	set_1byte_haddr_and_clrcnt;
+	mvi	HCNT[0], 1 ret;
+
+get_SCBID_from_host:
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+	mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+	call	dma_finish;
+	mov	ARG_1, DFDAT ret;
+
+phase_lock:     
+	test	SSTAT1, REQINIT jz phase_lock;
+	test	SSTAT1, SCSIPERR jnz phase_lock;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	mov	SCSISIGO, LASTPHASE ret;
 
 set_stcnt_from_hcnt:
 	mov	STCNT[0], HCNT[0];
@@ -1029,23 +1115,32 @@
 	mov	DINDIR, SINDIR;
 	mov	DINDIR, SINDIR ret;
 
+/*
+ * Setup haddr and count assuming that A is an
+ * index into an array of 32byte objects.
+ */
+set_32byte_haddr_and_clrcnt:
+	shr	DINDEX, 3, A;
+	shl	A, 5;
+set_1byte_haddr_and_clrcnt:	/* DINDEX must be 0 upon call */
+	add	HADDR[0], A, SINDIR;
+	mov	A, DINDEX;
+	adc	HADDR[1], A, SINDIR;
+	clr	A;
+	adc	HADDR[2], A, SINDIR;
+	adc	HADDR[3], A, SINDIR;
+	/* Clear Count */
+	clr	HCNT[1];
+	clr	HCNT[2] 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 */
+	mov	A, SINDEX;
+	mvi	HSCB_ADDR call set_32byte_haddr_and_clrcnt;
 	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 */
@@ -1092,25 +1187,12 @@
 	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:
+.if ( SCB_PAGING )
 	mov	SCB_NEXT, FREE_SCBH;
-	mvi	SCB_TAG, SCB_LIST_NULL;
-	mov	FREE_SCBH, SCBPTR ret;
+	mov	FREE_SCBH, SCBPTR;
+.endif
+	mvi	SCB_TAG, SCB_LIST_NULL ret;
 
 .if ( SCB_PAGING )
 get_free_or_disc_scb:
@@ -1120,16 +1202,6 @@
 	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;
@@ -1139,6 +1211,7 @@
 dequeue_free_scb:
 	mov	SCBPTR, FREE_SCBH;
 	mov	FREE_SCBH, SCB_NEXT ret;
+.endif
 
 add_scb_to_disc_list:
 /*
@@ -1153,4 +1226,3 @@
 	mov	SCBPTR,SCB_NEXT;
 	mov	SCB_PREV,DISCONNECTED_SCBH;
 	mov	SCBPTR,DISCONNECTED_SCBH ret;
-.endif
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h
--- v2.1.95/linux/drivers/scsi/aic7xxx/scsi_message.h	Thu Jul 31 12:37:17 1997
+++ linux/drivers/scsi/aic7xxx/scsi_message.h	Sat Apr 11 11:19:34 1998
@@ -1,7 +1,3 @@
-/*
- * 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 */
@@ -30,6 +26,7 @@
 
 /* Identify message */		     /* M/M */	
 #define MSG_IDENTIFYFLAG	0x80 
+#define MSG_IDENTIFY_DISCFLAG	0x40 
 #define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
 #define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
 
@@ -39,3 +36,6 @@
 
 #define MSG_EXT_WDTR		0x03
 #define MSG_EXT_WDTR_LEN	0x02
+#define MSG_EXT_WDTR_BUS_8_BIT	0x00
+#define MSG_EXT_WDTR_BUS_16_BIT	0x01
+#define MSG_EXT_WDTR_BUS_32_BIT	0x02 
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h
--- v2.1.95/linux/drivers/scsi/aic7xxx/sequencer.h	Thu Jul 31 12:37:17 1997
+++ linux/drivers/scsi/aic7xxx/sequencer.h	Sat Apr 11 11:19:34 1998
@@ -11,10 +11,7 @@
  * 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
+ * 2. 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 
@@ -36,49 +33,46 @@
  * 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 $
+ *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 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;
+	unsigned char immediate;
+	unsigned char source;
+	unsigned char destination;
+	unsigned char opcode_ret;
+#define DOWNLOAD_CONST_IMMEDIATE 0x80
 };
 
 struct ins_format2 {
-	u_int8_t shift_control;
-	u_int8_t source;
-	u_int8_t destination;
-	u_int8_t opcode_ret;
+	unsigned char shift_control;
+	unsigned char source;
+	unsigned char destination;
+	unsigned char 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;
+	unsigned char immediate;
+	unsigned char source;
+	unsigned char address;
+	unsigned char opcode_addr;
 #define ADDR_HIGH_BIT 0x01
 };
 
+#ifndef __KERNEL__
 struct instruction {
 	union {
 		struct ins_format1 format1;
 		struct ins_format2 format2;
 		struct ins_format3 format3;
-		u_int8_t	   bytes[4];
+		unsigned char	   bytes[4];
 	} format;
 	u_int	srcline;
 	struct symbol *patch_label;
-	struct {
-		struct instruction *stqe_next; /* next element */
-	} links;
+	STAILQ_ENTRY(instruction) links;
 };
+#endif
 
 #define	AIC_OP_OR	0x0
 #define	AIC_OP_AND	0x1
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.1.95/linux/drivers/scsi/aic7xxx.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/aic7xxx.c	Mon Apr 13 13:39:25 1998
@@ -38,7 +38,7 @@
  *  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.
  *
@@ -96,6 +96,73 @@
  *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
  *-M*************************************************************************/
 
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@dialnet.net>
+ *
+ * Copyright (c) 1997-1998 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accomodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
+ * itself.  A diff between the two version of the driver is now a several
+ * thousand line diff.  Second, in approach to solving the same problem.  The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone.  Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible.  To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver.  He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach.  Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux.  I have no objection to those issues.  My
+ * disagreement is on the needed functionality.  There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics.  Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers.  For the time
+ * being, I see issues such as these as major stumbling blocks to the 
+ * reliability of code based upon such middle ware.  Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code.  My approach is to import the sequencer
+ * code from FreeBSD wholesale.  Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements.  But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State".  Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
 #ifdef MODULE
 #include <linux/module.h>
 #endif
@@ -103,6 +170,7 @@
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -112,6 +180,8 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
+#include <linux/tqueue.h>
+#include <linux/tasks.h>
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -121,10 +191,11 @@
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
 #include "aic7xxx_seq.h"
+
 #include <linux/stat.h>
-#include <linux/malloc.h>	/* for kmalloc() */
+#include <linux/malloc.h>        /* for kmalloc() */
 
-#include <linux/config.h>	/* for CONFIG_PCI */
+#include <linux/config.h>        /* for CONFIG_PCI */
 
 /*
  * To generate the correct addresses for the controller to issue
@@ -138,13 +209,13 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.1 $"
+#define AIC7XXX_C_VERSION  "5.0.13"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #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_CHANNELS -1
 #define ALL_LUNS -1
 #define MAX_TARGETS  16
 #define MAX_LUNS     8
@@ -155,75 +226,78 @@
 #  define FALSE 0
 #endif
 
+#ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
 /*
- * Defines for PCI bus support, testing twin bus support, DMAing of
- * SCBs, tagged queueing, commands (SCBs) per lun, and SCSI bus reset
- * delay time.
- *
- *   o PCI bus support - this has been implemented and working since
- *     the December 1, 1994 release of this driver. If you don't have
- *     a PCI bus, then you can configure your kernel without PCI
- *     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.  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
- *     tagged queueing. Therefore, the maximum commands per lun is
- *     set to 2. If you want to implement tagged queueing, ensure
- *     this define is not commented out.
- *
- *   o Commands 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.
- *
- *   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
- *     FreeBSD driver (by Justin Gibbs) and allows for up to 255
- *     active SCBs.  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 sharing of IRQs is not an option any longer.  Linux supports
- *  it so we support it.
- *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
- */
-
-/* Uncomment this for tagged queueing. */
-#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
-#define AIC7XXX_TAGGED_QUEUEING
+ * We need the bios32.h file if we are kernel version 2.1.92 or less.  The
+ * full set of pci_* changes wasn't in place until 2.1.93
+ */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
+#  if defined(__sparc_v9__) || defined(__powerpc__)
+#    error "PPC and Sparc platforms are only support under 2.1.x and above"
+#  endif
+#  include <linux/bios32.h>
+#endif
+
+#if !defined(__alpha__)
+#  define MMAPIO
+#endif
+
+#if defined(__powerpc__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("eieio" ::: "memory")
+#elif defined(__i386__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
+#elif defined(__alpha__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("mb": : :"memory")
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+#  include <asm/spinlock.h>
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+#    define DRIVER_LOCK_INIT \
+       spin_lock_init(&p->spin_lock);
+#    define DRIVER_LOCK \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+#  else
+#    define DRIVER_LOCK_INIT
+#    define DRIVER_LOCK
+#    define DRIVER_UNLOCK
+#  endif
+#else
+#  define cpuid 0
+#  define DRIVER_LOCK_INIT
+#  define DRIVER_LOCK \
+       save_flags(cpu_flags); \
+       cli();
+#  define DRIVER_UNLOCK \
+       restore_flags(cpu_flags);
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
 #endif
 
 /*
@@ -238,7 +312,7 @@
 #ifdef CONFIG_AIC7XXX_RESET_DELAY
 #define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
 #else
-#define AIC7XXX_RESET_DELAY 15
+#define AIC7XXX_RESET_DELAY 5
 #endif
 
 /*
@@ -252,32 +326,18 @@
 #endif
 
 /*
- * Enable SCB paging.
- */
-#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
-#define AIC7XXX_PAGE_ENABLE
-#endif
-
-/*
- * 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.
- */
-#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
-#define AIC7XXX_USE_EXT_SCBRAM
-#endif
-
-/*
- * For debugging the abort/reset code.
- */
-#define AIC7XXX_DEBUG_ABORT
-
-/*
- * For general debug messages
- */
-#define AIC7XXX_DEBUG
-
-/*
+ * NOTE: Uncommenting the define below no longer has any effect, the
+ *       tagged queue value array is always active now.  I've added
+ *       a setup option to set this particular array and I'm hoping
+ *       insmod will be smart enough to set it properly as well.  It's
+ *       by use of this array that a person can disable tagged queueing.
+ *       The DEFAULT_TAG_COMMANDS define has been changed to disable
+ *       tagged queueing by default, so if your devices can handle tagged
+ *       queueing you will need to add a line to their lilo.conf file like:
+ *       append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ *       which will result in the first four devices on the first two
+ *       controllers being set to a tagged queue depth of 32.
+ *
  * 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
@@ -292,37 +352,36 @@
  * 
  * 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.
- *
+ * enabled, which is always now, the default is 8 commands per lun
+ * that indicates it supports tagged queueing.  All non-tagged devices
+ * use an internal queue depth of 3, with no more than one of those
+ * three commands active at one time.
  */
 /* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
 
-#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
 typedef struct
 {
-  unsigned char tag_commands[16];   /* Allow for wide/twin channel adapters. */
+  unsigned char tag_commands[16];   /* Allow for wide/twin 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).
+ * Make a define that will tell the driver not to use tagged queueing
+ * by default.
  */
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
+                              255, 255, 255, 255, 255, 255, 255, 255}
 
 /*
  * 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
+ * number of commands to use (see above).  When 255, 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.
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
  *
- * 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.
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
  *
  * 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
@@ -335,107 +394,42 @@
  * 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}},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
   {DEFAULT_TAG_COMMANDS},
-  {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+  {{255, 16, 4, 255, 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 {
-  AIC_NONE,
-  AIC_7770,	/* EISA aic7770 on motherboard */
-  AIC_7771,	/* EISA aic7771 on 274x */
-  AIC_284x,	/* VLB  aic7770 on 284x, BIOS disabled */
-  AIC_7850,	/* PCI  aic7850 */
-  AIC_7855,	/* PCI  aic7855 */
-  AIC_7860,	/* PCI  aic7860 (7850 Ultra) */
-  AIC_7861,     /* PCI  aic7861 on 2940AU */
-  AIC_7870,	/* PCI  aic7870 on motherboard */
-  AIC_7871,	/* PCI  aic7871 on 294x */
-  AIC_7872,	/* PCI  aic7872 on 3940 */
-  AIC_7873,	/* PCI  aic7873 on 3985 */
-  AIC_7874,	/* PCI  aic7874 on 294x Differential */
-  AIC_7880,	/* PCI  aic7880 on motherboard */
-  AIC_7881,	/* PCI  aic7881 on 294x Ultra */
-  AIC_7882,	/* PCI  aic7882 on 3940 Ultra */
-  AIC_7883,	/* PCI  aic7883 on 3985 Ultra */
-  AIC_7884	/* PCI  aic7884 on 294x Ultra Differential */
-} aha_chip_type;
-
-typedef enum {
-  AIC_777x,	/* AIC-7770 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 (ultra) */
-} aha_chip_class_type;
-
-typedef enum {
-  AIC_SINGLE,  /* Single Channel */
-  AIC_TWIN,    /* Twin Channel */
-  AIC_WIDE     /* Wide Channel */
-} aha_bus_type;
-
-typedef enum {
-  AIC_UNKNOWN,
-  AIC_ENABLED,
-  AIC_DISABLED
-} aha_status_type;
-
-typedef enum {
-  LIST_HEAD,
-  LIST_SECOND
-} insert_type;
-
-typedef enum {
-  ABORT_RESET_INACTIVE,
-  ABORT_RESET_PENDING,
-  ABORT_RESET_SUCCESS
-} aha_abort_reset_type;
+*/
 
 /*
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "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 */
+  "AIC-7xxx Unknown",                                   /* AIC_NONE */
+  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
+  "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 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter"            /* AIC_7895 */
 };
 
 /*
@@ -460,58 +454,58 @@
 #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 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)
  */
-#define HID0		0x80   /* 0,1: msb of ID2, 2-7: ID1      */
-#define HID1		0x81   /* 0-4: ID3, 5-7: LSB ID2         */
-#define HID2		0x82   /* product                        */
-#define HID3		0x83   /* firmware revision              */
+#define HID0                0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define HID1                0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define HID2                0x82   /* product                        */
+#define HID3                0x83   /* firmware revision              */
 
 /*
  * AIC-7770 I/O range to reserve for a card
  */
-#define MINREG		0xC00
-#define MAXREG		0xCBF
+#define MINREG                0xC00
+#define MAXREG                0xCBF
 
-#define INTDEF		0x5C		/* Interrupt Definition Register */
+#define INTDEF                0x5C      /* Interrupt Definition Register */
 
 /*
  * AIC-78X0 PCI registers
  */
-#define	CLASS_PROGIF_REVID	0x08
-#define		DEVREVID	0x000000FFul
-#define		PROGINFC	0x0000FF00ul
-#define		SUBCLASS	0x00FF0000ul
-#define		BASECLASS	0xFF000000ul
-
-#define	CSIZE_LATTIME		0x0C
-#define		CACHESIZE	0x0000003Ful	/* only 5 bits */
-#define		LATTIME		0x0000FF00ul
-
-#define	DEVCONFIG		0x40
-#define		MPORTMODE	0x00000400ul	/* aic7870 only */
-#define		RAMPSM		0x00000200ul	/* aic7870 only */
-#define		VOLSENSE	0x00000100ul
-#define		SCBRAMSEL	0x00000080ul
-#define		MRDCEN		0x00000040ul
-#define		EXTSCBTIME	0x00000020ul	/* aic7870 only */
-#define		EXTSCBPEN	0x00000010ul	/* aic7870 only */
-#define		BERREN		0x00000008ul
-#define		DACEN		0x00000004ul
-#define		STPWLEVEL	0x00000002ul
-#define		DIFACTNEGEN	0x00000001ul	/* aic7870 only */
+#define        CLASS_PROGIF_REVID        0x08
+#define                DEVREVID        0x000000FFul
+#define                PROGINFC        0x0000FF00ul
+#define                SUBCLASS        0x00FF0000ul
+#define                BASECLASS        0xFF000000ul
+
+#define        CSIZE_LATTIME                0x0C
+#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
+#define                LATTIME                0x0000FF00ul
+
+#define        DEVCONFIG                0x40
+#define                SCBSIZE32        0x00010400ul        /* aic789X only */
+#define                MPORTMODE        0x00000400ul        /* aic7870 only */
+#define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                VOLSENSE         0x00000100ul
+#define                SCBRAMSEL        0x00000080ul
+#define                MRDCEN           0x00000040ul
+#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
+#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
+#define                BERREN           0x00000008ul
+#define                DACEN            0x00000004ul
+#define                STPWLEVEL        0x00000002ul
+#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
 
 
 /*
@@ -535,69 +529,72 @@
 /*
  * SCSI ID Configuration Flags
  */
-#define CFXFER		0x0007		/* synchronous transfer rate */
-#define CFSYNCH		0x0008		/* enable synchronous transfer */
-#define CFDISC		0x0010		/* enable disconnection */
-#define CFWIDEB		0x0020		/* wide bus device (wide card) */
-/* UNUSED		0x00C0 */
-#define CFSTART		0x0100		/* send start unit SCSI command */
-#define CFINCBIOS	0x0200		/* include in BIOS scan */
-#define CFRNFOUND	0x0400		/* report even if not found */
-/* UNUSED		0xF800 */
-  unsigned short device_flags[16];	/* words 0-15 */
+#define CFXFER                0x0007      /* synchronous transfer rate */
+#define CFSYNCH               0x0008      /* enable synchronous transfer */
+#define CFDISC                0x0010      /* enable disconnection */
+#define CFWIDEB               0x0020      /* wide bus device (wide card) */
+#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
+/* UNUSED                0x0080 */
+#define CFSTART               0x0100      /* send start unit SCSI command */
+#define CFINCBIOS             0x0200      /* include in BIOS scan */
+#define CFRNFOUND             0x0400      /* report even if not found */
+#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
+/* UNUSED                0xF000 */
+  unsigned short device_flags[16];        /* words 0-15 */
 
 /*
  * BIOS Control Bits
  */
-#define CFSUPREM	0x0001		/* support all removable drives */
-#define CFSUPREMB	0x0002		/* support removable drives for boot only */
-#define CFBIOSEN	0x0004		/* BIOS enabled */
-/* UNUSED		0x0008 */
-#define CFSM2DRV	0x0010		/* support more than two drives */
-#define CF284XEXTEND	0x0020		/* extended translation (284x cards) */
-/* UNUSED		0x0040 */
-#define CFEXTEND	0x0080		/* extended translation enabled */
-/* UNUSED		0xFF00 */
-  unsigned short bios_control;		/* word 16 */
+#define CFSUPREM        0x0001  /* support all removable drives */
+#define CFSUPREMB       0x0002  /* support removable drives for boot only */
+#define CFBIOSEN        0x0004  /* BIOS enabled */
+/* UNUSED                0x0008 */
+#define CFSM2DRV        0x0010  /* support more than two drives */
+#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
+/* UNUSED                0x0040 */
+#define CFEXTEND        0x0080  /* extended translation enabled */
+/* UNUSED                0xFF00 */
+  unsigned short bios_control;  /* word 16 */
 
 /*
  * Host Adapter Control Bits
  */
-#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 */
-#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 boot */
-/* UNUSED		0xFF80 */
-  unsigned short adapter_control;	/* word 17 */
+#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 */
+#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 boot */
+#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
+/* UNUSED                0xFE80 */
+  unsigned short adapter_control;        /* word 17 */
 
 /*
  * Bus Release, Host Adapter ID
  */
-#define CFSCSIID	0x000F		/* host adapter SCSI ID */
-/* UNUSED		0x00F0 */
-#define CFBRTIME	0xFF00		/* bus release time */
-  unsigned short brtime_id;		/* word 18 */
+#define CFSCSIID        0x000F                /* host adapter SCSI ID */
+/* UNUSED                0x00F0 */
+#define CFBRTIME        0xFF00                /* bus release time */
+  unsigned short brtime_id;                /* word 18 */
 
 /*
  * Maximum targets
  */
-#define CFMAXTARG	0x00FF	/* maximum targets */
-/* UNUSED		0xFF00 */
-  unsigned short max_targets;		/* word 19 */
+#define CFMAXTARG        0x00FF        /* maximum targets */
+/* UNUSED                0xFF00 */
+  unsigned short max_targets;                /* word 19 */
 
-  unsigned short res_1[11];		/* words 20-30 */
-  unsigned short checksum;		/* word 31 */
+  unsigned short res_1[11];                /* words 20-30 */
+  unsigned short checksum;                /* word 31 */
 };
 
-#define SELBUS_MASK		0x0a
-#define 	SELNARROW	0x00
-#define 	SELBUSB		0x08
-#define SINGLE_BUS		0x00
+#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)
@@ -612,17 +609,22 @@
  * condition in this location. This then will modify a DID_OK status
  * into an appropriate error for the higher-level SCSI code.
  */
-#define aic7xxx_error(cmd)	((cmd)->SCp.Status)
+#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
 
 /*
  * Keep track of the targets returned status.
  */
-#define aic7xxx_status(cmd)	((cmd)->SCp.sent_command)
+#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
 
 /*
  * The position of the SCSI commands scb within the scb array.
  */
-#define aic7xxx_position(cmd)	((cmd)->SCp.have_data_in)
+#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
+
+/*
+ * So we can keep track of our host structs
+ */
+static struct aic7xxx_host *first_aic7xxx = NULL;
 
 /*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
@@ -637,14 +639,14 @@
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define	AIC7XXX_MAX_SG 27
+#define        AIC7XXX_MAX_SG 128
 
 /*
  * 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
+#define AIC7XXX_MAXSCB        255
 
 
 struct aic7xxx_hwscb {
@@ -660,53 +662,118 @@
 /*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
-					 */
-#define SCB_PIO_TRANSFER_SIZE	26 	/* amount we need to upload/download
-					 * via PIO to initialize a transaction.
-					 */
-/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
-                                         * or disconnected down in the sequencer.
-                                         */
+/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
+                                     * Also used as the tag for tagged I/O
+                                     */
+#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
+                                     * via PIO to initialize a transaction.
+                                     */
+/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
+                                     * or disconnected down in the sequencer.
+                                     */
 /*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
-                                         */
+/*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_FREE                = 0x0000,
+        SCB_WDTR_16BIT          = 0x0001,
+        SCB_WAITINGQ            = 0x0002,
+        SCB_ACTIVE              = 0x0004,
+        SCB_SENSE               = 0x0008,
+        SCB_ABORT               = 0x0010,
+        SCB_DEVICE_RESET        = 0x0020,
+        SCB_RESET               = 0x0040,
+        SCB_RECOVERY_SCB        = 0x0080,
+        SCB_WAS_BUSY            = 0x0100,
+        SCB_MSGOUT_SDTR         = 0x0400,
+        SCB_MSGOUT_WDTR         = 0x0800,
+        SCB_MSGOUT_WDTR_8BIT    = 0x0800,
+        SCB_MSGOUT_WDTR_16BIT   = 0x0801,
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_SDTR | SCB_MSGOUT_WDTR_16BIT,
+        SCB_QUEUED_ABORT        = 0x1000,
+        SCB_QUEUED_FOR_DONE     = 0x2000
 } scb_flag_type;
 
+typedef enum {
+        AHC_FNONE                 = 0x00000000,
+        AHC_PAGESCBS              = 0x00000001,
+        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
+        AHC_USEDEFAULTS           = 0x00000004,
+        AHC_INDIRECT_PAGING       = 0x00000008,
+        AHC_CHNLB                 = 0x00000020,
+        AHC_CHNLC                 = 0x00000040,
+        AHC_EXTEND_TRANS_A        = 0x00000100,
+        AHC_EXTEND_TRANS_B        = 0x00000200,
+        AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_B            = 0x00000800,
+        AHC_HANDLING_REQINITS     = 0x00001000,
+        AHC_TARGETMODE            = 0x00002000,
+        AHC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+        AHC_A_SCANNED             = 0x00100000,
+        AHC_B_SCANNED             = 0x00200000,
+        AHC_MULTI_CHANNEL         = 0x00400000,
+        AHC_BIOS_ENABLED          = 0x00800000,
+        AHC_ABORT_PENDING         = 0x02000000,
+        AHC_RESET_PENDING         = 0x04000000,
+        AHC_IN_ISR                = 0x10000000,
+        AHC_IN_ABORT              = 0x20000000,
+        AHC_IN_RESET              = 0x40000000
+} ahc_flag_type;
+
+typedef enum {
+        AHC_NONE                  = 0x00000000,
+        AHC_ULTRA                 = 0x00000001,
+        AHC_WIDE                  = 0x00000002,
+        AHC_TWIN                  = 0x00000008,
+        AHC_AIC7770               = 0x00000010,
+        AHC_AIC7850               = 0x00000020,
+        AHC_AIC7860               = 0x00000021,
+        AHC_AIC7870               = 0x00000040,
+        AHC_AIC7880               = 0x00000041,
+        AHC_AIC7895               = 0x00000081,
+        AHC_AIC78x0               = 0x000000E0,
+        AHC_274                   = 0x00000110,
+        AHC_284                   = 0x00000210,
+        AHC_294AU                 = 0x00000421,
+        AHC_294                   = 0x00000440,
+        AHC_294U                  = 0x00000441,
+        AHC_394                   = 0x00000840,
+        AHC_394U                  = 0x00000841,
+        AHC_394AU                 = 0x00000881,
+        AHC_398                   = 0x00001040,
+        AHC_398U                  = 0x00001041,
+        AHC_39x                   = 0x00001880
+} ahc_type;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
-	Scsi_Cmnd             *cmd;	      /* Scsi_Cmnd for this 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          sense_cmd[6];  /*
+        scb_flag_type          flags;         /* current state of scb */
+        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          tag_action;
+        unsigned char          sg_count;
+        unsigned char          sense_cmd[6];  /*
                                                * Allocate 6 characters for
                                                * sense command.
                                                */
-        unsigned char          sg_count;
+        unsigned int           sg_length; /* We init this during buildscb so we
+                                           * don't have to calculate anything
+                                           * during underflow/overflow/stat code
+                                           */
 };
 
 /*
@@ -724,7 +791,7 @@
   { ILLHADDR,  "Illegal Host Access" },
   { ILLSADDR,  "Illegal Sequencer Address referenced" },
   { ILLOPCODE, "Illegal Opcode in sequencer program" },
-  { PARERR,    "Sequencer Ram Parity Error" }
+  { SQPARERR,  "Sequencer Ram Parity Error" }
 };
 
 static unsigned char
@@ -740,58 +807,110 @@
   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;
 
+typedef struct {
+  unsigned char period;
+  unsigned char offset;
+} syncinfo_type;
+
 /*
- * Define a structure used for each host adapter, only one per IRQ.
+ * Define a structure used for each host adapter.  Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary.  It's also organized to try and be more
+ * cache line efficient.  Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
  */
 struct aic7xxx_host {
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
   struct Scsi_Host        *host;             /* pointer to scsi host */
-  struct aic7xxx_host     *next;             /* pointer to next aic7xxx device */
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
   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 */
   unsigned long            base;             /* card base address */
-  unsigned long            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 */
-  unsigned short           needsdtr;
-  unsigned short           sdtr_pending;
-  unsigned short           needwdtr_copy;    /* default config */
-  unsigned short           needwdtr;
-  unsigned short           wdtr_pending;
-  unsigned short           orderedtag;
-  unsigned short           discenable;	     /* Targets allowed to disconnect */
-  aha_chip_type            chip_type;        /* card type */
-  aha_chip_class_type      chip_class;
-  aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  unsigned char            chan_num;         /* for 39xx, channel number */
+  unsigned long            mbase;            /* I/O memory address */
+  volatile ahc_flag_type   flags;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+#endif
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+  ahc_type                 type;             /* card type */
+  unsigned long            last_reset;
+  unsigned long            isr_count;        /* Interrupt count */
+  unsigned long            spurious_int;
+  unsigned short           discenable;       /* Targets allowed to disconnect */
+  unsigned short           tagenable;        /* Targets using tagged I/O */
+  unsigned short           orderedtag;       /* Ordered Q tags allowed */
+  volatile unsigned char   activescbs;       /* active scbs */
+  unsigned char            max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
-  unsigned char            qcntmask;
-  unsigned char            qfullcount;
-  unsigned char            cmdoutcnt;
-  unsigned char            curqincnt;
-  unsigned char            activescbs;       /* active scbs */
-  scb_queue_type           waiting_scbs;     /*
+  volatile unsigned char   qoutfifonext;
+  volatile unsigned char   qinfifonext;
+
+  /*
+   * MAX_TARGETS is currently == 16, so that makes these entries the next
+   * 64 bytes
+   */
+
+#define  DEVICE_PRESENT                 0x01
+#define  BUS_DEVICE_RESET_PENDING       0x02
+#define  DEVICE_TIMEOUT                 0x04
+#define  DEVICE_PRINT_SDTR              0x08
+#define  DEVICE_PRINT_WDTR              0x10
+#define  DEVICE_SUCCESS                 0x20
+#define  DEVICE_TAGGED_SUCCESS          0x40
+  volatile unsigned char   dev_flags[MAX_TARGETS];
+  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
+  unsigned char            dev_temp_queue_depth[MAX_TARGETS];
+  unsigned char            dev_commands_sent[MAX_TARGETS];
+
+  /*
+   * The next 64.... 
+   */
+
+  long                     dev_last_reset[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            dev_mid_level_queue_depth[MAX_TARGETS];
+  unsigned char            dev_last_queue_full[MAX_TARGETS];
+  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+  unsigned char            dev_max_queue_depth[MAX_TARGETS];
+
+  /*
+   * The next 128....
+   */
+
+  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
+
+  /*
+   *
+   */
+
+  struct timer_list        dev_timer[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            msg_buf[9];       /* The message for the target */
+  unsigned char            msg_type;
+#define MSG_TYPE_NONE              0x00
+#define MSG_TYPE_INITIATOR_MSGOUT  0x01
+#define MSG_TYPE_INITIATOR_MSGIN   0x02
+  unsigned char            msg_len;          /* Length of message */
+  unsigned char            msg_index;        /* Index into msg_buf array */
+  syncinfo_type            syncinfo[MAX_TARGETS];
+  volatile scb_queue_type  waiting_scbs;     /*
                                               * SCBs waiting for space in
                                               * the QINFIFO.
                                               */
@@ -801,14 +920,41 @@
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
   } completeq;
-  struct aic7xxx_device_status {
-    long last_reset;
-#define  DEVICE_SUCCESS                 0x01
-#define  BUS_DEVICE_RESET_PENDING       0x02
-    int  flags;
-    int  commands_sent;
-    int  active_cmds;
-  } device_status[16];
+
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.  The only exceptions are the qinfifo, qoutfifo,
+   * and untagged_scbs array.  But, they are often accessed only once and each
+   * access into these arrays is likely to blow a cache line, so they are put
+   * down here so we can minimize the number of cache lines required to hold
+   * the preceeding entries.
+   */
+
+  volatile unsigned char   untagged_scbs[256];
+  volatile unsigned char   qoutfifo[256];
+  volatile unsigned char   qinfifo[256];
+  unsigned short           needsdtr;
+  unsigned short           sdtr_pending;
+  unsigned short           needwdtr;
+  unsigned short           wdtr_pending;
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /* channel B for twin adapters */
+  unsigned int             bios_address;
+  int                      board_name_index;
+  unsigned long            reset_start;
+  unsigned short           needsdtr_copy;    /* default config */
+  unsigned short           needwdtr_copy;    /* default config */
+  unsigned short           ultraenb;         /* Ultra mode target list */
+  unsigned short           bios_control;     /* bios control - SEEPROM */
+  unsigned short           adapter_control;  /* adapter control - SEEPROM */
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+  unsigned char            irq;              /* IRQ for this adapter */
+
 #ifdef AIC7XXX_PROC_STATS
   /*
    * Statistics Kept:
@@ -820,6 +966,10 @@
    *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
    *
    * Total amounts read/written above 512 bytes (amts under ignored)
+   *
+   * NOTE: Enabling this feature is likely to cause a noticeable performance
+   * decrease as the accesses into the stats structures blows apart multiple
+   * cache lines and is CPU time consuming.
    */
   struct aic7xxx_xferstats {
     long xfers;                              /* total xfer count */
@@ -841,7 +991,7 @@
 static struct {
   short period;
   /* Rates in Ultra mode have bit 8 of sxfr set */
-#define		ULTRA_SXFR 0x100
+#define                ULTRA_SXFR 0x100
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
@@ -861,55 +1011,34 @@
 static int num_aic7xxx_syncrates =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
-#ifdef CONFIG_PCI
-static int number_of_3940s = 0;
-static int number_of_3985s = 0;
-#endif /* CONFIG_PCI */
-
-#ifdef AIC7XXX_DEBUG
-
-#if 0
-static void
-debug_scb(struct aic7xxx_scb *scb)
-{
-  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,
-    le32_to_cpu(hscb->SCSI_cmd_pointer) );
-  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
-    le32_to_cpu(hscb->data_count),
-    le32_to_cpu(hscb->data_pointer),
-    hscb->SG_segment_count,
-    le32_to_cpu(hscb->SG_list_pointer));
-  printk("        sg_addr:%lx sg_len:%ld\n",
-    le32_to_cpu(hscb->sg_list[0].address),
-    le32_to_cpu(hscb->sg_list[0].length));
-}
-#endif
-
-#else
-#  define debug_scb(x)
-#endif AIC7XXX_DEBUG
-
-#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                        (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
+                        (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
                         ((scb->hscb)->target_channel_lun & 0x07)
 
-#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 CTL_OF_CMD(cmd) ((cmd->channel) & 0x01),  \
+                        ((cmd->target) & 0x0f), \
+                        ((cmd->lun) & 0x07)
 
 #define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
 /*
+ * A nice little define to make doing our printks a little easier
+ */
+
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
+
+/*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
  *       cards in the system.  This should be fixed.
  */
+static int aic7xxx_7895_irq_hack = -1;       /* This enables a hack to fix
+                                              * IRQ settings on buggy 7895
+                                              * MB controller setups
+                                              *  -1 == Disable this hack
+                                              *   0 == Use the Channel A IRQ
+                                              *   1 == Use the Channel B IRQ
+                                              */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
 static int aic7xxx_irq_trigger = -1;         /*
@@ -917,9 +1046,96 @@
                                               *  0 use edge triggered
                                               *  1 use level triggered
                                               */
-static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
-static int aic7xxx_verbose = 0;	             /* verbose messages */
-static struct aic7xxx_host *first_aic7xxx = NULL; /* list of all our devices */
+static int aic7xxx_reverse_scan = 0;         /*
+                                              * Set this to anything but 0
+                                              * to make the probe code
+                                              * reverse the order of PCI
+                                              * devices
+                                              */
+static int aic7xxx_override_term = 0;        /*
+                                              * Set this to non-0 to make the
+                                              * driver override any BIOS
+                                              * configured termination
+                                              * settings based upon the
+                                              * results of the cable detect
+                                              * logic.  This only applies
+                                              * to cards that have cable
+                                              * detection logic and a SEEPROM
+                                              */
+static int aic7xxx_panic_on_abort = 0;       /*
+                                              * Set this to non-0 in order
+                                              * to force the driver to panic
+                                              * the kernel and print out
+                                              * debugging info on an abort
+                                              * or reset call into the
+                                              * driver.
+                                              */
+
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+/*
+ * See the comments earlier in the file for what this item is all about
+ * If you have more than 4 controllers, you will need to increase the
+ * the number of items in the array below.  Additionally, if you don't
+ * want to have lilo pass a humongous config line to the aic7xxx driver,
+ * then you can get in and manually adjust these instead of leaving them
+ * at the default.  Pay attention to the comments earlier in this file
+ * concerning this array if you are going to hand modify these values.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+#define VERBOSE_NORMAL         0x0000
+#define VERBOSE_NEGOTIATION    0x0001
+#define VERBOSE_SEQINT         0x0002
+#define VERBOSE_SCSIINT        0x0004
+#define VERBOSE_PROBE          0x0008
+#define VERBOSE_PROBE2         0x0010
+#define VERBOSE_QUEUE          0x0020
+#define VERBOSE_MINOR_ERROR    0x0040
+#define VERBOSE_QUEUE_FULL     0x0080
+#define VERBOSE_ABORT          0x0f00
+#define VERBOSE_ABORT_MID      0x0100
+#define VERBOSE_ABORT_FIND     0x0200
+#define VERBOSE_ABORT_PROCESS  0x0400
+#define VERBOSE_ABORT_RETURN   0x0800
+#define VERBOSE_RESET          0xf000
+#define VERBOSE_RESET_MID      0x1000
+#define VERBOSE_RESET_FIND     0x2000
+#define VERBOSE_RESET_PROCESS  0x4000
+#define VERBOSE_RESET_RETURN   0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+           VERBOSE_PROBE;                     /* verbose messages */
 
 
 /****************************************************************************
@@ -929,52 +1145,44 @@
  *
  ***************************************************************************/
 
+
 static inline unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
-  if (p->maddr != NULL)
-    return (p->maddr[port]);
+  unsigned char x;
+  if(p->maddr)
+    x = p->maddr[port];
   else
-    return (inb(p->base + port));
+    x = inb(p->base + port);
+  mb();
+  return(x);
 }
 
 static inline void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
     p->maddr[port] = val;
   else
     outb(val, p->base + port);
+  mb();
 }
 
 static inline void
 aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
   {
-#if defined(__alpha__) || defined(__sparc_v9__) || defined(__powerpc__)
     int i;
 
     for (i=0; i < size; i++)
     {
       p->maddr[port] = valp[i];
     }
-#else
-    __asm __volatile("
-      cld;
-    1:  lodsb;
-      movb %%al,(%0);
-      loop 1b"      :
-              :
-      "r" (p->maddr + port),
-      "S" (valp), "c" (size)  :
-      "%esi", "%ecx", "%eax");
-#endif
   }
   else
-  {
     outsb(p->base + port, valp, size);
-  }
+  mb();
 }
 
 /*+F*************************************************************************
@@ -991,6 +1199,7 @@
 {
   int   i, n;
   char *p;
+  char *end;
 
   static struct {
     const char *name;
@@ -999,25 +1208,112 @@
     { "extended",    &aic7xxx_extended },
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
-    { "ultra",       &aic7xxx_enable_ultra },
     { "verbose",     &aic7xxx_verbose },
-    { NULL,          NULL }
+    { "reverse_scan",&aic7xxx_reverse_scan },
+    { "7895_irq_hack", &aic7xxx_7895_irq_hack },
+    { "override_term", &aic7xxx_override_term },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
+    { "tag_info",    NULL }
   };
 
-  for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+  end = strchr(s, '\0');
+
+  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
   {
-    for (i = 0; options[i].name; i++)
+    for (i = 0; i < NUMBER(options); i++)
     {
       n = strlen(options[i].name);
       if (!strncmp(options[i].name, p, n))
       {
-        if (p[n] == ':')
+        if (!strncmp(p, "tag_info", n))
+        {
+          if (p[n] == ':')
+          {
+            char *base;
+            char *tok, *tok_end, *tok_end2;
+            char tok_list[] = { '.', ',', '{', '}', '\0' };
+            int i, instance = -1, device = -1;
+            unsigned char done = FALSE;
+
+            base = p;
+            tok = base + n + 1;  /* Forward us just past the ':' */
+            tok_end = strchr(tok, '\0');
+            if (tok_end < end)
+              *tok_end = ',';
+            while(!done)
+            {
+              switch(*tok)
+              {
+                case '{':
+                  if (instance == -1)
+                    instance = 0;
+                  else if (device == -1)
+                    device = 0;
+                  tok++;
+                  break;
+                case '}':
+                  if (device != -1)
+                    device = -1;
+                  else if (instance != -1)
+                    instance = -1;
+                  tok++;
+                  break;
+                case ',':
+                case '.':
+                  if (instance == -1)
+                    done = TRUE;
+                  else if (device >= 0)
+                    device++;
+                  else if (instance >= 0)
+                    instance++;
+                  if ( (device >= MAX_TARGETS) || 
+                       (instance >= NUMBER(aic7xxx_tag_info)) )
+                    done = TRUE;
+                  tok++;
+                  if (!done)
+                  {
+                    base = tok;
+                  }
+                  break;
+                case '\0':
+                  done = TRUE;
+                  break;
+                default:
+                  done = TRUE;
+                  tok_end = strchr(tok, '\0');
+                  for(i=0; tok_list[i]; i++)
+                  {
+                    tok_end2 = strchr(tok, tok_list[i]);
+                    if ( (tok_end2) && (tok_end2 < tok_end) )
+                    {
+                      tok_end = tok_end2;
+                      done = FALSE;
+                    }
+                  }
+                  if ( (instance >= 0) && (device >= 0) &&
+                       (instance < NUMBER(aic7xxx_tag_info)) &&
+                       (device < MAX_TARGETS) )
+                    aic7xxx_tag_info[instance].tag_commands[device] =
+                      simple_strtoul(tok, NULL, 0) & 0xff;
+                  tok = tok_end;
+                  break;
+              }
+            }
+            while((p != base) && (p != NULL))
+              p = strtok(NULL, ",.");
+          }
+        }
+        else if (p[n] == ':')
         {
           *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
         }
+        else if (!strncmp(p, "verbose", n))
+        {
+          *(options[i].flag) = 0xff69;
+        }
         else
         {
-          *(options[i].flag) = !0;
+          *(options[i].flag) = ~(*(options[i].flag));
         }
       }
     }
@@ -1036,8 +1332,8 @@
 static inline void
 pause_sequencer(struct aic7xxx_host *p)
 {
-  outb(p->pause, p->base + HCNTRL);
-  while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+  aic_outb(p, p->pause, HCNTRL);
+  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
   {
     ;
   }
@@ -1055,9 +1351,10 @@
 unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 {
   if (unpause_always ||
-      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+        !(p->flags & AHC_HANDLING_REQINITS) ) )
   {
-    outb(p->unpause, p->base + HCNTRL);
+    aic_outb(p, p->unpause, HCNTRL);
   }
 }
 
@@ -1073,17 +1370,16 @@
 restart_sequencer(struct aic7xxx_host *p)
 {
   /* Set the sequencer address to 0. */
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   /*
    * Reset and unpause the sequencer.  The reset is suppose to
-   * start the sequencer running, but we do an unpause to make
-   * sure.
+   * start the sequencer running, so we immediately do a pause_sequencer
+   * since some of our code expects the sequencer paused after a restart
    */
-  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
-
-  unpause_sequencer(p, /*unpause_always*/ TRUE);
+  aic_outb(p, SEQRESET | FASTMODE, SEQCTL);
+  pause_sequencer(p);
 }
 
 
@@ -1135,11 +1431,12 @@
 aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
 {
   unsigned char opcode;
-  struct ins_format3 *instr;
+  struct ins_format3 instr;
+  unsigned char dconsts[4] = { 0, 0, 0, 0 };
 
-  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+  instr = *(struct ins_format3 *) &seqprog[instrptr * 4];
   /* Pull the opcode */
-  opcode = instr->opcode_addr >> 1;
+  opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1;
   switch (opcode)
   {
     case AIC_OP_JMP:
@@ -1152,15 +1449,13 @@
     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;
+      address = instr.address;
+      address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8;
       for (i = 0; i < NUMBER(patches); i++)
       {
         patch = &patches[i];
@@ -1174,20 +1469,23 @@
         }
       }
       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;
+      instr.address = address & 0xFF;
+      instr.opcode_addr &= ~ADDR_HIGH_BIT;
+      instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
     }
-
+       /*  Fall through  */
     case AIC_OP_OR:
     case AIC_OP_AND:
     case AIC_OP_XOR:
     case AIC_OP_ADD:
     case AIC_OP_ADC:
+      if (instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE)
+      {
+        instr.immediate = dconsts[instr.immediate];
+      }
+      instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE;
     case AIC_OP_ROL:
-      outsb(p->base + SEQRAM, &instr->immediate, 4);
+      aic_outsb(p, SEQRAM, &instr.immediate, 4);
       break;
 
     default:
@@ -1212,23 +1510,60 @@
   int i;
   int downloaded;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk("\n");
   options = 1;  /* Code for all options. */
   downloaded = 0;
-  if ((p->flags & ULTRA_ENABLED) != 0)
+  if (p->type & AHC_ULTRA)
+  {
     options |= ULTRA;
-  if (p->bus_type == AIC_TWIN)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option ULTRA\n",
+        p->host_no);
+  }
+  if (p->type & AHC_TWIN)
+  {
     options |= TWIN_CHANNEL;
-  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option "
+        "TWIN_CHANNEL\n", p->host_no);
+  }
+  if (p->type & AHC_WIDE)
+  {
+    options |= WIDE;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option WIDE\n",
+        p->host_no);
+  }
+  /* if (p->scb_data->maxscbs > p->scb_data->maxhscbs)  this should always
+                                                        be true, don't test,
+                                                        just do.            */
+  {
     options |= SCB_PAGING;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option SCB_PAGING\n",
+        p->host_no);
+  }
+  /* We don't actually support target mode yet, so leave this out 
+  if (p->flags & AHC_TARGETMODE)
+    options |= TARGET_MODE; */
+
+  if ( (options & ~(ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01)) )
+  {
+    printk(KERN_INFO "(scsi%d) Unknown bits set in the options field, "
+      "correcting.\n", p->host_no);
+    options &= ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01;
+  }
+
 
   cur_patch = patches;
-  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, PERRORDIS | LOADRAM, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   for (i = 0; i < sizeof(seqprog) / 4;  i++)
   {
@@ -1242,13 +1577,16 @@
     downloaded++;
   }
 
-  outb(FASTMODE, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk(KERN_INFO "(scsi%d) Download complete,", p->host_no);
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-     printk(" %d instructions downloaded\n", downloaded);
+    printk(" %d instructions downloaded\n", downloaded);
   }
 }
 
@@ -1264,7 +1602,7 @@
 static void
 aic7xxx_delay(int seconds)
 {
-  int i;
+  unsigned int i;
 
   /*                        
    * Call udelay() for 1 millisecond inside a loop for  
@@ -1278,139 +1616,65 @@
 
 /*+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)
+aic7xxx_info(struct Scsi_Host *dooh)
 {
-  static char buffer[128];
+  static char buffer[256];
+  char *bp;
+  struct aic7xxx_host *p;
 
-  strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
-  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
+  bp = &buffer[0];
+  p = (struct aic7xxx_host *)dooh->hostdata;
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(bp, AIC7XXX_C_VERSION);
+  strcat(bp, "/");
+  strcat(bp, AIC7XXX_H_VERSION);
+  strcat(bp, "\n");
+  strcat(bp, "       <");
+  strcat(bp, board_names[p->board_name_index]);
+  strcat(bp, ">");
 
-  return buffer;
+  return(bp);
 }
 
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_length
+ *   aic7xxx_scsirate
  *
  * Description:
- *   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.
+ *   Look up the valid period to SCSIRATE conversion in our table
  *-F*************************************************************************/
-static unsigned
-aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
+static unsigned char
+aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
+    unsigned char *period, unsigned char *offset, int target, int channel,
+    int set)
 {
-  int i, segments;
-  unsigned length;
-  struct scatterlist *sg;
+  int i = num_aic7xxx_syncrates;
+  unsigned char response_period;
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun;
 
-  segments = cmd->use_sg - sg_last;
-  sg = (struct scatterlist *) cmd->request_buffer;
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
 
-  if (cmd->use_sg)
+  response_period = *period;
+
+  /*
+   * If the offset is 0, then the device is requesting asynchronous
+   * transfers.
+   */
+  if ((*period != 0) && (*offset != 0))
   {
-    for (i = length = 0; i < segments; i++)
-    {
-      length += sg[i].length;
-    }
-  }
-  else
-  {
-    length = cmd->request_bufflen;
-  }
-
-  return (length);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_scsirate
- *
- * Description:
- *   Look up the valid period to SCSIRATE conversion in our table
- *-F*************************************************************************/
-static void
-aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    unsigned char *period, unsigned char *offset, int target, char channel)
-{
-  int i = num_aic7xxx_syncrates;
-  unsigned long ultra_enb_addr;
-  unsigned char ultra_enb, sxfrctl0;
-
-  /*
-   * If the offset is 0, then the device is requesting asynchronous
-   * transfers.
-   */
-  if ((*period <= aic7xxx_syncrates[i - 1].period) && *offset != 0)
-  {
-    for (i = 0; i < num_aic7xxx_syncrates; i++)
+    for (i = 0; i < num_aic7xxx_syncrates; i++)
     {
       if (*period <= aic7xxx_syncrates[i].period)
       {
@@ -1418,7 +1682,7 @@
          * Watch out for Ultra speeds when ultra is not enabled and
          * vice-versa.
          */
-        if (!(p->flags & ULTRA_ENABLED) &&
+        if (!(p->type & AHC_ULTRA) &&
             (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
         {
           /*
@@ -1431,11 +1695,31 @@
         *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
         *period = aic7xxx_syncrates[i].period;
 
-        if (aic7xxx_verbose)
+        /*
+         * When responding to a target that requests
+         * sync, that rate may fall between two rates
+         * that we can output, but still be a rate
+         * that we can receive.  Because of this,
+         * we may want to respond to the target with
+         * the same rate that it sent to us even
+         * if the period we use to send data to it
+         * is lower.  Only lower the response period
+         * if we must.
+         */
+        if ((i == 0) ||
+           ((aic7xxx_syncrates[i-1].rate & ULTRA_SXFR) != 0
+             && (p->type & AHC_ULTRA) == 0))
+        {
+          response_period = *period;
+        }
+
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
         {
-          printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, target, channel,
+          printk(INFO_LEAD "Synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, channel, target, lun,
                  aic7xxx_syncrates[i].english, *offset);
+          p->dev_flags[tindex] &= ~ DEVICE_PRINT_SDTR;
         }
         break;
       }
@@ -1450,35 +1734,43 @@
     *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);
+    response_period = 0;
+    if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+    {
+      printk(INFO_LEAD "Using asynchronous transfers.\n",
+             p->host_no, channel, target, lun);
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
     }
   }
 
   /*
    * Ensure Ultra mode is set properly for this target.
    */
-  ultra_enb_addr = ULTRA_ENB;
-  if ((channel == 'B') || (target > 7))
+  if ( (*scsirate != 0) && 
+       (aic7xxx_syncrates[i].rate & ULTRA_SXFR) )
   {
-    ultra_enb_addr++;
+    p->ultraenb |= target_mask;
   }
-  ultra_enb = inb(p->base + ultra_enb_addr);
-  sxfrctl0 = inb(p->base + SXFRCTL0);
-  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+  else
   {
-    ultra_enb |= 0x01 << (target & 0x07);
-    sxfrctl0 |= FAST20;
+    p->ultraenb &= ~target_mask;
   }
-  else
+  if (set)
   {
-    ultra_enb &= ~(0x01 << (target & 0x07));
+    unsigned char sxfrctl0;
+
+    sxfrctl0 = aic_inb(p, SXFRCTL0);
     sxfrctl0 &= ~FAST20;
+    if (p->ultraenb & target_mask)
+    {
+      sxfrctl0 |= FAST20;
+    }
+    aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+    aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1);
+    aic_outb(p, sxfrctl0, SXFRCTL0);
   }
-  outb(ultra_enb, p->base + ultra_enb_addr);
-  outb(sxfrctl0, p->base + SXFRCTL0);
+  return(response_period);
 }
 
 /*+F*************************************************************************
@@ -1490,7 +1782,7 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_init(scb_queue_type *queue)
+scbq_init(volatile scb_queue_type *queue)
 {
   queue->head = NULL;
   queue->tail = NULL;
@@ -1505,7 +1797,7 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
   scb->q_next = queue->head;
   queue->head = scb;
@@ -1521,13 +1813,16 @@
  *   Remove an SCB from the head of the list.
  *
  *-F*************************************************************************/
-static inline void
-scbq_remove_head(scb_queue_type *queue)
+static __inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
 {
+  struct aic7xxx_scb * scbp;
+  scbp = queue->head;
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
+  return(scbp);
 }
 
 /*+F*************************************************************************
@@ -1539,7 +1834,7 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
   if (queue->head == scb)
   {
@@ -1580,12 +1875,11 @@
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
-
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
@@ -1602,18 +1896,14 @@
  *   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,
-    int lun, unsigned char tag)
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    int target, int channel, int lun, unsigned char tag)
 {
   int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
   int slun = scb->hscb->target_channel_lun & 0x07;
   int match;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  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
   match = ((chan == channel) || (channel == ALL_CHANNELS));
   if (match != 0)
     match = ((targ == target) || (target == ALL_TARGETS));
@@ -1622,6 +1912,14 @@
   if (match != 0)
     match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
 
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+  {
+    printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
+      " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
+      scb->hscb->tag, (match) ? "matches" : "doesn't match",
+      p->host_no, channel, target, lun, tag);
+  }
+
   return (match);
 }
 
@@ -1639,10 +1937,11 @@
    * Invalidate the tag so that aic7xxx_find_scb doesn't think
    * it's active
    */
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+  aic_outb(p, 0, SCB_CONTROL);
 
-  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
-  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
 }
 
 /*+F*************************************************************************
@@ -1659,28 +1958,25 @@
   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);
-
+  aic_outb(p, scbptr, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+  prev = aic_inb(p, SCB_PREV);
   aic7xxx_add_curscb_to_free_list(p);
 
   if (prev != SCB_LIST_NULL)
   {
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   else
   {
-    outb(next, p->base + DISCONNECTED_SCBH);
+    aic_outb(p, next, DISCONNECTED_SCBH);
   }
 
   if (next != SCB_LIST_NULL)
   {
-    outb(next, p->base + SCBPTR);
-    outb(prev, p->base + SCB_PREV);
+    aic_outb(p, next, SCBPTR);
+    aic_outb(p, prev, SCB_PREV);
   }
   return next;
 }
@@ -1692,23 +1988,10 @@
  * Description:
  *   Set the specified target busy.
  *-F*************************************************************************/
-static void
-aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, unsigned char scbid)
+static __inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  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);
+  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
 }
 
 /*+F*************************************************************************
@@ -1719,28 +2002,17 @@
  *   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)
+static __inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+    int unbusy)
 {
-  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;
-
-  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);
+  busy_scbid = p->untagged_scbs[tcl];
   if (unbusy)
   {
-    outb(SCB_LIST_NULL, p->base + scb_offset);
+    p->untagged_scbs[tcl] = SCB_LIST_NULL;
   }
-  outb(active_scb, p->base + SCBPTR);
   return (busy_scbid);
 }
 
@@ -1760,17 +2032,17 @@
   unsigned char saved_scbptr;
   unsigned char curindex;
 
-  saved_scbptr = inb(p->base + SCBPTR);
+  saved_scbptr = aic_inb(p, SCBPTR);
   curindex = 0;
   for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
   {
-    outb(curindex, p->base + SCBPTR);
-    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+    aic_outb(p, curindex, SCBPTR);
+    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
     {
       break;
     }
   }
-  outb(saved_scbptr, p->base + SCBPTR);
+  aic_outb(p, saved_scbptr, SCBPTR);
   if (curindex >= p->scb_data->maxhscbs)
   {
     curindex = SCB_LIST_NULL;
@@ -1787,58 +2059,83 @@
  *   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)
+aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
 {
   struct aic7xxx_scb   *scbp = NULL;
-  struct aic7xxx_hwscb *hscbp = NULL;
-#ifdef AGRESSIVE
-  long processor_flags;
+  int scb_size = sizeof(struct aic7xxx_scb) +
+                 sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+  int i;
+  unsigned long scb_count = 0;
+  struct hw_scatterlist *hsgp;
+  struct aic7xxx_scb *scb_ap;
 
-  save_flags(processor_flags);
-  cli();
-#endif
 
-  scbp = p->scb_data->free_scbs.head;
-  if (scbp != NULL)
+  if (force_alloc == FALSE)
   {
-    scbq_remove_head(&p->scb_data->free_scbs);
+    scbp = scbq_remove_head(&p->scb_data->free_scbs);
+    if (scbp != NULL)
+      return(scbp);
   }
-  else
+  /*
+   * Either there wasn't an SCB or this is a strictly allocation call
+   */
+
+  if (p->scb_data->numscbs < p->scb_data->maxscbs)
   {
-    if (p->scb_data->numscbs < p->scb_data->maxscbs)
-    {
-      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++;
+
+    /*
+     * Optimize for 30 scbs at a time, but allow a final allocation of
+     * fewer than 30 scbs.  Except on 64 bit platforms, we optimize for
+     * 29 SCBs at a time because a pointer is 4 bytes larger and we don't
+     * want to overrun this suppossedly 32K allocation to 64K and waste
+     * tons of space.
+     */
+    if( sizeof(void *) == sizeof(int) )
+      scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+    else
+      scb_count = MIN(29, p->scb_data->maxscbs - p->scb_data->numscbs);
+    
+    scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
+    if (scb_ap != NULL)
+    {
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+      {
+        if (p->scb_data->numscbs == 0)
+          printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+        else
+          printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+      }
+      memset(scb_ap, 0, scb_count * scb_size);
+      hsgp = (struct hw_scatterlist *) &scb_ap[scb_count];
+      for (i=0; i < scb_count; i++)
+      {
+        scbp = &scb_ap[i];
+        scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+        scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+        memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+        scbp->hscb->tag = p->scb_data->numscbs;
         /*
          * Place in the scb array; never is removed
          */
-        p->scb_data->scb_array[scb_index] = scbp;
+        p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+        scbq_insert_head(&p->scb_data->free_scbs, scbp);
       }
     }
+    else
+    {
+      return(NULL);
+    }
   }
-#ifdef AIC7XXX_DEBUG
-  if (scbp != NULL)
+  if (force_alloc == TRUE)
   {
-    p->activescbs++;
+    return((struct aic7xxx_scb *)scb_count);
+  }
+  else
+  {
+    return(scbq_remove_head(&p->scb_data->free_scbs));
   }
-#endif
-
-#ifdef AGRESSIVE
-  restore_flags(processor_flags);
-#endif
-  return (scbp);
 }
 
 /*+F*************************************************************************
@@ -1853,11 +2150,8 @@
 static inline void
 aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  if (p->completeq.tail == NULL)
-    p->completeq.head = cmd;
-  else
-    p->completeq.tail->host_scribble = (char *) cmd;
-  p->completeq.tail = cmd;
+  cmd->host_scribble = (char *)p->completeq.head;
+  p->completeq.head = cmd;
 }
 
 /*+F*************************************************************************
@@ -1871,16 +2165,21 @@
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
-
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned int cpu_flags = 0;
+#endif
+  
+  DRIVER_LOCK
   while (p->completeq.head != NULL)
   {
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    p->device_status[TARGET_INDEX(cmd)].active_cmds--;
+    DRIVER_UNLOCK
     cmd->scsi_done(cmd);
+    DRIVER_LOCK
   }
-  p->completeq.tail = NULL;
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1893,24 +2192,17 @@
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_hwscb *hscb;
-  long flags;
-
-  hscb = scb->hscb;
-  save_flags(flags);
-  cli();
 
   scb->flags = SCB_FREE;
   scb->cmd = NULL;
-  hscb->control = 0;
-  hscb->target_status = 0;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+  scb->tag_action = 0;
+  scb->hscb->control = 0;
+  scb->hscb->target_status = 0;
+  scb->hscb->target_channel_lun = SCB_LIST_NULL;
 
   scbq_insert_head(&p->scb_data->free_scbs, scb);
-#ifdef AIC7XXX_DEBUG
-  p->activescbs--;  /* For debugging purposes. */
-#endif
-
-  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1924,25 +2216,31 @@
 aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   Scsi_Cmnd *cmd = scb->cmd;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_scb *scbp;
+  unsigned char queue_depth;
 
   if (scb->flags & SCB_RECOVERY_SCB)
   {
-    p->flags &= ~IN_TIMEOUT;
+    p->flags &= ~AHC_ABORT_PENDING;
   }
-  if (cmd->result == DID_OK)
+  if (scb->flags & SCB_RESET)
   {
-    if (scb->flags & SCB_ABORTED)
-    {
-      cmd->result = (DID_RESET << 16);
-    }
+      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
+        (cmd->result & 0xffff);
+  }
+  else if (scb->flags & SCB_ABORT)
+  {
+      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
+        (cmd->result & 0xffff);
   }
   if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
 
-    mask = 0x01 << TARGET_INDEX(scb->cmd);
-
+    mask = 0x01 << tindex;
+ 
     /*
      * Check to see if we get an invalid message or a message error
      * after failing to negotiate a wide or sync transfer message.
@@ -1959,6 +2257,17 @@
       p->wdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
+        }
         p->needwdtr &= ~mask;
         p->needwdtr_copy &= ~mask;
       }
@@ -1968,27 +2277,74 @@
       p->sdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+        }
         p->needsdtr &= ~mask;
         p->needsdtr_copy &= ~mask;
       }
     }
   }
-  aic7xxx_free_scb(p, scb);
-  aic7xxx_queue_cmd_complete(p, cmd);
+  queue_depth = p->dev_temp_queue_depth[tindex];
+  if (queue_depth >= p->dev_active_cmds[tindex])
+  {
+    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+    if (scbp)
+      scbq_insert_tail(&p->waiting_scbs, scbp);
+    if ( (queue_depth > p->dev_active_cmds[tindex]) && scbp)
+    {
+      scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+      if (scbp)
+        scbq_insert_tail(&p->waiting_scbs, scbp);
+    }
+  }
+  if ( (p->dev_timer[tindex].expires) &&
+      ((p->dev_active_cmds[tindex] == 1) ||
+       (p->dev_max_queue_depth[tindex] ==
+        p->dev_temp_queue_depth[tindex])) )
+  {
+    del_timer(&p->dev_timer[tindex]);
+    p->dev_timer[tindex].expires = 0;
+    p->dev_temp_queue_depth[tindex] = 
+          p->dev_max_queue_depth[tindex];
+  }
+  p->dev_active_cmds[tindex]--;
+  p->activescbs--;
+
+  /*
+   * If this was an untagged I/O, unbusy the target so the sequencer won't
+   * mistake things later
+   */
+  if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
+      scb->hscb->tag)
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
+  }
 
 #ifdef AIC7XXX_PROC_STATS
-  if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
-       (cmd->cmnd[0] != INQUIRY) )
   {
     int actual;
 
     /*
      * XXX: we should actually know how much actually transferred
      * XXX: for each command, but apparently that's too difficult.
+     * 
+     * We set a lower limit of 512 bytes on the transfer length.  We
+     * ignore anything less than this because we don't have a real
+     * reason to count it.  Read/Writes to tapes are usually about 20K
+     * and disks are a minimum of 512 bytes unless you want to count
+     * non-read/write commands (such as TEST_UNIT_READY) which we don't
      */
-    actual = aic7xxx_length(cmd, 0);
-    if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
-        && (aic7xxx_error(cmd) == 0))
+    actual = scb->sg_length;
+    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
     {
       struct aic7xxx_xferstats *sp;
       long *ptr;
@@ -1997,7 +2353,14 @@
       sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
       sp->xfers++;
 
-      if (cmd->request.cmd == WRITE)
+      /*
+       * For block devices, cmd->request.cmd is always == either READ or
+       * WRITE.  For character devices, this isn't always set properly, so
+       * we check data_cmnd[0].  This catches the conditions for st.c, but
+       * I'm still not sure if request.cmd is valid for sg devices.
+       */
+      if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
         sp->w_total512 += (actual >> 9);
@@ -2024,6 +2387,10 @@
     }
   }
 #endif /* AIC7XXX_PROC_STATS */
+
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
+
 }
 
 /*+F*************************************************************************
@@ -2039,20 +2406,25 @@
 aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
 {
   struct aic7xxx_scb *scb;
-  int i;
+  int i, found = 0;
 
   for (i = 0; i < p->scb_data->numscbs; i++)
   {
     scb = p->scb_data->scb_array[i];
     if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
-#ifdef AIC7XXX_DEBUG_ABORT
-      printk("(scsi%d:%d:%d) Aborting scb %d\n",
-             p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-#endif
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Aborting scb %d\n",
+             p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+      found++;
       aic7xxx_done(p, scb);
     }
   }
+  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
+  {
+    printk(INFO_LEAD "%d commands found and queued for "
+        "completion.\n", p->host_no, -1, -1, -1, found);
+  }
   if (complete)
   {
     aic7xxx_done_cmds_complete(p);
@@ -2076,14 +2448,9 @@
   /*
    * Select the SCB we want to abort and pull the next pointer out of it.
    */
-  curscb = inb(p->base + SCBPTR);
-  outb(scbpos, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-
-  /*
-   * Clear the necessary fields
-   */
-  outb(0, p->base + SCB_CONTROL);
+  curscb = aic_inb(p, SCBPTR);
+  aic_outb(p, scbpos, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
 
   aic7xxx_add_curscb_to_free_list(p);
 
@@ -2095,25 +2462,21 @@
     /*
      * First in the list
      */
-    outb(next, p->base + WAITING_SCBH);
+    aic_outb(p, next, WAITING_SCBH);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, p->base + SCBPTR);
-  scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-  scb->flags &= ~SCB_ACTIVE;
-  scb->cmd->result = (DID_RESET << 16);
-
+  aic_outb(p, curscb, SCBPTR);
   return (next);
 }
 
@@ -2126,219 +2489,381 @@
  *   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)
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+    int lun, unsigned char tag, int flags, int requeue,
+    volatile scb_queue_type *queue)
 {
-  unsigned char saved_queue[AIC7XXX_MAXSCB];
-  int      queued = inb(p->base + QINCNT) & p->qcntmask;
-  int      i;
   int      found;
+  unsigned char qinpos, qintail;
   struct aic7xxx_scb *scbp;
-  scb_queue_type removed_scbs;
 
   found = 0;
-  scbq_init (&removed_scbs);
-  for (i = 0; i < (queued - found); i++)
+  qinpos = aic_inb(p, QINPOS);
+  qintail = p->qinfifonext;
+
+  p->qinfifonext = qinpos;
+
+  while (qinpos != qintail)
   {
-    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))
+    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
     {
        /*
         * We found an scb that needs to be removed.
         */
-       if (requeue)
+       if (requeue && (queue != NULL))
+       {
+         if ( !(scbp->flags & SCB_WAITINGQ) )
+         {
+           scbq_insert_tail(queue, scbp);
+           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+           p->activescbs--;
+           scbp->flags |= SCB_WAITINGQ;
+         }
+         if ( !(scbp->tag_action & TAG_ENB) )
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       else if (requeue)
        {
-         scbq_insert_head(&removed_scbs, scbp);
+         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
        }
        else
        {
-         scbp->flags = flags;
-         scbp->flags &= ~SCB_ACTIVE;
-         /*
-          * XXX - Don't know what error to use here.
-          */
-         aic7xxx_error(scbp->cmd) = DID_RESET;
+        /*
+         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+         * flags we were called with, presumeably so aic7xxx_run_done_queue
+         * can find this scb
+         */
+         scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+                                       FALSE) == scbp->hscb->tag)
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
        }
-       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)
+    else
     {
-      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;
+      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
     }
   }
+  /*
+   * Now that we've done the work, clear out any left over commands in the
+   * qinfifo and update the KERNEL_QINPOS down on the card.
+   *
+   *  NOTE: This routine expect the sequencer to already be paused when
+   *        it is run....make sure it's that way!
+   */
+  qinpos = p->qinfifonext;
+  while(qinpos != qintail)
+  {
+    p->qinfifo[qinpos++] = SCB_LIST_NULL;
+  }
+  aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
 
   return (found);
 }
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ *   Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i=0;
+
+  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+  {
+    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+      return TRUE;
+    else
+      i++;
+  }
+  return FALSE;
+}
+
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_reset_device
  *
  * Description:
  *   The device at the given target/channel has been reset.  Abort
- *   all active and queued scbs for that target/channel.
+ *   all active and queued scbs for that target/channel.  This function
+ *   need not worry about linked next pointers because if was a MSG_ABORT_TAG
+ *   then we had a tagged command (no linked next), if it was MSG_ABORT or
+ *   MSG_BUS_DEV_RESET then the device won't know about any commands any more
+ *   and no busy commands will exist, and if it was a bus reset, then nothing
+ *   knows about any linked next commands any more.  In all cases, we don't
+ *   need to worry about the linked next or busy scb, we just need to clear
+ *   them.
  *-F*************************************************************************/
-static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+static void
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
                      int lun, unsigned char tag)
 {
   struct aic7xxx_scb *scbp;
-  unsigned char active_scb;
-  int i = 0;
-  int found;
+  unsigned char active_scb, tcl;
+  int i = 0, j, init_lists = FALSE;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(p->base + SCBPTR);
-
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
-         p->host_no, target, CHAN_TO_INT(channel), active_scb);
-#endif
+  active_scb = aic_inb(p, SCBPTR);
 
+  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+    printk(INFO_LEAD "Reset device, active_scb %d\n",
+         p->host_no, channel, target, lun, active_scb);
   /*
    * Deal with the busy target and linked next issues.
    */
   {
     int min_target, max_target;
-    unsigned char busy_scbid;
+    struct aic7xxx_scb *scbp, *prev_scbp;
 
     /* Make all targets 'relative' to bus A. */
     if (target == ALL_TARGETS)
     {
       switch (channel)
       {
-        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 0:
+                 min_target = 0;
+                 max_target = (p->type & AHC_WIDE) ? 15 : 7;
+                 break;
+        case 1:
+                 min_target = 8;
+                 max_target = 15;
+                 break;
         case ALL_CHANNELS:
         default:
-  	  min_target = 0;
-  	  max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-  	  break;
+                 min_target = 0;
+                 max_target = (p->type & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+                 break;
       }
     }
     else
     { 
-      min_target = target + channel == 'B' ? 8 : 0;
+      min_target = target | (channel << 3);
       max_target = min_target;
     }
 
+
     for (i = min_target; i <= max_target; i++)
     {
-      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
-      if (busy_scbid < p->scb_data->numscbs)
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Cleaning up status information "
+          "and delayed_scbs.\n", p->host_no, channel, i, lun);
+      if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
+            (p->dev_active_cmds[i]) &&
+            (p->tagenable & (0x01 << i)) )
+      {
+        printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
+          p->host_no, channel, i, lun);
+        printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
+          channel, i, lun);
+        p->dev_max_queue_depth[i] = 1;
+        p->dev_temp_queue_depth[i] = 1;
+        p->tagenable &= ~(0x01 << i);
+        p->orderedtag &= ~(0x01 << i);
+      }
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+      if ( tag == SCB_LIST_NULL )
+      {
+        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+        p->dev_last_reset[i] = jiffies;
+        p->dev_last_queue_full_count[i] = 0;
+        p->dev_last_queue_full[i] = 0;
+        p->dev_temp_queue_depth[i] =
+          p->dev_max_queue_depth[i];
+  /*
+   * In case this isn't a full bus reset, we want to add a 4 second timer in
+   * here so that we can delay all re-sent commands for this device for the
+   * 4 seconds and then have our timer routine pick them back up.
+   */
+        if( (p->dev_timer[i].prev != NULL) ||
+            (p->dev_timer[i].next != NULL) )
+        {
+          del_timer(&p->dev_timer[i]);
+        }
+        p->dev_timer[i].expires = jiffies + (3 * HZ);
+        add_timer(&p->dev_timer[i]);
+      }
+      for(j=0; j<MAX_LUNS; j++)
       {
-  	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 = le32_to_cpu(busy_scb->hscb->data_count) >> 24;
-
-  	if (next_scbid == SCB_LIST_NULL)
+        if (channel == 1)
+          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
+        else
+          tcl = (i << 4) | (channel << 3) | j;
+        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+             (tag == SCB_LIST_NULL) )
+          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+      }
+      j = 0; 
+      prev_scbp = NULL; 
+      scbp = p->delayed_scbs[i].head;
+      while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+      {
+        prev_scbp = scbp;
+        scbp = scbp->q_next;
+        if ( prev_scbp == scbp )
+        {
+          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
+          scbp = NULL;
+          prev_scbp->q_next = NULL;
+          p->delayed_scbs[i].tail = prev_scbp;
+        }
+        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
         {
-  	  busy_scbid = aic7xxx_find_scb(p, busy_scb);
-
-  	  if (busy_scbid != SCB_LIST_NULL)
+          scbq_remove(&p->delayed_scbs[i], prev_scbp);
+          if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
           {
-  	    outb(busy_scbid, p->base + SCBPTR);
-  	    next_scbid = inb(p->base + SCB_LINKED_NEXT);
-  	  }
-  	}
+            p->dev_active_cmds[i]++;
+            p->activescbs++;
+          }
+          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        }
+      }
+      if ( j > p->scb_data->numscbs )
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! There's a loop in the "
+            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
+        scbq_init(&p->delayed_scbs[i]);
+      }
+      if ( (p->delayed_scbs[i].head == NULL) &&
+           (p->dev_timer[i].expires) )
+      {
+        del_timer(&p->dev_timer[i]);
+        p->dev_timer[i].expires = 0;
+      }
+    }
+  }
 
-  	if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
-        {
-  	  aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
-  	}
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
+  aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
+
+/*
+ *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
+ *  ABORT/RESET commands.
+ */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+      target, lun );
+  {
+    struct aic7xxx_scb *scbp, *prev_scbp;
 
-  	if (next_scbid != SCB_LIST_NULL)
+    j = 0; 
+    prev_scbp = NULL; 
+    scbp = p->waiting_scbs.head;
+    while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if ( prev_scbp == scbp )
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
+        scbp = NULL;
+        prev_scbp->q_next = NULL;
+        p->waiting_scbs.tail = prev_scbp;
+      }
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+      {
+        scbq_remove(&p->waiting_scbs, prev_scbp);
+        if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
         {
-  	  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;
-  	}
+          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
+    if ( j > p->scb_data->numscbs )
+    {
+      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+        printk(WARN_LEAD "Yikes!! There's a loop in the "
+          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
+      scbq_init(&p->waiting_scbs);
+    }
   }
 
-  found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
-      SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
 
   /*
    * Search waiting for selection list.
    */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting for selection "
+      "list.\n", p->host_no, channel, target, lun);
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
+    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index >= p->scb_data->numscbs)
       {
-        panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
-              scb_index, p->scb_data->numscbs);
+       /*
+        * No aic7xxx_verbose check here.....we want to see this since it
+        * means either the kernel driver or the sequencer screwed things up
+        */
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic_inb(p, SCB_NEXT);
+        aic7xxx_add_curscb_to_free_list(p);
       }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      else
       {
-        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)
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
-          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))
+          next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (prev == SCB_LIST_NULL)
           {
-            scbq_insert_head(&p->waiting_scbs, next_scb);
-            next_scb->flags |= SCB_WAITINGQ;
+            /*
+             * This is either the first scb on the waiting list, or we
+             * have already yanked the first and haven't left any behind.
+             * Either way, we need to turn off the selection hardware if
+             * it isn't already off.
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
           }
         }
-        found++;
-      }
-      else
-      {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
       }
     }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
+        "selection list!\n", p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
   }
 
   /*
@@ -2348,47 +2873,114 @@
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + DISCONNECTED_SCBH);
+    next = aic_inb(p, DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, 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);
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic7xxx_rem_scb_from_disc_list(p, next);
       }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      else
       {
-        next = aic7xxx_rem_scb_from_disc_list(p, next);
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_rem_scb_from_disc_list(p, next);
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->hscb->control = 0;
+        }
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
+      }
+    }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
+        p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
+  }
+
+  /*
+   * Walk the free list making sure no entries on the free list have
+   * a valid SCB_TAG value or SCB_CONTROL byte.
+   */
+  {
+    unsigned char next;
+
+    j = 0;
+    next = aic_inb(p, FREE_SCBH);
+    while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
+    {
+      aic_outb(p, next, SCBPTR);
+      if ( aic_inb(p, SCB_TAG) < p->scb_data->numscbs )
+      {
+        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+          target, lun);
+        init_lists = TRUE;
+        next = SCB_LIST_NULL;
       }
       else
       {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        next = aic_inb(p, SCB_NEXT);
       }
     }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
+        p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
   }
 
   /*
    * Go through the hardware SCB array looking for commands that
    * were active but not on any list.
    */
-  for (i = 0; i < p->scb_data->maxhscbs; i++)
+  if (init_lists)
+  {
+    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+  }
+  for (i = p->scb_data->maxhscbs; i >= 0; --i)
   {
     unsigned char scbid;
 
-    outb(i, p->base + SCBPTR);
-    scbid = inb(p->base + SCB_TAG);
-    if (scbid < p->scb_data->numscbs)
+    aic_outb(p, i, SCBPTR);
+    if (init_lists)
+    {
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+      aic_outb(p, SCB_LIST_NULL, SCB_PREV);
+      aic_outb(p, 0, SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    else
     {
-      scbp = p->scb_data->scb_array[scbid];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      scbid = aic_inb(p, SCB_TAG);
+      if (scbid < p->scb_data->numscbs)
       {
-        aic7xxx_add_curscb_to_free_list(p);
+        scbp = p->scb_data->scb_array[scbid];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          aic_outb(p, 0, SCB_CONTROL);
+          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+          aic7xxx_add_curscb_to_free_list(p);
+        }
       }
     }
   }
@@ -2397,31 +2989,28 @@
    * 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.
+   * Any commands we find here we know this about, it wasn't on any queue,
+   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+   * lists, so it really must have been a paged out SCB.  In that case,
+   * we shouldn't need to bother with updating any counters, just mark
+   * the correct flags and go on.
    */
   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))
+    if ((scbp->flags & SCB_ACTIVE) &&
+        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+        !aic7xxx_scb_on_qoutfifo(p, scbp))
     {
-      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;
-      }
+      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
     }
   }
 
-  outb(active_scb, p->base + SCBPTR);
-  return (found);
+  aic_outb(p, active_scb, SCBPTR);
 }
 
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_clear_intstat
@@ -2433,10 +3022,10 @@
 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);
+  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, CLRSINT1);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT, CLRINT);
 }
 
 /*+F*************************************************************************
@@ -2449,32 +3038,26 @@
 static void
 aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 {
-  unsigned long processor_flags;
   unsigned char scsiseq;
 
-  save_flags(processor_flags);
-  cli();
-
   /* Disable reset interrupts. */
-  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
 
   /* Turn on the bus reset. */
-  scsiseq = inb(p->base + SCSISEQ);
-  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+  scsiseq = aic_inb(p, SCSISEQ);
+  aic_outb(p, scsiseq | SCSIRSTO, SCSISEQ);
 
   udelay(1000);
 
   /* Turn off the bus reset. */
-  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+  aic_outb(p, scsiseq & ~SCSIRSTO, SCSISEQ);
 
   aic7xxx_clear_intstat(p);
 
   /* Re-enable reset interrupts. */
-  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
 
   udelay(1000);
-
-  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -2484,22 +3067,19 @@
  * Description:
  *   Reset the channel.
  *-F*************************************************************************/
-static int
-aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
+static void
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
 {
   unsigned long offset, offset_max;
-  int found;
   unsigned char sblkctl;
-  char cur_channel;
+  int cur_channel;
+
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
 
-  pause_sequencer(p);
-  /*
-   * Clean up all the state information for the pending transactions
-   * on this bus.
-   */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  if (channel == 'B')
+  if (channel == 1)
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
@@ -2508,7 +3088,7 @@
   }
   else
   {
-    if (p->bus_type == AIC_WIDE)
+    if (p->type & AHC_WIDE)
     {
       p->needsdtr = p->needsdtr_copy;
       p->needwdtr = p->needwdtr_copy;
@@ -2534,80 +3114,77 @@
      */
     u_char targ_scratch;
 
-    targ_scratch = inb(p->base + offset);
+    targ_scratch = aic_inb(p, offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, p->base + offset);
-    offset++;
+    aic_outb(p, targ_scratch, offset++);
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-  sblkctl = inb(p->base + SBLKCTL);
-  cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
+  sblkctl = aic_inb(p, SBLKCTL);
+  cur_channel = (sblkctl & SELBUSB) >> 3;
   if (cur_channel != channel)
   {
     /*
      * Case 1: Command for another bus is active
      */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Stealthily resetting channel %c\n",
-           p->host_no, channel);
-#endif
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+        channel, -1, -1);
     /*
      * Stealthily reset the other bus without upsetting the current bus.
      */
-    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
     if (initiate_reset)
     {
       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(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
-    outb(sblkctl, p->base + SBLKCTL);
-    unpause_sequencer(p, /* unpause_always */ FALSE);
+    aic_outb(p, sblkctl, SBLKCTL);
   }
   else
   {
     /*
      * Case 2: A command from this bus is active or we're idle.
      */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Resetting current channel %c\n",
-           p->host_no, channel);
-#endif
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+        channel, -1, -1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    p->msg_type = MSG_TYPE_NONE;
+    p->msg_len = 0;
     if (initiate_reset)
     {
       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(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
+  }
+  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
+  /*
+   * Clean up all the state information for the pending transactions
+   * on this bus.
+   */
+  aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+
+  if ( !(p->type & AHC_TWIN) )
+  {
     restart_sequencer(p);
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
-#endif
   }
 
   /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-  return (found);
+  if(!(p->flags & AHC_IN_ISR))
+    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  return;
 }
 
 /*+F*************************************************************************
@@ -2622,47 +3199,108 @@
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
+  int tindex;
+  int sent;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+
 
   if (p->waiting_scbs.head == NULL)
     return;
 
-  pause_sequencer(p);
+  sent = 0;
+
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  scb = p->waiting_scbs.head;
-  while (scb != NULL)
+  DRIVER_LOCK
+  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
   {
-    if (p->curqincnt >= p->qfullcount)
+    tindex = TARGET_INDEX(scb->cmd);
+    if ( (p->dev_active_cmds[tindex] >=
+          p->dev_temp_queue_depth[tindex]) ||
+         (p->dev_last_reset[tindex] >= (jiffies + (3 * HZ))) )
     {
-      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
-      if (p->curqincnt >= p->qfullcount)
-      {
-        break;
-      }
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+    }
+    else
+    {
+        scb->flags &= ~SCB_WAITINGQ;
+        if ( !(scb->flags & SCB_QUEUED_ABORT) )
+        {
+          p->dev_active_cmds[tindex]++;
+          p->activescbs++;
+        }
+        if ( !(scb->tag_action) )
+        {
+          aic7xxx_busy_target(p, scb);
+        }
+        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+        sent++;
+    }
+  }
+  if (sent)
+  {
+    if(p->type & AHC_AIC78x0)
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
     }
+    if (p->activescbs > p->max_activescbs)
+      p->max_activescbs = p->activescbs;
+  }
+  DRIVER_UNLOCK
+}
 
-    /*
-     * We have some space.
-     */
-    scbq_remove_head(&(p->waiting_scbs));
-    scb->flags &= ~SCB_WAITINGQ;
 
-    outb(scb->hscb->tag, p->base + QINFIFO);
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_timer
+ *
+ * Description:
+ *   Take expired extries off of delayed queues and place on waiting queue
+ *   then run waiting queue to start commands.
+ ***************************************************************************/
+static void
+aic7xxx_timer(struct aic7xxx_host *p)
+{
+  int i;
+  unsigned long cpu_flags = 0;
+  struct aic7xxx_scb *scb;
 
-    if ((p->flags & PAGE_ENABLED) != 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
+  DRIVER_LOCK
+#else
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+#endif
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if ( (p->dev_timer[i].expires) && 
+          (p->dev_timer[i].expires <= jiffies) )
     {
-      /*
-       * We only care about this statistic when paging
-       * since it's impossible to overflow the qinfifo
-       * in the non-paging case.
-       */
-      p->curqincnt++;
+      p->dev_timer[i].expires = 0;
+      if ( (p->dev_timer[i].prev != NULL) ||
+           (p->dev_timer[i].next != NULL) )
+      {
+        del_timer(&p->dev_timer[i]);
+      }
+      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
+      while ( (scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL )
+      {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+      }
     }
-    scb = p->waiting_scbs.head;
   }
-
-  unpause_sequencer(p, FALSE);
+  aic7xxx_run_waiting_queues(p);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
+  DRIVER_UNLOCK
+#else
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#endif
 }
 
 /*+F*************************************************************************
@@ -2674,15 +3312,15 @@
  *   buffer on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char period, unsigned char offset)
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, 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);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+  p->msg_buf[p->msg_index++] = period;
+  p->msg_buf[p->msg_index++] = offset;
+  p->msg_len += 5;
 }
 
 /*+F*************************************************************************
@@ -2694,14 +3332,13 @@
  *   on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char bus_width)
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, 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);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+  p->msg_buf[p->msg_index++] = bus_width;
+  p->msg_len += 4;
 }
 
 /*+F*************************************************************************
@@ -2716,7 +3353,7 @@
 {
   struct aic7xxx_hwscb *hscb;
   Scsi_Cmnd *cmd;
-  int actual;
+  int actual, i;
 
   cmd = scb->cmd;
   hscb = scb->hscb;
@@ -2734,18 +3371,22 @@
      *  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 = scb->sg_length;
+    for (i=1; i < hscb->residual_SG_segment_count; i++)
+    {
+      actual -= scb->sg_list[scb->sg_count - i].length;
+    }
     actual -= (hscb->residual_data_count[2] << 16) |
               (hscb->residual_data_count[1] <<  8) |
               hscb->residual_data_count[0];
 
     if (actual < cmd->underflow)
     {
-      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);
+      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+          (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+          hscb->residual_SG_segment_count);
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
       aic7xxx_status(cmd) = hscb->target_status;
     }
@@ -2769,31 +3410,29 @@
  *   Interrupt handler for sequencer interrupts (SEQINT).
  *-F*************************************************************************/
 static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
 {
   unsigned short targ_mask;
   unsigned char  targ_scratch;
   int scratch_offset = target;
-  int found;
 
-  if (channel == 'B')
-  {
-    scratch_offset += 8;
-  }
+  scratch_offset += channel << 3;
+
   targ_mask = (0x01 << scratch_offset);
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
-  p->needsdtr |= p->needsdtr_copy & targ_mask;
-  p->needwdtr |= p->needwdtr_copy & targ_mask;
+  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 = aic_inb(p, 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);
+  aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+  aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+      target, -1);
   aic7xxx_run_done_queue(p, /*complete*/ TRUE);
 }
 
@@ -2809,107 +3448,35 @@
 {
   struct aic7xxx_scb *scb;
   unsigned short target_mask;
-  unsigned char target, scratch_offset;
+  unsigned char target, scratch_offset, lun;
+  unsigned char queue_flag = FALSE;
   char channel;
 
-  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
-  {
-    target = (inb(p->base + SELID) >> 4) & 0x0F;
-  }
-  else
-  {
-    target = (inb(p->base + SCSIID) >> 4) & 0x0F;
-  }
-  scratch_offset = target;
-  channel = 'A';
-  if (inb(p->base + SBLKCTL) & SELBUSB)
-  {
-    channel = 'B';
-    scratch_offset += 8;
-  }
+  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+  channel = (aic_inb(p, SBLKCTL) >> 3) & 0x01;
+  scratch_offset = target + (channel << 3);
+  lun = aic_inb(p, SAVED_TCL) & 0x07;
   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);
-
-        if (arg1 == SCB_LIST_NULL)
-        {
-          /* untagged request */
-          scb_index = busy_scbid;
-        }
-        else
-        {
-          scb_index = arg1;
-        }
-
-        if (scb_index < p->scb_data->numscbs)
-        {
-          scb = p->scb_data->scb_array[scb_index];
-          if (scb->hscb->control & ABORT_SCB)
-          {
-            /*
-             * 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;
-
-    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);
+        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               p->host_no, channel, target, lun,
+               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       }
       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));
+        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
       }
       break;
 
@@ -2917,559 +3484,652 @@
       {
         /*
          * The reconnecting target either did not send an identify
-         * message, or did, but we didn't find and SCB to match and
+         * message, or did, but we didn't find an 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));
+        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
 
-        found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+        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)
+      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
-               p->host_no, CHAN_TO_INT(channel), target);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+            target, lun);
         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);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+            channel, target, lun);
       }
       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];
+        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+        p->msg_len = 0;
+        p->msg_index = 0;
 
-	switch (message_code)
-	{
-          case MSG_EXT_SDTR:
-          {
-            unsigned char period;
-            unsigned char offset;
-            unsigned char saved_offset;
-            unsigned char targ_scratch;
-            unsigned char max_offset;
-            unsigned char rate;
+       /*
+        * We have to clear the SEQINT *BEFORE* we set the REQINIT handler
+        * active or else VLB and edge triggered EISA cards could loose the
+        * first REQINIT and cause a bus hang/reset cycle.
+        */
+        aic_outb(p, CLRSEQINT, CLRINT);
 
-            if (message_length != MSG_EXT_SDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
+       /*      
+        * To actually receive the message, simply turn on
+        * REQINIT interrupts and let our interrupt handler
+        * do the rest (REQINIT should already be true).
+        */
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
 
-            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);
+       /*
+        * We don't want the sequencer unpaused yet so we return early
+        */
+        return;
+      }
 
-            if (targ_scratch & WIDEXFER)
-              max_offset = MAX_OFFSET_16BIT;
-            else
-              max_offset = MAX_OFFSET_8BIT;
-            offset = MIN(saved_offset, max_offset);
+    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.
+         */
+        unsigned char targ_scratch;
+        unsigned char scb_index;
+        unsigned char last_msg;
 
-            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+        last_msg = aic_inb(p, LAST_MSG);
 
+        if ( (last_msg == MSG_IDENTIFYFLAG) &&
+             (scb->tag_action != 0 ) &&
+             !(p->flags & AHC_HANDLING_REQINITS) )
+        {
+          if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
+              (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
+          {
             /*
-             * Preserve the WideXfer flag.
+             * OK...the device seems able to accept tagged commands, but
+             * not ordered tag commands, only simple tag commands.  So, we
+             * disable ordered tag commands and go on with life just like
+             * normal.
              */
-            targ_scratch = rate | (targ_scratch & WIDEXFER);
-
+            p->orderedtag &= ~target_mask;
+            scb->tag_action = MSG_SIMPLE_Q_TAG;
+            scb->hscb->control &= ~SCB_TAG_TYPE;
+            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+            aic_outb(p, scb->hscb->control, SCB_CONTROL);
             /*
-             * Update both the target scratch area and current SCSIRATE.
+             * OK..we set the tag type to simple tag command, now we re-assert
+             * ATNO and hope this will take us into the identify phase again
+             * so we can resend the tag type and info to the device.
              */
-            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(targ_scratch, p->base + SCSIRATE);
-
+          }
+          else
+          {
+            unsigned char i, reset = 0;
+            struct aic7xxx_scb *scbp;
+            int old_verbose;
             /*
-             * See if we initiated Sync Negotiation and didn't have
-             * have to fall down to async transfers.
+             * Hmmmm....the device is flaking out on tagged commands.  The
+             * bad thing is that we already have tagged commands enabled in
+             * the device struct in the mid level code.  We also have a queue
+             * set according to the tagged queue depth.  Gonna have to live
+             * with it by controlling our queue depth internally and making
+             * sure we don't set the tagged command flag any more.
              */
-            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
-            {
-              /* We started it. */
-              if (saved_offset == offset)
-              {
-        	/*
-        	 * 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);
-              }
-            }
-            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);
-            }
+            p->tagenable &= ~target_mask;
+            p->orderedtag &= ~target_mask;
+            p->dev_max_queue_depth[scratch_offset] =
+               p->dev_temp_queue_depth[scratch_offset] = 1;
             /*
-             * Clear the flags.
+             * We set this command up as a bus device reset.  However, we have
+             * to clear the tag type as it's causing us problems.  We shouldnt
+             * have to worry about any other commands being active, since if
+             * the device is refusing tagged commands, this should be the
+             * first tagged command sent to the device, however, we do have
+             * to worry about any other tagged commands that may already be
+             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
+             * send all the commands back to the mid level code, then let them
+             * come back and get rebuilt as untagged commands.
              */
-            p->needsdtr &= ~target_mask;
-            break;
-          }
-
-          case MSG_EXT_WDTR:
-          {
-            unsigned char scratch, bus_width;
-
-            if (message_length != MSG_EXT_WDTR_LEN)
-            {
-              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)
-            {
-              /*
-               * Don't send an WDTR back to the target, since we asked first.
-               */
-              outb(0, p->base + RETURN_1);
-              switch (bus_width)
-              {
-        	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;
-              }
-            }
-            else
+            scb->tag_action = 0;
+            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+            scb->hscb->control |= MK_MESSAGE;
+            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
+
+            old_verbose = aic7xxx_verbose;
+            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+            for (i=0; i!=p->scb_data->numscbs; i++)
             {
-              int send_reject = FALSE;
-
-              /*
-               * 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. */
-                    send_reject = TRUE;
-        	  }
-        	  break;
-
-        	default:
-        	  break;
-              }
-              if (send_reject)
-              {
-                outb(SEND_REJ, p->base + RETURN_1);
-                printk(KERN_WARNING "scsi%d: Target %d, channel %c, initiating "
-                       "wide negotiation on a narrow bus - rejecting!",
-                       p->host_no, target, channel);
-              }
-              else
+              scbp = p->scb_data->scb_array[i];
+              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
               {
-                aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
-                outb(SEND_MSG, p->base + RETURN_1);
+                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+                {
+                  aic7xxx_reset_device(p, target, channel, lun, i);
+                  reset++;
+                }
               }
             }
-            p->needwdtr &= ~target_mask;
-            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(scratch, p->base + SCSIRATE);
-            break;
-	  }  /* case MSG_EXT_WDTR */
-
-          default:
+            aic7xxx_verbose = old_verbose;
             /*
-             * Unknown extended message - reject it.
+             * Wait until after the for loop to set the busy index since
+             * aic7xxx_reset_device will clear the busy index during its
+             * operation.
              */
-            outb(SEND_REJ, p->base + RETURN_1);
-            break;
-	}  /* switch (message_code) */
-      }  /* case EXTENDED_MSG */
-      break;
-
-    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.
-	 */
-	unsigned char targ_scratch;
-        unsigned char scb_index;
-
-        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 ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-	{
+            aic7xxx_busy_target(p, scb);
+            printk(INFO_LEAD "Device is refusing tagged commands, using "
+              "untagged I/O.\n", p->host_no, channel, target, lun);
+          }
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+        }
+        else if ( (last_msg == MSG_IDENTIFYFLAG) && 
+                  (scb->flags & SCB_MSGOUT_WDTR) )
+        {
           /*
            * 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 ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+          p->needwdtr_copy &= ~target_mask;
+          p->wdtr_pending &= ~target_mask;
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
           {
-            /*
-             * 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);
+            printk(INFO_LEAD "Refusing WIDE negotiation; using 8 bit "
+              "transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+          }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
+          if (p->needsdtr & target_mask)
+          {
+            p->sdtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_SDTR;
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+         /*
+          * note asynch xfers and clear flag
+          */
+          targ_scratch &= 0xF0;
+          p->needsdtr &= ~target_mask;
+          p->needsdtr_copy &= ~target_mask;
+          p->sdtr_pending &= ~target_mask;
+          p->syncinfo[scratch_offset].period = 0;
+          p->syncinfo[scratch_offset].offset = 0;
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_SDTR) )
+          {
+            printk(INFO_LEAD "Refusing synchronous negotiation; using "
+              "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR;
           }
+        }
+        else if (aic7xxx_verbose & VERBOSE_SEQINT)
+        {
           /*
            * Otherwise, we ignore it.
            */
-	}
-        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-        outb(targ_scratch, p->base + SCSIRATE);
+          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
+            "Ignoring.\n", p->host_no, channel, target, lun);
+        }
+        aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, targ_scratch, SCSIRATE);
       }
       break;
 
     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;
-
-	/*
-	 * 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, flags 0x%x, cmd 0x%lx.\n", p->host_no,
-        	 intstat, scb_index, scb->flags, (unsigned long) scb->cmd);
-	}
-	else
-	{
+        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 = aic_inb(p, SCB_TAG);
+        if (scb_index > p->scb_data->numscbs)
+        {
+          aic_outb(p, 0, RETURN_1);
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+            p->host_no, channel, target, lun, intstat, scb_index);
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        hscb = scb->hscb;
+
+        /*
+         * 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.
+         */
+        aic_outb(p, 0, RETURN_1);
+        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+            scb_index, scb->flags, (unsigned long) scb->cmd);
+        }
+        else
+        {
           cmd = scb->cmd;
-  	  hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
           aic7xxx_status(cmd) = hscb->target_status;
 
-          cmd->result |= hscb->target_status;
+          cmd->result = hscb->target_status;
 
           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));
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+                  p->host_no, CTL_OF_SCB(scb));
               break;
 
+            case COMMAND_TERMINATED:
             case CHECK_CONDITION:
-              if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+              if ( !(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 = cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer));
-        	scb->sg_list[0].length = cpu_to_le32(sizeof(cmd->sense_buffer));
-        	cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+                /*
+                 * XXX - How do we save the residual (if there is one).
+                 */
+                if ( hscb->residual_SG_segment_count != 0 )
+                  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 = 
+                  cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+                scb->sg_list[0].length = 
+                  cpu_to_le32(sizeof(cmd->sense_buffer));
 
                 /*
                  * XXX - We should allow disconnection, but can't as it
                  * might allow overlapped tagged commands.
                  */
-  		/* hscb->control &= DISCENB; */
+                  /* hscb->control &= DISCENB; */
                 hscb->control = 0;
-        	hscb->target_status = 0;
-        	hscb->SG_segment_count = 1;
-
-        	addr = VIRT_TO_BUS(&scb->sg_list[0]);
-                hscb->SG_list_pointer = cpu_to_le32(addr);
+                hscb->target_status = 0;
+                hscb->SG_list_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
                 hscb->data_pointer = scb->sg_list[0].address;
+                hscb->data_count = scb->sg_list[0].length;
+                hscb->SCSI_cmd_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->residual_SG_segment_count = 0;
+                hscb->residual_data_count[0] = 0;
+                hscb->residual_data_count[1] = 0;
+                hscb->residual_data_count[2] = 0;
+
+                scb->sg_count = hscb->SG_segment_count = 1;
+                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->flags &= ~SCB_MSGOUT_BITS;
+                scb->tag_action = 0;
+                /*
+                 * This problem could be caused if the target has lost power
+                 * or found some other way to loose the negotiation settings,
+                 * so if needed, we'll re-negotiate while doing the sense cmd.
+                 * However, if this SCB already was attempting to negotiate,
+                 * then we assume this isn't the problem and skip this part.
+                 */
+                if ( !(scb->flags & SCB_MSGOUT_BITS) )
+                {
+                  if ( p->needwdtr_copy & target_mask )
+                  {
+                    p->needwdtr |= target_mask;
+                    p->wdtr_pending |= target_mask;
+                    hscb->control |= MK_MESSAGE;
+                    scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                  }
+                  if ( p->needsdtr_copy & target_mask )
+                  {
+                    p->needsdtr |= target_mask;
+                    if ((hscb->control & MK_MESSAGE) == 0)
+                    {
+                      p->sdtr_pending |= target_mask;
+                      hscb->control |= MK_MESSAGE;
+                      scb->flags |= SCB_MSGOUT_SDTR;
+                    }
+                  }
+                }
 
-        	/* Maintain SCB_LINKED_NEXT */
-        	hscb->data_count &= cpu_to_le32(0xFF000000);
-  		hscb->data_count |= scb->sg_list[0].length;
-
-        	addr = VIRT_TO_BUS(scb->sense_cmd);
-                hscb->SCSI_cmd_pointer = cpu_to_le32(addr);
-        	hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-
-                scb->sg_count = hscb->SG_segment_count;
-        	scb->flags |= SCB_SENSE;
+                scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
                  * an untagged request.
                  */
-                aic7xxx_busy_target(p, target, channel, hscb->tag);
-        	outb(SEND_SENSE, p->base + RETURN_1);
+                aic7xxx_busy_target(p, scb);
+                aic_outb(p, SEND_SENSE, RETURN_1);
+                aic7xxx_error(cmd) = DID_OK;
+                break;
               }  /* first time sense, no errors */
-  	      else
-  	      {
-        	if (aic7xxx_error(cmd) == 0)
-  		{
-        	  aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-  		}
-  	      }
+              aic7xxx_error(cmd) = DID_OK;
+              scb->flags &= ~SCB_SENSE;
               break;
 
             case QUEUE_FULL:
-#ifdef NOT_YET
-              if (scb->hscb->control & TAG_ENB)
+              queue_flag = TRUE;    /* Mark that this is a QUEUE_FULL and */
+            case BUSY:              /* drop through to here */
+            {
+              struct aic7xxx_scb *next_scbp, *prev_scbp;
+              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+              /*
+               * We have to look three places for queued commands:
+               *  1: QINFIFO
+               *  2: p->waiting_scbs queue
+               *  3: WAITING_SCBS list on card (for commands that are started
+               *     but haven't yet made it to the device)
+               */
+              aic7xxx_search_qinfifo(p, target, channel, lun,
+                SCB_LIST_NULL, 0, TRUE,
+                &p->delayed_scbs[scratch_offset]);
+              next_scbp = p->waiting_scbs.head;
+              while ( next_scbp != NULL )
               {
-        	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;
+                prev_scbp = next_scbp;
+                next_scbp = next_scbp->q_next;
+                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
+                     SCB_LIST_NULL) )
+                {
+                  scbq_remove(&p->waiting_scbs, prev_scbp);
+                  scbq_insert_tail(&p->delayed_scbs[scratch_offset],
+                    prev_scbp);
+                }
               }
-#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))
+              next_scbp = NULL;
+              active_hscb = aic_inb(p, SCBPTR);
+              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+              next_hscb = aic_inb(p, WAITING_SCBH);
+              while (next_hscb != SCB_LIST_NULL)
+              {
+                aic_outb(p, next_hscb, SCBPTR);
+                scb_index = aic_inb(p, SCB_TAG);
+                next_scbp = p->scb_data->scb_array[scb_index];
+                if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                    SCB_LIST_NULL) )
+                {
+                  scbq_insert_head(&p->delayed_scbs[scratch_offset],
+                    next_scbp);
+                  next_scbp->flags |= SCB_WAITINGQ;
+                  p->dev_active_cmds[scratch_offset]--;
+                  p->activescbs--;
+                  next_hscb = aic_inb(p, SCB_NEXT);
+                  aic_outb(p, 0, SCB_CONTROL);
+                  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                  aic7xxx_add_curscb_to_free_list(p);
+                  if (prev_hscb == SCB_LIST_NULL)
+                  {
+                    aic_outb(p, 0, SCSISEQ);    /* We were first on the list,
+                                                 * so we kill the selection
+                                                 * hardware.  Let the sequencer
+                                                 * re-init the hardware itself
+                                                 */
+                    aic_outb(p, next_hscb, WAITING_SCBH);
+                  }
+                  else
+                  {
+                    aic_outb(p, prev_hscb, SCBPTR);
+                    aic_outb(p, next_hscb, SCB_NEXT);
+                  }
+                }
+                else
+                {
+                  prev_hscb = next_hscb;
+                  next_hscb = aic_inb(p, SCB_NEXT);
+                }
+              }
+              aic_outb(p, active_hscb, SCBPTR);
+              scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
+              p->dev_active_cmds[scratch_offset]--;
+              p->activescbs--;
+              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+                  
+              if (p->dev_timer[scratch_offset].expires == 0) 
               {
-  		/*
-        	 * 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);
+                if ( p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ * 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
+                else
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ / 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
               }
-              udelay(1000);  /*  A small pause (1ms) to help the drive */
-              break;
+              if (aic7xxx_verbose & VERBOSE_QUEUE_FULL)
+              {
+                if (queue_flag)
+                  printk(INFO_LEAD "Queue full received; queue depth %d, "
+                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
+                    p->dev_max_queue_depth[scratch_offset],
+                    p->dev_active_cmds[scratch_offset]);
+                else
+                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
 
+              }
+              if (queue_flag)
+              {
+                p->dev_temp_queue_depth[scratch_offset] = 
+                  p->dev_active_cmds[scratch_offset];
+                if ( p->dev_last_queue_full[scratch_offset] !=
+                     p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_last_queue_full[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                }
+                else
+                {
+                  p->dev_last_queue_full_count[scratch_offset]++;
+                }
+                if ( (p->dev_last_queue_full_count[scratch_offset] > 14) &&
+                     (p->dev_active_cmds[scratch_offset] > 4) )
+                {
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+                      CTL_OF_SCB(scb), p->dev_active_cmds[scratch_offset]);
+                  p->dev_max_queue_depth[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full[scratch_offset] = 0;
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
+                }
+              }
+              break;
+            }
+            
             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_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+                     CTL_OF_SCB(scb), scb->hscb->target_status);
               if (!aic7xxx_error(cmd))
               {
-        	aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
               }
               break;
           }  /* end switch */
-	}  /* end else of */
+        }  /* end else of */
       }
       break;
 
     case AWAITING_MSG:
       {
-	unsigned char scb_index;
-        unsigned char message_offset;
+        unsigned char scb_index;
 
-	scb_index = inb(p->base + SCB_TAG);
-	scb = p->scb_data->scb_array[scb_index];
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        p->msg_index = p->msg_len = 0;
+        /*
+         * 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.
+         */
 
-	/*
-	 * 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)
-	{
-          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));
-	}
+        if (scb->flags & SCB_DEVICE_RESET)
+        {
+          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+            printk(INFO_LEAD "Bus device reset mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
+        }
         else if (scb->flags & SCB_ABORT)
         {
-          if ((scb->hscb->control & TAG_ENB) != 0)
+          if (scb->hscb->control & TAG_ENB)
           {
-            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+            if (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG)
+            {
+              p->msg_buf[p->msg_index++] = scb->tag_action;
+              p->msg_buf[p->msg_index++] = scb->hscb->tag;
+              p->msg_len += 2;
+            }
+            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
           }
           else
           {
-            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+            p->msg_buf[p->msg_index++] = MSG_ABORT;
           }
-          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)
-	{
-          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+              CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
-          unsigned char target_scratch;
-          unsigned short ultra_enable;
-          int i, sxfr;
+          unsigned char period, offset;
 
           /*
            * Pull the user defined setting from scratch RAM.
            */
-          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++)
+          period = p->syncinfo[scratch_offset].period;
+          offset = p->syncinfo[scratch_offset].offset;
+          if ( (p->needsdtr_copy & target_mask) == 0)
           {
-            if (sxfr == aic7xxx_syncrates[i].rate)
-            break;
+            period = 0;
+            offset = 0;
           }
-          aic7xxx_construct_sdtr(p, message_offset,
-                                 aic7xxx_syncrates[i].period,
-                                 target_scratch & WIDEXFER ?
-                                 MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
+          aic7xxx_construct_sdtr(p, period, offset);
         }
         else 
         {
           panic("aic7xxx: AWAITING_MSG for an SCB that does "
-                "not have a waiting message.");
-	}
+                "not have a waiting message.\n");
+        }
+        /*
+         * We've set everything up to send our message, now to actually do
+         * so we need to enable reqinit interrupts and let the interrupt
+         * handler do the rest.  We don't want to unpause the sequencer yet
+         * though so we'll return early.  We also have to make sure that
+         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+         * or else it's possible on VLB cards to loose the first REQINIT
+         * interrupt.  Edge triggered EISA cards could also loose this
+         * interrupt, although PCI and level triggered cards should not
+         * have this problem since they continually interrupt the kernel
+         * until we take care of the situation.
+         */
+        aic_outb(p, CLRSEQINT, CLRINT);
+        p->msg_index = 0;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+        return;
       }
       break;
 
     case DATA_OVERRUN:
       {
-	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++)
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned char lastphase = aic_inb(p, LASTPHASE);
+        unsigned int i;
+
+        scb = (p->scb_data->scb_array[scb_index]);
+        /*
+         * 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.
+         *    If we retrieved sense info on this target, then the 
+         *    base SENSE info should have been saved prior to the
+         *    overrun error.  In that case, we return DID_OK and let
+         *    the mid level code pick up on the sense info.  Otherwise
+         *    we return DID_ERROR so the command will get retried.
+         */
+        if ( !(scb->flags & SCB_SENSE) )
         {
-          printk(KERN_INFO "     sg[%d] - Addr 0x%x : Length %d\n",
-                 i,
+          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+            p->host_no, CTL_OF_SCB(scb), 
+            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+            scb->sg_length, scb->sg_count);
+          for (i = 0; i < scb->sg_count; i++)
+          {
+            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, 
                  le32_to_cpu(scb->sg_list[i].address),
-                 le32_to_cpu(scb->sg_list[i].length));
+                 le32_to_cpu(scb->sg_list[i].length) );
+          }
+          aic7xxx_error(scb->cmd) = DID_ERROR;
         }
-	/*
-	 * 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;
+        else
+          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+            p->host_no, CTL_OF_SCB(scb));
+      }
+      break;
+
+    case TRACEPOINT:
+      {
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
+          target, lun);
+      }
+      break;
+
+    case TRACEPOINT2:
+      {
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
+          target, lun);
       }
       break;
 
-/* #if AIC7XXX_NOT_YET */
+#if AIC7XXX_NOT_YET 
     /* XXX Fill these in later */
     case MSG_BUFFER_BUSY:
       printk("aic7xxx: Message buffer busy.\n");
@@ -3477,33 +4137,376 @@
     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;
+#endif
 
-    default:		   /* unknown */
-      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-             p->host_no, intstat, inb(p->base + SCSISIGI));
+    default:                   /* unknown */
+      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, channel, target, lun, intstat,
+             aic_inb(p, SCSISIGI));
       break;
   }
 
   /*
    * Clear the sequencer interrupt and unpause the sequencer.
    */
-  outb(CLRSEQINT, p->base + CLRINT);
+  aic_outb(p, CLRSEQINT, CLRINT);
   unpause_sequencer(p, /* unpause always */ TRUE);
 }
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_parse_msg
+ *
+ * Description:
+ *   Parses incoming messages into actions on behalf of
+ *   aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int reject, done;
+  unsigned char target_scratch, scratch_offset;
+  unsigned short target_mask;
+
+  reject = done = FALSE;
+  scratch_offset = TARGET_INDEX(scb->cmd);
+  target_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+  target_mask = (0x01 << scratch_offset);
+
+  /*
+   * Parse as much of the message as is availible,
+   * rejecting it if we don't support it.  When
+   * the entire message is availible and has been
+   * handled, return TRUE indicating that we have
+   * parsed an entire message.
+   */
+
+  if (p->msg_buf[0] != MSG_EXTENDED)
+  {
+    reject = TRUE;
+  }
+
+  /*
+   * Just accept the length byte outright and perform
+   * more checking once we know the message type.
+   */
+
+  if ( !reject && (p->msg_len > 2) )
+  {
+    switch(p->msg_buf[2])
+    {
+      case MSG_EXT_SDTR:
+      {
+        unsigned char period, response_period, offset;
+        unsigned char max_offset, saved_offset, rate;
+
+        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        saved_offset = p->msg_buf[4];
+
+        if (target_scratch & WIDEXFER)
+        {
+          max_offset = MAX_OFFSET_16BIT;
+        }
+        else
+        {
+          max_offset = MAX_OFFSET_8BIT;
+        }
+        offset = MIN(saved_offset, max_offset);
+        response_period = aic7xxx_scsirate(p, &rate, &period,
+          &offset, scb->cmd->target, scb->cmd->channel, /* set */ TRUE);
+        /* Preserve the WideXfer flag */
+        target_scratch = rate | (target_scratch & WIDEXFER);
+
+        /*
+         * Update the TARGET_SCRATCH, the SCSIRATE, and our syncinfo
+         * areas.
+         */
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, target_scratch, SCSIRATE);
+        p->syncinfo[scratch_offset].period = response_period;
+        p->syncinfo[scratch_offset].offset = offset;
+
+        /*
+         * Did we start this, if not, or if we went to low and had to
+         * go async, then send an SDTR back to the target
+         */
+        p->needsdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          if (saved_offset != offset)
+          {
+            p->needsdtr_copy &= ~target_mask;
+            reject = TRUE; 
+          }
+          scb->flags &= ~SCB_MSGOUT_SDTR;
+          p->sdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_SDTR;
+          p->sdtr_pending |= target_mask;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_WDTR:
+      {
+        unsigned char bus_width;
+          
+        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+        {
+          break;
+        }
+
+        bus_width = p->msg_buf[3];
+        p->needwdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              target_scratch |= WIDEXFER;
+              break;
+            }
+          }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->wdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          switch(bus_width)
+          {
+            default:
+            {
+              if (p->type & AHC_WIDE)
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                p->needwdtr_copy |= target_mask;
+                scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                target_scratch |= WIDEXFER;
+                if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                     (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+                {
+                  printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                    p->host_no, CTL_OF_SCB(scb));
+                  p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+                }
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              scb->flags |= SCB_MSGOUT_WDTR_8BIT;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              break;
+            }
+          }
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          p->wdtr_pending |= target_mask;
+        }
+        aic_outb(p, target_scratch, SCSIRATE);
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        p->syncinfo[scratch_offset].offset =
+          (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ? 
+          MAX_OFFSET_8BIT : MAX_OFFSET_16BIT;
+        if ( !(p->wdtr_pending & target_mask) && !reject)
+        {
+          /*
+           * We've successfully completed the wide negotiation, so let's start
+           * up the sync negotiation now.
+           */
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          if ((p->needsdtr & target_mask) && !(p->sdtr_pending & target_mask))
+          {
+            p->sdtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_SDTR;
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          }
+        }
+        done = TRUE;
+        break;
+      }
+      default:
+      {
+        reject = TRUE;
+        break;
+      }
+    } /* end of switch(p->msg_type) */
+  } /* end of if (!reject && (p->msg_len > 2)) */
+
+  if (reject)
+  {
+    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+  }
+  return(done);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_reqinit
+ *
+ * Description:
+ *   Interrupt handler for REQINIT interrupts (used to transfer messages to
+ *    and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char lastbyte;
+  unsigned char phasemis;
+  int done;
+
+  switch(p->msg_type)
+  {
+    case MSG_TYPE_INITIATOR_MSGOUT:
+      {
+        if (p->msg_len == 0)
+          panic("aic7xxx: REQINIT with no active message!\n");
+
+        lastbyte = (p->msg_index == (p->msg_len - 1));
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
+
+        if (lastbyte || phasemis)
+        {
+          /* Time to end the message */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+
+          if (phasemis == 0)
+          {
+            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+            aic_outb(p, 0, RETURN_1);
+          }
+          else
+          {
+            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+          }
+          unpause_sequencer(p, TRUE);
+        }
+        else
+        {
+          /*
+           * Present the byte on the bus (clearing REQINIT) but don't
+           * unpause the sequencer.
+           */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
+        }
+        break;
+      }
+    case MSG_TYPE_INITIATOR_MSGIN:
+      {
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+        if (phasemis == 0)
+        {
+          p->msg_len++;
+          /* Pull the byte in without acking it */
+          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+          done = aic7xxx_parse_msg(p, scb);
+          /* Ack the byte */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_inb(p, SCSIDATL);
+          p->msg_index++;
+        }
+        if (phasemis || done)
+        {
+          /* Time to end our message session */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          p->flags &= ~AHC_HANDLING_REQINITS;
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          unpause_sequencer(p, TRUE);
+        }
+        break;
+      }
+    default:
+      {
+        panic("aic7xxx: Unknown REQINIT message type.\n");
+        break;
+      }
+  } /* End of switch(p->msg_type) */
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_handle_scsiint
  *
  * Description:
@@ -3516,8 +4519,8 @@
   unsigned char status;
   struct aic7xxx_scb *scb;
 
-  scb_index = inb(p->base + SCB_TAG);
-  status = inb(p->base + SSTAT1);
+  scb_index = aic_inb(p, SCB_TAG);
+  status = aic_inb(p, SSTAT1);
 
   if (scb_index < p->scb_data->numscbs)
   {
@@ -3532,14 +4535,35 @@
     scb = NULL;
   }
 
+
+  if ( (p->flags & AHC_HANDLING_REQINITS) && (status & REQINIT) )
+  {
+    if (scb)
+    {
+      aic7xxx_handle_reqinit(p, scb);
+    }
+    else
+    {
+      p->flags &= ~AHC_HANDLING_REQINITS;
+      aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+      aic_outb(p, CLRREQINIT, CLRSINT1);
+      aic_outb(p, CLRSCSIINT, CLRINT);
+      p->msg_type = MSG_TYPE_NONE;
+      p->msg_index = 0;
+      p->msg_len = 0;
+    }
+    return;
+  }
+
   if ((status & SCSIRSTI) != 0)
   {
-    char channel;
+    int channel;
 
-    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
 
-    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-           p->host_no, channel);
+    if (aic7xxx_verbose & VERBOSE_RESET)
+      printk(WARN_LEAD "Someone else reset the channel!!\n",
+           p->host_no, channel, -1, -1);
     /*
      * Go through and abort all commands for the channel, but do not
      * reset the channel again.
@@ -3554,35 +4578,27 @@
      * 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';
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+    unsigned char target = (saved_tcl >> 4) & 0x0F;
+    int channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
     int printerror = TRUE;
 
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     if (lastphase == P_MESGOUT)
     {
-      unsigned char sindex;
       unsigned char message;
 
-      sindex = inb(p->base + SINDEX);
-      message = inb(p->base + sindex - 1);
+      message = aic_inb(p, SINDEX);
 
-      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)
+      if ((message == MSG_ABORT) || (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);
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+            CTL_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+        aic7xxx_run_done_queue(p, FALSE);
         scb = NULL;
         printerror = 0;
       }
@@ -3607,20 +4623,26 @@
         {
           tag = SCB_LIST_NULL;
         }
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
+        aic7xxx_run_done_queue(p, FALSE);
       }
       else
-      {
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+      {  /* Since we don't really know what happened here, we'll wait */
+         /* for the commands to timeout and get aborted if need be    */
+        aic7xxx_add_curscb_to_free_list(p);
       }
-      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);
+      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+      scb = NULL;
+    }
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if ((status & SELTO) != 0)
   {
@@ -3628,9 +4650,18 @@
     unsigned char nextscb;
     Scsi_Cmnd *cmd;
 
-    scbptr = inb(p->base + WAITING_SCBH);
-    outb(scbptr, p->base + SCBPTR);
-    scb_index = inb(p->base + SCB_TAG);
+    scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr >= p->scb_data->maxhscbs)
+    {
+      scb_index = SCB_LIST_NULL;
+      printk(WARN_LEAD "Bad scbptr %d during SELTO.\n", 
+        p->host_no, -1, -1, -1, scbptr);
+    }
+    else
+    {
+      aic_outb(p, scbptr, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+    }
 
     scb = NULL;
     if (scb_index < p->scb_data->numscbs)
@@ -3643,63 +4674,80 @@
     }
     if (scb == NULL)
     {
-      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
-             p->host_no, scb_index);
+      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, -1, -1, -1, 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));
+             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
     }
     else
     {
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       */
       cmd = scb->cmd;
       cmd->result = (DID_TIME_OUT << 16);
 
       /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
+       * Clear out this hardware SCB
+       */
+      aic_outb(p, 0, SCB_CONTROL);
+
+      /*
+       * Clear out a few values in the card that are in an undetermined
+       * state.
        */
-      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);
+      aic_outb(p, MSG_NOOP, MSG_OUT);
 
       /*
        * Shift the waiting for selection queue forward
        */
-      nextscb = inb(p->base + SCB_NEXT);
-      outb(nextscb, p->base + WAITING_SCBH);
+      nextscb = aic_inb(p, SCB_NEXT);
+      aic_outb(p, nextscb, WAITING_SCBH);
 
       /*
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
+      /*
+       * XXX - If we queued an abort tag, go clean up the disconnected list.
+       * We know that this particular SCB had to be the queued abort since
+       * the disconnected SCB would have gotten a reconnect instead.
+       * However, if this is an abort command, then DID_TIMEOUT isn't
+       * appropriate, neither is returning the command for that matter.
+       * What we need to do then is to let the command timeout again so
+       * we get a reset since this abort just failed.
+       */
+      if (p->flags & SCB_QUEUED_ABORT)
+      {
+        cmd->result = 0;
+        scb->flags &= ~SCB_QUEUED_ABORT;
+        scb = NULL;
+      }
     }
     /*
      * Stop the selection.
      */
-    outb(0, p->base + SCSISEQ);
-    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if (scb == NULL)
   {
-    printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+    printk(WARN_LEAD "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));
+           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, 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);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
@@ -3711,7 +4759,7 @@
     char  *phase;
     Scsi_Cmnd *cmd;
     unsigned char mesg_out = MSG_NOOP;
-    unsigned char lastphase = inb(p->base + LASTPHASE);
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
 
     cmd = scb->cmd;
     switch (lastphase)
@@ -3746,8 +4794,8 @@
      * 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);
+    printk(WARN_LEAD "Parity error during phase %s.\n",
+           p->host_no, CTL_OF_SCB(scb), phase);
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -3757,19 +4805,11 @@
      */
     if (mesg_out != MSG_NOOP)
     {
-      outb(mesg_out, p->base + MSG_OUT);
-      outb(1, p->base + MSG_LEN);
+      aic_outb(p, mesg_out, MSG_OUT);
       scb = NULL;
     }
-    else
-    {
-      /*
-       * 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);
+    aic_outb(p, CLRSCSIPERR, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause_always */ TRUE);
   }
   else
@@ -3778,19 +4818,87 @@
      * 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);
+    if (aic7xxx_verbose & VERBOSE_SCSIINT)
+      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+        p->host_no, -1, -1, -1, status);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
   if (scb != NULL)
   {
     aic7xxx_done(p, scb);
-    aic7xxx_done_cmds_complete(p);
   }
 }
 
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_pci_intr
+ *
+ * Description:
+ *   Check the scsi card for PCI errors and clear the interrupt
+ *
+ *   NOTE: If you don't have this function and a 2940 card encounters
+ *         a PCI error condition, the machine will end up locked as the
+ *         interrupt handler gets slammed with non-stop PCI error interrupts
+ *-F*************************************************************************/
+static void
+aic7xxx_pci_intr(struct aic7xxx_host *p)
+{
+  unsigned char status1;
+  int error;
+
+  error = 0;
+  error = pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, &status1);
+
+  if (error == 0)
+  {
+    if (status1 & DPE)
+      printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+        "phase.\n", p->host_no, -1, -1, -1);
+    if (status1 & SSE)
+      printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RMA)
+      printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RTA)
+      printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & STA)
+      printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & DPR)
+      printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+        "PERR#\n", p->host_no, -1, -1, -1);
+  }
+  else
+  {
+    printk(WARN_LEAD "Error reading PCI config register during PCI ERROR"
+      "interrupt.\n", p->host_no, -1, -1, -1);
+    aic_outb(p,  CLRPARERR, CLRINT);
+    return;
+  }
+  
+  pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, status1);
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+}
+#endif
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_isr
@@ -3801,169 +4909,138 @@
 static void
 aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
-  struct aic7xxx_host *p = (struct aic7xxx_host *) dev_id;
+  struct aic7xxx_host *p;
   unsigned char intstat;
-  unsigned long flags;
 
-  /*
-   * Handle all the interrupt sources - especially for SCSI
-   * interrupts, we won't get a second chance at them.
-   */
-  intstat = inb(p->base + INTSTAT);
-  if (! (intstat & INT_PEND))	/* Interrupt for another device */
-    return;
+  p = (struct aic7xxx_host *)dev_id;
 
   /*
-   * Keep track of interrupts for /proc/scsi
+   * Just a few sanity checks.  Make sure p != NULL, that we have an
+   * interrupt pending, and that we aren't already in our int handler.
+   * Also, if PCI, then we are going to check for a PCI bus error status
+   * should we get too many spurious interrupts.
    */
-  p->isr_count++;
-
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+  if (p == NULL)
   {
-    /*
-     * 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)
-    {
-      /* Try clearing all interrupts. */
-      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
-    }
+    printk(KERN_WARNING "aic7xxx: ISR routine called with NULL dev_id\n");
     return;
   }
-
-  if (p->flags & IN_ISR)
+  else if (!(aic_inb(p, INTSTAT) & INT_PEND))
+  {
+#ifdef CONFIG_PCI
+    if ((p->type & AHC_AIC78x0) && (p->spurious_int > 500))
+    {
+      if ( aic_inb(p, ERROR) & PCIERRSTAT )
+      {
+        aic7xxx_pci_intr(p);
+      }
+      p->spurious_int = 0;
+    }
+    else
+    {
+      p->spurious_int++;
+    }
+#endif
+    return;
+  }
+  else if (p->flags & AHC_IN_ISR)
   {
-    printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
-           p->host_no);
     return;
   }
 
   /*
-   * Indicate that we're in the interrupt handler.
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
    */
-  save_flags(flags);
-  cli();
-  p->flags |= IN_ISR;
+  intstat = aic_inb(p, INTSTAT);
+  p->spurious_int = 0;
 
+  /*
+   * Keep track of interrupts for /proc/scsi
+   */
+  p->isr_count++;
+  p->flags |= AHC_IN_ISR;
+
+  /*
+   * Indicate that we're in the interrupt handler.
+   */
   if (intstat & CMDCMPLT)
   {
     struct aic7xxx_scb *scb = NULL;
     Scsi_Cmnd *cmd;
-    unsigned char qoutcnt;
     unsigned char scb_index;
-    int i, interrupts_cleared = 0;
 
     /*
+     * Clear interrupt status before running the completion loop.
+     * This eliminates a race condition whereby a command could
+     * complete between the last check of qoutfifo and the
+     * CLRCMDINT statement.  This would result in us thinking the
+     * qoutfifo was empty when it wasn't, and in actuality be a lost
+     * completion interrupt.  With multiple devices or tagged queueing
+     * this could be very bad if we caught all but the last completion
+     * and no more are imediately sent.
+     */
+    aic_outb(p, CLRCMDINT, CLRINT);
+    /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
-    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
-#if 1
-  if (qoutcnt >= p->qfullcount - 1)
-    printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
-           "qoutcnt = %d.\n", qoutcnt);
-#endif
-    while (qoutcnt > 0)
+    while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
     {
-      if ((p->flags & PAGE_ENABLED) != 0)
+      scb_index = p->qoutfifo[p->qoutfifonext];
+      p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+      if ( scb_index >= p->scb_data->numscbs )
+        scb = NULL;
+      else
+        scb = p->scb_data->scb_array[scb_index];
+      if (scb == NULL)
       {
-        p->cmdoutcnt += qoutcnt;
-        if (p->cmdoutcnt >= p->qfullcount)
-        {
-          /*
-           * Since paging only occurs on aic78x0 chips, we can use
-           * Auto Access Pause to clear the command count.
-           */
-          outb(0, p->base + CMDOUTCNT);
-          p->cmdoutcnt = 0;
-        }
+        printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+          -1, -1, -1, scb_index);
+        continue;
       }
-      for (i = 0; i < qoutcnt; i++)
+      else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
       {
-        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)
+        printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+          "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+          (unsigned long) scb->cmd);
+        continue;
+      }
+      switch (status_byte(scb->hscb->target_status))
+      {
+        case QUEUE_FULL:
+        case BUSY:
+          scb->hscb->target_status = 0;
+          scb->cmd->result = 0;
+          aic7xxx_error(scb->cmd) = DID_OK;
+          break;
+        default:
+          cmd = scb->cmd;
+          if (scb->hscb->residual_SG_segment_count != 0)
           {
-            tag = scb->hscb->tag;
+            aic7xxx_calculate_residual(p, scb);
           }
-          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);
-      }
-      /*
-       * Clear interrupt status before checking the output queue again.
-       * This eliminates a race condition whereby a command could
-       * complete between the queue poll and the interrupt clearing,
-       * so notification of the command being complete never made it
-       * back up to the kernel.
-       */
-      outb(CLRCMDINT, p->base + CLRINT);
-      interrupts_cleared++;
-      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
-    }
-
-    if (interrupts_cleared == 0)
-    {
-      outb(CLRCMDINT, p->base + CLRINT);
+          cmd->result |= (aic7xxx_error(cmd) << 16);
+          if (scb->tag_action)
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
+          else
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_SUCCESS | DEVICE_PRESENT;
+          aic7xxx_done(p, scb);
+          break;
+      }      
     }
-
-    aic7xxx_done_cmds_complete(p);
   }
 
   if (intstat & BRKADRINT)
   {
     int i;
-    unsigned char errno = inb(p->base + ERROR);
+    unsigned char errno = aic_inb(p, ERROR);
 
-    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+    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)
@@ -3971,11 +5048,15 @@
         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);
+    printk(KERN_ERR "(scsi%d)   LINE=%d\n", p->host_no,
+      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+    aic7xxx_reset_channel(p, 0, TRUE);
+    if ( p->type & AHC_TWIN )
+    {
+      aic7xxx_reset_channel(p, 1, TRUE);
+      restart_sequencer(p);
+    }
+    aic_outb(p, CLRBRKADRINT, CLRINT);
   }
 
   if (intstat & SEQINT)
@@ -3987,14 +5068,37 @@
   {
     aic7xxx_handle_scsiint(p, intstat);
   }
-
-  if (p->waiting_scbs.head != NULL)
+  if(!(p->flags & (AHC_IN_ABORT | AHC_IN_RESET)))
   {
+    aic7xxx_done_cmds_complete(p);
     aic7xxx_run_waiting_queues(p);
   }
+  p->flags &= ~AHC_IN_ISR;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   do_aic7xxx_isr
+ *
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static void
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long cpu_flags;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
 
-  p->flags &= ~IN_ISR;
-  restore_flags(flags);
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  aic7xxx_isr(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#else
+  DRIVER_LOCK
+  aic7xxx_isr(irq, dev_id, regs);
+  DRIVER_UNLOCK
+#endif
 }
 
 /*+F*************************************************************************
@@ -4017,54 +5121,58 @@
 static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
-  int default_depth = 2;
+  int default_depth = 3;
+  unsigned char tindex;
+  unsigned short target_mask;
+
+  tindex = device->id | (device->channel << 3);
+  target_mask = (1 << tindex);
 
   device->queue_depth = default_depth;
-#ifdef AIC7XXX_TAGGED_QUEUEING
+  p->dev_mid_level_queue_depth[tindex] = 3;
+  p->dev_temp_queue_depth[tindex] = 1;
+  p->dev_max_queue_depth[tindex] = 1;
+  p->tagenable &= ~target_mask;
+
   if (device->tagged_supported)
   {
-    unsigned short target_mask;
     int tag_enabled = TRUE;
 
-    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;
-    }
+    default_depth = 8;  /* Not many SCBs to work with. */
 #endif
  
     if (!(p->discenable & target_mask))
     {
-      printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+        printk(INFO_LEAD "Disconnection disabled, unable to "
              "enable tagged queueing.\n",
-             p->host_no, device->id, device->channel);
+             p->host_no, device->channel, device->id, device->lun);
     }
     else
     {
-#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
-      device->queue_depth = default_depth;
-#else
       if (p->instance >= NUMBER(aic7xxx_tag_info))
       {
+        static int print_warning = TRUE;
+        if(print_warning)
+        {
+          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+                           " installed controllers.\n");
+          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+                           " the aic7xxx.c source file.\n");
+          print_warning = FALSE;
+        }
         device->queue_depth = default_depth;
       }
       else
       {
-        unsigned char  tindex;
 
-        tindex = device->id | (device->channel << 3);
-        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
         {
           tag_enabled = FALSE;
-          device->queue_depth = 2;  /* Tagged queueing is disabled. */
+          device->queue_depth = 3;  /* Tagged queueing is disabled. */
         }
         else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
@@ -4076,21 +5184,24 @@
             aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
       }
-#endif
       if ((device->tagged_queue == 0) && tag_enabled)
       {
-        if (aic7xxx_verbose)
+        if (aic7xxx_verbose & VERBOSE_QUEUE)
         {
-    	  printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
-    	         "queue depth %d.\n", p->host_no,
-    	         device->id, device->channel, device->queue_depth);
-        }
+              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
+                p->host_no, device->channel, device->id,
+                device->lun, device->queue_depth);
+        }
+        p->dev_max_queue_depth[tindex] = device->queue_depth;
+        p->dev_temp_queue_depth[tindex] = device->queue_depth;
+        p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
+        p->tagenable |= target_mask;
+        p->orderedtag |= target_mask;
         device->tagged_queue = 1;
         device->current_tag = SCB_LIST_NULL;
       }
     }
   }
-#endif
 }
 
 /*+F*************************************************************************
@@ -4111,17 +5222,29 @@
 {
   Scsi_Device *device;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  int scbnum;
 
+  scbnum = 0;
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
       aic7xxx_device_queue_depth(p, device);
+      scbnum += device->queue_depth;
     }
   }
+  while (scbnum > p->scb_data->numscbs)
+  {
+    /*
+     * Pre-allocate the needed SCBs to get around the possibility of having
+     * to allocate some when memory is more or less exhausted and we need
+     * the SCB in order to perform a swap operation (possible deadlock)
+     */
+    if ( aic7xxx_allocate_scb(p, TRUE) == NULL )
+      return;
+  }
 }
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_probe
@@ -4144,8 +5267,8 @@
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
  *-F*************************************************************************/
-static aha_chip_type
-aic7xxx_probe(int slot, int base, aha_status_type *bios)
+static ahc_type
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 {
   int i;
   unsigned char buf[4];
@@ -4153,13 +5276,13 @@
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_chip_type type;
+    ahc_type type;
     int bios_disabled;
   } AIC7xxx[] = {
-    { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
-    { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_7770, FALSE }, /* motherboard 7770  */
-    { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x, FALSE }, /* 284x BIOS enabled */
-    { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x, TRUE }   /* 284x BIOS disabled */
+    { 4, { 0x04, 0x90, 0x77, 0x71 }, AHC_274, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x70 }, AHC_AIC7770, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x56 }, AHC_284, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 }, AHC_284, TRUE }   /* 284x BIOS disabled */
   };
 
   /*
@@ -4183,13 +5306,13 @@
       {
         if (AIC7xxx[i].bios_disabled)
         {
-          *bios = AIC_DISABLED;
+          *flags |= AHC_USEDEFAULTS;
         }
         else
         {
-          *bios = AIC_ENABLED;
+          *flags |= AHC_BIOS_ENABLED;
         }
-	return (AIC7xxx[i].type);
+        return (AIC7xxx[i].type);
       }
 
       printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
@@ -4197,9 +5320,8 @@
     }
   }
 
-  return (AIC_NONE);
+  return (AHC_NONE);
 }
-#endif /* __sparc_v9__ or __powerpc__ */
 
 /*+F*************************************************************************
  * Function:
@@ -4236,11 +5358,11 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)	\
-  {						\
-    ;  /* Do nothing */				\
-  }						\
-  (void) inb(p->base + SEECTL_2840);
+  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
+  }                                                \
+  (void) aic_inb(p, SEECTL_2840);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -4253,7 +5375,7 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
     CLOCK_PULSE(p);
 
     /*
@@ -4263,10 +5385,10 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4277,10 +5399,10 @@
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
 
@@ -4293,11 +5415,11 @@
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
-      outb(temp, p->base + SEECTL_2840);
+      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4314,11 +5436,11 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(CK_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
   }
 
@@ -4365,16 +5487,16 @@
    * is needed.  Reason: after the 7870 chip reset, there
    * should be no contention.
    */
-  outb(SEEMS, p->base + SEECTL);
+  aic_outb(p, SEEMS, SEECTL);
   wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
   {
     wait--;
     udelay(1000);  /* 1 msec */
   }
-  if ((inb(p->base + SEECTL) & SEERDY) == 0)
+  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
-    outb(0, p->base + SEECTL);
+    aic_outb(p, 0, SEECTL);
     return (0);
   }
   return (1);
@@ -4390,7 +5512,7 @@
 static inline void
 release_seeprom(struct aic7xxx_host *p)
 {
-  outb(0, p->base + SEECTL);
+  aic_outb(p, 0, SEECTL);
 }
 
 /*+F*************************************************************************
@@ -4444,8 +5566,8 @@
  *   this case, has no implied timing.
  *-F*************************************************************************/
 static int
-read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
-    unsigned int len, 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 char temp;
@@ -4457,9 +5579,9 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + SEECTL) & SEERDY) == 0)	\
-  {						\
-    ;  /* Do nothing */				\
+  while ((aic_inb(p, SEECTL) & SEERDY) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
   }
 
   /*
@@ -4482,7 +5604,7 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
     CLOCK_PULSE(p);
 
     /*
@@ -4492,10 +5614,10 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
     /*
@@ -4506,10 +5628,10 @@
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4522,11 +5644,11 @@
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
-      outb(temp, p->base + SEECTL);
+      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4544,11 +5666,11 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS | SEECK, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
   }
 
@@ -4571,7 +5693,6 @@
   }
   printk("\n");
 #endif
-
   if (checksum != scarray[len - 1])
   {
     return (0);
@@ -4594,13 +5715,13 @@
   unsigned char brdctl;
 
   brdctl = BRDCS | BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl |= value;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDCS;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
 }
 
 /*+F*************************************************************************
@@ -4613,8 +5734,77 @@
 static inline unsigned char
 read_brdctl(struct aic7xxx_host *p)
 {
-  outb(BRDRW | BRDCS, p->base + BRDCTL);
-  return (inb(p->base + BRDCTL));
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  return (aic_inb(p, BRDCTL));
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic785x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  aic_outb(p, 0, BRDCTL);
+  brdctl = aic_inb(p, BRDCTL);
+  *int_50 = !(brdctl & BRDDAT5);
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = ( aic_inb(p, SPIOCAP) & EEPROM ) != 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * 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.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the two internal connectors.  BRDDAT6
+   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_50 = !(brdctl & BRDDAT6);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = (brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+  
 }
 
 /*+F*************************************************************************
@@ -4629,82 +5819,72 @@
 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\n");
-      printk(KERN_INFO "         detected settings and use manual termination "
-                       "if necessary.\n"); 
-
+      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination on "
+                       "controller:\n");
+      printk(KERN_INFO "aic7xxx: <%s> at ", board_names[p->board_name_index]);
+      switch(p->type & 0x1ff1)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+          printk("EISA slot %d\n", p->pci_device_fn);
+          break;
+        case AHC_284:
+          printk("VLB slot %d\n", p->pci_device_fn);
+          break;
+        default:
+          printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+            PCI_FUNC(p->pci_device_fn));
+          break;
+      }
+      printk(KERN_INFO "aic7xxx: Please verify driver detected settings are "
+        "correct.\n");
+      printk(KERN_INFO "aic7xxx: If not, then please properly set the device "
+        "termination\n");
+      printk(KERN_INFO "aic7xxx: in the Adaptec SCSI BIOS by hitting CTRL-A "
+        "when prompted\n");
+      printk(KERN_INFO "aic7xxx: during machine bootup.\n");
       /* Configure auto termination. */
-      outb(SEECS | SEEMS, p->base + SEECTL);
-
-      /*
-       * 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.
-       */
-      write_brdctl(p, 0);
+      aic_outb(p, SEECS | SEEMS, SEECTL);
 
-      /*
-       * 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).
-       */
-      brdctl_int = read_brdctl(p);
-      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
-      if (max_targ > 8)
+      if ( (p->type & AHC_AIC7860) == AHC_AIC7860 )
       {
-        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
+        aic785x_cable_detect(p, &internal50_present, &external_present,
+          &eprom_present);
       }
-
-      /*
-       * Set the rom bank to 1 and determine
-       * the other signals.
-       */
-      write_brdctl(p, BRDDAT5);
-
-      /*
-       * 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.
-       */
-      brdctl_ext = read_brdctl(p);
-      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
-      eprom_present = brdctl_ext & BRDDAT7;
-      if (aic7xxx_verbose)
-      {
-        if (max_targ > 8)
-        {
-          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
-        {
-          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);
+      else
+      {
+        aic787x_cable_detect(p, &internal50_present, &internal68_present,
+          &external_present, &eprom_present);
       }
+      if (max_targ > 8)
+      {
+        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
+      {
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+               internal50_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
+        internal68_present = 0;
+      }
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "aic7xxx: EEPROM %s present.\n",
+             eprom_present ? "is" : "is not");
 
       /*
        * Now set the termination based on what we found.  BRDDAT6
@@ -4718,16 +5898,18 @@
         high_on = TRUE;
       }
 
-      if ((internal50_present + internal68_present + external_present) <= 1)
+      if ( ( (internal50_present ? 1 : 0) +
+             (internal68_present ? 1 : 0) +
+             (external_present   ? 1 : 0) ) <= 1)
       {
         low_on = TRUE;
       }
           
       if (internal50_present && internal68_present && external_present)
       {
-        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
-               "         Only two connectors on the adapter may be "
-               "used at a time!\n");
+        printk(KERN_INFO "aic7xxx: Illegal cable configuration!!  Only two\n");
+        printk(KERN_INFO "aic7xxx: connectors on the SCSI controller may be "
+               "in use at a time!\n");
       }
 
       if (high_on == TRUE)
@@ -4738,28 +5920,23 @@
       if (low_on == TRUE)
         *sxfrctl1 |= STPWEN;
 
-      if (aic7xxx_verbose)
+      if (max_targ > 8)
       {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-                 low_on ? "ON" : "OFF",
-                 high_on ? "ON" : "OFF");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
-        }
+        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+              low_on ? "ON" : "OFF", high_on ? "ON" : "OFF");
+      }
+      else
+      {
+        printk(KERN_INFO "aic7xxx: Termination %s\n",
+          low_on ? "Enabled" : "Disabled");
       }
-      aic7xxx_verbose = old_verbose;
     }
     else
     {
       if (adapter_control & CFSTERM)
-      {
         *sxfrctl1 |= STPWEN;
-      }
-      outb(SEEMS | SEECS, p->base + SEECTL);
+
+      aic_outb(p, SEEMS | SEECS, SEECTL);
       /*
        * Configure high byte termination.
        */
@@ -4771,7 +5948,7 @@
       {
         write_brdctl(p, 0);
       }
-      if (aic7xxx_verbose)
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
       {
         printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
                (adapter_control & CFSTERM) ? "ON" : "OFF",
@@ -4794,7 +5971,6 @@
 detect_maxscb(struct aic7xxx_host *p)
 {
   int i;
-  unsigned char max_scbid = 255;
 
   /*
    * It's possible that we've already done this for multichannel
@@ -4806,90 +5982,35 @@
      * We haven't initialized the SCB settings yet.  Walk the SCBs to
      * determince how many there are.
      */
-    outb(0, p->base + FREE_SCBH);
+    aic_outb(p, 0, FREE_SCBH);
 
     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)
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, i, SCB_CONTROL);
+      if (aic_inb(p, SCB_CONTROL) != i)
         break;
-      outb(0, p->base + SCBPTR);
-      if (inb(p->base + SCB_CONTROL) != 0)
+      aic_outb(p, 0, SCBPTR);
+      if (aic_inb(p, SCB_CONTROL) != 0)
         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. */
-
-      /* 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);
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
+      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
     }
 
     /* Make sure the last SCB terminates the free list. */
-    outb(i - 1, p->base + SCBPTR);
-    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+    aic_outb(p, i - 1, SCBPTR);
+    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
 
     /* Ensure we clear the first (0) SCBs control byte. */
-    outb(0, p->base + SCBPTR);
-    outb(0, p->base + SCB_CONTROL);
+    aic_outb(p, 0, SCBPTR);
+    aic_outb(p, 0, SCB_CONTROL);
 
     p->scb_data->maxhscbs = i;
   }
 
-  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;
-  }
-
-  /*
-   * Set the Queue Full Count.  Some cards have more queue space than
-   * SCBs.
-   */
-  switch (p->chip_class)
-  {
-    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*************************************************************************
@@ -4900,15 +6021,14 @@
  *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
 static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+  int reset_delay)
 {
-  int i;
-  unsigned char sblkctl, flags = 0;
-  int max_targets, irq_flags = 0;
+  int i, result;
+  int max_targets;
   int found = 1;
-  char channel_ids[] = {'A', 'B', 'C'};
   unsigned char target_settings;
-  unsigned char scsi_conf, sxfrctl1;
+  unsigned char term, scsi_conf, sxfrctl1;
   unsigned short ultraenable = 0;
   struct Scsi_Host *host;
 
@@ -4917,78 +6037,12 @@
    */
   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(p->base + SBLKCTL);
-  if (p->flags & PAGE_ENABLED)
-    flags = PAGESCBS;
-
-  switch (sblkctl & SELBUS_MASK)
-  {
-    case SELNARROW:     /* narrow/normal bus */
-      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 */
-      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;
-
-    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);
-  }
-
-  /*
-   * Detect SCB parameters and initialize the SCB array.
-   */
-  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;
+  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+  host->can_queue = AIC7XXX_MAXSCB;
+  host->cmd_per_lun = 3;
   host->sg_tablesize = AIC7XXX_MAX_SG;
   host->select_queue_depths = aic7xxx_select_queue_depth;
   host->this_id = p->scsi_id;
@@ -4996,110 +6050,231 @@
   host->n_io_port = 0xFF;
   host->base = (unsigned char *) p->mbase;
   host->irq = p->irq;
-  if (p->bus_type == AIC_WIDE)
+  if (p->type & AHC_WIDE)
   {
     host->max_id = 16;
   }
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     host->max_channel = 1;
   }
 
   p->host = host;
+  p->last_reset = 0;
   p->host_no = host->host_no;
   p->isr_count = 0;
+  p->next = NULL;
   p->completeq.head = NULL;
   p->completeq.tail = NULL;
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
 
-  for (i = 0; i < NUMBER(p->device_status); i++)
+  for (i = 0; i < NUMBER(p->untagged_scbs); 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;
+    p->untagged_scbs[i] = SCB_LIST_NULL;
+    p->qinfifo[i] = SCB_LIST_NULL;
+    p->qoutfifo[i] = SCB_LIST_NULL;
+  }
+  /*
+   * We currently have no commands of any type
+   */
+  p->qinfifonext = 0;
+  p->qoutfifonext = 0;
+
+  for (i = 0; i < MAX_TARGETS; i++)
+  {
+    p->dev_commands_sent[i] = 0;
+    p->dev_flags[i] = DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+    p->dev_active_cmds[i] = 0;
+    p->dev_last_reset[i] = 0;
+    p->dev_last_queue_full[i] = 0;
+    p->dev_last_queue_full_count[i] = 0;
+    p->dev_max_queue_depth[i] = 1;
+    p->dev_temp_queue_depth[i] = 1;
+    p->dev_mid_level_queue_depth[i] = 3;
+    scbq_init(&p->delayed_scbs[i]);
+    init_timer(&p->dev_timer[i]);
+    p->dev_timer[i].expires = 0;
+    p->dev_timer[i].data = (unsigned long)p;
+    p->dev_timer[i].function = (void *)aic7xxx_timer;
+    p->syncinfo[i].period = 0;
+    p->syncinfo[i].offset = 0;
+  }
+
+  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+    board_names[p->board_name_index]);
+  switch(p->type & 0x1ff1)
+  {
+    case AHC_AIC7770:
+    case AHC_274:
+      printk("EISA slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_284:
+      printk("VLB slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+        PCI_FUNC(p->pci_device_fn));
+      break;
   }
-
-  /*
-   * Request an IRQ for the board. Only allow sharing IRQs with PCI devices.
-   */
-#ifdef AIC7XXX_OLD_ISR_TYPE
-  irq_flags = SA_INTERRUPT;
-#endif
-  if (p->chip_class != AIC_777x)
-    irq_flags |= SA_SHIRQ;
-  if (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", p) < 0)
+  if (p->type & AHC_TWIN)
   {
-    printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-           p->irq);
-    return (0);
+    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+           p->host_no, p->scsi_id, p->scsi_id_b);
   }
-
-  /*
-   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
-   */
-  if (p->bus_type == AIC_TWIN)
+  else
   {
-    /*
-     * The controller is gated to channel B after a chip reset; set
-     * bus B values first.
-     */
-    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)
+    char *channel;
+
+    channel = "";
+
+    if ((p->type & AHC_39x) != 0)
+    {
+      channel = " A";
+
+      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+      {
+        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+    }
+    if (p->type & AHC_WIDE)
     {
-      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
     }
     else
     {
-      outb(DFON | SPIOEN, p->base + SXFRCTL0);
+      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
     }
+    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
+  }
+  aic_outb(p, 0, SEQ_FLAGS);
 
+  /*
+   * Detect SCB parameters and initialize the SCB array.
+   */
+  detect_maxscb(p);
+  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+    p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+    p->base, p->irq);
+  printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
+    p->host_no, p->mbase, (unsigned long)p->maddr);
+
+
+
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if ((p->type & AHC_AIC7770) == AHC_AIC7770)
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
+    if (result < 0)
+    {
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
+    }
+  }
+  if (result < 0)
+  {
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring.\n",
+           p->host_no, p->irq);
+    return (0);
+  }
+
+  /*
+   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
+   */
+  if (p->type & AHC_TWIN)
+  {
+    /*
+     * The controller is gated to channel B after a chip reset; set
+     * bus B values first.
+     */
+    term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+    aic_outb(p, p->scsi_id_b, SCSIID);
+    scsi_conf = aic_inb(p, SCSICONF + 1);
+    sxfrctl1 = aic_inb(p, SXFRCTL1);
+    aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    if (p->type & AHC_ULTRA)
+    {
+      aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
+    }
+    else
+    {
+      aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    }
+    if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+    {
+      scsi_conf &= ~0x07;
+      scsi_conf |= p->scsi_id_b;
+      aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
+    }
     if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
     {
       /* Reset SCSI bus B. */
-      if (aic7xxx_verbose)
-        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+      if (aic7xxx_verbose & VERBOSE_PROBE)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
 
       aic7xxx_reset_current_bus(p);
     }
 
     /* Select channel A */
-    outb(SELNARROW, p->base + SBLKCTL);
+    aic_outb(p, SELNARROW, SBLKCTL);
   }
 
-  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)
+  term = ((p->flags & AHC_TERM_ENB_A) != 0) ? STPWEN : 0;
+  aic_outb(p, p->scsi_id, SCSIID);
+  scsi_conf = aic_inb(p, SCSICONF);
+  sxfrctl1 = aic_inb(p, SXFRCTL1);
+  aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  if (p->type & AHC_ULTRA)
   {
-    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
   }
   else
   {
-    outb(DFON | SPIOEN, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  }
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+  {
+    scsi_conf &= ~0x07;
+    scsi_conf |= p->scsi_id;
+    aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF);
   }
 
+
   if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
   {
     /* Reset SCSI bus A. */
-    if (aic7xxx_verbose)
-      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+    if (aic7xxx_verbose & VERBOSE_PROBE)
+    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
+      char *channel = "";
+      if (p->flags & AHC_MULTI_CHANNEL)
+      {
+        channel = " A";
+        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+    }
 
     aic7xxx_reset_current_bus(p);
 
     /*
      * Delay for the reset delay.
      */
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    if (!reset_delay)
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
   }
 
   /*
@@ -5114,7 +6289,10 @@
   p->sdtr_pending = 0x0;
   p->needwdtr_copy = 0x0;
   p->wdtr_pending = 0x0;
-  if (p->bus_type == AIC_SINGLE)
+  p->tagenable = 0x0;
+  p->ultraenb = 0x0;
+  p->discenable = 0xffff;
+  if ((p->type & (AHC_TWIN|AHC_WIDE)) == 0)
   {
     max_targets = 8;
   }
@@ -5126,31 +6304,36 @@
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (p->flags & USE_DEFAULTS)
+  if (p->flags & AHC_USEDEFAULTS)
   {
-    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
-           "device parameters.\n");
-    p->discenable = 0xFFFF;
+    printk(KERN_INFO "(scsi%d) Host adapter BIOS disabled. Using default SCSI "
+           "device parameters.\n", p->host_no);
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = 0xffff;
+    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
   }
   else
   {
-    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
-        inb(p->base + DISC_DSB));
+    p->discenable = ~((aic_inb(p, DISC_DSB + 1) << 8) |
+        aic_inb(p, DISC_DSB));
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = (aic_inb(p, ULTRA_ENB + 1) << 8) | 
+          aic_inb(p, ULTRA_ENB);
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (p->flags & USE_DEFAULTS)
+    if (p->flags & AHC_USEDEFAULTS)
     {
       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))
+      if (p->type & AHC_ULTRA)
         ultraenable |= (0x01 << i);
     }
     else
     {
-      target_settings = inb(p->base + TARG_SCRATCH + i);
+      target_settings = aic_inb(p, TARG_SCRATCH + i);
       if (target_settings & 0x0F)
       {
         p->needsdtr_copy |= (0x01 << i);
@@ -5168,24 +6351,33 @@
          */
         target_settings &= 0x7F;
       }
-      if (p->flags & ULTRA_ENABLED)
+    }
+
+    aic_outb(p, target_settings, TARG_SCRATCH + i);
+    if (p->needsdtr_copy & (0x01 << i))
+    {
+      short sxfr, j;
+
+      sxfr = target_settings & SXFR;
+      if ((p->ultraenb & (1 << i)) != 0)
       {
-        switch (target_settings & 0x70)
-        {
-          case 0x00:
-          case 0x10:
-          case 0x20:
-            ultraenable |= (0x01 << i);
-            break;
-          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
-            target_settings &= ~(0x70);
-            break;
-          default:
-            break;
-        }
+        /* Want an ultra speed in the table */
+        sxfr |= 0x100;
       }
+      for (j = 0; j < NUMBER(aic7xxx_syncrates); j++)
+      {
+        if (sxfr == aic7xxx_syncrates[j].rate)
+          break;
+      }
+      p->syncinfo[i].period = aic7xxx_syncrates[j].period;
+      p->syncinfo[i].offset =
+       (p->type & AHC_WIDE) ? MAX_OFFSET_16BIT : MAX_OFFSET_8BIT;
+    }
+    else
+    {
+      p->syncinfo[i].period = 0;
+      p->syncinfo[i].offset = 0;
     }
-    outb(target_settings, p->base + TARG_SCRATCH + i);
   }
 
   /*
@@ -5193,26 +6385,14 @@
    * work on some cards that don't leave these fields cleared
    * when BIOS is not installed.
    */
-  if (p->bus_type != AIC_WIDE)
+  if ( !(p->type & AHC_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);
+  aic_outb(p, 0, ULTRA_ENB);
+  aic_outb(p, 0, ULTRA_ENB + 1);
 
   /*
    * Allocate enough hardware scbs to handle the maximum number of
@@ -5230,8 +6410,8 @@
     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");
+      printk("(scsi%d) Unable to allocate hardware SCB array; "
+             "failing detection.\n", p->host_no);
       release_region(p->base, MAXREG - MINREG);
       free_irq(p->irq, p);
       return(0);
@@ -5241,40 +6421,35 @@
 
     /* 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);
+    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
+
+    /* Set up the fifo areas at the same time */
+    hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+
+    /* The Q-FIFOs we just set up are all empty */
+    aic_outb(p, 0, QINPOS);
+    aic_outb(p, 0, KERNEL_QINPOS);
+    aic_outb(p, 0, QOUTPOS);
 
-  /*
-   * Set FIFO depth and command out count.  These are only used when
-   * paging is enabled and should not be touched for AIC-7770 based
-   * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1
-   * which are used to control termination.
-   */
-  if (p->flags & PAGE_ENABLED)
-  {
-    outb(p->qfullcount, p->base + FIFODEPTH);
-    outb(0, p->base + CMDOUTCNT);
   }
 
   /*
    * 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);
+  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
 
   /*
    * Message out buffer starts empty
    */
-  outb(0, p->base + MSG_LEN);
+  aic_outb(p, MSG_NOOP, MSG_OUT);
 
   /*
    * Load the sequencer program, then re-enable the board -
@@ -5285,24 +6460,24 @@
    */
   aic7xxx_loadseq(p);
 
-  if (p->chip_class == AIC_777x)
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
   {
-    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
   }
 
   /*
+   * Link us into the list of valid hosts
+   */
+  p->next = first_aic7xxx;
+  first_aic7xxx = p;
+
+  /*
    * 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);
 
-  /*
-   * Add it to our list of adapters.
-   */
-  p->next = first_aic7xxx;
-  first_aic7xxx = p;
-
   return (found);
 }
 
@@ -5314,38 +6489,56 @@
  *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
  *   is paused upon return.
  *-F*************************************************************************/
-static void
+int
 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;
+  hcntrl = (aic_inb(p, 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);
+  aic_outb(p, PAUSE | CHIPRST, 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))
+  while ((wait > 0) && ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0))
   {
     udelay(1000);  /* 1 msec = 1000 usec */
     wait = wait - 1;
   }
 
-  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+  if ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0)
   {
     printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
   }
 
-  outb(hcntrl | PAUSE, p->base + HCNTRL);
+  aic_outb(p, hcntrl | PAUSE, HCNTRL);
+
+  switch( aic_inb(p, SBLKCTL) & 0x0a )
+  {
+    case 0:  /* normal narrow card */
+      break;
+    case 2:  /* Wide card */
+      p->type |= AHC_WIDE;
+      break;
+    case 8:  /* Twin card */
+      p->type |= AHC_TWIN;
+      p->flags |= AHC_MULTI_CHANNEL;
+      break;
+    default: /* hmmm...we don't know what this is */
+      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+        aic_inb(p, SBLKCTL) & 0x0a);
+      return(-1);
+  }
+  return(0);
 }
 
 /*+F*************************************************************************
@@ -5357,8 +6550,7 @@
  *   and a pointer to a aic7xxx_host struct upon success.
  *-F*************************************************************************/
 static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, unsigned long base, unsigned long mbase,
-    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
@@ -5375,46 +6567,45 @@
     memset(p, 0, sizeof(struct aic7xxx_host));
     p->host = host;
 
-    if (scb_data != NULL)
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
     {
-      /*
-       * We are sharing SCB data areas; use the SCB data pointer
-       * provided.
-       */
-      p->scb_data = scb_data;
-      p->flags |= SHARED_SCBDATA;
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
     }
     else
     {
       /*
-       * We are not sharing SCB data; allocate one.
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the aic7xxx_host struct, and return NULL.
        */
-      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;
-      }
+      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;
+      p->base = temp->base;
+      p->mbase = temp->mbase;
+      p->maddr = temp->maddr;
+      p->flags = temp->flags;
+      p->type = temp->type;
+      p->unpause = temp->unpause;
+      p->pause = temp->pause;
+      p->pci_bus = temp->pci_bus;
+      p->pci_device_fn = temp->pci_device_fn;
+      p->bios_address = temp->bios_address;
+      p->irq = temp->irq;
+      p->scsi_id = temp->scsi_id;
+      p->scsi_id_b = temp->scsi_id_b;
+      p->discenable = temp->discenable;
+      p->ultraenb = temp->ultraenb;
+      p->tagenable = 0;
+      p->orderedtag = 0;
+      p->board_name_index = temp->board_name_index;
+      p->adapter_control = temp->adapter_control;
+      p->bios_control = temp->bios_control;
+      DRIVER_LOCK_INIT
     }
   }
   return (p);
@@ -5429,49 +6620,48 @@
  *   the driver (struct aic7xxx_host *).
  *-F*************************************************************************/
 static void
-aic7xxx_free (struct aic7xxx_host *p)
+aic7xxx_free(struct aic7xxx_host *p)
 {
-  int i;
+  int i, jump;
 
   /*
-   * 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.
+   * Free the allocated hardware SCB space.
    */
-  if (!(p->flags & SHARED_SCBDATA))
+  if (p->scb_data->hscbs != NULL)
   {
-    /*
-     * 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);
+    kfree(p->scb_data->hscbs);
+  }
+  /*
+   * Free the driver SCBs.  These were allocated on an as-need
+   * basis. However, we allocated them 30 at a time up until the
+   * very last allocation (if there was one).  So, we need to free
+   * every 30th pointer to free the array (this also frees the
+   * SG_array structs as well).
+   *
+   * Note, on 64 bit machines we allocate 29 at a time instead.
+   */
+  jump = (sizeof(int) == sizeof(void *)) ? 30 : 29;
+  for (i = 0; i < p->scb_data->numscbs; i += jump)
+  {
+    kfree(p->scb_data->scb_array[i]);
   }
   /*
+   * Free the SCB data area.
+   */
+  kfree(p->scb_data);
+
+  /*
    * Free the instance of the device structure.
    */
+
+  /*
+   * XXXXXXXX  FIXXXXXMEEEEEE.  How do we unmap the I/O range we have mapped
+   * if we are doing MMAPed I/O ??????????  Our biggest concern is the issue
+   * of possibly calling unmap on an area that *might* be used on another
+   * controller as well (aka, the 4096 byte MMAPed area is back to back
+   * with another controller, and the PAGE_SIZE is greater then 4096, allowing
+   * us to remap in a shared page).
+   */
   scsi_unregister(p->host);
 }
 
@@ -5492,46 +6682,42 @@
   unsigned short scarray[128];
   struct seeprom_config *sc = (struct seeprom_config *) scarray;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
     printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
   }
-  switch (p->chip_type)
+  switch (p->type & 0x00001ff1)
   {
-    case AIC_7770:  /* None of these adapters have seeproms. */
-    case AIC_7771:
-    case AIC_7855:
+    case AHC_AIC7770:  /* None of these adapters have seeproms. */
+    case AHC_274:
       break;
 
-    case AIC_284x:
+    case AHC_284:
       have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
       break;
 
-    case AIC_7850:  /* The 2910B is a 7850 with a seeprom. */
-    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),
+    case AHC_AIC7850:  /* The 2910B is a 7850 with a seeprom. */
+    case AHC_294AU:
+    case AHC_AIC7870:  /* For these controllers we try the three possible */
+    case AHC_AIC7895:  /* SEEPROM read types.  If none works, then we are */
+    case AHC_294:      /* SOL.  This should catch any SEEPROM variety     */
+    case AHC_394:      /* Adaptec or some motherboard manufacturer might  */
+    case AHC_294U:     /* throw at us, and since we perform a checksum    */
+    case AHC_394U:     /* during the read, we should get bogus seeprom    */
+    case AHC_AIC7860:  /* reads. */
+    case AHC_AIC7880:
+    case AHC_398:
+    case AHC_398U:
+      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   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),
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(scarray)/2, C46);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(*sc)/2, C56_66);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(scarray)/2, C56_66);
       break;
 
@@ -5541,19 +6727,19 @@
 
   if (!have_seeprom)
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("\naic7xxx: No SEEPROM available; using defaults.\n");
     }
-    p->flags |= USE_DEFAULTS;
+    p->flags |= AHC_USEDEFAULTS;
+    p->flags &= ~AHC_BIOS_ENABLED;
   }
   else
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("done\n");
     }
-    p->flags |= HAVE_SEEPROM;
 
     /*
      * Update the settings in sxfrctl1 to match the termination settings.
@@ -5564,14 +6750,17 @@
      * First process the settings that are different between the VLB
      * and PCI adapter seeproms.
      */
-    if (p->chip_class == AIC_777x)
+    if (p->type & AHC_284)
     {
       /* VLB adapter seeproms */
       if (sc->bios_control & CF284XEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CF284XSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
       /*
        * 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
@@ -5589,30 +6778,90 @@
     {
       /* PCI adapter seeproms */
       if (sc->bios_control & CFEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CFSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
 
       /* Limit to 16 targets just in case. */
       max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
     }
 
+    p->discenable = 0;
+
+    for (i = 0; i < max_targets; i++)
+    {
+      if( (p->type & AHC_ULTRA) &&
+         !(sc->adapter_control & CFULTRAEN) &&
+          (sc->device_flags[i] & CFSYNCHISULTRA) )
+      {
+        p->flags |= AHC_NEWEEPROM_FMT;
+        break;
+      }
+    }
+
     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);
+      }
+      if (p->flags & AHC_NEWEEPROM_FMT)
+      {
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= (0x01 << i);
+        }
+      }
+      else if (sc->adapter_control & CFULTRAEN)
+      {
+        p->ultraenb |= (0x01 << i);
+      }
+      if ( ((target_settings & 0x70) == 0x40) &&
+           (p->ultraenb & (0x01 << i)) )
+      {
+        target_settings &= ~0x70;
+        p->ultraenb &= ~(0x01 << i);
+      }
+      aic_outb(p, target_settings, TARG_SCRATCH + i);
     }
-    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
-    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
+    aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+    aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+    aic_outb(p,  (p->ultraenb & 0xFF), ULTRA_ENB);
+    aic_outb(p,  ((p->ultraenb >> 8) & 0xFF), ULTRA_ENB + 1);
 
     p->scsi_id = sc->brtime_id & CFSCSIID;
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
+
+    if (p->bios_control & CFBIOSEN)
+    {
+      p->flags &= ~AHC_USEDEFAULTS;
+      p->flags |= AHC_BIOS_ENABLED;
+    }
+    else
+    {
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->flags |= AHC_USEDEFAULTS;
+    }
+
+    if ((p->type & 0x1ff1) == AHC_AIC7895)
+    {
+      if (p->adapter_control & CFBPRIMARY)
+        p->flags |= AHC_CHANNEL_B_PRIMARY;
+    }
 
     scsi_conf = (p->scsi_id & 0x7);
     if (sc->adapter_control & CFSPARITY)
@@ -5621,37 +6870,39 @@
      * The 7850 controllers with a seeprom, do not honor the CFRESETB
      * flag in the seeprom.  Assume that we want to reset the SCSI bus.
      */
-    if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850))
+    if (sc->adapter_control & CFRESETB)
       scsi_conf |= RESET_SCSI;
-
-    if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
-    {
-      /*
-       * We allow the operator to override ultra enable through
-       * the boot prompt.
-       */
-      if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
-      {
-        /* Treat us as a non-ultra card */
-        p->flags &= ~ULTRA_ENABLED;
-      }
-    }
+    /*
+     * We may be a 2842, if so, preserve the TERM_ENB bit in scsi conf
+     */
+    if ( (p->flags & AHC_TERM_ENB_A) && 
+        ((p->type & AHC_AIC7770) == AHC_AIC7770) )
+      scsi_conf |= TERM_ENB;
+    /*
+     * If this is an Ultra card, is Ultra mode enabled?  If not, disable
+     * it in the host struct as well
+     */
+    if ( (p->type & AHC_ULTRA) && 
+        !(sc->adapter_control & CFULTRAEN) &&
+        !(p->flags & AHC_NEWEEPROM_FMT) )
+      p->type &= ~AHC_ULTRA;
 
     /* Set the host ID */
-    outb(scsi_conf, p->base + SCSICONF);
+    aic_outb(p, scsi_conf, SCSICONF);
     /* In case we are a wide card */
-    outb(p->scsi_id, p->base + SCSICONF + 1);
+    aic_outb(p, p->scsi_id, SCSICONF + 1);
 
-    if (p->chip_class != AIC_777x)
+    if ((p->type & AHC_AIC7860) == AHC_AIC7860)
     {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
       /*
        * Update the settings in sxfrctl1 to match the termination
        * settings.
        */
-      *sxfrctl1 = 0;
-      configure_termination(p, sxfrctl1, sc->adapter_control,
-        (unsigned char) sc->max_targets & CFMAXTARG);
+        configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
     }
+    else if (have_seeprom && ((p->type & AHC_AIC7770) != AHC_AIC7770))
+      configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
   }
   return (have_seeprom);
 }
@@ -5671,28 +6922,40 @@
 int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
   int found = 0;
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
-  aha_status_type adapter_bios;
-  unsigned char hcntrl, hostconf, irq = 0;
-  int slot, base;
+  ahc_flag_type flags = 0;
+  ahc_type type;
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
+
+#ifdef MODULE
+  /*
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
+   */
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx, NULL);
+
 #endif
-  aha_chip_class_type chip_class;
-  aha_chip_type chip_type;
-  int chan_num = 0;
-  unsigned char sxfrctl1, sblkctl;
-  int i;
-  struct aic7xxx_host *p;
 
   template->proc_dir = &proc_scsi_aic7xxx;
-  template->name = aic7xxx_info(NULL);
   template->sg_tablesize = AIC7XXX_MAX_SG;
 
-#if !defined(__sparc_v9__) && !defined(__powerpc__)
+
+#if defined(__i386__) || defined(__alpha__)
   /*
    * EISA/VL-bus card signature probe.
    */
-  for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+  slot = MINSLOT;
+  while (slot <= MAXSLOT)
   {
     base = SLOTBASE(slot) + MINREG;
 
@@ -5702,354 +6965,571 @@
        * Some other driver has staked a
        * claim to this i/o region already.
        */
-      continue;
+      slot++;
+      continue; /* back to the beginning of the for loop */
     }
-
-    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
-    if (chip_type != AIC_NONE)
+    flags = 0;
+    type = aic7xxx_probe(slot, base + HID0, &flags);
+    switch (type)
     {
-
-      switch (chip_type)
-      {
-        case AIC_7770:
-        case AIC_7771:
+      case AHC_AIC7770:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at EISA %d\n",
-                 board_names[chip_type], slot);
-          break;
-        case AIC_284x:
+               board_names[2], slot);
+        break;
+      case AHC_274:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[3], slot);
+        break;
+      case AHC_284:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at VLB %d\n",
-                 board_names[chip_type], slot);
-          break;
-        default:
-          break;
-      }
+               board_names[4], slot);
+        break;
+      default:
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
+    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+    if (temp_p == NULL)
+    {
+      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+      slot++;
+      continue; /* back to the beginning of the while loop */
+    }
+    /*
+     * Pause the card preserving the IRQ type.  Allow the operator
+     * to override the IRQ trigger.
+     */
+    if (aic7xxx_irq_trigger == 1)
+      hcntrl = IRQMS;  /* Level */
+    else if (aic7xxx_irq_trigger == 0)
+      hcntrl = 0;  /* Edge */
+    else
+      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+    memset(temp_p, 0, sizeof(struct aic7xxx_host));
+    temp_p->unpause = hcntrl | INTEN;
+    temp_p->pause = hcntrl | PAUSE | INTEN;
+    temp_p->base = base;
+    temp_p->type = type;
+    temp_p->flags = flags | AHC_PAGESCBS;
+    temp_p->mbase = 0;
+    temp_p->maddr = 0;
+    temp_p->pci_bus = 0;
+    temp_p->pci_device_fn = slot;
+    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+    if (aic7xxx_chip_reset(temp_p) == -1)
+      temp_p->irq = 0;
+    else
+      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    switch (temp_p->irq)
+    {
+      case 9:
+      case 10:
+      case 11:
+      case 12:
+      case 14:
+      case 15:
+        break;
 
-      /*
-       * Pause the card preserving the IRQ type.  Allow the operator
-       * to override the IRQ trigger.
-       */
-      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);
+      default:
+        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level %d, ignoring.\n", temp_p->irq);
+        kfree(temp_p);
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
 
-      p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
-      if (p == NULL)
-      {
-        printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-        continue;
-      }
-      aic7xxx_chip_reset(p);
+    /*
+     * We are commited now, everything has been checked and this card
+     * has been found, now we just set it up
+     */
+    /*
+     * Insert our new struct into the list at the end
+     */
+    if (list_p == NULL)
+    {
+      list_p = current_p = temp_p;
+    }
+    else
+    {
+      current_p = list_p;
+      while (current_p->next != NULL)
+        current_p = current_p->next;
+      current_p->next = temp_p;
+    }
+    if (aic7xxx_extended)
+    {
+      temp_p->flags |= AHC_EXTEND_TRANS_A;
+      if (temp_p->flags & AHC_MULTI_CHANNEL)
+        temp_p->flags |= AHC_EXTEND_TRANS_B;
+    }
 
-      irq = inb(INTDEF + base) & 0x0F;
-      switch (irq)
+    switch (temp_p->type & 0x1ff1)
+    {
+      case AHC_AIC7770:
+        temp_p->board_name_index = 2;
+      case AHC_274:
       {
-        case 9:
-        case 10:
-        case 11:
-        case 12:
-        case 14:
-        case 15:
-          break;
-
-        default:
-          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
-          "level %d, ignoring.\n", irq);
-          irq = 0;
-          aic7xxx_free(p);
-          break;
-      }
+        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
 
-      if (irq != 0)
-      {
-        p->irq = irq & 0x0F;
-        p->chip_class = AIC_777x;
-#ifdef AIC7XXX_PAGE_ENABLE
-        p->flags |= PAGE_ENABLED;
-#endif
-        p->instance = found;
-        if (aic7xxx_extended)
+        /*
+         * 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 (temp_p->board_name_index == 0)
+          temp_p->board_name_index = 3;
+        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
         {
-          p->flags |= EXTENDED_TRANSLATION;
+          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
         }
 
-        switch (p->chip_type)
+        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+        {
+          temp_p->flags |= AHC_USEDEFAULTS;
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        }
+        else
         {
-          case AIC_7770:
-          case AIC_7771:
+          temp_p->flags &= ~AHC_USEDEFAULTS;
+          temp_p->flags |= AHC_BIOS_ENABLED;
+          if ( (temp_p->bios_control & 0x20) == 0 )
           {
-            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)
+            switch(temp_p->bios_control & 0x07)
             {
-              p->flags |= USE_DEFAULTS;
+              case 0x0:
+                temp_p->bios_address = 0xcc000;
+                break;
+              case 0x1:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd4000;
+                break;
+              case 0x3:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xdc000;
+                break;
+              case 0x5:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe4000;
+                break;
+              case 0x7:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
           }
-
-          case AIC_284x:
-            if (!load_seeprom(p, &sxfrctl1))
+          else
+          {
+            switch(temp_p->bios_control & 0x06)
             {
-              if (aic7xxx_verbose)
-                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+              case 0x0:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
-
-          default:  /* Won't get here. */
-            break;
+          }
         }
-        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, 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)
+        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+        if (temp_p->flags & AHC_USEDEFAULTS)
         {
-          /*
-           * We detected a Rev E board, we allow paging on this board.
-           */
-          printk("Revision >= E\n");
-          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+          temp_p->scsi_id = temp_p->scsi_id_b = 7;
+          temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
         }
         else
         {
-          /* Do not allow paging. */
-          p->flags &= ~PAGE_ENABLED;
-          printk("Revision <= C\n");
+          if ( ((temp_p->adapter_control >> 8) & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_A;
+          if ( (temp_p->adapter_control & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_B;
+          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
         }
+        break;
+      }
 
-        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))
+      case AHC_284:
+        load_seeprom(temp_p, &sxfrctl1);
+        temp_p->board_name_index = 4;
+        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
         {
-          /*
-           * We successfully found a board and registered it.
-           */
-          found = found + 1;
-        }
-        else
-        {
-          /*
-           * Something went wrong; release and free all resources.
-           */
-          aic7xxx_free(p);
+          case 0x00:
+            temp_p->bios_address = 0xe0000;
+            break;
+          case 0x20:
+            temp_p->bios_address = 0xc8000;
+            break;
+          case 0x40:
+            temp_p->bios_address = 0xd0000;
+            break;
+          case 0x60:
+            temp_p->bios_address = 0xd8000;
+            break;
+          default:
+            break; /* can't get here */
         }
-      }
+        break;
+
+      default:  /* Won't get here. */
+        break;
+    }
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+        temp_p->irq,
+        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
     }
+
+    /*
+     * Set the FIFO threshold and the bus off time.
+     */
+    hostconf = aic_inb(temp_p, HOSTCONF);
+    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+    slot++;
+    found++;
   }
-#endif /* __sparc_v9__ or __powerpc__ */
+
+#endif /* defined(__i386__) || defined(__alpha__) */
 
 #ifdef CONFIG_PCI
   /*
    * PCI-bus probe.
    */
-  if (pci_present())
+  if (pcibios_present())
   {
     struct
     {
       unsigned short      vendor_id;
       unsigned short      device_id;
-      aha_chip_type       chip_type;
-      aha_chip_class_type chip_class;
+      ahc_type            type;
+      ahc_flag_type       flags;
+      int                 board_name_index;
     } 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_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},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AIC_7873, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AIC_7874, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AIC_7880, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AIC_7881, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AIC_7882, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AIC_7883, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+       AHC_FNONE,                                            1 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       5 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       6 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  7 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_294AU,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  8 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                      9 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     10 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_394,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     11 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_398,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     12 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     13 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     14 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     15 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_394U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     16 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_398U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     17 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     18 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
     };
 
-    int error, flags;
-    unsigned short index = 0;
-    unsigned char ultra_enb = 0;
-    unsigned int  devconfig, class_revid;
-    scb_data_type *shared_scb_data = NULL;
-    char rev_id[] = {'B', 'C', 'D'};
+    unsigned short command;
+    unsigned int  devconfig, i;
+#ifdef MMAPIO
+    unsigned long page_offset;
+#endif
+    struct aic7xxx_host *first_7895 = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
     struct pci_dev *pdev = NULL;
-    unsigned long iobase, mbase;
-    unsigned int irq;
+#else
+    int index;
+    unsigned int piobase, mmapbase;
+    unsigned char pci_bus, pci_devfn;
+#endif
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
+    {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+      pdev = NULL;
       while ((pdev = pci_find_device(aic7xxx_pci_devices[i].vendor_id,
                                      aic7xxx_pci_devices[i].device_id,
-				    pdev)))
+                                     pdev)))
+#else
+      index = 0;
+      while (!(pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
+                                   aic7xxx_pci_devices[i].device_id,
+                                   index++, &pci_bus, &pci_devfn)) )
+#endif
       {
-        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)
+        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
         {
-          case AIC_7855:
-            flags |= USE_DEFAULTS;
-            break;
-
-          case AIC_7872:  /* 3940 */
-          case AIC_7882:  /* 3940-Ultra */
-            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 */
-            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;
-
-          default:
-            break;
+          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
+          {
+            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+              "supported by\n");
+            printk(KERN_INFO "         this driver, we are ignoring it.\n");
+          }
         }
+        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+                                    GFP_ATOMIC)) != NULL )
+        {
+          memset(temp_p, 0, sizeof(struct aic7xxx_host));
+          temp_p->type = aic7xxx_pci_devices[i].type;
+          temp_p->flags = aic7xxx_pci_devices[i].flags;
+          temp_p->board_name_index = aic7xxx_pci_devices[i].board_name_index;
 
-        /*
-         * Read sundry information from PCI BIOS.
-         */
-	iobase = pdev->base_address[0];
-	mbase = pdev->base_address[1];
-	irq = pdev->irq;
-        error = pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-        error += pci_read_config_dword(pdev, CLASS_PROGIF_REVID, &class_revid);
-        printk("aic7xxx: <%s> at PCI %d\n",
-               board_names[chip_type], PCI_SLOT(pdev->devfn));
+          /*
+           * Read sundry information from PCI BIOS.
+           */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+          temp_p->irq = pdev->irq;
+          temp_p->pci_bus = pdev->bus->number;
+          temp_p->pci_device_fn = pdev->devfn;
+          temp_p->base = pdev->base_address[0];
+          temp_p->mbase = pdev->base_address[1];
+          pci_read_config_word(pdev, PCI_COMMAND, &command);
+          pci_write_config_word(pdev, PCI_COMMAND,
+             command | PCI_COMMAND_MASTER |
+             PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#else
+          temp_p->pci_bus = pci_bus;
+          temp_p->pci_device_fn = pci_devfn;
+          pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+            &temp_p->irq);
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+            &piobase);
+          temp_p->base = piobase;
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
+            &mmapbase);
+          temp_p->mbase = mmapbase;
+          pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+          pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+            command | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+            PCI_COMMAND_IO);
+#endif
+
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic7xxx_pci_devices[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
 
-        /*
-         * 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) {
-          unsigned short pci_command;
-
-          /* Enable bus mastering since this thing must do DMA. */
-          pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-          pci_command |= PCI_COMMAND_MASTER;
-#ifdef __powerpc__
-          /* Enable I/O and memory-space access */
-          pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+          /*
+           * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
+           * we mask it off.
+           */
+          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          temp_p->unpause = (aic_inb(temp_p, HCNTRL) & IRQMS) | INTEN;
+          temp_p->pause = temp_p->unpause | PAUSE;
+
+#ifdef MMAPIO
+          base = temp_p->mbase & PAGE_MASK;
+          page_offset = temp_p->mbase - base;
+          /*
+           * replace the next line with this one if you are using 2.1.x:
+           * temp_p->maddr = ioremap(base, page_offset + 256);
+           */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+          temp_p->maddr = ioremap(base, page_offset + 256);
+#else
+          temp_p->maddr = vremap(base, page_offset + 256);
 #endif
-          pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-        } else {
-          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;
+          if(temp_p->maddr)
+          {
+            temp_p->maddr += page_offset;
+          }
 #endif
-        p->instance = found;
+
+          aic_outb(temp_p, temp_p->pause, HCNTRL);
+          while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+
+          temp_p->bios_address = 0;
 
           /*
            * Remember how the card was setup in case there is no seeprom.
            */
-          p->scsi_id = inb(p->base + SCSIID) & OID;
-          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+          temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          /*
+           * Get current termination setting
+           */
+          sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+
+          if (aic7xxx_chip_reset(temp_p) == -1)
           {
-            p->flags |= ULTRA_ENABLED;
-            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
           }
-	  sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
 
-          aic7xxx_chip_reset(p);
-
-#ifdef AIC7XXX_USE_EXT_SCBRAM
-          if (devconfig & RAMPSM)
+          switch (temp_p->type & 0x1ff1)
           {
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            /*
-             * XXX - Assume 9 bit SRAM and enable parity checking.
-             */
-            devconfig |= EXTSCBPEN;
+            case AHC_394:   /* 3940 */
+            case AHC_394U:  /* 3940-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 5:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                default:
+                  break;
+              }
+              break;
 
-            /*
-             * 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);
-          }
+            case AHC_398:   /* 3985 */
+            case AHC_398U:  /* 3985-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 8:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                case 12:
+                  temp_p->flags |= AHC_CHNLC;
+                  break;
+                default:
+                  break;
+              }
+              break;
+
+            case AHC_AIC7895:
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              if (PCI_FUNC(temp_p->pci_device_fn) != 0)
+              {
+                temp_p->flags |= AHC_CHNLB;
+              }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              devconfig |= SCBSIZE32;
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#else
+              pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                &devconfig);
+              devconfig |= SCBSIZE32;
+              pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                devconfig);
 #endif
+              if (aic7xxx_7895_irq_hack != -1)
+              {
+                if (first_7895 == NULL)
+                {
+                  printk(KERN_INFO "aic7xxx: Using 7895_irq_hack.  Please "
+                    "upgrade your motherboard BIOS\n");
+                  first_7895 = temp_p;
+                }
+                else if (aic7xxx_7895_irq_hack == 0)
+                {
+                  if (temp_p->flags & AHC_CHNLB)
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+                else
+                {
+                  if ( !(temp_p->flags & AHC_CHNLB) )
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * Loading of the SEEPROM needs to come after we've set the flags
+           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
+           * on 394x and 398x cards we'll end up reading the wrong settings
+           * for channels B and C
+           */
+          if ( !(load_seeprom(temp_p, &sxfrctl1)) )
+          {
+            temp_p->flags |= AHC_USEDEFAULTS;
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+            temp_p->scsi_id = temp_p->scsi_id_b = 7;
+          }
 
-          if ((p->flags & USE_DEFAULTS) == 0)
+          /*
+           * and then we need another switch based on the type in order to
+           * make sure the channel B primary flag is set properly on 7895
+           * controllers....Arrrgggghhh!!!
+           */
+          switch(temp_p->type & 0x1ff1)
           {
-            load_seeprom(p, &sxfrctl1);
+            case AHC_AIC7895:
+              current_p = list_p;
+              while(current_p != NULL)
+              {
+                if ( (current_p->pci_bus == temp_p->pci_bus) &&
+                     (PCI_SLOT(current_p->pci_device_fn) ==
+                      PCI_SLOT(temp_p->pci_device_fn)) )
+                {
+                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+                    temp_p->flags |= 
+                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+                  else
+                    current_p->flags |=
+                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                }
+                current_p = current_p->next;
+              }
+              break;
+            default:
+              break;
           }
 
           /*
            * Take the LED out of diagnostic mode
            */
-          sblkctl = inb(p->base + SBLKCTL);
-          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+          aic_outb(temp_p, 
+            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+            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);
+          aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
 
-          if (p->flags & USE_DEFAULTS)
+          if (temp_p->flags & AHC_USEDEFAULTS)
           {
             int j;
+            unsigned char k;
             /*
              * Default setup; should only be used if the adapter does
              * not have a SEEPROM.
@@ -6061,115 +7541,315 @@
              */
             for (j = TARG_SCRATCH; j < 0x60; j++)
             {
-              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
+              k = aic_inb(temp_p, j);
+              /* Check for all zeros and ones.  Break out if we pass */
+              if( (k != 0x00) && (k != 0xff) )
                 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))
+            /* If j makes it to 0x60, then all entries are either 0x00 or
+             * 0xff.  We would then assume we have *not* been initialized
+             * and drop through here.  OTOH, if even one entry is inited,
+             * then as long as we appear to have a valid SCSI ID, we'll use
+             * the leftover BIOS values.
+             */
+            if ((j != 0x60) && (temp_p->scsi_id != 0))
             {
-              p->flags &= ~USE_DEFAULTS;
-              if (aic7xxx_verbose)
+              temp_p->flags &= ~AHC_USEDEFAULTS;
+              if (aic7xxx_verbose & VERBOSE_PROBE2)
               {
                 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.
                */
+              temp_p->flags &= ~AHC_BIOS_ENABLED;
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
               sxfrctl1 = STPWEN;
-              p->scsi_id = 7;
+              temp_p->scsi_id = 7;
             }
-            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
-                 p->base + SCSICONF);
+            aic_outb(temp_p, (temp_p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+                 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;
-            }
+            aic_outb(temp_p, temp_p->scsi_id, SCSICONF + 1);
           }
-
-          /*
-           * Print some additional information about the adapter.
-           */
-          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, "
-                 "IO Mem 0x%lx, IRQ %x",
-                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
-                 p->base, p->mbase, p->irq);
-          if ((class_revid & DEVREVID) < 3)
+          else /* not using defaults */
           {
-            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A;
           }
-          printk("\n");
 
           if (aic7xxx_extended)
-            p->flags |= EXTENDED_TRANSLATION;
-
-          if (aic7xxx_verbose)
-            printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                   (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+            temp_p->flags |= AHC_EXTEND_TRANS_A;
 
           /*
            * 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)
+          sxfrctl1 |= aic_inb(temp_p, SXFRCTL1);
+          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+          if ( list_p == NULL )
           {
-            aic7xxx_free(p);
+            list_p = current_p = temp_p;
           }
           else
           {
-            found = found + 1;
+            current_p = list_p;
+            while(current_p->next != NULL)
+              current_p = current_p->next;
+            current_p->next = temp_p;
+          }
+          temp_p->next = NULL;
+          found++;
+        }  /* Found an Adaptec PCI device. */
+        else /* Well, we found one, but we couldn't get any memory */
+        {
+          printk("aic7xxx: Found <%s>\n", 
+            board_names[aic7xxx_pci_devices[i].board_name_index]);
+          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+            "skipping.\n");
+        }
+      } /* while(pdev=....) */
+    } /* for PCI_DEVICES */
+  } /* PCI BIOS present */
+#endif CONFIG_PCI
+  /*
+   * Now, we re-order the probed devices by BIOS address and BUS class.
+   * In general, we follow this algorithm to make the adapters show up
+   * in the same order under linux that the computer finds them.
+   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+   *     address, going from lowest to highest.
+   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+   *     address, going from lowest to highest.
+   *  3: Remaining VLB/EISA controllers going in slot order.
+   *  4: Remaining PCI controllers, going in PCI device order (reversable)
+   */
 
-#ifdef AIC7XXX_USE_EXT_SCBRAM
+  {
+    struct aic7xxx_host *vlb_enab, *vlb_disab, *pci;
+    struct aic7xxx_host *prev_p;
+    struct aic7xxx_host *p;
+    unsigned char left;
+
+    prev_p = vlb_enab = vlb_disab = pci = NULL;
+
+    temp_p = list_p;
+    while (temp_p != NULL)
+    {
+      switch(temp_p->type)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+        case AHC_284:
+          if (temp_p->flags & AHC_BIOS_ENABLED)
+          {
+            if (vlb_enab == NULL)
+            {
+              vlb_enab = temp_p;
+              temp_p = temp_p->next;
+              vlb_enab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_enab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->bios_address < temp_p->bios_address))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_enab = temp_p;
+                temp_p = temp_p->next;
+                vlb_enab->next = current_p;
+              }
+            }
+          }
+          else
+          {
+            if (vlb_disab == NULL)
+            {
+              vlb_disab = temp_p;
+              temp_p = temp_p->next;
+              vlb_disab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_disab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->base < temp_p->base))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_disab = temp_p;
+                temp_p = temp_p->next;
+                vlb_disab->next = current_p;
+              }
+            }
+          }
+          break;
+        default:  /* All PCI controllers fall through to default */
+          if (pci == NULL)
+          {
+            pci = temp_p;
+            temp_p = temp_p->next;
+            pci->next = NULL;
+          }
+          else
+          {
+            current_p = pci;
+            prev_p = NULL;
+            if (!aic7xxx_reverse_scan)
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) < 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            else
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) > 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
             /*
-             * Set the shared SCB data once we've successfully probed a
-             * 398x adapter.
-             *
-             * Note that we can only do this if the use of external
-             * SCB RAM is enabled.
+             * Are we dealing with a 7985 where we need to sort the
+             * channels as well, if so, the bios_address values should
+             * be the same
              */
-            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+                 (temp_p->pci_bus == current_p->pci_bus) &&
+                 (PCI_SLOT(temp_p->pci_device_fn) ==
+                  PCI_SLOT(current_p->pci_device_fn)) )
             {
-              if (shared_scb_data == NULL)
+              if (temp_p->flags & AHC_CHNLB)
               {
-                shared_scb_data = p->scb_data;
+                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+              else
+              {
+                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
               }
             }
-#endif
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              pci = temp_p;
+              temp_p = temp_p->next;
+              pci->next = current_p;
+            }
           }
-
-          index++;
-      }  /* Found an Adaptec PCI device. */
+          break;
+      }  /* End of switch(temp_p->type) */
+    } /* End of while (temp_p != NULL) */
+    /*
+     * At this point, the cards have been broken into 4 sorted lists, now
+     * we run through the lists in order and register each controller
+     */
+    left = found;
+    temp_p = vlb_enab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = pci;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = vlb_disab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
   }
-#endif CONFIG_PCI
-
   return (found);
 }
 
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_buildscb
@@ -6191,57 +7871,61 @@
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
+  hscb->control = 0;
+  scb->tag_action = 0;
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-    if (cmd->device->tagged_queue)
+    if (p->tagenable & mask)
     {
       cmd->tag = hscb->tag;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+      p->dev_commands_sent[TARGET_INDEX(cmd)]++;
+      if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
       {
         hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
       }
       else
       {
-        hscb->control |= MSG_ORDERED_Q_TAG;
-        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+        if (p->orderedtag & mask)
+        {
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+        }
+        else
+        {
+          hscb->control |= MSG_SIMPLE_Q_TAG;
+          scb->tag_action = MSG_SIMPLE_Q_TAG;
+        }
+        p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
       }
     }
-#endif  /* Tagged queueing */
   }
-
-  if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
+  if ( (p->needwdtr & mask) &&
+      !(p->wdtr_pending & mask) &&
+      !(scb->tag_action))
   {
     p->wdtr_pending |= mask;
     hscb->control |= MK_MESSAGE;
-    scb->flags |= SCB_MSGOUT_WDTR;
-#if 0
-    printk("scsi%d: Sending WDTR request to target %d.\n",
-           p->host_no, cmd->target);
-#endif
+    if (p->needwdtr_copy & mask)
+      scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+    else
+      scb->flags |= SCB_MSGOUT_WDTR_8BIT;
   }
   else
   {
-    if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
+    if ( (p->needsdtr & mask) &&
+        !(p->sdtr_pending & mask) &&
+        !(p->wdtr_pending & mask) &&
+        !(scb->tag_action) )
     {
       p->sdtr_pending |= mask;
       hscb->control |= MK_MESSAGE;
       scb->flags |= SCB_MSGOUT_SDTR;
-#if 0
-      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
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
-	((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
 
   /*
    * The interpretation of request_buffer and request_bufflen
@@ -6253,8 +7937,6 @@
   /*
    * XXX - this relies on the host data being stored in a
    *       little-endian format.
-   *
-   * No longer is that an issue, I've "big-endian'ified" this driver. -DaveM
    */
   hscb->SCSI_cmd_length = cmd->cmd_len;
   hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
@@ -6272,46 +7954,42 @@
     int i;
 
     sg = (struct scatterlist *)cmd->request_buffer;
+    scb->sg_length = 0;
     for (i = 0; i < cmd->use_sg; i++)
     {
       scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
-      scb->sg_list[i].length = cpu_to_le32((unsigned int) sg[i].length);
+      scb->sg_list[i].length = cpu_to_le32(sg[i].length);
+      scb->sg_length += sg[i].length;
     }
     hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(scb->sg_list));
     hscb->SG_segment_count = cmd->use_sg;
-    scb->sg_count = hscb->SG_segment_count;
+    scb->sg_count = cmd->use_sg;
 
     /* 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 | cpu_to_le32(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), le32_to_cpu(hscb->data_count));
-#endif
+    hscb->data_count = scb->sg_list[0].length;
   }
   else
   {
-#if 0
-  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)
     {
-      hscb->SG_segment_count = 1;
       scb->sg_count = 1;
       scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
       scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+      scb->sg_length = cmd->request_bufflen;
+      hscb->SG_segment_count = 1;
       hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
-      hscb->data_count = scb->sg_list[0].length | cpu_to_le32(SCB_LIST_NULL << 24);
-      hscb->data_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+      hscb->data_count = scb->sg_list[0].length;
+      hscb->data_pointer = scb->sg_list[0].address;
     }
     else
     {
-      hscb->SG_segment_count = 0;
       scb->sg_count = 0;
+      scb->sg_length = 0;
+      hscb->SG_segment_count = 0;
       hscb->SG_list_pointer = 0;
+      hscb->data_count = 0;
       hscb->data_pointer = 0;
-      hscb->data_count = cpu_to_le32(SCB_LIST_NULL << 24);
     }
   }
 }
@@ -6326,58 +8004,53 @@
 int
 aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
-  long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+  int tindex = TARGET_INDEX(cmd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  if (p->host != cmd->host)
-  {
-    printk(KERN_INFO "scsi%d: Internal host structure != scsi.c host "
-      "structure.\n", p->host_no);
-  }
-
   /*
    * Check to see if channel was scanned.
    */
-  if (!(p->flags & A_SCANNED) && (cmd->channel == 0))
+  if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
   {
-    printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no);
-    p->flags |= A_SCANNED;
+    printk(INFO_LEAD "Scanning channel for devices.\n",
+      p->host_no, 0, -1, -1);
+    p->flags |= AHC_A_SCANNED;
   }
   else
   {
-    if (!(p->flags & B_SCANNED) && (cmd->channel == 1))
+    if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
     {
-      printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no);
-      p->flags |= B_SCANNED;
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 1, -1, -1);
+      p->flags |= AHC_B_SCANNED;
     }
   }
 
-#if 0
-  printk("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
-	cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
-	cmd->lun & 0x07);
-#endif
-
-  if (p->device_status[TARGET_INDEX(cmd)].active_cmds
-      > cmd->device->queue_depth)
+  if (p->dev_active_cmds[tindex] > cmd->device->queue_depth)
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
-           p->host_no, cmd->target, cmd->channel);
+    printk(WARN_LEAD "Commands queued exceeds queue "
+           "depth, active=%d\n",
+           p->host_no, CTL_OF_CMD(cmd), 
+           p->dev_active_cmds[tindex]);
+    if ( p->dev_active_cmds[tindex] > 220 )
+      p->dev_active_cmds[tindex] = 0;
   }
-  scb = aic7xxx_allocate_scb(p);
+  DRIVER_LOCK
+  scb = aic7xxx_allocate_scb(p, FALSE);
+  DRIVER_UNLOCK
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
+    panic("(scsi%d) aic7xxx_queue:Couldn't get a free SCB.\n", p->host_no);
   }
   else
   {
     scb->cmd = cmd;
     aic7xxx_position(cmd) = scb->hscb->tag;
-#if 0
-    debug_scb(scb);
-#endif;
 
     /*
      * Construct the SCB beforehand, so the sequencer is
@@ -6385,17 +8058,6 @@
      */
     aic7xxx_buildscb(p, cmd, scb);
 
-#if 0
-    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->hscb->tag, (unsigned int) scb->cmd,
-	   scb->flags, (unsigned int) p->free_scb);
-#endif
-
     /*
      * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
      * is set up properly, and the parity error flag is reset, then send
@@ -6410,19 +8072,20 @@
 
     scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    save_flags(processor_flags);
-    cli();
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
+    DRIVER_LOCK
+    if (p->delayed_scbs[tindex].head != NULL) 
+    {
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+    }
+    else
+    {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+    }
+    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
     {
       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->hscb->tag);
-#endif;
+    DRIVER_UNLOCK
   }
   return (0);
 }
@@ -6443,103 +8106,58 @@
 {
   struct aic7xxx_scb   *scb;
   struct aic7xxx_hwscb *hscb;
-  unsigned char bus_state;
   int result = -1;
-  char channel;
+  int channel;
+  unsigned char saved_scbptr, lastphase;
+  unsigned char hscb_index;
+  int disconnected;
 
   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 *) p, (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);
-
-  switch (bus_state)
+  lastphase = aic_inb(p, LASTPHASE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
   {
-    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(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
+         p->host_no, CTL_OF_SCB(scb), scb->flags);
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        printk("Data-Out phase\n");
+        break;
+      case P_DATAIN:
+        printk("Data-In phase\n");
+        break;
+      case P_COMMAND:
+        printk("Command phase\n");
+        break;
+      case P_MESGOUT:
+        printk("Message-Out phase\n");
+        break;
+      case P_STATUS:
+        printk("Status phase\n");
+        break;
+      case P_MESGIN:
+        printk("Message-In phase\n");
+        break;
+      default:
       /*
        * We're not in a valid phase, so assume we're idle.
        */
-      printk("while idle, LASTPHASE = 0x%x, ", bus_state);
-      break;
+        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
+        break;
+    }
+    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+         aic_inb(p, SCSISIGI),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
   }
-  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));
 
-  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)
-    {
-      /*
-       * We could be starving this command; try sending and ordered tag
-       * command to the target we come from.
-       */
-      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;
+  channel = cmd->channel;
 
     /*
-     * Send an Abort Message:
+     * Send a Device Reset 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
@@ -6550,154 +8168,155 @@
      * 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];
+  saved_scbptr = aic_inb(p, SCBPTR);
+  disconnected = FALSE;
 
-    if (bus_state != P_BUSFREE)
+  if (lastphase != P_BUSFREE)
+  {
+    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
     {
-      if (active_scb_index >= p->scb_data->numscbs)
-      {
-        /*
-         * 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);
-      }
-      else
-      {
-        /* 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)
-        {
-          /*
-           * 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.
-           */
-          result = SCSI_RESET_PENDING;
-          aic7xxx_error(active_scb->cmd) = DID_RESET;
-        }
-        else
-        {
-          aic7xxx_error(scb->cmd) = DID_RESET;
-          result = SCSI_RESET_PENDING;
-        }
-        unpause_sequencer(p, /* unpause_always */ TRUE);
-      }
+      printk(WARN_LEAD "Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no,
+            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
+      return(SCSI_RESET_ERROR);
     }
-    else
-    {
-      unsigned char hscb_index, linked_next;
-      int disconnected;
-
-      disconnected = FALSE;
-      hscb_index = aic7xxx_find_scb(p, scb);
-      if (hscb_index == SCB_LIST_NULL)
+    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
+    { 
+      if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
       {
-        disconnected = TRUE;
-        linked_next = (le32_to_cpu(scb->hscb->data_count) >> 24) & 0xFF;
+        /* Send the abort message to the active SCB. */
+        aic_outb(p, MSG_BUS_DEV_RESET, MSG_OUT);
+        aic_outb(p, lastphase | ATNO, SCSISIGO);
+        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+          printk(INFO_LEAD "Device reset message in "
+                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_PENDING);
       }
       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)
-      {
+        /* We want to send out the message, but it could screw an already */
+        /* in place and being used message.  Instead, we return an error  */
+        /* to try and start the bus reset phase since this command is     */
+        /* probably hung (aborts failed, and now reset is failing).  We   */
+        /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
+        /* any more on this device, but instead will escalate to a bus or */
+        /* host reset (additionally, we won't try to abort any more).     */
+        printk(WARN_LEAD "Device reset, Message buffer "
+                "in use\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_ERROR);
+      }
+    }
+  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
+  hscb_index = aic7xxx_find_scb(p, scb);
+  if (hscb_index == SCB_LIST_NULL)
+  {
+    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
+  }
+  else
+  {
+    aic_outb(p, hscb_index, SCBPTR);
+    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
+    {
+      disconnected = TRUE;
+    }
+  }
+  if (disconnected)
+  {
         /*
-         * Simply set the ABORT_SCB control bit and preserve the
-         * linked next pointer.
+         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+         * the rest on a reconnect.
          */
-        scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
-        scb->hscb->data_count &= cpu_to_le32(~0xFF000000);
-        scb->hscb->data_count |= cpu_to_le32(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;
-
-          scb_control = inb(p->base + SCB_CONTROL);
-          outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
-        }
+    scb->hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+        BUS_DEVICE_RESET_PENDING;
+    if (hscb_index != SCB_LIST_NULL)
+    {
+      unsigned char scb_control;
+
+      aic_outb(p, hscb_index, SCBPTR);
+      scb_control = aic_inb(p, SCB_CONTROL);
+      aic_outb(p, scb_control | MK_MESSAGE, 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.
+         * want to abort is not tagged, then this will be the only
+         * outstanding command and we can simply shove it on the
+         * qoutfifo and be done.  If it is tagged, then it goes right
+         * in with all the others, no problem :)  We need to add it
+         * to the qinfifo and let the sequencer know it is there.
+         * Now, the only problem left to deal with is, *IF* this
+         * command completes, in spite of the MK_MESSAGE bit in the
+         * control byte, then we need to pick that up in the interrupt
+         * routine and clean things up.  This *shouldn't* ever happen.
          */
-        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;
-      }
-    }
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Queueing device reset "
+           "command.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    scb->flags |= SCB_QUEUED_ABORT;
+    result = SCSI_RESET_PENDING;
   }
+  else if (result == -1)
+  {
+    result = SCSI_RESET_ERROR;
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
   return (result);
 }
 
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p)
+{
+  int i;
+
+  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if(p->dev_flags[i] & DEVICE_PRESENT)
+    {
+      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%s, SDTR:%s, q_depth=%d:%d\n",
+        p->host_no, 0, i, 0, p->dev_flags[i],
+        (p->needwdtr_copy & (1 << i)) ? "Yes" : "No",
+        (p->needsdtr_copy & (1 << i)) ? "Yes" : "No",
+        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+    }
+  }
+  printk("SIMODE0=0x%x, SIMODE1=0x%x, SSTAT0=0x%x, SSTAT1=0x%x, INTSTAT=0x%x\n",
+    aic_inb(p, SIMODE0), aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+    aic_inb(p, SSTAT1), aic_inb(p, INTSTAT) );
+  printk("p->flags=0x%x, p->type=0x%x, sequencer %s paused\n",
+     p->flags, p->type,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  panic("Stopping to debug\n");
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_abort
  *
  * Description:
@@ -6708,86 +8327,309 @@
 {
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
-  int    base, result;
-  unsigned long processor_flags;
+  int    result, found=0;
+  unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+  Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
 
-  save_flags(processor_flags);
-  cli();
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  if (scb != NULL)
+  DRIVER_LOCK
+
+/*
+ *  Run the isr to grab any command in the QOUTFIFO and any other misc.
+ *  assundry tasks.  This should also set up the bh handler if there is
+ *  anything to be done, but it won't run until we are done here since
+ *  we are following a straight code path without entering the scheduler
+ *  code.
+ */
+
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    aic7xxx_isr(p->irq, p, (void *)NULL);
+    pause_sequencer(p);
   }
-  else
+
+  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+                      /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range or doesn't even match it's own*/
+                      /*  timeout serial number.                        */
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
+  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
+                        /*  has already been recycled for another command   */
+                        /*  Either way, this SCB has nothing to do with this*/
+                        /*  command and we need to deal with cmd without    */
+                        /*  touching the SCB.                               */
+                        /*  The theory here is to return a value that will  */
+                        /*  make the queued for complete command actually   */
+                        /*  finish successfully, or to indicate that we     */
+                        /*  don't have this cmd any more and the mid level  */
+                        /*  code needs to find it.                          */
+    cmd_next = p->completeq.head;
+    cmd_prev = NULL;
+    while (cmd_next != NULL) 
+    {
+      if (cmd_next == cmd) 
+      {
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "Abort called for command "
+          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        if ( cmd_prev == NULL )
+          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+        else
+          cmd_prev->host_scribble = cmd_next->host_scribble;
+        cmd_next->done(cmd_next);
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+                                         * completion */
+      }                                  
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called for already completed"
+        " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+    
+/*   At this point we know the following:
+ *     the SCB pointer is valid
+ *     the command pointer passed in to us and the scb->cmd pointer match
+ *     this then means that the command we need to abort is the same as the
+ *     command held by the scb pointer and is a valid abort request.
+ *   Now, we just have to figure out what to do from here.  Current plan is:
+ *     if we have already been here on this command, escalate to a reset
+ *     if scb is on waiting list or QINFIFO, send it back as aborted
+ *     if scb is on WAITING_SCB list in sequencer, free scb and send back
+ *     if scb is disconnected and not completed, abort with abort message
+ *     if scb is currently running, then it may be causing the bus to hang
+ *       so we want a return value that indicates a reset would be appropriate
+ *       if the command does not finish shortly
+ *     if scb is already complete but not on completeq, we're screwed because
+ *       this can't happen (except if the command is in the QOUTFIFO, in which
+ *       case we would like it to complete successfully instead of having to
+ *       to be re-done)
+ *   All other scenarios already dealt with by previous code.
+ */
+
+  if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
   {
-    printk("aic7xxx: Abort called with no SCB for cmd.\n");
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB aborted once already, "
+        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_SNOOZE);
+  }
+  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
+          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
+           BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "Reset/Abort pending for this "
+        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_PENDING);
   }
-#endif
 
-  if (p->flags & IN_TIMEOUT)
+  found = 0;
+  p->flags |= AHC_IN_ABORT;
+  if (aic7xxx_verbose & VERBOSE_ABORT)
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+
+/*
+ *   First, let's check to see if the currently running command is our target
+ *    since if it is, the return is fairly easy and quick since we don't want
+ *    to touch the command in case it might complete, but we do want a timeout
+ *    in case it's actually hung, so we really do nothing, but tell the mid
+ *    level code to reset the timeout.
+ */
+
+  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
   {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
-    {
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_PENDING);
-    }
-    else
+   /*
+    *  Check to see if the sequencer is just sitting on this command, or
+    *   if it's actively being run.
+    */
+    result = aic_inb(p, LASTPHASE);
+    switch (result)
     {
-      /*
-       * 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);
+      case P_DATAOUT:    /*    For any of these cases, we can assume we are */
+      case P_DATAIN:     /*    an active command and act according.  For    */
+      case P_COMMAND:    /*    anything else we are going to fall on through*/
+      case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
+      case P_MESGOUT:    /*    chances to finish and then escalate to a     */
+      case P_MESGIN:     /*    reset call                                   */
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB is currently active.  "
+                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, FALSE);
+        p->flags &= ~AHC_IN_ABORT;
+        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
+        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
+        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
+        break;                          /*  out.                           */
+      default:
+        break;
     }
   }
-  if (cmd->serial_number != cmd->serial_number_at_timeout)
+
+  if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+      int tindex = TARGET_INDEX(cmd);
+     
+      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+        printk(INFO_LEAD "SCB found on waiting list and "
+            "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      scbq_remove(&p->waiting_scbs, scb);
+      scbq_remove(&p->delayed_scbs[tindex], scb);
+      p->dev_active_cmds[tindex]++;
+      p->activescbs++;
+      scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+      scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+      found = 1;
   }
-  else if (scb == NULL)
+
+/*
+ *  We just checked the waiting_q, now for the QINFIFO
+ */
+  if ( found == 0 )
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+    if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
+                     cmd->channel,
+                     cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                     FALSE, NULL)) != 0) &&
+                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "SCB found in QINFIFO and "
+        "aborted.\n", p->host_no, CTL_OF_SCB(scb));
   }
-  else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
+
+/*
+ *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
+ */
+
+  if ( found == 0 )
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+    unsigned char scb_next_ptr;
+    prev_hscbptr = SCB_LIST_NULL;
+    saved_hscbptr = aic_inb(p, SCBPTR);
+    next_hscbptr = aic_inb(p, WAITING_SCBH);
+    while ( next_hscbptr != SCB_LIST_NULL )
+    {
+      aic_outb(p,  next_hscbptr, SCBPTR );
+      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
+      {
+        found = 1;
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB found on hardware waiting"
+            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+        if ( prev_hscbptr == SCB_LIST_NULL )
+        {
+            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
+            aic_outb(p, 0, SCSISEQ);    /* stop the selection since we just
+                                         * grabbed the scb out from under the
+                                         * card */
+        }
+        else
+        {
+            scb_next_ptr = aic_inb(p, SCB_NEXT);
+            aic_outb(p, prev_hscbptr, SCBPTR);
+            aic_outb(p, scb_next_ptr, SCB_NEXT);
+            aic_outb(p, next_hscbptr, SCBPTR);
+        }
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        aic7xxx_add_curscb_to_free_list(p);
+        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+        break;
+      }
+      prev_hscbptr = next_hscbptr;
+      next_hscbptr = aic_inb(p, SCB_NEXT);
+    }
+    aic_outb(p,  saved_hscbptr, SCBPTR );
   }
-  else
+        
+/*
+ *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
+ *  OK...the sequencer's paused, interrupts are off, and we haven't found the
+ *  command anyplace where it could be easily aborted.  Time for the hard
+ *  work.  We also know the command is valid.  This essentially means the
+ *  command is disconnected, or connected but not into any phases yet, which
+ *  we know due to the tests we ran earlier on the current active scb phase.
+ *  At this point we can queue the abort tag and go on with life.
+ */
+
+  if ( found == 0 )
   {
-    /*
-     * 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;
-     }
+    p->flags |= AHC_ABORT_PENDING;
+    scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+    scb->hscb->control |= MK_MESSAGE;
+    result=aic7xxx_find_scb(p, scb);
+    if ( result != SCB_LIST_NULL ) 
+    {
+      saved_hscbptr = aic_inb(p, SCBPTR);
+      aic_outb(p, result, SCBPTR);
+      tmp_char = aic_inb(p, SCB_CONTROL);
+      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
+      aic_outb(p, saved_hscbptr, SCBPTR);
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
+        " SCB.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
   }
-  restore_flags(processor_flags);
-  return (result);
+  if (found)
+  {
+    aic7xxx_run_done_queue(p, TRUE);
+    aic7xxx_run_waiting_queues(p);
+  }
+  p->flags &= ~AHC_IN_ABORT;
+  unpause_sequencer(p, FALSE);
+  DRIVER_UNLOCK
+
+/*
+ *  On the return value.  If we found the command and aborted it, then we know
+ *  it's already sent back and there is no reason for a further timeout, so
+ *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
+ *  there hasn't been a bus hang or something that might keep the abort from
+ *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time this
+ *  is passed back, the timeout on the command gets extended, the second time
+ *  we pass this back, the mid level SCSI code calls our reset function, which
+ *  would shake loose a hung bus.
+ */
+  if ( found != 0 )
+    return(SCSI_ABORT_SUCCESS);
+  else
+    return(SCSI_ABORT_PENDING); 
 }
 
 
@@ -6806,190 +8648,259 @@
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
-  unsigned long base;
-  int    found, tindex, min_target, max_target;
+  int    tindex;
   int    result = -1;
-  char   channel = 'A';
-  unsigned long processor_flags;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+#define DEVICE_RESET 0x01
+#define BUS_RESET    0x02
+#define HOST_RESET   0x04
+#define FAIL         0x08
+#define RESET_DELAY  0x10
+  int        action;
+  Scsi_Cmnd *cmd_prev, *cmd_next;
+
+
+  if ( cmd == NULL )
+  {
+    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
+      "pointer, failing.\n");
+    return(SCSI_RESET_SNOOZE);
+  }
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
-  channel = cmd->channel ? 'B': 'A';
   tindex = TARGET_INDEX(cmd);
 
-#if 0   /* AIC7XXX_DEBUG_ABORT */
-  if (scb != NULL)
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
+  DRIVER_LOCK
+
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    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);
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
   }
-  else
+
+  if (scb == NULL)
   {
-    printk("aic7xxx: Reset called with no SCB for cmd.\n");
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+    {
+      action = HOST_RESET;
+    }
+    else
+    {
+      action = BUS_RESET;
+    }
   }
-#endif
-
-  /* 
-   * This routine is called by scsi.c, in which case the interrupts
-   * very well may be on when we are called.  As such, we need to save
-   * the flags to be sure, then turn interrupts off, and then call our
-   * various method funtions which all assume interrupts are off.
-   */
-  save_flags(processor_flags);
-  cli();
-
-  if (scb->cmd != cmd)
-    scb = NULL;
-
-  if (p->flags & IN_TIMEOUT)
+  else if (scb->cmd != cmd) 
   {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+    printk(INFO_LEAD "Reset called with recycled SCB "
+        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    cmd_prev = NULL;
+    cmd_next = p->completeq.head;
+    while ( cmd_next != NULL )
+    {
+      if (cmd_next == cmd)
+      {
+        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+          printk(INFO_LEAD "Reset, found cmd on completeq"
+          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_RESET_NOT_RUNNING);
+      }
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
+    {
+      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "Reset, cmd not found,"
+          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
+    }
+    else
     {
-      restore_flags(processor_flags);
-      return (SCSI_RESET_PENDING);
+      if (aic7xxx_verbose & VERBOSE_RESET_MID)
+        printk(INFO_LEAD "Reset called, no scb, "
+          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
+      scb = NULL;
+      action = HOST_RESET;
     }
   }
   else
   {
-    if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
-        && (scb != NULL))
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called, scb %d, flags "
+        "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
     {
-      /*
-       * 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 (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->flags & SCB_ABORTED)
-          {
-            result = SCSI_RESET_PENDING;
-          }
-          else if (!(scb->flags & SCB_ACTIVE))
-          {
-            result = SCSI_RESET_NOT_RUNNING;
-          }
-        }
-
-        if (result == -1)
-        {
-          if ((flags & SCSI_RESET_SYNCHRONOUS) &&
-              (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
-          {
-            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(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+          CTL_OF_SCB(scb));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
+    }
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+    {
+      action = HOST_RESET;
+    }
+    else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
+    {
+      action = BUS_RESET;
+    }
+    else 
+    {
+      action = DEVICE_RESET;
     }
   }
-  if (result == -1)
+  if ( (action & DEVICE_RESET) && 
+        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
   {
-    /*
-     * The bus device reset failed; try resetting the channel.
-     */
-    if (!(flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
-        && (flags & SCSI_RESET_ASYNCHRONOUS))
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Bus device reset already sent to "
+        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) &&
+       (scb->flags & SCB_QUEUED_ABORT) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
     {
-      if (scb == NULL)
-      {
-	result = SCSI_RESET_NOT_RUNNING;
-      }
-      else if (!(scb->flags & SCB_ACTIVE))
-      {
-	result = SCSI_RESET_NOT_RUNNING;
-      }
-      else if ((scb->flags & SCB_ABORTED) &&
-               (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
-      {
-	result = SCSI_RESET_PENDING;
-      }
+      printk(INFO_LEAD "Have already attempted to reach "
+        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "message, will escalate to bus "
+        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
     }
-
-    if (result == -1)
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) && 
+       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+     printk(INFO_LEAD "Bus device reset stupid when "
+        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & BUS_RESET) && !(p->type & AHC_TWIN) )
+  {
+    action = HOST_RESET;
+  }
+  if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+       !(action & (HOST_RESET | BUS_RESET)))
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
     {
-      /*
-       * The reset channel function assumes that the sequencer is paused.
-       */
-      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
-       * command, perform completion processing.
-       *
-       */
-      if ((flags & SCSI_RESET_SYNCHRONOUS) && (scb == NULL))
+      printk(INFO_LEAD "Reset called too soon after last "
+        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
+        CTL_OF_CMD(cmd));
+    }
+    action = BUS_RESET;
+  }
+  if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
+        (action & (HOST_RESET | BUS_RESET)) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Reset called too soon after "
+        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = RESET_DELAY;
+  }
+  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
+        && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
+  {
+    printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!!  Card must have left to go "
+        "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_SNOOZE);
+  }
+/*
+ *  By this point, we want to already know what we are going to do and
+ *  only have the following code implement our course of action.
+ */
+  switch (action)
+  {
+    case RESET_DELAY:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_PENDING);
+      break;
+    case FAIL:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_ERROR);
+      break;
+    case DEVICE_RESET:
+      p->flags |= AHC_IN_RESET;
+      result = aic7xxx_bus_device_reset(p, cmd);
+      aic7xxx_run_done_queue(p, TRUE);
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      p->flags &= ~AHC_IN_RESET;
+      DRIVER_UNLOCK
+      return(result);
+      break;
+    case BUS_RESET:
+    case HOST_RESET:
+    default:
+      p->reset_start = jiffies;
+      p->flags |= AHC_IN_RESET;
+      aic7xxx_reset_channel(p, cmd->channel, TRUE);
+      if ( (p->type & AHC_TWIN) && (action & HOST_RESET) )
       {
-	cmd->result = DID_RESET << 16;
-	cmd->scsi_done(cmd);
+        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
+        restart_sequencer(p);
       }
-
-      switch (p->bus_type)
+      if (scb == NULL)
       {
-	case AIC_TWIN:
-	  if (channel == 'B')
-	  {
-            min_target = 8;
-            max_target = 15;
-	  }
-	  else
-	  {
-            min_target = 0;
-            max_target = 7;
-	  }
-	  break;
-
-	case AIC_WIDE:
-	  min_target = 0;
-	  max_target = 15;
-	  break;
-
-	case AIC_SINGLE:
-        default:
-	  min_target = 0;
-	  max_target = 7;
-	  break;
+        cmd->result = DID_RESET << 16;
+        cmd->done(cmd);
       }
-
-      for (tindex = min_target; tindex <= max_target; tindex++)
+      p->last_reset = jiffies;
+      if (action != HOST_RESET)
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+      else
       {
-	p->device_status[tindex].last_reset = jiffies;
-      }
-
-      result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-      p->flags &= ~IN_TIMEOUT;
-    }
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
+          SIMODE1);
+        aic7xxx_clear_intstat(p);
+        p->flags &= ~AHC_HANDLING_REQINITS;
+        p->msg_type = MSG_TYPE_NONE;
+        p->msg_index = 0;
+        p->msg_len = 0;
+      }
+      p->flags &= ~AHC_IN_RESET;
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(result);
+      break;
   }
-  aic7xxx_run_waiting_queues(p);
-  restore_flags(processor_flags);
-  return (result);
 }
 
 /*+F*************************************************************************
@@ -7016,7 +8927,7 @@
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);
 
-  if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024))
+  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
   {
     heads = 255;
     sectors = 63;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h
--- v2.1.95/linux/drivers/scsi/aic7xxx.h	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/aic7xxx.h	Tue Apr 14 13:01:12 1998
@@ -23,40 +23,88 @@
 #ifndef _aic7xxx_h
 #define _aic7xxx_h
 
-#define AIC7XXX_H_VERSION  "$Revision: 3.2 $"
+#define AIC7XXX_H_VERSION  "3.2.4"
 
-#ifdef __i386__
-#define AIC7XXX_BIOSPARAM	aic7xxx_biosparam
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if defined(__i386__)
+#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
 #else
-#define AIC7XXX_BIOSPARAM	NULL
+#  define AIC7XXX_BIOSPARAM NULL
 #endif
 
 /*
  * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
  * to do with card config are filled in after the card is detected.
  */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+#define AIC7XXX	{						\
+	next: NULL,						\
+	module: NULL,						\
+	proc_dir: NULL,						\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: NULL,						\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	eh_strategy_handler: NULL,				\
+	eh_abort_handler: NULL,					\
+	eh_device_reset_handler: NULL,				\
+	eh_bus_reset_handler: NULL,				\
+	eh_host_reset_handler: NULL,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING,			\
+	use_new_eh_code: 0					\
+}
+#else
 #define AIC7XXX	{						\
-	proc_info:       aic7xxx_proc_info,					\
-	detect:          aic7xxx_detect,					\
-	info:            aic7xxx_info,						\
-	queuecommand:    aic7xxx_queue,						\
-	abort:           aic7xxx_abort,						\
-	reset:           aic7xxx_reset,						\
-	bios_param:      AIC7XXX_BIOSPARAM,					\
-	can_queue:       -1,			/* max simultaneous cmds      */\
-	this_id:         -1,			/* scsi id of host adapter    */\
-	sg_tablesize:    SG_ALL,		/* max scatter-gather cmds    */\
-	cmd_per_lun:     2,			/* cmds per lun (linked cmds) */\
-	use_clustering:  ENABLE_CLUSTERING,					\
-	use_new_eh_code: 0			/* Enable new error code */	\
+	next: NULL,						\
+	usage_count: NULL,					\
+	proc_dir: NULL, 					\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: NULL,						\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING			\
 }
+#endif
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 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 int aic7xxx_abort(Scsi_Cmnd *);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
 
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.1.95/linux/drivers/scsi/aic7xxx_proc.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/aic7xxx_proc.c	Sat Apr 11 11:19:34 1998
@@ -53,9 +53,6 @@
 
 static int aic7xxx_buffer_size = 0;
 static char *aic7xxx_buffer = NULL;
-static const char *bus_names[] = { "Single", "Twin", "Wide" };
-static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
-   "AIC-787x", "AIC-788x" };
 
 
 /*+F*************************************************************************
@@ -87,13 +84,14 @@
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
   int    size = 0;
+  unsigned char i;
 #ifdef AIC7XXX_PROC_STATS
   struct aic7xxx_xferstats *sp;
   unsigned char target, lun;
-  int i;
 #endif
 
   HBAptr = NULL;
+
   for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
     ;
 
@@ -109,6 +107,7 @@
       return (length);
     }
   }
+
   HBAptr = p->host;
 
   if (inout == TRUE) /* Has data been written to the file? */ 
@@ -124,16 +123,20 @@
    * if proc_stats is defined, then we sweep the stats structure to see
    * how many drives we will be printing out for and add 384 bytes per
    * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
    */
 
-  size = 1536;
+  size = 4096;
 #ifdef AIC7XXX_PROC_STATS
   for (target = 0; target < MAX_TARGETS; target++)
   {
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
       if (p->stats[target][lun].xfers != 0)
-        size += 384;
+        size += 512;
     }
   }
 #endif
@@ -156,29 +159,20 @@
 
   size = 0;
   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));
-#if 0
-  size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
 #ifdef AIC7XXX_RESET_DELAY
   size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
 #endif
-#ifdef AIC7XXX_CMDS_PER_LUN
-  size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
-#endif
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Disabled\n");
-#endif
-#ifdef AIC7XXX_PAGE_ENABLE
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Disabled\n");
-#endif
+  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
+  size += sprintf(BLS, "                             Check below to see "
+                       "which\n"
+                       "                             devices use tagged "
+                       "queueing\n");
+  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled (This is no longer "
+                       "an option)\n");
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
 #else
@@ -187,17 +181,54 @@
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
-      board_names[p->chip_type]);
-  size += sprintf(BLS, "                         (%s chipset)\n",
-      chip_names[p->chip_class]);
-  size += sprintf(BLS, "               Host Bus: %s\n", bus_names[p->bus_type]);
-  size += sprintf(BLS, "                Base IO: 0x%lx\n", p->base);
-  size += sprintf(BLS, "         Base IO Memory: 0x%lx\n", p->mbase);
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel\n");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->type & AHC_WIDE)
+      wide = "Wide ";
+    if (p->type & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s\n",
+      ultra, wide, channel);
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( !(p->type & AHC_AIC78x0) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+    size += sprintf(BLS, "                         %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
+  else
+  {
+    size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
   size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
-  size += sprintf(BLS, "                   SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  size += sprintf(BLS, "             Interrupts: %d", p->isr_count);
-  if (p->chip_class == AIC_777x)
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->type & AHC_AIC7770)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
@@ -206,16 +237,39 @@
   {
     size += sprintf(BLS, "\n");
   }
-  size += sprintf(BLS, "          Serial EEPROM: %s\n",
-      (p->flags & HAVE_SEEPROM) ? "True" : "False");
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
   size += sprintf(BLS, "   Extended Translation: %sabled\n",
-      (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis");
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
   size += sprintf(BLS, "         SCSI Bus Reset: %sabled\n",
       aic7xxx_no_reset ? "Dis" : "En");
-  size += sprintf(BLS, "             Ultra SCSI: %sabled\n",
-      (p->flags & ULTRA_ENABLED) ? "En" : "Dis");
-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable);
-  
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->type & AHC_ULTRA)
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+#ifdef AIC7XXX_CMDS_PER_LUN
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
+#else
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
+#endif
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Statistics:\n");
@@ -228,15 +282,15 @@
       {
         continue;
       }
-      if (p->bus_type == AIC_TWIN)
+      if (p->type & AHC_TWIN)
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A' + (target >> 3), (target & 0x7), lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, (target >> 3), (target & 0x7), lun);
       }
       else
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A', target, lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, 0, target, lun);
       }
       size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
           sp->xfers, sp->r_total, sp->w_total);
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.1.95/linux/drivers/scsi/aic7xxx_reg.h	Tue Dec  2 20:41:21 1997
+++ linux/drivers/scsi/aic7xxx_reg.h	Sat Apr 11 11:19:34 1998
@@ -30,13 +30,6 @@
 #define		ACTNEGEN        	0x02
 #define		STPWEN          	0x01
 
-#define	SCSISIGI        		0x03
-#define		ATNI            	0x10
-#define		SELI            	0x08
-#define		BSYI            	0x04
-#define		REQI            	0x02
-#define		ACKI            	0x01
-
 #define	SCSISIGO        		0x03
 #define		CDO             	0x80
 #define		IOO             	0x40
@@ -47,6 +40,13 @@
 #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
@@ -147,6 +147,16 @@
 #define		SELID_MASK      	0xf0
 #define		ONEBIT          	0x08
 
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		HAS_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
 #define	BRDCTL          		0x1d
 #define		BRDDAT7         	0x80
 #define		BRDDAT6         	0x40
@@ -181,11 +191,9 @@
 
 #define	DISC_DSB        		0x32
 
-#define	MSG_LEN         		0x34
-
-#define	MSG_OUT         		0x35
+#define	MSG_OUT         		0x34
 
-#define	DMAPARAMS       		0x3d
+#define	DMAPARAMS       		0x35
 #define		WIDEODD         	0x40
 #define		SCSIEN          	0x20
 #define		SDMAENACK       	0x10
@@ -196,36 +204,21 @@
 #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	SEQ_FLAGS       		0x36
+#define		IDENTIFY_SEEN   	0x80
+#define		SCBPTR_VALID    	0x20
 #define		DPHASE          	0x10
-#define		PAGESCBS        	0x04
+#define		AMTARGET        	0x08
 #define		WIDE_BUS        	0x02
 #define		TWIN_BUS        	0x01
 
-#define	SAVED_TCL       		0x42
-
-#define	SG_COUNT        		0x43
+#define	SAVED_TCL       		0x37
 
-#define	SG_NEXT         		0x44
+#define	SG_COUNT        		0x38
 
-#define	WAITING_SCBH    		0x48
+#define	SG_NEXT         		0x39
 
-#define	SAVED_LINKPTR   		0x49
-
-#define	SAVED_SCBPTR    		0x4a
-
-#define	REJBYTE         		0x4b
-
-#define	LASTPHASE       		0x4c
+#define	LASTPHASE       		0x3d
 #define		P_MESGIN        	0xe0
 #define		PHASE_MASK      	0xe0
 #define		P_STATUS        	0xc0
@@ -238,40 +231,46 @@
 #define		P_BUSFREE       	0x01
 #define		P_DATAOUT       	0x00
 
-#define	MSGIN_EXT_LEN   		0x4d
+#define	WAITING_SCBH    		0x3e
+
+#define	DISCONNECTED_SCBH		0x3f
 
-#define	MSGIN_EXT_OPCODE		0x4e
+#define	FREE_SCBH       		0x40
 
-#define	MSGIN_EXT_BYTES 		0x4f
+#define	HSCB_ADDR       		0x41
 
-#define	DISCONNECTED_SCBH		0x52
+#define	SCBID_ADDR      		0x45
 
-#define	FREE_SCBH       		0x53
+#define	TMODE_CMDADDR   		0x49
 
-#define	HSCB_ADDR       		0x54
+#define	KERNEL_QINPOS   		0x4d
 
-#define	CUR_SCBID       		0x58
+#define	QINPOS          		0x4e
 
-#define	ARG_1           		0x59
-#define	RETURN_1        		0x59
+#define	QOUTPOS         		0x4f
+
+#define	TMODE_CMDADDR_NEXT		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
 #define		SEND_MSG        	0x80
 #define		SEND_SENSE      	0x40
 #define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
 
-#define	SCSICONF        		0x5a
-
-#define	CMDOUTCNT       		0x5a
+#define	LAST_MSG        		0x52
 
-#define	SCSICONF2       		0x5b
+#define	SCSICONF        		0x5a
+#define		TERM_ENB        	0x80
 #define		RESET_SCSI      	0x40
-
-#define	FIFODEPTH       		0x5b
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
 
 #define	HOSTCONF        		0x5d
 
 #define	HA_274_BIOSCTRL 		0x5f
-#define		BIOSDISABLED    	0x30
 #define		BIOSMODE        	0x30
+#define		BIOSDISABLED    	0x30
 #define		CHANNEL_B_PRIMARY	0x08
 
 #define	SEQCTL          		0x60
@@ -315,16 +314,16 @@
 
 #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	BCTL            		0x84
-#define		ACE             	0x08
-#define		ENABLE          	0x01
-
 #define	BUSTIME         		0x85
 #define		BOFF            	0xf0
 #define		BON             	0x0f
@@ -356,13 +355,13 @@
 #define		SEQINT_MASK     	0xf1
 #define		DATA_OVERRUN    	0xe1
 #define		MSGIN_PHASEMIS  	0xd1
-#define		MSG_BUFFER_BUSY 	0xc1
+#define		TRACEPOINT2     	0xc1
+#define		TRACEPOINT      	0xb1
 #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		ABORT_REQUESTED 	0x51
 #define		EXTENDED_MSG    	0x41
 #define		NO_MATCH        	0x31
 #define		NO_IDENT        	0x21
@@ -374,18 +373,22 @@
 #define		BAD_PHASE       	0x01
 #define		SEQINT          	0x01
 
-#define	ERROR           		0x92
-#define		PARERR          	0x08
-#define		ILLOPCODE       	0x04
-#define		ILLSADDR        	0x02
-#define		ILLHADDR        	0x01
-
 #define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
 #define		CLRBRKADRINT    	0x08
 #define		CLRSCSIINT      	0x04
 #define		CLRCMDINT       	0x02
 #define		CLRSEQINT       	0x01
 
+#define	ERROR           		0x92
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
 #define	DFCNTRL         		0x93
 
 #define	DFSTATUS        		0x94
@@ -410,17 +413,15 @@
 
 #define	QOUTCNT         		0x9e
 
-#define	SCB_BASE        		0xa0
-
 #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
@@ -440,8 +441,6 @@
 
 #define	SCB_DATACNT     		0xb0
 
-#define	SCB_LINKED_NEXT 		0xb3
-
 #define	SCB_CMDPTR      		0xb4
 
 #define	SCB_CMDLEN      		0xb8
@@ -466,10 +465,24 @@
 #define		DI_2840         	0x01
 
 
-#define	MAX_OFFSET_16BIT	0x08
+#define	CMD_GROUP_CODE_SHIFT	0x05
 #define	BUS_8_BIT	0x00
+#define	QOUTFIFO_OFFSET	0x01
+#define	CMD_GROUP2_BYTE_DELTA	0xfa
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_16_BIT	0x01
+#define	QINFIFO_OFFSET	0x02
+#define	CMD_GROUP5_BYTE_DELTA	0x0b
+#define	MAX_OFFSET_16BIT	0x08
+#define	UNTAGGEDSCB_OFFSET	0x00
 #define	SCB_LIST_NULL	0xff
 #define	SG_SIZEOF	0x08
-#define	MAX_OFFSET_8BIT	0x0f
+#define	CMD_GROUP4_BYTE_DELTA	0x04
+#define	CMD_GROUP0_BYTE_DELTA	0xfc
+#define	HOST_MSG	0xff
 #define	BUS_32_BIT	0x02
-#define	BUS_16_BIT	0x01
+
+
+/* Downloaded Constant Definitions */
+#define	TMODE_NUMCMDS	0x01
+#define	QCNTMASK	0x00
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/aic7xxx_seq.h linux/drivers/scsi/aic7xxx_seq.h
--- v2.1.95/linux/drivers/scsi/aic7xxx_seq.h	Tue Dec  2 20:41:21 1997
+++ linux/drivers/scsi/aic7xxx_seq.h	Sat Apr 11 11:19:34 1998
@@ -1,54 +1,39 @@
 /*
   * DO NOT EDIT - This file is automatically generated.
   */
-static u_int8_t seqprog[] = {
+static unsigned char seqprog[] = {
 	0xff, 0x6a, 0x03, 0x02,
+	0x32, 0x6a, 0x00, 0x00,
 	0x12, 0x6a, 0x00, 0x00,
-	0x00, 0x65, 0x6f, 0x16,
-	0x40, 0x0b, 0x3c, 0x1a,
-	0x20, 0x0b, 0x37, 0x1a,
-	0x40, 0x00, 0x03, 0x1a,
+	0x00, 0x65, 0x92, 0x16,
+	0xf7, 0x01, 0x01, 0x02,
+	0xff, 0x4e, 0x64, 0x02,
+	0xbf, 0x60, 0x60, 0x02,
+	0x60, 0x0b, 0x37, 0x1a,
+	0x40, 0x00, 0x05, 0x1a,
 	0x08, 0x1f, 0x1f, 0x04,
-	0x40, 0x0b, 0x3c, 0x1a,
-	0x20, 0x0b, 0x37, 0x1a,
-	0x40, 0x00, 0x03, 0x1a,
+	0x60, 0x0b, 0x37, 0x1a,
+	0x40, 0x00, 0x05, 0x1a,
 	0x08, 0x1f, 0x1f, 0x04,
-	0xff, 0x48, 0x2c, 0x18,
-	0xff, 0x40, 0x64, 0x02,
-	0x00, 0x9c, 0x03, 0x1e,
-	0x00, 0x6a, 0xad, 0x17,
-	0xff, 0x65, 0x03, 0x1c,
-	0xff, 0x9b, 0x58, 0x02,
-	0xff, 0x58, 0x90, 0x02,
-	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0x58, 0x77, 0x17,
-	0x28, 0xa0, 0x2a, 0x1a,
-	0x50, 0x6a, 0x60, 0x00,
-	0xff, 0x90, 0x4a, 0x02,
-	0x00, 0xa1, 0xa1, 0x17,
-	0xff, 0x6c, 0x59, 0x02,
-	0xff, 0x59, 0x27, 0x1c,
-	0xff, 0x4a, 0x90, 0x02,
-	0x00, 0x65, 0xaa, 0x17,
-	0x00, 0x6a, 0x52, 0x17,
-	0xff, 0x65, 0x1f, 0x18,
-	0x51, 0x6a, 0x91, 0x00,
-	0xff, 0x58, 0xb3, 0x02,
-	0x00, 0x65, 0xbb, 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,
+	0xff, 0x3e, 0x1d, 0x18,
+	0x40, 0x60, 0x60, 0x00,
+	0x00, 0x4d, 0x06, 0x1c,
+	0x01, 0x4e, 0x4e, 0x06,
+	0xbf, 0x60, 0x60, 0x02,
+	0x00, 0x6a, 0xd8, 0x17,
+	0xff, 0x4e, 0x64, 0x06,
+	0x02, 0x6a, 0x93, 0x17,
+	0x0d, 0x6a, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0xff, 0x99, 0x65, 0x02,
+	0xff, 0x65, 0x90, 0x02,
+	0x0d, 0x6a, 0x35, 0x00,
+	0x00, 0x65, 0xb3, 0x17,
+	0xff, 0x3e, 0xba, 0x02,
+	0xff, 0x90, 0x3e, 0x02,
+	0xff, 0x3e, 0x90, 0x02,
+	0x00, 0x65, 0x20, 0x16,
+	0x00, 0x65, 0x05, 0x10,
 	0xf7, 0x1f, 0x65, 0x02,
 	0x08, 0xa1, 0x64, 0x02,
 	0x00, 0x65, 0x65, 0x00,
@@ -57,316 +42,381 @@
 	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,
+	0x12, 0x65, 0x64, 0x00,
+	0x00, 0x01, 0x01, 0x00,
 	0x31, 0x6a, 0x65, 0x00,
-	0x80, 0x42, 0x52, 0x1a,
+	0x80, 0x37, 0x2d, 0x1a,
 	0xff, 0x65, 0x65, 0x06,
-	0xff, 0x42, 0x6e, 0x02,
+	0xff, 0x37, 0x6e, 0x02,
 	0xff, 0x6e, 0x64, 0x02,
-	0x00, 0x6c, 0x56, 0x1e,
+	0x00, 0x6c, 0x31, 0x1e,
 	0x20, 0x01, 0x01, 0x00,
-	0x4c, 0x42, 0x64, 0x0a,
-	0x08, 0x1f, 0x5a, 0x1e,
-	0x08, 0x42, 0x42, 0x00,
+	0x4c, 0x37, 0x64, 0x0a,
+	0x08, 0x1f, 0x35, 0x1e,
+	0x08, 0x37, 0x37, 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,
+	0xff, 0x6c, 0x04, 0x03,
+	0x40, 0x0b, 0x78, 0x1a,
+	0x80, 0x0b, 0x71, 0x1e,
+	0xa4, 0x6a, 0x03, 0x00,
+	0x40, 0x6a, 0x0b, 0x00,
+	0x10, 0x03, 0x6f, 0x1e,
+	0xff, 0x50, 0x64, 0x02,
+	0x49, 0x6a, 0xa9, 0x17,
+	0x01, 0x6a, 0x93, 0x00,
+	0xff, 0x6a, 0x65, 0x02,
+	0x08, 0x01, 0x01, 0x00,
+	0x02, 0x0b, 0x41, 0x1e,
+	0xf7, 0x01, 0x01, 0x02,
+	0xff, 0x06, 0x66, 0x02,
+	0xff, 0x66, 0x99, 0x02,
+	0x01, 0x65, 0x65, 0x06,
+	0x80, 0x66, 0x48, 0x1e,
+	0xff, 0x66, 0x51, 0x02,
+	0x10, 0x03, 0x40, 0x1a,
+	0xfc, 0x65, 0x64, 0x06,
+	0x00, 0x65, 0x4c, 0x12,
+	0xff, 0x6a, 0x99, 0x00,
+	0x01, 0x64, 0x8c, 0x06,
+	0x84, 0x6a, 0x03, 0x00,
+	0x08, 0x01, 0x01, 0x00,
+	0x02, 0x0b, 0x4f, 0x1e,
+	0xff, 0x06, 0x64, 0x02,
+	0xff, 0x64, 0x99, 0x02,
+	0xff, 0x6a, 0x65, 0x02,
+	0x5b, 0x64, 0x64, 0x0a,
+	0x00, 0x62, 0x62, 0x06,
+	0xfc, 0x65, 0x65, 0x06,
+	0xff, 0x6a, 0x6a, 0x02,
+	0xfa, 0x65, 0x65, 0x06,
+	0xff, 0x6a, 0x6a, 0x02,
+	0x04, 0x65, 0x65, 0x06,
+	0x0b, 0x65, 0x65, 0x06,
+	0xff, 0x65, 0x64, 0x02,
+	0x00, 0x8c, 0x8c, 0x06,
+	0x02, 0x0b, 0x5d, 0x1e,
+	0x01, 0x65, 0x60, 0x18,
+	0xf7, 0x01, 0x01, 0x02,
+	0xff, 0x06, 0x99, 0x02,
+	0xff, 0x65, 0x65, 0x06,
+	0xff, 0x65, 0x5d, 0x1a,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0x40, 0x51, 0x69, 0x1e,
+	0xe4, 0x6a, 0x03, 0x00,
+	0x08, 0x01, 0x01, 0x00,
+	0x04, 0x6a, 0x5c, 0x17,
+	0x01, 0x50, 0x50, 0x06,
+	0x01, 0x50, 0x6c, 0x98,
+	0xff, 0x6a, 0x50, 0x02,
+	0xff, 0x6a, 0x9d, 0x00,
+	0x02, 0x6a, 0x91, 0x00,
+	0x40, 0x51, 0x6f, 0x1a,
+	0xff, 0x6a, 0x03, 0x02,
+	0x00, 0x65, 0x05, 0x10,
+	0x20, 0x6a, 0x0b, 0x00,
+	0xf0, 0x19, 0x37, 0x02,
+	0x08, 0x6a, 0x0c, 0x00,
+	0x08, 0x11, 0x11, 0x00,
+	0x08, 0x6a, 0x28, 0x16,
+	0x08, 0x6a, 0x34, 0x00,
+	0x00, 0x65, 0x82, 0x10,
+	0x12, 0x6a, 0x00, 0x00,
+	0x40, 0x6a, 0x0b, 0x00,
+	0xff, 0x3e, 0x90, 0x02,
+	0xff, 0xba, 0x3e, 0x02,
+	0xff, 0xa1, 0x37, 0x02,
+	0x08, 0x6a, 0x0c, 0x00,
+	0x08, 0x11, 0x11, 0x00,
+	0x08, 0x6a, 0x28, 0x16,
+	0x80, 0x6a, 0x34, 0x00,
+	0x80, 0x36, 0x36, 0x00,
+	0x00, 0x65, 0x9b, 0x17,
+	0xff, 0x3d, 0x64, 0x02,
+	0xbf, 0x64, 0x9a, 0x1e,
+	0x80, 0x64, 0xc9, 0x1c,
+	0xa0, 0x64, 0xd4, 0x1c,
+	0xc0, 0x64, 0xd1, 0x1c,
+	0xe0, 0x64, 0xf5, 0x1c,
 	0x01, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
+	0x00, 0x65, 0x82, 0x10,
 	0xf7, 0x11, 0x11, 0x02,
-	0x00, 0x65, 0x6f, 0x16,
+	0x00, 0x65, 0x92, 0x16,
 	0xff, 0x06, 0x6a, 0x02,
-	0x09, 0x0c, 0x6c, 0x1e,
-	0x08, 0x0c, 0x03, 0x1a,
+	0xf7, 0x01, 0x01, 0x02,
+	0x09, 0x0c, 0x8f, 0x1e,
+	0x08, 0x0c, 0x05, 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,
+	0x01, 0x6a, 0x3d, 0x00,
+	0x03, 0x36, 0x36, 0x03,
 	0x08, 0x6a, 0x66, 0x00,
-	0xa9, 0x6a, 0x74, 0x17,
-	0x00, 0x65, 0x82, 0x10,
-	0x79, 0x6a, 0x3d, 0x00,
-	0x00, 0x65, 0x4f, 0x17,
-	0x10, 0x41, 0x76, 0x1a,
+	0xa9, 0x6a, 0xa6, 0x17,
+	0x00, 0x65, 0xa5, 0x10,
+	0x79, 0x6a, 0x35, 0x00,
+	0x40, 0x3d, 0x9d, 0x1a,
+	0x04, 0x35, 0x35, 0x00,
+	0x00, 0x65, 0x6c, 0x17,
+	0x10, 0x36, 0x97, 0x1a,
 	0x88, 0x6a, 0x66, 0x00,
-	0xac, 0x6a, 0x70, 0x17,
-	0x00, 0x65, 0x6d, 0x17,
-	0xff, 0xa3, 0x43, 0x02,
-	0x44, 0x6a, 0x66, 0x00,
-	0xa4, 0x6a, 0x73, 0x17,
-	0xff, 0x43, 0x88, 0x1a,
+	0xac, 0x6a, 0xa2, 0x17,
+	0x00, 0x65, 0x9f, 0x17,
+	0xff, 0xa3, 0x38, 0x02,
+	0x39, 0x6a, 0x66, 0x00,
+	0xa4, 0x6a, 0xa5, 0x17,
+	0xff, 0x38, 0xac, 0x1a,
 	0x80, 0x02, 0x02, 0x00,
 	0xff, 0x6a, 0x8c, 0x00,
 	0xff, 0x6a, 0x8d, 0x00,
 	0xff, 0x6a, 0x8e, 0x00,
-	0x00, 0x65, 0x6d, 0x17,
-	0x01, 0x43, 0x8a, 0x18,
-	0xbf, 0x3d, 0x3d, 0x02,
-	0x00, 0x3d, 0x44, 0x17,
-	0x80, 0x02, 0xa2, 0x1a,
-	0xff, 0x65, 0x9c, 0x1e,
-	0xff, 0x43, 0x43, 0x06,
-	0xff, 0x43, 0x9c, 0x1e,
+	0x00, 0x65, 0x9f, 0x17,
+	0xe7, 0x35, 0x35, 0x02,
+	0x01, 0x38, 0xae, 0x18,
+	0xbf, 0x35, 0x35, 0x02,
+	0x00, 0x35, 0x61, 0x17,
+	0x80, 0x02, 0xc6, 0x1a,
+	0xff, 0x65, 0xc0, 0x1e,
+	0xff, 0x38, 0x38, 0x06,
+	0xff, 0x38, 0xc0, 0x1e,
 	0xff, 0x6a, 0x64, 0x02,
-	0x08, 0x44, 0x44, 0x06,
-	0x00, 0x45, 0x45, 0x08,
+	0x08, 0x39, 0x39, 0x06,
+	0x00, 0x3a, 0x3a, 0x08,
 	0x88, 0x6a, 0x66, 0x00,
-	0x44, 0x6a, 0x73, 0x17,
+	0x39, 0x6a, 0xa5, 0x17,
 	0x08, 0x6a, 0x8c, 0x00,
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
 	0x0d, 0x93, 0x93, 0x00,
-	0x00, 0x65, 0x9d, 0x17,
-	0x88, 0x6a, 0x95, 0x17,
-	0x00, 0x65, 0x6d, 0x17,
-	0x10, 0x0c, 0x82, 0x1e,
+	0x00, 0x65, 0xd1, 0x17,
+	0x88, 0x6a, 0xc9, 0x17,
+	0x00, 0x65, 0x9f, 0x17,
+	0x10, 0x0c, 0xa5, 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,
+	0xff, 0x38, 0xa8, 0x02,
+	0x10, 0x36, 0x36, 0x00,
+	0x00, 0x65, 0x82, 0x10,
 	0x7f, 0x02, 0x02, 0x02,
 	0xe1, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
-	0x00, 0x65, 0x4f, 0x17,
+	0x00, 0x65, 0x82, 0x10,
+	0x00, 0x65, 0x6c, 0x17,
 	0x88, 0x6a, 0x66, 0x00,
-	0xb4, 0x6a, 0x72, 0x17,
+	0xb4, 0x6a, 0xa4, 0x17,
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
-	0x00, 0x65, 0x6d, 0x17,
-	0x3d, 0x6a, 0x44, 0x17,
-	0x00, 0x65, 0x5c, 0x10,
-	0x00, 0x65, 0x4f, 0x17,
+	0x00, 0x65, 0x9f, 0x17,
+	0x3d, 0x6a, 0x61, 0x17,
+	0x00, 0x65, 0x82, 0x10,
+	0x00, 0x65, 0x6c, 0x17,
 	0xff, 0x06, 0xa2, 0x02,
-	0x00, 0x65, 0x5c, 0x10,
-	0xff, 0x34, 0xb2, 0x1a,
-	0x08, 0x6a, 0x32, 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,
+	0x00, 0x65, 0x82, 0x10,
+	0xff, 0x34, 0x65, 0x02,
+	0x80, 0x65, 0xe6, 0x18,
+	0x0f, 0xa1, 0x65, 0x02,
+	0x07, 0xa1, 0x65, 0x02,
+	0x40, 0xa0, 0x64, 0x02,
+	0x00, 0x65, 0x65, 0x00,
+	0x80, 0x65, 0x65, 0x00,
+	0x80, 0xa0, 0xde, 0x1e,
+	0xff, 0x65, 0x06, 0x02,
+	0x00, 0x65, 0xe7, 0x10,
+	0x20, 0xa0, 0xe9, 0x1e,
+	0xff, 0x65, 0x06, 0x02,
+	0x00, 0x65, 0x9b, 0x17,
+	0xa0, 0x3d, 0xef, 0x18,
+	0x23, 0xa0, 0x06, 0x02,
+	0x00, 0x65, 0x9b, 0x17,
+	0xa0, 0x3d, 0xef, 0x18,
+	0x00, 0xb9, 0xe9, 0x10,
+	0xff, 0x65, 0xe9, 0x18,
+	0xa1, 0x6a, 0x91, 0x00,
+	0x10, 0x51, 0xef, 0x1c,
 	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x66, 0x66, 0x06,
-	0xff, 0x6c, 0x06, 0x02,
-	0x00, 0x65, 0xb4, 0x10,
+	0xff, 0x65, 0x06, 0x02,
+	0x00, 0x65, 0x9b, 0x17,
+	0xa0, 0x3d, 0xef, 0x18,
+	0x10, 0x3d, 0x03, 0x00,
+	0x00, 0x65, 0xd4, 0x10,
 	0x40, 0x6a, 0x0c, 0x00,
-	0xff, 0x6a, 0x34, 0x02,
-	0x00, 0x65, 0x5c, 0x10,
-	0x64, 0x6a, 0x3f, 0x17,
-	0xff, 0x64, 0x4b, 0x02,
-	0x80, 0x64, 0x0e, 0x1b,
-	0x04, 0x64, 0x01, 0x1d,
-	0x02, 0x64, 0x04, 0x1d,
-	0x00, 0x6a, 0xd1, 0x1c,
-	0x03, 0x64, 0x0c, 0x1d,
-	0x01, 0x64, 0xf5, 0x1c,
-	0x07, 0x64, 0x30, 0x1d,
-	0x08, 0x64, 0xcf, 0x1c,
+	0xff, 0x34, 0x52, 0x02,
+	0x80, 0x34, 0xf3, 0x18,
+	0x7f, 0xa0, 0xa0, 0x02,
+	0x08, 0x6a, 0x34, 0x00,
+	0x00, 0x65, 0x82, 0x10,
+	0x64, 0x6a, 0x59, 0x17,
+	0x80, 0x64, 0x2f, 0x1b,
+	0x04, 0x64, 0x22, 0x1d,
+	0x02, 0x64, 0x25, 0x1d,
+	0x00, 0x6a, 0x02, 0x1d,
+	0x03, 0x64, 0x2d, 0x1d,
+	0x01, 0x64, 0x20, 0x1d,
+	0x07, 0x64, 0x50, 0x1d,
+	0x08, 0x64, 0x00, 0x1d,
 	0x11, 0x6a, 0x91, 0x00,
-	0x07, 0x6a, 0x32, 0x17,
+	0x07, 0x6a, 0x52, 0x17,
 	0xff, 0x06, 0x6a, 0x02,
-	0x00, 0x65, 0x5c, 0x10,
-	0xff, 0xa8, 0xd3, 0x1a,
-	0xff, 0xa2, 0xda, 0x1e,
-	0x01, 0x6a, 0x3d, 0x00,
-	0x00, 0xb9, 0x77, 0x17,
-	0xff, 0xa2, 0xda, 0x1e,
+	0x00, 0x65, 0x82, 0x10,
+	0xff, 0xa8, 0x04, 0x1b,
+	0xff, 0xa2, 0x0f, 0x1f,
+	0x01, 0x6a, 0x35, 0x00,
+	0x00, 0xb9, 0xb3, 0x17,
+	0xff, 0xa2, 0x0f, 0x1f,
 	0x71, 0x6a, 0x91, 0x00,
-	0x40, 0x59, 0xda, 0x18,
-	0xff, 0xb9, 0xb3, 0x02,
-	0x00, 0x65, 0xe7, 0x10,
-	0x20, 0xa0, 0xe0, 0x1a,
-	0xff, 0x90, 0x4a, 0x02,
-	0xff, 0xb3, 0x49, 0x02,
-	0x00, 0xa1, 0xa1, 0x17,
-	0xff, 0x49, 0x6d, 0x02,
-	0xff, 0x4a, 0x90, 0x02,
-	0xff, 0x5b, 0x64, 0x02,
-	0x00, 0x5a, 0xe1, 0x1c,
-	0x01, 0x5a, 0x5a, 0x06,
-	0xff, 0xb9, 0x9d, 0x02,
+	0x40, 0x51, 0x0f, 0x19,
+	0x0d, 0x6a, 0x35, 0x00,
+	0x00, 0xb9, 0xb3, 0x17,
+	0xff, 0x3e, 0xba, 0x02,
+	0xff, 0x90, 0x3e, 0x02,
+	0x00, 0x65, 0x20, 0x16,
+	0x00, 0x65, 0x8b, 0x10,
+	0x20, 0xa0, 0x16, 0x1b,
+	0xff, 0x37, 0x64, 0x02,
+	0x00, 0x6a, 0x93, 0x17,
+	0x01, 0x6a, 0x93, 0x00,
+	0xff, 0x6a, 0x99, 0x00,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0xff, 0x4f, 0x64, 0x02,
+	0x01, 0x6a, 0x93, 0x17,
+	0x01, 0x6a, 0x93, 0x00,
+	0xff, 0xb9, 0x99, 0x02,
+	0x0a, 0x93, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0x01, 0x4f, 0x4f, 0x06,
 	0x02, 0x6a, 0x91, 0x00,
-	0x08, 0xa0, 0xe7, 0x1e,
-	0x91, 0x6a, 0x91, 0x00,
-	0xff, 0xb3, 0xf3, 0x1c,
-	0xff, 0xb3, 0x64, 0x02,
-	0x00, 0xb9, 0xed, 0x1c,
-	0x00, 0x65, 0xaa, 0x17,
-	0xff, 0x64, 0x90, 0x02,
-	0x00, 0x65, 0xef, 0x10,
-	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0xb3, 0x77, 0x17,
-	0xff, 0x48, 0xba, 0x02,
-	0xff, 0x90, 0x48, 0x02,
-	0x00, 0x65, 0x2f, 0x16,
-	0x00, 0x65, 0x69, 0x10,
-	0x00, 0x65, 0xaa, 0x17,
-	0x00, 0x65, 0x69, 0x10,
-	0x4d, 0x6a, 0x3a, 0x17,
-	0xff, 0x4d, 0x64, 0x02,
-	0x00, 0x66, 0x3a, 0x17,
-	0xff, 0x64, 0x64, 0x06,
-	0x52, 0x66, 0xfb, 0x18,
-	0xff, 0x66, 0x66, 0x06,
-	0xff, 0x64, 0xf7, 0x1a,
+	0x00, 0x65, 0xd5, 0x17,
+	0x00, 0x65, 0x8b, 0x10,
 	0x41, 0x6a, 0x91, 0x00,
-	0x20, 0x59, 0xcd, 0x1c,
-	0x80, 0x59, 0xcf, 0x18,
-	0x10, 0x4c, 0x03, 0x00,
-	0x00, 0x65, 0xcf, 0x10,
+	0x00, 0x65, 0x82, 0x10,
 	0x04, 0xa0, 0xa0, 0x00,
-	0x00, 0x65, 0xbb, 0x17,
-	0x00, 0x65, 0x69, 0x10,
-	0x10, 0x41, 0xcf, 0x1e,
-	0xff, 0x43, 0xa3, 0x02,
+	0x00, 0x65, 0xe1, 0x17,
+	0x00, 0x65, 0x8b, 0x10,
+	0x10, 0x36, 0x00, 0x1f,
+	0xff, 0x38, 0xa3, 0x02,
 	0xa4, 0x6a, 0x66, 0x00,
-	0x44, 0x6a, 0x73, 0x17,
+	0x39, 0x6a, 0xa5, 0x17,
 	0xac, 0x6a, 0x66, 0x00,
-	0x14, 0x6a, 0x73, 0x17,
-	0xa9, 0x6a, 0x74, 0x17,
-	0x00, 0x65, 0xcf, 0x10,
-	0xef, 0x41, 0x41, 0x02,
-	0x00, 0x65, 0xcf, 0x10,
-	0x78, 0x64, 0xcd, 0x1a,
+	0x14, 0x6a, 0xa5, 0x17,
+	0xa9, 0x6a, 0xa6, 0x17,
+	0x00, 0x65, 0x00, 0x11,
+	0xef, 0x36, 0x36, 0x02,
+	0x00, 0x65, 0x00, 0x11,
+	0x0f, 0x64, 0x64, 0x02,
 	0x07, 0x64, 0x64, 0x02,
-	0x00, 0x42, 0x42, 0x00,
-	0x00, 0x42, 0xa1, 0x17,
-	0xff, 0x6c, 0x59, 0x02,
-	0xff, 0x59, 0x28, 0x19,
-	0xff, 0x59, 0x18, 0x1d,
-	0xff, 0x59, 0x90, 0x02,
-	0x04, 0xa0, 0x2d, 0x1f,
-	0x00, 0x65, 0x2a, 0x11,
+	0x00, 0x37, 0x37, 0x00,
+	0x00, 0x65, 0x8b, 0x17,
+	0xff, 0x51, 0x37, 0x1d,
+	0x20, 0x36, 0x3f, 0x1f,
+	0x00, 0x90, 0x7d, 0x17,
+	0x00, 0x65, 0x40, 0x11,
 	0xff, 0x06, 0x6a, 0x02,
-	0x01, 0x0c, 0x19, 0x1f,
-	0x04, 0x0c, 0x19, 0x1b,
-	0xe0, 0x03, 0x4c, 0x02,
-	0xe0, 0x4c, 0x2d, 0x19,
-	0x20, 0x12, 0x2d, 0x19,
-	0x20, 0x41, 0x41, 0x00,
-	0x59, 0x6a, 0x3a, 0x17,
-	0xff, 0x3f, 0x64, 0x02,
-	0x00, 0x59, 0x65, 0x06,
-	0x00, 0x65, 0x2d, 0x13,
-	0xff, 0x59, 0x90, 0x02,
-	0xff, 0x42, 0x64, 0x02,
-	0x00, 0xa1, 0x2d, 0x19,
-	0x20, 0xa0, 0x2d, 0x1f,
-	0x04, 0xa0, 0x2d, 0x1f,
-	0x00, 0x6a, 0x52, 0x17,
-	0xff, 0x65, 0x2d, 0x1d,
+	0x00, 0x65, 0x9b, 0x17,
+	0xe0, 0x3d, 0x4d, 0x19,
+	0x20, 0x12, 0x4d, 0x19,
+	0x51, 0x6a, 0x54, 0x17,
+	0xff, 0x51, 0x90, 0x02,
+	0x20, 0xa0, 0x4d, 0x1f,
+	0x00, 0x90, 0x7d, 0x17,
+	0x00, 0x65, 0x7a, 0x17,
+	0xff, 0x37, 0x64, 0x02,
+	0x00, 0xa1, 0x49, 0x19,
+	0x04, 0xa0, 0x49, 0x1f,
 	0xfb, 0xa0, 0xa0, 0x02,
-	0x40, 0x41, 0x41, 0x00,
-	0x00, 0x65, 0xcf, 0x10,
+	0x80, 0x36, 0x36, 0x00,
+	0x80, 0xa0, 0x00, 0x1f,
+	0x7f, 0xa0, 0xa0, 0x02,
+	0xff, 0x6a, 0x52, 0x17,
+	0x00, 0x65, 0x00, 0x11,
+	0x04, 0xa0, 0x4c, 0x1f,
+	0x00, 0x65, 0xe1, 0x17,
+	0x00, 0x65, 0x4d, 0x11,
+	0x00, 0x65, 0xd5, 0x17,
 	0x31, 0x6a, 0x91, 0x00,
-	0x0c, 0x6a, 0x32, 0x17,
-	0x00, 0x65, 0xcf, 0x10,
+	0x0c, 0x6a, 0x52, 0x17,
+	0x00, 0x65, 0x00, 0x11,
 	0x61, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0xcf, 0x10,
-	0x50, 0x6a, 0x60, 0x00,
-	0xff, 0x34, 0x36, 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,
+	0x00, 0x65, 0x00, 0x11,
+	0x10, 0x3d, 0x03, 0x00,
+	0xff, 0x65, 0x34, 0x03,
 	0xff, 0x06, 0x6a, 0x02,
-	0x01, 0x0c, 0x3b, 0x1f,
-	0x04, 0x0c, 0x3b, 0x1b,
-	0xe0, 0x03, 0x4c, 0x02,
-	0xe0, 0x4c, 0x42, 0x19,
+	0x01, 0x0c, 0x55, 0x1f,
+	0x04, 0x0c, 0x55, 0x1b,
+	0xe0, 0x03, 0x3d, 0x02,
+	0xe0, 0x3d, 0x5f, 0x19,
 	0xff, 0x65, 0x66, 0x02,
 	0xff, 0x12, 0x6d, 0x03,
 	0xff, 0x06, 0x6a, 0x03,
+	0xff, 0x65, 0x06, 0x02,
+	0x02, 0x0b, 0x5d, 0x1f,
+	0xff, 0x6a, 0x6a, 0x03,
 	0xd1, 0x6a, 0x91, 0x00,
-	0x00, 0x65, 0x5c, 0x10,
+	0x00, 0x65, 0x82, 0x10,
 	0xff, 0x65, 0x93, 0x02,
-	0x01, 0x0b, 0x4c, 0x1b,
-	0x10, 0x0c, 0x45, 0x1f,
-	0x04, 0x0b, 0x49, 0x1b,
+	0x01, 0x0b, 0x69, 0x1b,
+	0x10, 0x0c, 0x62, 0x1f,
+	0x04, 0x0b, 0x66, 0x1b,
 	0xff, 0x6a, 0x65, 0x02,
-	0x04, 0x93, 0x4b, 0x1b,
-	0x01, 0x94, 0x4a, 0x1f,
-	0x10, 0x94, 0x4b, 0x1b,
+	0x04, 0x93, 0x68, 0x1b,
+	0x01, 0x94, 0x67, 0x1f,
+	0x10, 0x94, 0x68, 0x1b,
 	0xc7, 0x93, 0x93, 0x02,
-	0x38, 0x93, 0x4d, 0x1b,
+	0x38, 0x93, 0x6a, 0x1b,
 	0xff, 0x6a, 0x6a, 0x03,
-	0x80, 0x41, 0x4e, 0x1f,
-	0x40, 0x41, 0x4e, 0x1b,
+	0x80, 0x36, 0x6b, 0x1b,
 	0x21, 0x6a, 0x91, 0x01,
 	0xff, 0x65, 0x90, 0x02,
-	0xff, 0x59, 0x64, 0x02,
-	0x00, 0xb9, 0x56, 0x19,
-	0x04, 0xa0, 0x60, 0x1b,
-	0x01, 0x65, 0x65, 0x06,
-	0xff, 0x3e, 0x64, 0x02,
-	0x00, 0x65, 0x52, 0x19,
-	0x00, 0x6a, 0xad, 0x17,
-	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0x59, 0x77, 0x17,
-	0xff, 0xa8, 0x5e, 0x1f,
-	0x10, 0xa0, 0xa0, 0x00,
-	0x08, 0xa0, 0x4e, 0x1f,
+	0xff, 0x51, 0x72, 0x19,
+	0xff, 0x37, 0x64, 0x02,
+	0xa1, 0x6a, 0x77, 0x11,
+	0xff, 0x51, 0x64, 0x02,
+	0xb9, 0x6a, 0x77, 0x11,
+	0xff, 0xba, 0x79, 0x1d,
+	0xff, 0xba, 0x90, 0x02,
+	0xff, 0x65, 0x65, 0x06,
+	0x00, 0x6c, 0x74, 0x19,
+	0xff, 0x90, 0x65, 0x03,
 	0xff, 0x6a, 0x65, 0x01,
-	0x08, 0xa0, 0x5f, 0x1b,
-	0xff, 0xba, 0x66, 0x1d,
-	0xff, 0xbb, 0x49, 0x02,
+	0x20, 0x36, 0x88, 0x1f,
+	0x00, 0x90, 0x6e, 0x17,
+	0xff, 0x65, 0x88, 0x1d,
+	0xff, 0xba, 0x82, 0x1d,
+	0xff, 0xbb, 0x66, 0x02,
 	0xff, 0xba, 0x90, 0x02,
-	0xff, 0x49, 0xbb, 0x02,
+	0xff, 0x66, 0xbb, 0x02,
 	0xff, 0x65, 0x90, 0x02,
-	0xff, 0xbb, 0x6b, 0x1d,
-	0xff, 0xba, 0x49, 0x02,
+	0xff, 0xbb, 0x87, 0x1d,
+	0xff, 0xba, 0x66, 0x02,
 	0xff, 0xbb, 0x90, 0x02,
-	0xff, 0x49, 0xba, 0x02,
+	0xff, 0x66, 0xba, 0x02,
 	0xff, 0x65, 0x90, 0x03,
-	0xff, 0xba, 0x52, 0x03,
-	0xff, 0x6a, 0x6a, 0x03,
+	0xff, 0xba, 0x3f, 0x03,
+	0x00, 0x6a, 0xd8, 0x17,
+	0x0d, 0x6a, 0x35, 0x00,
+	0x00, 0x51, 0xb3, 0x11,
+	0xff, 0x3f, 0x96, 0x1d,
+	0xff, 0x6a, 0x51, 0x00,
+	0x00, 0x3f, 0x6e, 0x17,
+	0xff, 0x65, 0x96, 0x1d,
+	0x20, 0x36, 0x36, 0x00,
+	0x20, 0xa0, 0x92, 0x1b,
+	0xff, 0xb9, 0x51, 0x03,
+	0xff, 0x6a, 0x51, 0x01,
+	0xff, 0x65, 0x66, 0x02,
+	0x45, 0x6a, 0xab, 0x17,
+	0x01, 0x6a, 0x8c, 0x01,
+	0xff, 0x37, 0x64, 0x02,
+	0x00, 0x6a, 0x93, 0x17,
+	0x0d, 0x6a, 0x93, 0x00,
+	0x00, 0x65, 0xd1, 0x17,
+	0xff, 0x99, 0x51, 0x03,
+	0x01, 0x0c, 0x9b, 0x1f,
+	0x04, 0x0c, 0x9b, 0x1b,
+	0xe0, 0x03, 0x3d, 0x02,
+	0xff, 0x3d, 0x03, 0x03,
 	0xff, 0x8c, 0x08, 0x02,
 	0xff, 0x8d, 0x09, 0x02,
 	0xff, 0x8e, 0x0a, 0x03,
@@ -377,19 +427,21 @@
 	0xff, 0x6c, 0x6d, 0x02,
 	0xff, 0x6c, 0x6d, 0x02,
 	0xff, 0x6c, 0x6d, 0x03,
-	0x3d, 0x65, 0x66, 0x0a,
-	0x55, 0x65, 0x64, 0x0a,
-	0x00, 0x54, 0x88, 0x06,
+	0x3d, 0x64, 0x66, 0x0a,
+	0x55, 0x64, 0x64, 0x0a,
+	0x00, 0x6c, 0x88, 0x06,
 	0xff, 0x66, 0x64, 0x02,
-	0x00, 0x55, 0x89, 0x08,
+	0x00, 0x6c, 0x89, 0x08,
 	0xff, 0x6a, 0x64, 0x02,
-	0x00, 0x56, 0x8a, 0x08,
-	0x00, 0x57, 0x8b, 0x08,
-	0x1c, 0x6a, 0x8c, 0x00,
+	0x00, 0x6c, 0x8a, 0x08,
+	0x00, 0x6c, 0x8b, 0x08,
 	0xff, 0x6a, 0x8d, 0x02,
-	0xff, 0x6a, 0x8e, 0x02,
-	0xff, 0x3d, 0x93, 0x02,
-	0x04, 0x3d, 0x8f, 0x1b,
+	0xff, 0x6a, 0x8e, 0x03,
+	0xff, 0x65, 0x64, 0x02,
+	0x41, 0x6a, 0xa9, 0x17,
+	0x1c, 0x6a, 0x8c, 0x00,
+	0xff, 0x35, 0x93, 0x02,
+	0x04, 0x35, 0xc3, 0x1b,
 	0xa0, 0x6a, 0x65, 0x00,
 	0x1c, 0x65, 0x64, 0x06,
 	0xff, 0x6c, 0x99, 0x02,
@@ -399,14 +451,14 @@
 	0xff, 0x6c, 0x99, 0x02,
 	0xff, 0x6c, 0x99, 0x02,
 	0xff, 0x6c, 0x99, 0x02,
-	0x00, 0x65, 0x86, 0x19,
+	0x00, 0x65, 0xba, 0x19,
 	0x0a, 0x93, 0x93, 0x00,
-	0x00, 0x65, 0x9d, 0x17,
-	0x04, 0x3d, 0x4e, 0x1f,
-	0xa0, 0x6a, 0x95, 0x17,
-	0x00, 0x65, 0x96, 0x17,
-	0x00, 0x65, 0x96, 0x17,
-	0x00, 0x65, 0x96, 0x11,
+	0x00, 0x65, 0xd1, 0x17,
+	0x04, 0x35, 0x6b, 0x1f,
+	0xa0, 0x6a, 0xc9, 0x17,
+	0x00, 0x65, 0xca, 0x17,
+	0x00, 0x65, 0xca, 0x17,
+	0x00, 0x65, 0xca, 0x11,
 	0xff, 0x65, 0x66, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
@@ -415,69 +467,58 @@
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x03,
-	0x08, 0x94, 0x9d, 0x1f,
+	0x08, 0x94, 0xd1, 0x1f,
 	0xf7, 0x93, 0x93, 0x02,
-	0x08, 0x93, 0x9f, 0x1b,
+	0x08, 0x93, 0xd3, 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, 0xa8, 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, 0xb9, 0x19,
-	0xff, 0x52, 0xb0, 0x19,
+	0xff, 0x40, 0xba, 0x02,
+	0xff, 0x90, 0x40, 0x02,
+	0xff, 0x6a, 0xb9, 0x01,
+	0xff, 0x40, 0xdf, 0x19,
+	0xff, 0x3f, 0xdb, 0x19,
 	0xff, 0x6a, 0x65, 0x01,
-	0xff, 0x52, 0x90, 0x02,
-	0x10, 0xa0, 0xb4, 0x1f,
-	0xef, 0xa0, 0xa0, 0x02,
-	0x00, 0x65, 0xb6, 0x11,
-	0xff, 0xa8, 0xb6, 0x1b,
-	0xff, 0xb3, 0xb8, 0x1d,
-	0x01, 0x6a, 0x3d, 0x00,
-	0x00, 0xb9, 0x77, 0x17,
-	0x00, 0x90, 0x61, 0x11,
-	0xff, 0x53, 0x90, 0x02,
-	0xff, 0xba, 0x53, 0x03,
+	0xff, 0x3f, 0x90, 0x02,
+	0x01, 0x6a, 0x35, 0x00,
+	0x00, 0xb9, 0xb3, 0x17,
+	0x00, 0x90, 0x7d, 0x11,
+	0xff, 0x40, 0x90, 0x02,
+	0xff, 0xba, 0x40, 0x03,
 	0xff, 0x6a, 0xbb, 0x00,
-	0xff, 0x52, 0xba, 0x02,
-	0xff, 0x90, 0x52, 0x02,
-	0xff, 0xba, 0x4e, 0x1d,
+	0xff, 0x3f, 0xba, 0x02,
+	0xff, 0x90, 0x3f, 0x02,
+	0xff, 0xba, 0x6b, 0x1d,
 	0xff, 0xba, 0x90, 0x02,
-	0xff, 0x52, 0xbb, 0x02,
-	0xff, 0x52, 0x90, 0x03,
+	0xff, 0x3f, 0xbb, 0x02,
+	0xff, 0x3f, 0x90, 0x03,
 };
-#define	ULTRA           	0x8
-#define	SCB_PAGING      	0x4
-#define	TWIN_CHANNEL    	0x2
+#define	WIDE            	0x20
+#define	ULTRA           	0x10
+#define	SCB_PAGING      	0x8
+#define	TWIN_CHANNEL    	0x4
+#define	TARGET_MODE     	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, 0, 0x0e0, 0x0e3 },
-	{ 0x00000004, 1, 0x0e8, 0x0ed },
-	{ 0x00000004, 0, 0x102, 0x103 },
-	{ 0x00000004, 0, 0x113, 0x114 },
-	{ 0x00000004, 1, 0x114, 0x118 },
-	{ 0x00000004, 1, 0x123, 0x128 },
-	{ 0x00000004, 0, 0x128, 0x12a },
-	{ 0x00000004, 0, 0x152, 0x16c },
-	{ 0x00000004, 1, 0x16c, 0x16d },
-	{ 0x00000004, 0, 0x1ad, 0x1c2 },
+	{ 0x00000002, 0, 0x001, 0x002 },
+	{ 0x00000002, 1, 0x002, 0x003 },
+	{ 0x00000004, 0, 0x009, 0x00d },
+	{ 0x00000008, 0, 0x012, 0x013 },
+	{ 0x00000008, 1, 0x018, 0x019 },
+	{ 0x00000004, 0, 0x020, 0x024 },
+	{ 0x00000010, 0, 0x02a, 0x031 },
+	{ 0x00000002, 0, 0x038, 0x071 },
+	{ 0x00000020, 0, 0x0d6, 0x0d7 },
+	{ 0x00000020, 1, 0x0d7, 0x0d8 },
+	{ 0x00000020, 0, 0x12f, 0x130 },
+	{ 0x00000020, 1, 0x130, 0x131 },
+	{ 0x00000008, 0, 0x134, 0x135 },
+	{ 0x00000008, 1, 0x13c, 0x13f },
+	{ 0x00000008, 0, 0x13f, 0x140 },
+	{ 0x00000002, 0, 0x15c, 0x15f },
+	{ 0x00000008, 0, 0x1d5, 0x1d7 },
+	{ 0x00000008, 0, 0x1d8, 0x1e1 },
 	{ 0x00000000, 0, 0x000, 0x000 }
 };
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c
--- v2.1.95/linux/drivers/scsi/dtc.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/dtc.c	Sat Apr 11 11:13:25 1998
@@ -263,7 +263,7 @@
 /* With interrupts enabled, it will sometimes hang when doing heavy
  * reads. So better not enable them until I finger it out. */
       if (instance->irq != IRQ_NONE)
-	 if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc")) {
+	 if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) {
 	 printk("scsi%d : IRQ%d not free, interrupts disabled\n",
 	      instance->host_no, instance->irq);
 	 instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/dtc.h linux/drivers/scsi/dtc.h
--- v2.1.95/linux/drivers/scsi/dtc.h	Sun Dec 21 17:04:48 1997
+++ linux/drivers/scsi/dtc.h	Sat Apr 11 11:13:25 1998
@@ -112,6 +112,7 @@
 #endif
 
 #define NCR5380_intr dtc_intr
+#define do_NCR5380_intr do_dtc_intr
 #define NCR5380_queue_command dtc_queue_command
 #define NCR5380_abort dtc_abort
 #define NCR5380_reset dtc_reset
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.1.95/linux/drivers/scsi/eata.c	Fri Apr 10 13:03:49 1998
+++ linux/drivers/scsi/eata.c	Sat Apr 11 11:16:31 1998
@@ -316,6 +316,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/spinlock.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -599,7 +600,7 @@
 #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)
 #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)
 
-static void interrupt_handler(int, void *, struct pt_regs *);
+static void do_interrupt_handler(int, void *, struct pt_regs *);
 static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
@@ -872,7 +873,7 @@
       }
 
    /* Board detected, allocate its IRQ */
-   if (request_irq(irq, interrupt_handler,
+   if (request_irq(irq, do_interrupt_handler,
              SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
              driver_name, (void *) &sha[j])) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
@@ -1935,7 +1936,7 @@
    return;
 }
 
-static void interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
+static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) {
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,95)
 
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.1.95/linux/drivers/scsi/eata_dma.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/eata_dma.c	Sat Apr 11 11:13:25 1998
@@ -81,6 +81,7 @@
 #include <asm/pgtable.h>
 #ifdef __mips__
 #include <asm/cachectl.h>
+#include <asm/spinlock.h>
 #endif
 #include <linux/blk.h>
 #include "scsi.h"
@@ -240,6 +241,16 @@
     } 
 }
 
+void eata_int_handler(int, void *, struct pt_regs *);
+
+void do_eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    eata_int_handler(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
@@ -1535,7 +1546,7 @@
     for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we     */
 	if (reg_IRQ[i] >= 1){       /* exchange the interrupt handler which  */
 	    free_irq(i, NULL);      /* we used for probing with the real one */
-	    request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
+	    request_irq(i, (void *)(do_eata_int_handler), SA_INTERRUPT|SA_SHIRQ, 
 			"eata_dma", NULL);
 	}
     }
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.1.95/linux/drivers/scsi/eata_pio.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/eata_pio.c	Sat Apr 11 11:13:25 1998
@@ -56,6 +56,8 @@
 
 #include <linux/stat.h>
 #include <linux/config.h>	/* for CONFIG_PCI */
+#include <linux/blk.h>
+#include <asm/spinlock.h>
 
 struct proc_dir_entry proc_scsi_eata_pio = {
     PROC_SCSI_EATA_PIO, 9, "eata_pio",
@@ -109,6 +111,17 @@
     }
 }
 
+void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs);
+
+void do_eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    eata_pio_int_handler(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
     uint eata_stat = 0xfffff;
@@ -697,7 +710,7 @@
     }
     
     if (!reg_IRQ[gc->IRQ]) {    /* Interrupt already registered ? */
-	if (!request_irq(gc->IRQ, eata_pio_int_handler, SA_INTERRUPT, 
+	if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, 
 			 "EATA-PIO", NULL)){
 	    reg_IRQ[gc->IRQ]++;
 	    if (!gc->IRQ_TR)
@@ -983,7 +996,7 @@
     
     for (i = 0; i <= MAXIRQ; i++)
 	if (reg_IRQ[i])
-	    request_irq(i, eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+	    request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
     
     HBA_ptr = first_HBA;
   
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.1.95/linux/drivers/scsi/esp.c	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/esp.c	Sat Apr 11 11:13:25 1998
@@ -37,6 +37,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/idprom.h>
+#include <asm/spinlock.h>
 
 #define DEBUG_ESP
 /* #define DEBUG_ESP_HME */
@@ -172,6 +173,7 @@
 
 /* Forward declarations. */
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+static void do_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
 
 /* Debugging routines */
 struct esp_cmdstrings {
@@ -799,7 +801,7 @@
 					goto esp_irq_acquired; /* BASIC rulez */
 				}
 			}
-			if(request_irq(esp->ehost->irq, esp_intr, SA_SHIRQ,
+			if(request_irq(esp->ehost->irq, do_esp_intr, SA_SHIRQ,
 				       "Sparc ESP SCSI", NULL))
 				panic("Cannot acquire ESP irq line");
 esp_irq_acquired:
@@ -812,7 +814,7 @@
 			dcookie.imap = dcookie.iclr = 0;
 			dcookie.pil = -1;
 			dcookie.bus_cookie = sbus;
-			if(request_irq(esp->ehost->irq, esp_intr,
+			if(request_irq(esp->ehost->irq, do_esp_intr,
 				       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
 				       "Sparc ESP SCSI", &dcookie))
 				panic("Cannot acquire ESP irq line");
@@ -4036,6 +4038,15 @@
 
 esp_handle_done:
 	return;
+}
+
+static void do_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	esp_intr(irq, dev_id, pregs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 #ifndef __sparc_v9__
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v2.1.95/linux/drivers/scsi/fdomain.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/fdomain.c	Sat Apr 11 11:13:25 1998
@@ -264,6 +264,7 @@
 #include "hosts.h"
 #include "fdomain.h"
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
@@ -948,7 +949,7 @@
       /* Register the IRQ with the kernel */
 
       retcode = request_irq( interrupt_level,
-			     fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);
+			     do_fdomain_16x0_intr, SA_INTERRUPT, "fdomain", NULL);
 
       if (retcode < 0) {
 	 if (retcode == -EINVAL) {
@@ -1608,6 +1609,15 @@
    in_interrupt_flag = 0;
 #endif
    return;
+}
+
+void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(&io_request_lock, flags);
+   fdomain_16x0_intr(irq, dev_id, regs);
+   spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.1.95/linux/drivers/scsi/g_NCR5380.c	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/g_NCR5380.c	Sat Apr 11 11:13:25 1998
@@ -251,7 +251,7 @@
 	    instance->irq = NCR5380_probe_irq(instance, 0xffff);
 
 	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
+	    if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) {
 		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h
--- v2.1.95/linux/drivers/scsi/g_NCR5380.h	Mon Jan  5 00:23:39 1998
+++ linux/drivers/scsi/g_NCR5380.h	Sat Apr 11 11:13:25 1998
@@ -155,6 +155,7 @@
     NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
 
 #define NCR5380_intr generic_NCR5380_intr
+#define do_NCR5380_intr do_generic_NCR5380_intr
 #define NCR5380_queue_command generic_NCR5380_queue_command
 #define NCR5380_abort generic_NCR5380_abort
 #define NCR5380_reset generic_NCR5380_reset
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.1.95/linux/drivers/scsi/gdth.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/gdth.c	Sat Apr 11 11:13:25 1998
@@ -102,6 +102,7 @@
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/spinlock.h>
 
 #if LINUX_VERSION_CODE >= 0x010300
 #include <linux/blk.h>
@@ -116,6 +117,7 @@
 
 #if LINUX_VERSION_CODE >= 0x010346
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+static void do_gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
 #else
 static void gdth_interrupt(int irq,struct pt_regs *regs);
 #endif
@@ -2155,6 +2157,15 @@
 /* SCSI interface functions */
 
 #if LINUX_VERSION_CODE >= 0x010346
+static void do_gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    gdth_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
 #else
 static void gdth_interrupt(int irq,struct pt_regs *regs)
@@ -2759,7 +2770,7 @@
             save_flags(flags);
             cli();
 #if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
 #endif
@@ -2868,7 +2879,7 @@
             save_flags(flags);
             cli();
 #if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
 #endif
@@ -2974,7 +2985,7 @@
             save_flags(flags);
             cli();
 #if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+            if (request_irq(ha->irq,do_gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
 #else
             if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
 #endif
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c
--- v2.1.95/linux/drivers/scsi/gvp11.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/scsi/gvp11.c	Sat Apr 11 11:13:25 1998
@@ -12,6 +12,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -51,6 +52,15 @@
     }
 }
 
+static void do_gvp11_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    gvp11_intr(irq, dummy, fp);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static int gvp11_xfer_mask = 0;
 
 void gvp11_setup (char *str, int *ints)
@@ -361,7 +371,7 @@
 	if (num_gvp11++ == 0) {
 		first_instance = instance;
 		gvp11_template = instance->hostt;
-		request_irq(IRQ_AMIGA_PORTS, gvp11_intr, 0,
+		request_irq(IRQ_AMIGA_PORTS, do_gvp11_intr, 0,
 			    "GVP11 SCSI", gvp11_intr);
 	}
 	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.1.95/linux/drivers/scsi/hosts.h	Wed Apr  1 20:11:52 1998
+++ linux/drivers/scsi/hosts.h	Tue Apr 14 13:01:12 1998
@@ -108,6 +108,11 @@
     const char *(* info)(struct Scsi_Host *);
 
     /*
+     * ioctl interface
+     */
+    int (*ioctl)(Scsi_Device *dev, int cmd, void *arg);
+
+    /*
      * The command function takes a target, a command (this is a SCSI
      * command formatted as per the SCSI spec, nothing strange), a
      * data buffer pointer, and data buffer length pointer.  The return
@@ -263,6 +268,11 @@
      * to use the new error handling code.
      */
     unsigned use_new_eh_code:1;
+
+    /*
+     * True for emulated SCSI host adapters (e.g. ATAPI)
+     */
+    unsigned emulated:1;
 
 } Scsi_Host_Template;
 
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.1.95/linux/drivers/scsi/ibmmca.c	Wed Feb  4 11:36:00 1998
+++ linux/drivers/scsi/ibmmca.c	Sat Apr 11 11:13:25 1998
@@ -298,6 +298,7 @@
 #include <linux/stat.h>
 #include <linux/mca.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include "sd.h"
 #include "scsi.h"
@@ -834,6 +835,7 @@
 
 /*local functions in forward declaration */
 static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
+static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
 static void issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, 
                        unsigned char attn_reg);
 static void internal_done (Scsi_Cmnd * cmd);
@@ -856,6 +858,17 @@
 
 /*--------------------------------------------------------------------*/
 
+
+static void 
+do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long flags;
+
+  spin_lock_irqsave(&io_request_lock, flags);
+  interrupt_handler(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static void 
 interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -1526,7 +1539,7 @@
     return 0;
 
   /* get interrupt request level */
-  if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
+  if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
     {
       printk("IBM MCA SCSI: Unable to get IRQ %d.\n", IM_IRQ);
       return 0;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.1.95/linux/drivers/scsi/ide-scsi.c	Sat Jan 10 10:42:55 1998
+++ linux/drivers/scsi/ide-scsi.c	Fri Apr 10 15:22:21 1998
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.5		Jan   2, 1998
+ * linux/drivers/scsi/ide-scsi.c	Version 0.6		Jan  27, 1998
  *
  * Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
  */
@@ -20,9 +20,12 @@
  *                       Use variable timeout for each command.
  * Ver 0.5   Jan  2 98   Fix previous PD/CD support.
  *                       Allow disabling of SCSI-6 to SCSI-10 transformation.
+ * Ver 0.6   Jan 27 98   Allow disabling of SCSI command translation layer
+ *                        for access through /dev/sg.
+ *                       Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
  */
 
-#define IDESCSI_VERSION "0.5"
+#define IDESCSI_VERSION "0.6"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -37,6 +40,7 @@
 
 #include <asm/io.h>
 #include <asm/bitops.h>
+#include <asm/uaccess.h>
 
 #include "../block/ide.h"
 
@@ -44,6 +48,7 @@
 #include "hosts.h"
 #include "sd.h"
 #include "ide-scsi.h"
+#include <scsi/sg.h>
 
 #define IDESCSI_DEBUG_LOG		0
 
@@ -68,12 +73,25 @@
  */
 #define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
 #define PC_WRITING			1	/* Data direction */
+#define PC_TRANSFORM			2	/* transform SCSI commands */
+
+/*
+ *	SCSI command transformation layer
+ */
+#define IDESCSI_TRANSFORM		0	/* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation */
+
+/*
+ *	Log flags
+ */
+#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
 
 typedef struct {
 	ide_drive_t *drive;
 	idescsi_pc_t *pc;			/* Current packet command */
 	unsigned int flags;			/* Status/Action flags */
-	int transform;				/* Transform SCSI-6 commands */
+	int transform;				/* SCSI cmd translation layer */
+	int log;				/* log flags */
 } idescsi_scsi_t;
 
 /*
@@ -153,11 +171,10 @@
  */
 static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
-	u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
-	int i;
+	u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
+	char *atapi_buf;
 
-	if (!scsi->transform)
+	if (!test_bit(PC_TRANSFORM, &pc->flags))
 		return;
 	if (drive->media == ide_cdrom) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
@@ -165,35 +182,54 @@
 			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
 			c[0] += (READ_10 - READ_6);
 		}
-		if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
-			pc->request_transfer -= 4;
+		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+			if (!scsi_buf)
+				return;
+			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
+				return;
+			memset(atapi_buf, 0, pc->buffer_size + 4);
 			memset (c, 0, 12);
-			c[0] = sc[0] | 0x40;	c[2] = sc[2];		c[8] = sc[4] - 4;
-			if (c[0] == MODE_SENSE_10) return;
-			for (i = 0; i <= 7; i++) buf[i] = 0;
-			for (i = 8; i < pc->buffer_size - 4; i++) buf[i] = buf[i + 4];
+			c[0] = sc[0] | 0x40;	c[1] = sc[1];		c[2] = sc[2];
+			c[8] = sc[4] + 4;	c[9] = sc[5];
+			if (sc[4] + 4 > 255)
+				c[7] = sc[4] + 4 - 255;
+			if (c[0] == MODE_SELECT_10) {
+				atapi_buf[1] = scsi_buf[0];	/* Mode data length */
+				atapi_buf[2] = scsi_buf[1];	/* Medium type */
+				atapi_buf[3] = scsi_buf[2];	/* Device specific parameter */
+				atapi_buf[7] = scsi_buf[3];	/* Block descriptor length */
+				memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
+			}
+			pc->buffer = atapi_buf;
+			pc->request_transfer += 4;
+			pc->buffer_size += 4;
 		}
 	}
 }
 
 static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
 {
-	idescsi_scsi_t *scsi = drive->driver_data;
-	u8 *buf = pc->buffer;
-	int i;
+	u8 *atapi_buf = pc->buffer;
+	u8 *sc = pc->scsi_cmd->cmnd;
+	u8 *scsi_buf = pc->scsi_cmd->request_buffer;
 
-	if (!scsi->transform)
+	if (!test_bit(PC_TRANSFORM, &pc->flags))
 		return;
 	if (drive->media == ide_cdrom) {
-		if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
-			buf[0] = buf[1];	buf[1] = buf[2];
-			buf[2] = 0;		buf[3] = 8;
-			for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
-			for (i = 11; i >= 4; i--) buf[i] = 0;
+		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
+			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
+			scsi_buf[1] = atapi_buf[2];		/* Medium type */
+			scsi_buf[2] = atapi_buf[3];		/* Device specific parameter */
+			scsi_buf[3] = atapi_buf[7];		/* Block descriptor length */
+			memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
+		}
+		if (pc->c[0] == INQUIRY) {
+			scsi_buf[2] |= 2;			/* ansi_revision */
+			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;	/* response data format */
 		}
-		if (pc->c[0] == INQUIRY)
-			buf[2] |= 2;
 	}
+	if (atapi_buf && atapi_buf != scsi_buf)
+		kfree(atapi_buf);
 }
 
 static inline void idescsi_free_bh (struct buffer_head *bh)
@@ -207,12 +243,24 @@
 	}
 }
 
+static void hexdump(u8 *x, int len)
+{
+	int i;
+
+	printk("[ ");
+	for (i = 0; i < len; i++)
+		printk("%x ", x[i]);
+	printk("]\n");
+}
+
 static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
 {
 	ide_drive_t *drive = hwgroup->drive;
 	idescsi_scsi_t *scsi = drive->driver_data;
 	struct request *rq = hwgroup->rq;
 	idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
+	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
+	u8 *scsi_buf = pc->scsi_cmd->request_buffer;
 
 	if (rq->cmd != IDESCSI_PC_RQ) {
 		ide_end_request (uptodate, hwgroup);
@@ -220,21 +268,23 @@
 	}
 	ide_end_drive_cmd (drive, 0, 0);
 	if (rq->errors >= ERROR_MAX) {
-#if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
 		pc->scsi_cmd->result = DID_ERROR << 16;
+		if (log)
+			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
 	} else if (rq->errors) {
-#if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
 		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+		if (log)
+			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
 	} else {
-#if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: success for %lu\n", drive->name, pc->scsi_cmd->serial_number);
-#endif /* IDESCSI_DEBUG_LOG */
 		pc->scsi_cmd->result = DID_OK << 16;
 		idescsi_transform_pc2 (drive, pc);
+		if (log) {
+			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
+			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+				printk(", rst = ");
+				hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
+			} else printk("\n");
+		}
 	}
 	pc->done(pc->scsi_cmd);
 	idescsi_free_bh (rq->bh);
@@ -274,9 +324,8 @@
 	status = GET_STAT();						/* Clear the interrupt */
 
 	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */
-#if IDESCSI_DEBUG_LOG
-		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDESCSI_DEBUG_LOG */
+		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 		ide_sti();
 		if (status & ERR_STAT)
 			rq->errors++;
@@ -306,11 +355,13 @@
 		}
 	}
 	if (ireason & IDESCSI_IREASON_IO) {
+		clear_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
 			idescsi_input_buffers (drive, pc, bcount);
 		else
 			atapi_input_bytes (drive,pc->current_position,bcount);
 	} else {
+		set_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
 			idescsi_output_buffers (drive, pc, bcount);
 		else
@@ -421,7 +472,8 @@
 	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_SHORT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
 	ide_add_setting(drive,	"bios_head",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
 	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
-	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1,	1,		1,		&scsi->transform,	NULL);
+	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
+	ide_add_setting(drive,	"log",		SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);
 }
 
 /*
@@ -437,7 +489,11 @@
 	scsi->drive = drive;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
 		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
-	scsi->transform = 1;
+	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+	set_bit(IDESCSI_LOG_CMD, &scsi->log);
+#endif /* IDESCSI_DEBUG_LOG */
 	idescsi_add_settings(drive);
 }
 
@@ -554,6 +610,19 @@
 	return "SCSI host adapter emulation for IDE ATAPI devices";
 }
 
+int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+{
+	ide_drive_t *drive = idescsi_drives[dev->id];
+	idescsi_scsi_t *scsi = drive->driver_data;
+
+	if (cmd == SG_SET_TRANSFORM) {
+		set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+		return 0;
+	} else if (cmd == SG_GET_TRANSFORM)
+		return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg);
+	return -EINVAL;
+}
+
 static inline struct buffer_head *idescsi_kmalloc_bh (int count)
 {
 	struct buffer_head *bh, *bhp, *first_bh;
@@ -624,20 +693,27 @@
 	return first_bh;
 }
 
+static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
+{
+	idescsi_scsi_t *scsi = drive->driver_data;
+
+	if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
+		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+	return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
+}
+
 int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
 	ide_drive_t *drive = idescsi_drives[cmd->target];
+	idescsi_scsi_t *scsi;
 	struct request *rq = NULL;
 	idescsi_pc_t *pc = NULL;
 
-#if IDESCSI_DEBUG_LOG
-	printk ("idescsi_queue called, serial = %lu, cmd[0] = %x, id = %d\n", cmd->serial_number, cmd->cmnd[0], cmd->target);
-#endif	/* IDESCSI_DEBUG_LOG */
-
 	if (!drive) {
 		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
 		goto abort;
 	}
+	scsi = drive->driver_data;
 	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
 	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
 	if (rq == NULL || pc == NULL) {
@@ -661,7 +737,19 @@
 	pc->scsi_cmd = cmd;
 	pc->done = done;
 	pc->timeout = jiffies + cmd->timeout_per_command;
+
+	if (should_transform(drive, cmd))
+		set_bit(PC_TRANSFORM, &pc->flags);
 	idescsi_transform_pc1 (drive, pc);
+
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
+		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+		hexdump(cmd->cmnd, cmd->cmd_len);
+		if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
+			printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+			hexdump(pc->c, 12);
+		}
+	}
 
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ide-scsi.h linux/drivers/scsi/ide-scsi.h
--- v2.1.95/linux/drivers/scsi/ide-scsi.h	Sun Dec 21 17:09:12 1997
+++ linux/drivers/scsi/ide-scsi.h	Fri Apr 10 15:22:21 1998
@@ -10,6 +10,7 @@
 extern int idescsi_detect (Scsi_Host_Template *host_template);
 extern int idescsi_release (struct Scsi_Host *host);
 extern const char *idescsi_info (struct Scsi_Host *host);
+extern int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 extern int idescsi_abort (Scsi_Cmnd *cmd);
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
@@ -20,6 +21,7 @@
 	detect:          idescsi_detect,	/* detect	*/		\
 	release:         idescsi_release,	/* release	*/		\
 	info:            idescsi_info,		/* info		*/		\
+	ioctl:           idescsi_ioctl,		/* ioctl        */		\
 	queuecommand:    idescsi_queue,		/* queuecommand */		\
 	abort:           idescsi_abort,		/* abort	*/		\
 	reset:           idescsi_reset,		/* reset	*/		\
@@ -28,7 +30,8 @@
 	this_id:         -1,			/* this_id	*/		\
 	sg_tablesize:    256,			/* sg_tablesize	*/		\
 	cmd_per_lun:     5,			/* cmd_per_lun	*/		\
-	use_clustering:  DISABLE_CLUSTERING	/* clustering	*/		\
+	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/		\
+	emulated:        1			/* emulated     */		\
 }
 
 #endif /* IDESCSI_H */
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v2.1.95/linux/drivers/scsi/in2000.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/in2000.c	Sat Apr 11 11:13:25 1998
@@ -117,6 +117,7 @@
 
 #include <linux/blk.h>
 #include <linux/stat.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "sd.h"
@@ -1638,7 +1639,14 @@
 
 }
 
+static void do_in2000_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+   unsigned long flags;
 
+   spin_lock_irqsave(&io_request_lock, flags);
+   in2000_intr(irq, dev_id, regs);
+   spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 #define RESET_CARD         0
 #define RESET_CARD_AND_BUS 1
@@ -2064,7 +2072,7 @@
       write1_io(0,IO_FIFO_READ);             /* start fifo out in read mode */
       write1_io(0,IO_INTR_MASK);    /* allow all ints */
       x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
-      if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
+      if (request_irq(x, do_in2000_intr, SA_INTERRUPT, "in2000", NULL)) {
          printk("in2000_detect: Unable to allocate IRQ.\n");
          detect_count--;
          continue;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c
--- v2.1.95/linux/drivers/scsi/mac53c94.c	Sat Aug 16 09:53:08 1997
+++ linux/drivers/scsi/mac53c94.c	Sat Apr 11 11:13:25 1998
@@ -19,6 +19,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -57,6 +58,7 @@
 static void mac53c94_init(struct fsc_state *);
 static void mac53c94_start(struct fsc_state *);
 static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static void do_mac53c94_interrupt(int, void *, struct pt_regs *);
 static void cmd_done(struct fsc_state *, int result);
 static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
 static int data_goes_out(Scsi_Cmnd *);
@@ -117,7 +119,7 @@
 		*prev_statep = state;
 		prev_statep = &state->next;
 
-		if (request_irq(state->intr, mac53c94_interrupt, 0,
+		if (request_irq(state->intr, do_mac53c94_interrupt, 0,
 				"53C94", state)) {
 			printk(KERN_ERR "mac53C94: can't get irq %d\n", state->intr);
 		}
@@ -268,6 +270,16 @@
 
 	if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
 		set_dma_cmds(state, cmd);
+}
+
+static void
+do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	mac53c94_interrupt(irq, dev_id, ptregs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 static void
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c
--- v2.1.95/linux/drivers/scsi/mesh.c	Sat Sep  6 10:04:15 1997
+++ linux/drivers/scsi/mesh.c	Sat Apr 11 11:13:25 1998
@@ -23,6 +23,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -138,6 +139,7 @@
 static void reselected(struct mesh_state *);
 static void handle_reset(struct mesh_state *);
 static void mesh_interrupt(int, void *, struct pt_regs *);
+static void do_mesh_interrupt(int, void *, struct pt_regs *);
 static void handle_msgin(struct mesh_state *);
 static void mesh_done(struct mesh_state *);
 static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
@@ -207,7 +209,7 @@
 		*prev_statep = ms;
 		prev_statep = &ms->next;
 
-		if (request_irq(ms->meshintr, mesh_interrupt, 0, "MESH", ms)) {
+		if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
 			printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
 		}
 
@@ -973,6 +975,16 @@
 	}
 	ms->phase = idle;
 	out_8(&mr->sync_params, ASYNC_PARAMS);
+}
+
+static void
+do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	mesh_interrupt(irq, dev_id, ptregs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 static void
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.95/linux/drivers/scsi/ncr53c8xx.c	Fri Apr 10 13:03:49 1998
+++ linux/drivers/scsi/ncr53c8xx.c	Mon Apr 13 13:30:50 1998
@@ -112,6 +112,7 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -557,6 +558,7 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
 #else
 static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
 #endif
@@ -4612,10 +4614,10 @@
 	if (bootverbose > 1)
 		printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
 		        ncr_name(np), device->slot.irq, (u_long) np);
-	if (request_irq(device->slot.irq, ncr53c8xx_intr,
+	if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
 			SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) {
 #else
-	if (request_irq(device->slot.irq, ncr53c8xx_intr,
+	if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
 			SA_INTERRUPT, "ncr53c8xx", np)) {
 #endif
 #else
@@ -9787,17 +9789,22 @@
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
 {
-     unsigned long flags;
-
 #ifdef DEBUG_NCR53C8XX
      printk("ncr53c8xx : interrupt received\n");
 #endif
 
      if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-     spin_lock_irqsave(&io_request_lock, flags);
      ncr_exception((ncb_p) dev_id);
-     spin_unlock_irqrestore(&io_request_lock, flags);
      if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+}
+
+static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+     unsigned long flags;
+
+     spin_lock_irqsave(&io_request_lock, flags);
+     ncr53c8xx_intr(irq, dev_id, regs);
+     spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 #else
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c
--- v2.1.95/linux/drivers/scsi/pas16.c	Sun Jan  4 10:55:09 1998
+++ linux/drivers/scsi/pas16.c	Sat Apr 11 11:13:25 1998
@@ -426,7 +426,7 @@
 	    instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
 
 	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
+	    if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
 		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h
--- v2.1.95/linux/drivers/scsi/pas16.h	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/pas16.h	Sat Apr 11 11:13:25 1998
@@ -186,6 +186,7 @@
 
 
 #define NCR5380_intr pas16_intr
+#define do_NCR5380_intr do_pas16_intr
 #define NCR5380_queue_command pas16_queue_command
 #define NCR5380_abort pas16_abort
 #define NCR5380_reset pas16_reset
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.1.95/linux/drivers/scsi/pci2000.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/pci2000.c	Sat Apr 11 11:13:25 1998
@@ -35,6 +35,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -466,6 +467,14 @@
 		OpDone (SCpnt, rc << 16);
 	return 0;
 	}
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+	{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	Irq_Handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	}
 /****************************************************************
  *	Name:	internal_done :LOCAL
  *
@@ -552,7 +561,7 @@
 				}
 			if ( setirq )																// if not shared, posses
 				{
-				if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2000", NULL) )
+				if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2000", NULL) )
 					{
 					printk ("Unable to allocate IRQ for PSI-2000 controller.\n");
 					goto unregister;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.1.95/linux/drivers/scsi/pci2220i.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/pci2220i.c	Sat Apr 11 11:13:25 1998
@@ -37,6 +37,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -431,6 +432,14 @@
 	SCpnt->result = DecodeError (shost, status);
 	SCpnt->scsi_done (SCpnt);
 	}
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+	{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	Irq_Handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	}
 /****************************************************************
  *	Name:	Pci2220i_QueueCommand
  *
@@ -691,7 +700,7 @@
 				}
 			if ( setirq )																// if not shared, posses
 				{
-				if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) )
+				if ( request_irq (pshost->irq, do_Irq_Handler, 0, "pci2220i", NULL) )
 					{
 					printk ("Unable to allocate IRQ for PSI-2220I controller.\n");
 					goto unregister;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c
--- v2.1.95/linux/drivers/scsi/psi240i.c	Wed Nov  5 13:09:56 1997
+++ linux/drivers/scsi/psi240i.c	Sat Apr 11 11:13:25 1998
@@ -36,6 +36,7 @@
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
@@ -370,6 +371,14 @@
 	SCpnt->result = DecodeError (shost, status);
 	SCpnt->scsi_done (SCpnt);
 	}
+static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+	{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	Irq_Handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	}
 /****************************************************************
  *	Name:	Psi240i_QueueCommand
  *
@@ -595,7 +604,7 @@
 
 		save_flags (flags);
 		cli ();
-		if ( request_irq (chipConfig.irq, Irq_Handler, 0, "psi240i", NULL) )
+		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", NULL) )
 			{
 			printk ("Unable to allocate IRQ for PSI-240I controller.\n");
 			restore_flags (flags);
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- v2.1.95/linux/drivers/scsi/qlogicfas.c	Sun Feb  2 05:34:32 1997
+++ linux/drivers/scsi/qlogicfas.c	Sat Apr 11 11:13:25 1998
@@ -125,6 +125,7 @@
 #include <linux/unistd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 #include "sd.h"
 #include "hosts.h"
 #include "qlogicfas.h"
@@ -446,7 +447,7 @@
 #if QL_USE_IRQ
 /*----------------------------------------------------------------*/
 /* interrupt handler */
-static void	       ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+static void	    ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
 {
 Scsi_Cmnd	   *icmd;
 	REG0;
@@ -464,6 +465,15 @@
 /* if result is CHECK CONDITION done calls qcommand to request sense */
 	(icmd->scsi_done) (icmd);
 }
+
+static void	    do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	ql_ihandl(irq, dev_id, regs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
 #endif
 
 /*----------------------------------------------------------------*/
@@ -609,7 +619,7 @@
 	else
 		printk( "Ql: Using preset IRQ %d\n", qlirq );
 
-	if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL))
+	if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL))
 		host->can_queue = 1;
 #endif
 	request_region( qbase , 0x10 ,"qlogicfas");
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.1.95/linux/drivers/scsi/qlogicisp.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/qlogicisp.c	Sat Apr 11 11:13:25 1998
@@ -26,6 +26,7 @@
 #include <linux/unistd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/spinlock.h>
 
 #include "sd.h"
 #include "hosts.h"
@@ -516,6 +517,7 @@
 static int	isp1020_mbox_command(struct Scsi_Host *, u_short []); 
 static int	isp1020_return_status(struct Status_Entry *);
 static void	isp1020_intr_handler(int, void *, struct pt_regs *);
+static void	do_isp1020_intr_handler(int, void *, struct pt_regs *);
 
 #if USE_NVRAM_DEFAULTS
 static int	isp1020_get_defaults(struct Scsi_Host *);
@@ -585,7 +587,7 @@
 
 		host->this_id = hostdata->host_param.initiator_scsi_id;
 
-		if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
+		if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
 				"qlogicisp", host))
 		{
 			printk("qlogicisp : interrupt %d already in use\n",
@@ -800,6 +802,15 @@
 
 
 #define ASYNC_EVENT_INTERRUPT	0x01
+
+void do_isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	isp1020_intr_handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.1.95/linux/drivers/scsi/qlogicpti.c	Sat Sep  6 10:04:16 1997
+++ linux/drivers/scsi/qlogicpti.c	Sat Apr 11 11:13:25 1998
@@ -31,6 +31,7 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/machines.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
@@ -562,6 +563,7 @@
 }
 
 static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
 
 /* Detect all PTI Qlogic ISP's in the machine. */
 __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
@@ -669,7 +671,7 @@
 					goto qpti_irq_acquired; /* BASIC rulez */
 				}
 			}
-			if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+			if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
 				       SA_SHIRQ, "PTI Qlogic/ISP SCSI", NULL)) {
 				printk("Cannot acquire PTI Qlogic/ISP irq line\n");
 				/* XXX Unmap regs, unregister scsi host, free things. */
@@ -685,7 +687,7 @@
 			dcookie.imap = dcookie.iclr = 0;
 			dcookie.pil = -1;
 			dcookie.bus_cookie = sbus;
-			if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+			if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
 				       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
 				       "PTI Qlogic/ISP SCSI", &dcookie)) {
 				printk("Cannot acquire PTI Qlogic/ISP irq line\n");
@@ -1038,6 +1040,15 @@
 	}
 
 	return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
+}
+
+static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	qlogicpti_intr_handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 #ifndef __sparc_v9__
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.95/linux/drivers/scsi/scsi.c	Fri Apr 10 13:03:49 1998
+++ linux/drivers/scsi/scsi.c	Sun Apr 12 11:05:00 1998
@@ -332,7 +332,6 @@
 scsi_make_blocked_list(void)  
 {
     int block_count = 0, index;
-    unsigned long flags;
     struct Scsi_Host * sh[128], * shpnt;
 
     /*
@@ -1078,7 +1077,6 @@
     kdev_t dev;
     struct request * req = NULL;
     int tablesize;
-    unsigned long flags;
     struct buffer_head * bh, *bhp;
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
@@ -1278,7 +1276,6 @@
 #ifdef DEBUG_DELAY
     unsigned long clock;
 #endif
-    unsigned long        flags;
     struct Scsi_Host   * host;
     int                  rtn = 0;
     unsigned long        timeout;
@@ -1373,7 +1370,9 @@
 	SCpnt->result = temp;
 #ifdef DEBUG_DELAY
 	clock = jiffies + 4 * HZ;
+	spin_unlock_irq(&io_request_lock);
 	while (jiffies < clock) barrier();
+	spin_lock_irq(&io_request_lock);
 	printk("done(host = %d, result = %04x) : routine at %p\n",
 	       host->host_no, temp, host->hostt->command);
 #endif
@@ -1401,7 +1400,6 @@
 		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
 		  int timeout, int retries)
 {
-    unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
     Scsi_Device      * device = SCpnt->device;
 
@@ -1795,7 +1793,6 @@
 void *scsi_malloc(unsigned int len)
 {
     unsigned int nbits, mask;
-    unsigned long flags;
     int i, j;
     if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
 	return NULL;
@@ -1821,7 +1818,6 @@
 int scsi_free(void *obj, unsigned int len)
 {
     unsigned int page, sector, nbits, mask;
-    unsigned long flags;
 
 #ifdef DEBUG
     unsigned long ret = 0;
@@ -2400,7 +2396,6 @@
     struct Scsi_Host * shpnt;
     struct Scsi_Host * host = NULL;
     Scsi_Device * SDpnt;
-    unsigned long flags;
     FreeSectorBitmap * new_dma_malloc_freelist = NULL;
     unsigned int new_dma_sectors = 0;
     unsigned int new_need_isa_buffer = 0;
@@ -2709,7 +2704,6 @@
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
-    unsigned long                 flags;
     int                           online_status;
     int                           pcount;
     Scsi_Cmnd                   * SCpnt;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.1.95/linux/drivers/scsi/scsi_ioctl.c	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/scsi_ioctl.c	Sun Apr 12 11:05:00 1998
@@ -96,6 +96,7 @@
 
 static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
 {
+    unsigned long flags;
     int result;
     Scsi_Cmnd * SCpnt;
     Scsi_Device * SDpnt;
@@ -105,9 +106,11 @@
     {
 	struct semaphore sem = MUTEX_LOCKED;
 	SCpnt->request.sem = &sem;
+	spin_lock_irqsave(&io_request_lock, flags);
 	scsi_do_cmd(SCpnt,  cmd, NULL,  0,
 		    scsi_ioctl_done,  MAX_TIMEOUT,
 		    MAX_RETRIES);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	down(&sem);
         SCpnt->request.sem = NULL;
     }
@@ -166,6 +169,7 @@
  */
 static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
 {
+    unsigned long flags;
     char * buf;
     unsigned char cmd[12]; 
     char * cmd_in;
@@ -271,8 +275,10 @@
     {
 	struct semaphore sem = MUTEX_LOCKED;
 	SCpnt->request.sem = &sem;
+	spin_lock_irqsave(&io_request_lock, flags);
 	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
 		    timeout, retries);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	down(&sem);
         SCpnt->request.sem = NULL;
     }
@@ -405,6 +411,8 @@
 	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
 	break;
     default :           
+	if (dev->host->hostt->ioctl)
+		return dev->host->hostt->ioctl(dev, cmd, arg);
 	return -EINVAL;
     }
     return -EINVAL;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.1.95/linux/drivers/scsi/scsi_obsolete.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/scsi_obsolete.c	Sun Apr 12 11:05:00 1998
@@ -143,7 +143,9 @@
 
 void scsi_old_times_out (Scsi_Cmnd * SCpnt)
 {
+    unsigned long flags;
 
+    spin_lock_irqsave(&io_request_lock, flags);
     switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
     {
     case NORMAL_TIMEOUT:
@@ -154,12 +156,12 @@
 	}
 
 	if (!scsi_abort (SCpnt, DID_TIME_OUT))
-	    return;
+	    break;
     case IN_ABORT:
 	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
 	       SCpnt->host->host_no, SCpnt->pid);
 	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
-	    return;
+	    break;
     case IN_RESET:
     case (IN_ABORT | IN_RESET):
 	/* This might be controversial, but if there is a bus hang,
@@ -173,7 +175,7 @@
 	SCpnt->internal_timeout |= IN_RESET2;
         scsi_reset (SCpnt,
 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
-        return;
+        break;
     case (IN_ABORT | IN_RESET | IN_RESET2):
 	/* Obviously the bus reset didn't work.
 	 * Let's try even harder and call for an HBA reset.
@@ -185,28 +187,29 @@
 	SCpnt->internal_timeout |= IN_RESET3;
         scsi_reset (SCpnt,
 		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
-	return;
+	break;
 
     default:
 	printk("SCSI host %d reset (pid %ld) timed out again -\n",
 	       SCpnt->host->host_no, SCpnt->pid);
 	printk("probably an unrecoverable SCSI bus or device hang.\n");
-	return;
+	break;
 
     }
+    spin_unlock_irqrestore(&io_request_lock, flags);
 
 }
 
-
+/*
+ *  From what I can find in scsi_obsolete.c, this function is only called
+ *  by scsi_old_done and scsi_reset.  Both of these functions run with the
+ *  io_request_lock already held, so we need do nothing here about grabbing
+ *  any locks.
+ */
 static void scsi_request_sense (Scsi_Cmnd * SCpnt)
 {
-    unsigned long flags;
-
-    save_flags(flags);
-    cli();
     SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
     update_timeout(SCpnt, SENSE_TIMEOUT);
-    restore_flags(flags);
 
 
     memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
@@ -688,28 +691,25 @@
 static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
 {
     int oldto;
-    unsigned long flags;
     struct Scsi_Host * host = SCpnt->host;
 
     while(1)
     {
-	save_flags(flags);
-	cli();
 
 	/*
 	 * Protect against races here.  If the command is done, or we are
 	 * on a different command forget it.
 	 */
 	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-	    restore_flags(flags);
 	    return 0;
 	}
 
 	if (SCpnt->internal_timeout & IN_ABORT)
 	{
-	    restore_flags(flags);
+	    spin_unlock_irq(&io_request_lock);
 	    while (SCpnt->internal_timeout & IN_ABORT)
 		barrier();
+	    spin_lock_irq(&io_request_lock);
 	}
 	else
 	{
@@ -725,7 +725,6 @@
 		       SCpnt->channel, SCpnt->target, SCpnt->lun);
 	    }
 
-	    restore_flags(flags);
 	    if (!host->host_busy) {
 		SCpnt->internal_timeout &= ~IN_ABORT;
 		update_timeout(SCpnt, oldto);
@@ -749,11 +748,8 @@
 				   */
 	    case SCSI_ABORT_SNOOZE:
 		if(why == DID_TIME_OUT) {
-		    save_flags(flags);
-		    cli();
 		    SCpnt->internal_timeout &= ~IN_ABORT;
 		    if(SCpnt->flags & WAS_TIMEDOUT) {
-			restore_flags(flags);
 			return 1; /* Indicate we cannot handle this.
 				   * We drop down into the reset handler
 				   * and try again
@@ -763,15 +759,11 @@
 			oldto = SCpnt->timeout_per_command;
 			update_timeout(SCpnt, oldto);
 		    }
-		    restore_flags(flags);
 		}
 		return 0;
 	    case SCSI_ABORT_PENDING:
 		if(why != DID_TIME_OUT) {
-		    save_flags(flags);
-		    cli();
 		    update_timeout(SCpnt, oldto);
-		    restore_flags(flags);
 		}
 		return 0;
 	    case SCSI_ABORT_SUCCESS:
@@ -837,7 +829,6 @@
 static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
     int temp;
-    unsigned long flags;
     Scsi_Cmnd * SCpnt1;
     Scsi_Device * SDpnt;
     struct Scsi_Host * host = SCpnt->host;
@@ -894,8 +885,6 @@
 #endif
 
     while (1) {
-	save_flags(flags);
-	cli();
 
 	/*
 	 * Protect against races here.  If the command is done, or we are
@@ -903,15 +892,15 @@
 	 */
 	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
 	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-	    restore_flags(flags);
 	    return 0;
 	  }
 
 	if (SCpnt->internal_timeout & IN_RESET)
 	{
-	    restore_flags(flags);
+	    spin_unlock_irq(&io_request_lock);
 	    while (SCpnt->internal_timeout & IN_RESET)
 		barrier();
+	    spin_lock_irq(&io_request_lock);
 	}
 	else
 	{
@@ -920,7 +909,6 @@
 
 	    if (host->host_busy)
 	    {
-		restore_flags(flags);
                 for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
                 {
                     SCpnt1 = SDpnt->device_queue;
@@ -955,7 +943,6 @@
 	    else
 	    {
 		if (!host->block) host->host_busy++;
-		restore_flags(flags);
 		host->last_reset = jiffies;
 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 		temp = host->hostt->reset(SCpnt, reset_flags);
@@ -985,10 +972,7 @@
 	        else if (temp & SCSI_RESET_BUS_RESET)
 		  scsi_mark_bus_reset(host, SCpnt->channel);
 		else scsi_mark_device_reset(SCpnt->device);
-		save_flags(flags);
-		cli();
 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-		restore_flags(flags);
 		return 0;
 	    case SCSI_RESET_PENDING:
 	        if (temp & SCSI_RESET_HOST_RESET)
@@ -1048,11 +1032,8 @@
 		 * and we return 1 so that we get a message on the
 		 * screen.
 		 */
-		save_flags(flags);
-		cli();
 		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
 		update_timeout(SCpnt, 0);
-		restore_flags(flags);
 		/* If you snooze, you lose... */
 	    case SCSI_RESET_ERROR:
 	    default:
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c
--- v2.1.95/linux/drivers/scsi/scsiiom.c	Tue Mar 10 10:03:33 1998
+++ linux/drivers/scsi/scsiiom.c	Sat Apr 11 11:13:25 1998
@@ -269,6 +269,15 @@
     }
 }
 
+static void
+do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    DC390_Interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 static void
 DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.1.95/linux/drivers/scsi/seagate.c	Fri Nov 14 10:36:16 1997
+++ linux/drivers/scsi/seagate.c	Sat Apr 11 11:13:25 1998
@@ -91,6 +91,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -343,6 +344,7 @@
 
 static int hostno = -1;
 static void seagate_reconnect_intr (int, void *, struct pt_regs *);
+static void do_seagate_reconnect_intr (int, void *, struct pt_regs *);
 
 #ifdef FAST
 static int fast = 1;
@@ -505,7 +507,7 @@
  */
     instance = scsi_register (tpnt, 0);
     hostno = instance->host_no;
-    if (request_irq ((int) irq, seagate_reconnect_intr, SA_INTERRUPT,
+    if (request_irq ((int) irq, do_seagate_reconnect_intr, SA_INTERRUPT,
                 (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", NULL))
     {
       printk ("scsi%d : unable to allocate IRQ%d\n", hostno, (int) irq);
@@ -630,6 +632,16 @@
  * host adapter.  This occurs on the interrupt triggered by the target
  * asserting SEL.
  */
+
+static void do_seagate_reconnect_intr (int irq, void *dev_id, 
+                                    struct pt_regs *regs)
+{
+  unsigned long flags;
+
+  spin_lock_irqsave(&io_request_lock, flags);
+  seagate_reconnect_intr(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+}
 
 static void seagate_reconnect_intr (int irq, void *dev_id, 
                                     struct pt_regs *regs)
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.1.95/linux/drivers/scsi/sg.c	Fri Apr 10 13:03:49 1998
+++ linux/drivers/scsi/sg.c	Mon Apr 13 13:48:07 1998
@@ -95,6 +95,8 @@
 	return 0;
     case SG_GET_TIMEOUT:
 	return scsi_generics[dev].timeout;
+    case SG_EMULATED_HOST:
+    	return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg);
     default:
 	return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
     }
@@ -226,7 +228,6 @@
     struct inode *inode = filp->f_dentry->d_inode;
     int dev=MINOR(inode->i_rdev);
     int i;
-    unsigned long flags;
     struct scsi_generic *device=&scsi_generics[dev];
 
     /*
@@ -250,22 +251,18 @@
     /*
      * Wait until the command is actually done.
      */
-    spin_lock_irqsave(&io_request_lock, flags);
     while(!device->pending || !device->complete)
     {
 	if (filp->f_flags & O_NONBLOCK)
 	{
-	    spin_unlock_irqrestore(&io_request_lock, flags);
 	    return -EAGAIN;
 	}
 	interruptible_sleep_on(&device->read_wait);
 	if (signal_pending(current))
 	{
-	    spin_unlock_irqrestore(&io_request_lock, flags);
 	    return -ERESTARTSYS;
 	}
     }
-    spin_unlock_irqrestore(&io_request_lock, flags);
 
     /*
      * Now copy the result back to the user buffer.
@@ -364,6 +361,7 @@
 static ssize_t sg_write(struct file *filp, const char *buf, 
                         size_t count, loff_t *ppos)
 {
+    unsigned long	  flags;
     struct inode         *inode = filp->f_dentry->d_inode;
     int			  bsize,size,amt,i;
     unsigned char	  cmnd[MAX_COMMAND_SIZE];
@@ -531,9 +529,11 @@
      * do not do any more here - when the interrupt arrives, we will
      * then do the post-processing.
      */
+    spin_lock_irqsave(&io_request_lock, flags);
     scsi_do_cmd (SCpnt,(void *) cmnd,
 		 (void *) device->buff,amt,
 		 sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+    spin_unlock_irqrestore(&io_request_lock, flags);
 
 #ifdef DEBUG
     printk("done cmd\n");
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.1.95/linux/drivers/scsi/sr.c	Fri Apr 10 13:03:49 1998
+++ linux/drivers/scsi/sr.c	Mon Apr 13 16:57:32 1998
@@ -427,7 +427,6 @@
     Scsi_Cmnd * SCpnt = NULL;
     struct request * req = NULL;
     Scsi_Device * SDev;
-    unsigned long flags;
     int flag = 0;
 
     while (1==1){
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.1.95/linux/drivers/scsi/st.c	Tue Mar 10 10:03:33 1998
+++ linux/drivers/scsi/st.c	Mon Apr 13 13:48:07 1998
@@ -30,6 +30,7 @@
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 /* The driver prints some debugging information on the console if DEBUG
    is defined and non-zero. */
@@ -250,6 +251,9 @@
 st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
 	   int timeout, int retries)
 {
+  unsigned long flags;
+
+  spin_lock_irqsave(&io_request_lock, flags);
   if (SCpnt == NULL)
     if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
       printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
@@ -264,6 +268,7 @@
 
   scsi_do_cmd(SCpnt, (void *)cmd, (STp->buffer)->b_data, bytes,
 	      st_sleep_done, timeout, retries);
+  spin_unlock_irqrestore(&io_request_lock, flags);
 
   down(SCpnt->request.sem);
 
@@ -976,6 +981,7 @@
     ST_mode * STm;
     ST_partstat * STps;
     int dev = TAPE_NR(inode->i_rdev);
+    unsigned long flags;
 
     STp = &(scsi_tapes[dev]);
 
@@ -1271,10 +1277,12 @@
       STp->write_pending = 1;
 #endif
 
+      spin_lock_irqsave(&io_request_lock, flags);
       scsi_do_cmd (SCpnt,
 		   (void *) cmd, (STp->buffer)->b_data,
 		   (STp->buffer)->writing,
 		   st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
+      spin_unlock_irqrestore(&io_request_lock, flags);
     }
     else if (SCpnt != NULL)
       {
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- v2.1.95/linux/drivers/scsi/t128.c	Fri Jan 23 18:10:32 1998
+++ linux/drivers/scsi/t128.c	Sat Apr 11 11:13:25 1998
@@ -250,7 +250,7 @@
 	    instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
 
 	if (instance->irq != IRQ_NONE) 
-	    if (request_irq(instance->irq, t128_intr, SA_INTERRUPT, "t128", NULL)) {
+	    if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) {
 		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h
--- v2.1.95/linux/drivers/scsi/t128.h	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/t128.h	Sat Apr 11 11:13:25 1998
@@ -163,6 +163,7 @@
 #endif
 
 #define NCR5380_intr t128_intr
+#define do_NCR5380_intr do_t128_intr
 #define NCR5380_queue_command t128_queue_command
 #define NCR5380_abort t128_abort
 #define NCR5380_reset t128_reset
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.1.95/linux/drivers/scsi/tmscsim.c	Mon Apr  6 17:41:00 1998
+++ linux/drivers/scsi/tmscsim.c	Sat Apr 11 11:13:25 1998
@@ -41,6 +41,7 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -1157,7 +1158,7 @@
 
     if( !used_irq )
     {
-	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
+	if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
 	{
 	    printk("DC390: register IRQ error!\n");
 	    return( -1 );
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v2.1.95/linux/drivers/scsi/ultrastor.c	Tue Aug 12 20:26:26 1997
+++ linux/drivers/scsi/ultrastor.c	Sat Apr 11 11:13:25 1998
@@ -137,6 +137,7 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/dma.h>
 
 #define ULTRASTOR_PRIVATE	/* Get the private stuff from ultrastor.h */
@@ -294,6 +295,7 @@
 #endif
 
 static void ultrastor_interrupt(int, void *, struct pt_regs *);
+static void do_ultrastor_interrupt(int, void *, struct pt_regs *);
 static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
 
 
@@ -507,7 +509,7 @@
     config.mscp_free = ~0;
 #endif
 
-    if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL)) {
+    if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL)) {
 	printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 	       config.interrupt);
 	return FALSE;
@@ -577,7 +579,7 @@
 	  printk("U24F: invalid IRQ\n");
 	  return FALSE;
 	}
-      if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL))
+      if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", NULL))
 	{
 	  printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 		 config.interrupt);
@@ -1155,6 +1157,15 @@
 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
     printk("USx4F: interrupt: returning\n");
 #endif
+}
+
+static void do_ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    ultrastor_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.95/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.1.95/linux/drivers/scsi/wd7000.c	Wed Apr  1 20:11:53 1998
+++ linux/drivers/scsi/wd7000.c	Sat Apr 11 11:13:25 1998
@@ -154,6 +154,7 @@
 #include <linux/sched.h>
 #include <linux/malloc.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
@@ -1148,6 +1149,15 @@
 #endif
 }
 
+void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&io_request_lock, flags);
+    wd7000_intr_handle(irq, dev_id, regs);
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 
 int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
 {
@@ -1314,7 +1324,7 @@
 	return (0);
     }
 
-    if (request_irq (host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
+    if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
 	printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
 	return (0);
     }
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.95/linux/drivers/sound/Config.in	Wed Apr  8 19:36:27 1998
+++ linux/drivers/sound/Config.in	Sun Apr 12 11:42:15 1998
@@ -2,6 +2,7 @@
 if [ "$CONFIG_PAS" = "y" ]; then
     int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10
     int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3
+    bool 'Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK
 fi
 
 dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v2.1.95/linux/drivers/sound/gus_card.c	Wed Apr  8 19:36:27 1998
+++ linux/drivers/sound/gus_card.c	Sun Apr 12 11:42:15 1998
@@ -3,6 +3,7 @@
  *
  * Detection routine for the Gravis Ultrasound.
  */
+ 
 /*
  * Copyright (C) by Hannu Savolainen 1993-1997
  *
@@ -10,6 +11,15 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
+ *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
+ *
+ * Status:
+ *              Tested... 
+ */
+      
+ 
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -23,10 +33,14 @@
 void            gusintr(int irq, void *dev_id, struct pt_regs *dummy);
 
 int             gus_base = 0, gus_irq = 0, gus_dma = 0;
+int             gus_no_wave_dma = 0; 
 extern int      gus_wave_volume;
 extern int      gus_pcm_volume;
 extern int      have_gus_max;
 int             gus_pnp_flag = 0;
+#ifdef CONFIG_GUS16
+static int      db16 = 0;	/* Has a Gus16 AD1848 on it */
+#endif
 
 void attach_gus_card(struct address_info *hw_config)
 {
@@ -120,6 +134,10 @@
 
 #ifdef CONFIG_GUSMAX
 	if (have_gus_max)
+		adintr(irq, (void *)hw_config->slots[1], NULL);
+#endif
+#ifdef CONFIG_GUS16
+	if (db16)
 		adintr(irq, (void *)hw_config->slots[3], NULL);
 #endif
 
@@ -192,6 +210,8 @@
 }
 #endif
 
+
+
 #ifdef MODULE
 
 static struct address_info config;
@@ -207,7 +227,10 @@
 int             dma16 = -1;	/* Set this for modules that need it */
 int             type = 0;	/* 1 for PnP */
 int             gus16 = 0;
-static int      db16 = 0;	/* Has a Gus16 AD1848 on it */
+#ifdef CONFIG_GUSMAX
+static int      no_wave_dma = 0;/* Set if no dma is to be used for the 
+				   wave table (GF1 chip) */
+#endif
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
@@ -215,7 +238,12 @@
 MODULE_PARM(dma16, "i");
 MODULE_PARM(type, "i");
 MODULE_PARM(gus16, "i");
+#ifdef CONFIG_GUSMAX
+MODULE_PARM(no_wave_dma, "i");
+#endif
+#ifdef CONFIG_GUS16
 MODULE_PARM(db16, "i");
+#endif
 
 int init_module(void)
 {
@@ -231,6 +259,10 @@
 	config.dma = dma;
 	config.dma2 = dma16;
 	config.card_subtype = type;
+	
+#ifdef CONFIG_GUSMAX
+	gus_no_wave_dma = no_wave_dma;
+#endif
 
 #if defined(CONFIG_GUS16)
 	if (probe_gus_db16(&config) && gus16)
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.1.95/linux/drivers/sound/gus_wave.c	Wed Apr  8 19:36:27 1998
+++ linux/drivers/sound/gus_wave.c	Sun Apr 12 11:42:15 1998
@@ -11,11 +11,14 @@
  * for more info.
  */
 /*
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer    : ioctl code reworked (vmalloc/vfree removed)
+ * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
+ *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
  */
+ 
+ 
 #include <linux/config.h>
 
-
 #define GUSPNP_AUTODETECT
 
 #include "sound_config.h"
@@ -70,10 +73,11 @@
 };
 
 static struct voice_alloc_info *voice_alloc;
-
+static struct address_info *gus_hw_config;
 extern int      gus_base;
 extern int      gus_irq, gus_dma;
 extern int      gus_pnp_flag;
+extern int      gus_no_wave_dma;
 static int      gus_dma2 = -1;
 static int      dual_dma_mode = 0;
 static long     gus_mem_size = 0;
@@ -833,7 +837,7 @@
 
 	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */
 
-	gusintr(gus_irq, NULL, NULL);	/* Serve pending interrupts */
+	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
 
 	inb(u_Status);		/* Touch the status register */
 
@@ -1649,22 +1653,26 @@
 
 	voice_alloc->timestamp = 0;
 
-	if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
-	{
-		/* printk( "GUS: Loading samples without DMA\n"); */
-		gus_no_dma = 1;	/* Upload samples using PIO */
+	if (gus_no_wave_dma) {
+		gus_no_dma = 1;
+	} else {
+		if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
+		{
+			/* printk( "GUS: Loading samples without DMA\n"); */
+			gus_no_dma = 1;	/* Upload samples using PIO */
+		}
+		else
+			gus_no_dma = 0;
 	}
-	else
-		gus_no_dma = 0;
 
 	init_waitqueue(&dram_sleeper);
 	gus_busy = 1;
 	active_device = GUS_DEV_WAVE;
 
-	gusintr(gus_irq, NULL, NULL);	/* Serve pending interrupts */
+	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
 	gus_initialize();
 	gus_reset();
-	gusintr(gus_irq, NULL, NULL);	/* Serve pending interrupts */
+	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
 
 	return 0;
 }
@@ -2953,6 +2961,7 @@
 	gus_irq = irq;
 	gus_dma = dma;
 	gus_dma2 = dma2;
+	gus_hw_config = hw_config;
 
 	if (gus_dma2 == -1)
 		gus_dma2 = dma;
@@ -3114,8 +3123,8 @@
 	reset_sample_memory();
 
 	gus_initialize();
-
-	if (gus_mem_size > 0)
+	
+	if ((gus_mem_size > 0) & !gus_no_wave_dma)
 	{
 		if ((dev = sound_alloc_audiodev()) != -1)
 		{
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v2.1.95/linux/drivers/sound/pas2_card.c	Wed Apr  8 19:36:27 1998
+++ linux/drivers/sound/pas2_card.c	Sun Apr 12 11:42:15 1998
@@ -37,6 +37,11 @@
 static int      pas_intr_mask = 0;
 static int      pas_irq = 0;
 static int      pas_sb_base = 0;
+#ifndef CONFIG_PAS_JOYSTICK
+static int	joystick = 0;
+#else
+static int 	joystick = 1;
+#endif
 
 
 char            pas_model = 0;
@@ -142,9 +147,7 @@
 						 */ , 0xB88);
 
 	pas_write(0x80
-#ifdef PAS_JOYSTICK_ENABLE
-		  | 0x40
-#endif
+		  | joystick?0x40:0
 		  ,0xF388);
 
 	if (pas_irq < 0 || pas_irq > 15)
@@ -379,6 +382,8 @@
 MODULE_PARM(sb_irq,"i");
 MODULE_PARM(sb_dma,"i");
 MODULE_PARM(sb_dma16,"i");
+
+MODULE_PARM(joystick,"i");
 
 struct address_info config;
 struct address_info sbhw_config;
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c
--- v2.1.95/linux/drivers/sound/vidc.c	Wed Apr  8 19:36:28 1998
+++ linux/drivers/sound/vidc.c	Mon Apr 13 17:03:04 1998
@@ -6,11 +6,9 @@
  *	Copyright (C) 1997 by Russell King <rmk@arm.uk.linux.org>
  */
 
-#include <linux/config.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include "sound_config.h"
-
 #include "vidc.h"
 
 int vidc_busy;
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/vidc_audio.c linux/drivers/sound/vidc_audio.c
--- v2.1.95/linux/drivers/sound/vidc_audio.c	Wed Apr  8 19:36:28 1998
+++ linux/drivers/sound/vidc_audio.c	Mon Apr 13 17:03:04 1998
@@ -6,11 +6,9 @@
  * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
  */
 
-#include <linux/config.h>
-#include "sound_config.h"
 #include <asm/hardware.h>
 #include <asm/io.h>
-
+#include "sound_config.h"
 #include "vidc.h"
 
 /*
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/vidc_mixer.c linux/drivers/sound/vidc_mixer.c
--- v2.1.95/linux/drivers/sound/vidc_mixer.c	Wed Apr  8 19:36:28 1998
+++ linux/drivers/sound/vidc_mixer.c	Mon Apr 13 17:03:04 1998
@@ -6,9 +6,7 @@
  * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
  */
 
-#include <linux/config.h>
 #include "sound_config.h"
-
 #include "vidc.h"
 
 int vidc_volume;
diff -u --recursive --new-file v2.1.95/linux/drivers/sound/vidc_synth.c linux/drivers/sound/vidc_synth.c
--- v2.1.95/linux/drivers/sound/vidc_synth.c	Wed Apr  8 19:36:28 1998
+++ linux/drivers/sound/vidc_synth.c	Mon Apr 13 17:03:04 1998
@@ -5,9 +5,8 @@
  *
  * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
  */
-#include <linux/config.h>
-#include "sound_config.h"
 
+#include "sound_config.h"
 #include "vidc.h"
 
 static struct synth_info vidc_info =
diff -u --recursive --new-file v2.1.95/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.1.95/linux/fs/binfmt_misc.c	Sun Oct 12 10:16:38 1997
+++ linux/fs/binfmt_misc.c	Sat Apr 11 17:19:56 1998
@@ -34,7 +34,7 @@
 
 struct binfmt_entry {
 	struct binfmt_entry *next;
-	int id;
+	long id;
 	int flags;			/* type, status, etc. */
 	int offset;			/* offset of magic */
 	int size;			/* size of magic/mask */
@@ -243,7 +243,7 @@
 static char *copyarg(char **dp, const char **sp, int *count,
 		     char del, int special, int *err)
 {
-	char c, *res = *dp;
+	char c = 0, *res = *dp;
 
 	while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
 		switch (c) {
@@ -370,7 +370,7 @@
 	if (!data)
 		sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
 	else {
-		if (!(e = get_entry((int) data))) {
+		if (!(e = get_entry((long) data))) {
 			err = -ENOENT;
 			goto _err;
 		}
@@ -428,7 +428,7 @@
 		count--;
 	if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
 		if (data) {
-			if ((e = get_entry((int) data)))
+			if ((e = get_entry((long) data)))
 				e->flags = (e->flags & ~ENTRY_ENABLED)
 					    | (int)(buffer[0] - '0');
 			put_entry(e);
@@ -437,7 +437,7 @@
 		}
 	} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
 		if (data)
-			clear_entry((int) data);
+			clear_entry((long) data);
 		else
 			clear_entries();
 	} else {
diff -u --recursive --new-file v2.1.95/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.1.95/linux/include/asm-alpha/processor.h	Thu Feb 12 20:56:12 1998
+++ linux/include/asm-alpha/processor.h	Tue Apr 14 12:54:33 1998
@@ -92,6 +92,9 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
+#define copy_segments(nr, tsk, mm)	do { } while (0)
+#define release_segments(mm)		do { } while (0)
+
 /* NOTE: The task struct and the stack go together!  */
 #define alloc_task_struct() \
         ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h
--- v2.1.95/linux/include/asm-arm/a.out.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/a.out.h	Sun Apr 12 11:42:15 1998
@@ -1,16 +1,18 @@
 #ifndef __ARM_A_OUT_H__
 #define __ARM_A_OUT_H__
 
+#include <linux/types.h>
+
 struct exec
 {
-  unsigned long a_info;		/* Use macros N_MAGIC, etc for access */
-  unsigned a_text;		/* length of text, in bytes */
-  unsigned a_data;		/* length of data, in bytes */
-  unsigned a_bss;		/* length of uninitialized data area for file, in bytes */
-  unsigned a_syms;		/* length of symbol table data in file, in bytes */
-  unsigned a_entry;		/* start address */
-  unsigned a_trsize;		/* length of relocation info for text, in bytes */
-  unsigned a_drsize;		/* length of relocation info for data, in bytes */
+  __u32 a_info;		/* Use macros N_MAGIC, etc for access */
+  __u32 a_text;		/* length of text, in bytes */
+  __u32 a_data;		/* length of data, in bytes */
+  __u32 a_bss;		/* length of uninitialized data area for file, in bytes */
+  __u32 a_syms;		/* length of symbol table data in file, in bytes */
+  __u32 a_entry;	/* start address */
+  __u32 a_trsize;	/* length of relocation info for text, in bytes */
+  __u32 a_drsize;	/* length of relocation info for data, in bytes */
 };
 
 /*
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/a.out.h linux/include/asm-arm/arch-a5k/a.out.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/a.out.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP		(0x01a00000)
-#define LIBRARY_START_TEXT	(0x00c00000)
-#endif
-
-#endif
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/dma.h linux/include/asm-arm/arch-a5k/dma.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/dma.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/dma.h	Wed Dec 31 16:00:00 1969
@@ -1,101 +0,0 @@
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS		0x03000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-	case 2:  disable_irq(64); break;
-	default: printk (dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    switch(dmanr) {
-	case 2:  break;
-	default: printk (dma_str, "clear_dma_ff", dmanr); break;
-    }
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
-
-#endif /* _ASM_ARCH_DMA_H */
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/hardware.h linux/include/asm-arm/arch-a5k/hardware.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/hardware.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/hardware.h	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/hardware.h
- *
- * Copyright (C) 1996 Russell King.
- *
- * This file contains the hardware definitions of the A5000 series machines.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-#define HAS_IOC
-#define HAS_PCIO
-#define HAS_MEMC
-#define HAS_MEMC1A
-#define HAS_VIDC
-
-/*
- * Optional hardware
- */
-#define HAS_EXPMASK
-
-#ifndef __ASSEMBLER__
-
-/*
- * for use with inb/outb
- */
-#define VIDC_BASE		0x80100000
-#define IOCEC4IO_BASE		0x8009c000
-#define IOCECIO_BASE		0x80090000
-#define IOC_BASE		0x80080000
-#define MEMCECIO_BASE		0x80000000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE		((volatile unsigned char *)0x03360000)
-#define IOEB_BASE		((volatile unsigned char *)0x03350050)
-#define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0x0302a000)
-#define PCIO_BASE		0x03010000
-
-/*
- * Mapping areas
- */
-#define IO_END			0x03ffffff
-#define IO_BASE			0x03000000
-#define IO_SIZE			(IO_END - IO_BASE)
-#define IO_START		0x03000000
-
-/*
- * Screen mapping information
- */
-#define SCREEN2_END		0x02078000
-#define SCREEN2_BASE		0x02000000
-#define SCREEN1_END		SCREEN2_BASE
-#define SCREEN1_BASE		0x01f88000
-#define SCREEN_START		0x02000000
-
-/*
- * RAM definitions
- */
-#define MAPTOPHYS(a)		(((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a)		((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
-#define GET_MEMORY_END(p)	(PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_BASE		(PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE		(PAGE_OFFSET + 0x80000)
-
-#else
-
-#define IOEB_BASE		0x03350050
-#define IOC_BASE		0x03200000
-#define PCIO_FLOPPYDMABASE	0x0302a000
-#define PCIO_BASE		0x03010000
-#define IO_BASE			0x03000000
-
-#endif
-#endif
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/ide.h linux/include/asm-arm/arch-a5k/ide.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/ide.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/ide.h	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/ide.h
- *
- * Copyright (c) 1997 Russell King
- */
-
-static __inline__ int
-ide_default_irq(ide_ioreg_t base)
-{
-	if (base == 0x1f0)
-		return 11;
-	return 0;
-}
-
-static __inline__ ide_ioreg_t
-ide_default_io_base(int index)
-{
-	if (index == 0)
-		return 0x1f0;
-	return 0;
-}
-
-static __inline__ int
-ide_default_stepping(int index)
-{
-	return 0;
-}
-
-static __inline__ void
-ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int stepping, int *irq)
-{
-	ide_ioreg_t port = base;
-	ide_ioreg_t ctrl = base + 0x206;
-	int i;
-
-	i = 8;
-	while (i--) {
-		*p++ = port;
-		port += 1 << stepping;
-	}
-	*p++ = ctrl;
-	if (irq != NULL)
-		irq = 0;
-}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/io.h linux/include/asm-arm/arch-a5k/io.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/io.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/io.h	Wed Dec 31 16:00:00 1969
@@ -1,215 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/io.h
- *
- * Copyright (C) 1997 Russell King
- *
- * Modifications:
- *  06-Dec-1997	RMK	Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x)	((unsigned long)(x))
-#define bus_to_virt(x)	((void *)(x))
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef	ARCH_IO_DELAY
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
- * and are translated to the start of IO.  Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x)	(!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-extern __inline__ void __outb (unsigned int value, unsigned int port)
-{
-	unsigned long temp;
-	__asm__ __volatile__(
-	"tst	%2, #0x80000000\n\t"
-	"mov	%0, %4\n\t"
-	"addeq	%0, %0, %3\n\t"
-	"strb	%1, [%0, %2, lsl #2]"
-	: "=&r" (temp)
-	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-	: "cc");
-}
-
-extern __inline__ void __outw (unsigned int value, unsigned int port)
-{
-	unsigned long temp;
-	__asm__ __volatile__(
-	"tst	%2, #0x80000000\n\t"
-	"mov	%0, %4\n\t"
-	"addeq	%0, %0, %3\n\t"
-	"str	%1, [%0, %2, lsl #2]"
-	: "=&r" (temp)
-	: "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-	: "cc");
-}
-
-extern __inline__ void __outl (unsigned int value, unsigned int port)
-{
-	unsigned long temp;
-	__asm__ __volatile__(
-	"tst	%2, #0x80000000\n\t"
-	"mov	%0, %4\n\t"
-	"addeq	%0, %0, %3\n\t"
-	"str	%1, [%0, %2, lsl #2]"
-	: "=&r" (temp)
-	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-	: "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)					\
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
-{										\
-	unsigned long temp, value;						\
-	__asm__ __volatile__(							\
-	"tst	%2, #0x80000000\n\t"						\
-	"mov	%0, %4\n\t"							\
-	"addeq	%0, %0, %3\n\t"							\
-	"ldr" ##instr## "	%1, [%0, %2, lsl #2]"				\
-	: "=&r" (temp), "=r" (value)						\
-	: "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)		\
-	: "cc");								\
-	return (unsigned sz)value;						\
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)			\
-{										\
-	if (__PORT_PCIO(port))							\
-		return (unsigned int)(PCIO_BASE + (port << 2));			\
-	else									\
-		return (unsigned int)(IO_BASE + (port << 2));			\
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)	\
-	DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)							\
-({										\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"strb	%0, [%1, %2]"						\
-		: : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"strb	%0, [%1, %2]"						\
-		: : "r" (value), "r" (IO_BASE), "r" ((port) << 2));		\
-})
-
-#define __inbc(port)								\
-({										\
-	unsigned char result;							\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"ldrb	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"ldrb	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
-	result;									\
-})
-
-#define __outwc(value,port)							\
-({										\
-	unsigned long v = value;						\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"str	%0, [%1, %2]"						\
-		: : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));	\
-	else									\
-		__asm__ __volatile__(						\
-		"str	%0, [%1, %2]"						\
-		: : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));		\
-})
-
-#define __inwc(port)								\
-({										\
-	unsigned short result;							\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
-	result & 0xffff;							\
-})
-
-#define __outlc(v,p) __outwc((v),(p))
-
-#define __inlc(port)								\
-({										\
-	unsigned long result;							\
-	if (__PORT_PCIO((port)))						\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));		\
-	else									\
-		__asm__ __volatile__(						\
-		"ldr	%0, [%1, %2]"						\
-		: "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));		\
-	result;									\
-})
-
-#define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	if (__PORT_PCIO((port)))						\
-		addr = PCIO_BASE + ((port) << 2);				\
-	else									\
-		addr = IO_BASE + ((port) << 2);					\
-	addr;									\
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)								\
-	(*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)								\
-	(*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)								\
-	(*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)								\
-	(*(volatile unsigned long *)(p))
-
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/irq.h linux/include/asm-arm/arch-a5k/irq.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/irq.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,130 +0,0 @@
-/*
- * include/asm-arm/arch-a5k/irq.h
- *
- * Copyright (C) 1996 Russell King
- *
- * Changelog:
- *   24-09-1996	RMK	Created
- *   10-10-1996	RMK	Brought up to date with arch-sa110eval
- *   22-10-1996	RMK	Changed interrupt numbers & uses new inb/outb macros
- *   11-01-1998	RMK	Added mask_and_ack_irq
- */
-
-#define BUILD_IRQ(s,n,m) \
-	void IRQ##n##_interrupt(void); \
-	void fast_IRQ##n##_interrupt(void); \
-	void bad_IRQ##n##_interrupt(void); \
-	void probe_IRQ##n##_interrupt(void);
-
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt		timer_IRQ_interrupt
-
-#define IRQ_INTERRUPT(n)	IRQ##n##_interrupt
-#define FAST_INTERRUPT(n)	fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n)	bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n)	probe_IRQ##n##_interrupt
-                                
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
-	static const int addrmasks[] = {
-		X((IOC_IRQMASKA - IOC_BASE)<<18 | (1 << 15)),
-		X((IOC_IRQMASKB - IOC_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		X((IOC_FIQMASK - IOC_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0)
-	};
-	unsigned int temp1, temp2;
-
-	__asm__ __volatile__(
-"	ldr	%1, [%5, %3, lsl #2]\n"
-"	teq	%1, #0\n"
-"	beq	2f\n"
-"	ldrb	%0, [%2, %1, lsr #16]\n"
-"	bic	%0, %0, %1\n"
-"	strb	%0, [%2, %1, lsr #16]\n"
-"	tst	%1, #0x8000\n"			/* do we need an IRQ clear? */
-"	strneb	%1, [%2, %4]\n"
-"2:"
-	: "=&r" (temp1), "=&r" (temp2)
-	: "r" (ioaddr(IOC_BASE)), "r" (irq),
-	  "I" ((IOC_IRQCLRA - IOC_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
-	extern void ecard_disableirq (unsigned int);
-	extern void ecard_disablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOC_IRQMASKA) & ~mask, IOC_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOC_IRQMASKB) & ~mask, IOC_IRQMASKB);
-		break;
-	case 4:
-		ecard_disableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOC_FIQMASK) & ~mask, IOC_FIQMASK);
-		break;
-	case 12:
-		ecard_disablefiq (irq & 7);
-	}
-}
-
-static __inline__ void unmask_irq(unsigned int irq)
-{
-	extern void ecard_enableirq (unsigned int);
-	extern void ecard_enablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOC_IRQMASKA) | mask, IOC_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOC_IRQMASKB) | mask, IOC_IRQMASKB);
-		break;
-	case 4:
-		ecard_enableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOC_FIQMASK) | mask, IOC_FIQMASK);
-		break;
-	case 12:
-		ecard_enablefiq (irq & 7);
-	}
-}
-
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-	return inb(IOC_IRQMASKA) | inb(IOC_IRQMASKB) << 8;
-}
-
-static __inline__ void irq_init_irq(void)
-{
-	outb(0, IOC_IRQMASKA);
-	outb(0, IOC_IRQMASKB);
-	outb(0, IOC_FIQMASK);
-}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/irqs.h linux/include/asm-arm/arch-a5k/irqs.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/irqs.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/irqs.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/irqs.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define IRQ_PRINTER		0
-#define IRQ_BATLOW		1
-#define IRQ_FLOPPYINDEX		2
-#define IRQ_VSYNCPULSE		3
-#define IRQ_POWERON		4
-#define IRQ_TIMER0		5
-#define IRQ_TIMER1		6
-#define IRQ_IMMEDIATE		7
-#define IRQ_EXPCARDFIQ		8
-#define IRQ_SOUNDCHANGE		9
-#define IRQ_SERIALPORT		10
-#define IRQ_HARDDISK		11
-#define IRQ_FLOPPYDISK		12
-#define IRQ_EXPANSIONCARD	13
-#define IRQ_KEYBOARDTX		14
-#define IRQ_KEYBOARDRX		15
-
-#define FIQ_FLOPPYDATA		0
-#define FIQ_ECONET		2
-#define FIQ_SERIALPORT		4
-#define FIQ_EXPANSIONCARD	6
-#define FIQ_FORCE		7
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/mmu.h linux/include/asm-arm/arch-a5k/mmu.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/mmu.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  22-11-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt(ppage) ppage
-
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/oldlatches.h linux/include/asm-arm/arch-a5k/oldlatches.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/oldlatches.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (a5k) machine"
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/processor.h linux/include/asm-arm/arch-a5k/processor.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/processor.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/processor.h	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/processor.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  10-09-1996	RMK	Created
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 26MB
- */
-#define TASK_SIZE	(0x01a00000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/serial.h linux/include/asm-arm/arch-a5k/serial.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/serial.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/serial.h	Wed Dec 31 16:00:00 1969
@@ -1,40 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  15-10-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-	{ 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS3 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS }, 	/* ttyS4 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS5 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS6 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS7 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS8 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS9 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS10 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS11 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS12 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
-
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/shmparam.h linux/include/asm-arm/arch-a5k/shmparam.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/shmparam.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/system.h linux/include/asm-arm/arch-a5k/system.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/system.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/system.h	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/system.h
- *
- * Copyright (c) 1996 Russell King
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-extern __inline__ void arch_hard_reset (void)
-{
-	extern void ecard_reset (int card);
-
-	/*
-	 * Reset all expansion cards.
-	 */
-	ecard_reset (-1);
-
-	/*
-	 * copy branch instruction to reset location and call it
-	 */
-	*(unsigned long *)0 = *(unsigned long *)0x03800000;
-	((void(*)(void))0)();
-
-	/*
-	 * If that didn't work, loop endlessly
-	 */
-	while (1);
-}
-
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/time.h linux/include/asm-arm/arch-a5k/time.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/time.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/time.h	Wed Dec 31 16:00:00 1969
@@ -1,96 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/time.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  24-Sep-1996	RMK	Created
- *  10-Oct-1996	RMK	Brought up to date with arch-sa110eval
- *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
- */
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
-	unsigned int count1, count2, status1, status2;
-	unsigned long offset = 0;
-
-	status1 = IOC_IRQREQA;
-	barrier ();
-	outb (0, IOC_T0LATCH);
-	barrier ();
-	count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-	barrier ();
-	status2 = inb(IOC_IRQREQA);
-	barrier ();
-	outb (0, IOC_T0LATCH);
-	barrier ();
-	count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-
-	if (count2 < count1) {
-		/*
-		 * This means that we haven't just had an interrupt
-		 * while reading into status2.
-		 */
-		if (status2 & (1 << 5))
-			offset = tick;
-		count1 = count2;
-	} else if (count2 > count1) {
-		/*
-		 * We have just had another interrupt while reading
-		 * status2.
-		 */
-		offset += tick;
-		count1 = count2;
-	}
-
-	count1 = LATCH - count1;
-	/*
-	 * count1 = number of clock ticks since last interrupt
-	 */
-	offset += count1 * tick / LATCH;
-	return offset;
-}
-
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
-
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
-	extern int iic_control (unsigned char, int, char *, int);
-	unsigned int year, mon, day, hour, min, sec;
-	char buf[8];
-
-	outb(LATCH & 255, IOC_T0LTCHL);
-	outb(LATCH >> 8, IOC_T0LTCHH);
-	outb(0, IOC_T0GO);
-
-	iic_control (0xa0, 0xc0, buf, 1);
-	year = buf[0];
-	if ((year += 1900) < 1970)
-		year += 100;
-
-	iic_control (0xa0, 2, buf, 5);
-	mon  = buf[4] & 0x1f;
-	day  = buf[3] & 0x3f;
-	hour = buf[2];
-	min  = buf[1];
-	sec  = buf[0];
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(sec);
-
-	return mktime(year, mon, day, hour, min, sec);
-}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/timex.h linux/include/asm-arm/arch-a5k/timex.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/timex.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/timex.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/timex.h
- *
- * A5000 architecture timex specifications
- *
- * Copyright (C) 1997, 1998 Russell King
- */
-
-/*
- * On the RiscPC, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE		2000000
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-a5k/uncompress.h linux/include/asm-arm/arch-a5k/uncompress.h
--- v2.1.95/linux/include/asm-arm/arch-a5k/uncompress.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-a5k/uncompress.h	Wed Dec 31 16:00:00 1969
@@ -1,104 +0,0 @@
-/*
- * linux/include/asm-arm/arch-a5k/uncompress.h
- *
- * Copyright (C) 1996 Russell King
- */
-#define VIDMEM ((char *)0x02000000)
- 
-#include "../arch/arm/drivers/char/font.h"
-
-int video_num_columns, video_num_lines, video_size_row;
-int white, bytes_per_char_h;
-extern unsigned long con_charconvtable[256];
-
-struct param_struct {
-	unsigned long page_size;
-	unsigned long nr_pages;
-	unsigned long ramdisk_size;
-	unsigned long mountrootrdonly;
-	unsigned long rootdev;
-	unsigned long video_num_cols;
-	unsigned long video_num_rows;
-	unsigned long video_x;
-	unsigned long video_y;
-	unsigned long memc_control_reg;
-	unsigned char sounddefault;
-	unsigned char adfsdrives;
-	unsigned char bytes_per_char_h;
-	unsigned char bytes_per_char_v;
-	unsigned long unused[256/4-11];
-};
-
-static struct param_struct *params = (struct param_struct *)0x0207c000;
- 
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
-	extern void ll_write_char(char *, unsigned long);
-	int x,y;
-	unsigned char c;
-	char *ptr;
-
-	x = params->video_x;
-	y = params->video_y;
-
-	while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
-		if ( c == '\n' ) {
-			x = 0;
-			if ( ++y >= video_num_lines ) {
-				y--;
-			}
-		} else {
-			ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
-			ll_write_char(ptr, c|(white<<8));
-			if ( ++x >= video_num_columns ) {
-				x = 0;
-				if ( ++y >= video_num_lines ) {
-					y--;
-				}
-			}
-		}
-	}
-
-	params->video_x = x;
-	params->video_y = y;
-}
-
-static void error(char *x);
-
-/*
- * Setup for decompression
- */
-static void arch_decomp_setup(void)
-{
-	int i;
-	
-	video_num_lines = params->video_num_rows;
-	video_num_columns = params->video_num_cols;
-	bytes_per_char_h = params->bytes_per_char_h;
-	video_size_row = video_num_columns * bytes_per_char_h;
-	if (bytes_per_char_h == 4)
-		for (i = 0; i < 256; i++)
-			con_charconvtable[i] =
-				(i & 128 ? 1 << 0  : 0) |
-				(i & 64  ? 1 << 4  : 0) |
-				(i & 32  ? 1 << 8  : 0) |
-				(i & 16  ? 1 << 12 : 0) |
-				(i & 8   ? 1 << 16 : 0) |
-				(i & 4   ? 1 << 20 : 0) |
-				(i & 2   ? 1 << 24 : 0) |
-				(i & 1   ? 1 << 28 : 0);
-	else
-		for (i = 0; i < 16; i++)
-			con_charconvtable[i] =
-				(i & 8   ? 1 << 0  : 0) |
-				(i & 4   ? 1 << 8  : 0) |
-				(i & 2   ? 1 << 16 : 0) |
-				(i & 1   ? 1 << 24 : 0);
-
-	white = bytes_per_char_h == 8 ? 0xfc : 7;
-
-	if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
-}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/a.out.h linux/include/asm-arm/arch-arc/a.out.h
--- v2.1.95/linux/include/asm-arm/arch-arc/a.out.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/a.out.h	Sun Apr 12 11:42:15 1998
@@ -2,8 +2,9 @@
  * linux/include/asm-arm/arch-arc/a.out.h
  *
  * Copyright (C) 1996 Russell King
+ *
+ * Acorn Archimedes/A5000 a.out.h specs
  */
-
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/dma.h linux/include/asm-arm/arch-arc/dma.h
--- v2.1.95/linux/include/asm-arm/arch-arc/dma.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/dma.h	Sun Apr 12 11:42:15 1998
@@ -1,95 +1,38 @@
+/*
+ * linux/include/asm-arm/arch-arc/dma.h
+ *
+ * Copyright (C) 1996-1998 Russell King
+ *
+ * Acorn Archimedes/A5000 architecture virtual DMA
+ * implementation
+ *
+ * Modifications:
+ *  04-04-1998	RMK	Merged arc and a5k versions
+ */
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#define MAX_DMA_ADDRESS		0x03000000
-
-#ifdef KERNEL_ARCH_DMA
+#include <linux/config.h>
 
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-    case 0:  disable_irq(64); break;
-    case 1:  break;
-    default: printk (dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-#define clear_dma_ff(dmanr)
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
+#define MAX_DMA_ADDRESS		0x03000000
 
-/* Set transfer size for a specific DMA channel.
+/*
+ * DMA modes - we have two, IN and OUT
  */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
+typedef enum {
+	DMA_MODE_READ,
+	DMA_MODE_WRITE
+} dmamode_t;
+
+#define MAX_DMA_CHANNELS	4
+
+#define DMA_0			0
+#define DMA_1			1
+#define DMA_VIRTUAL_FLOPPY	2
+#define DMA_VIRTUAL_SOUND	3
 
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#ifdef CONFIG_ARCH_A5K
+#define DMA_FLOPPY		DMA_VIRTUAL_FLOPPY
+#endif
 
 #endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h
--- v2.1.95/linux/include/asm-arm/arch-arc/hardware.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/hardware.h	Sun Apr 12 11:42:15 1998
@@ -3,20 +3,31 @@
  *
  * Copyright (C) 1996 Russell King.
  *
- * This file contains the hardware definitions of the A3/4/5xx series machines.
+ * This file contains the hardware definitions of the
+ * Acorn Archimedes/A5000 machines.
+ *
+ * Modifications:
+ *  04-04-1998	PJB/RMK	Merged arc and a5k versions
  */
 
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
+#include <linux/config.h>
+
 /*
- * What hardware must be present
+ * What hardware must be present - these can be tested by the kernel
+ * source.
  */
 #define HAS_IOC
 #define HAS_MEMC
 #define HAS_MEMC1A
 #define HAS_VIDC
 
+#ifdef CONFIG_ARCH_A5K
+#define HAS_PCIO
+#endif
+
 /*
  * Optional hardware
  */
@@ -29,8 +40,10 @@
  */
 #define VIDC_BASE		0x80100000
 #define IOCEC4IO_BASE		0x8009c000
+#ifdef CONFIG_ARCH_ARC
 #define LATCHAADDR		0x80094010
 #define LATCHBADDR		0x80094006
+#endif
 #define IOCECIO_BASE		0x80090000
 #define IOC_BASE		0x80080000
 #define MEMCECIO_BASE		0x80000000
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/ide.h linux/include/asm-arm/arch-arc/ide.h
--- v2.1.95/linux/include/asm-arm/arch-arc/ide.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/ide.h	Sun Apr 12 11:42:15 1998
@@ -2,17 +2,33 @@
  * linux/include/asm-arm/arch-arc/ide.h
  *
  * Copyright (c) 1997,1998 Russell King
+ *
+ * IDE definitions for the Acorn Archimedes/A5000
+ * architecture
+ *
+ * Modifications:
+ *  04-04-1998	PJB	Merged `arc' and `a5k' versions
  */
 
+#include <linux/config.h>
+
 static __inline__ int
 ide_default_irq(ide_ioreg_t base)
 {
+#ifdef CONFIG_ARCH_A5K
+	if (base == 0x1f0)
+		return 11;
+#endif
 	return 0;
 }
 
 static __inline__ ide_ioreg_t
 ide_default_io_base(int index)
 {
+#ifdef CONFIG_ARCH_A5K
+	if (index == 0)
+		return 0x1f0;
+#endif
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/io.h linux/include/asm-arm/arch-arc/io.h
--- v2.1.95/linux/include/asm-arm/arch-arc/io.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/io.h	Sun Apr 12 11:42:15 1998
@@ -10,16 +10,6 @@
 #define __ASM_ARM_ARCH_IO_H
 
 /*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x)	((unsigned long)(x))
-#define bus_to_virt(x)	((void *)(x))
-
-/*
  * This architecture does not require any delayed IO, and
  * has the constant-optimised IO
  */
@@ -58,7 +48,7 @@
 	"tst	%2, #0x80000000\n\t"
 	"mov	%0, %4\n\t"
 	"addeq	%0, %0, %3\n\t"
-	"strb	%1, [%0, %2, lsl #2]"
+	"str	%1, [%0, %2, lsl #2]"
 	: "=&r" (temp)
 	: "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
 	: "cc");
@@ -71,7 +61,7 @@
 	"tst	%2, #0x80000000\n\t"
 	"mov	%0, %4\n\t"
 	"addeq	%0, %0, %3\n\t"
-	"strb	%1, [%0, %2, lsl #2]"
+	"str	%1, [%0, %2, lsl #2]"
 	: "=&r" (temp)
 	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
 	: "cc");
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h
--- v2.1.95/linux/include/asm-arm/arch-arc/irq.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/irq.h	Sun Apr 12 11:42:15 1998
@@ -6,7 +6,7 @@
  * Changelog:
  *   24-09-1996	RMK	Created
  *   10-10-1996	RMK	Brought up to date with arch-sa110eval
- *   05-11-1996	RMK	Changed interrupt numbers & uses new inb/outb macros
+ *   22-10-1996	RMK	Changed interrupt numbers & uses new inb/outb macros
  *   11-01-1998	RMK	Added mask_and_ack_irq
  */
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/irqs.h linux/include/asm-arm/arch-arc/irqs.h
--- v2.1.95/linux/include/asm-arm/arch-arc/irqs.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/irqs.h	Sun Apr 12 11:42:15 1998
@@ -1,12 +1,26 @@
 /*
  * linux/include/asm-arm/arch-arc/irqs.h
  *
- * Copyright (C) 1996 Russell King, Dave Gilbert (gilbertd@cs.man.ac.uk)
+ * Copyright (C) 1996 Russell King, Dave Gilbert
+ *
+ * Modifications:
+ *  04-04-1998	PJB	Merged arc and a5k versions
  */
 
+#include <linux/config.h>
+
+#if defined(CONFIG_ARCH_A5K)
+#define IRQ_PRINTER		0
+#define IRQ_BATLOW		1
+#define IRQ_FLOPPYINDEX		2
+#define IRQ_FLOPPYDISK		12
+#elif defined(CONFIG_ARCH_ARC)
 #define IRQ_PRINTERBUSY		0
-#define IRQ_SERIALRING		1
+#define	IRQ_SERIALRING		1
 #define IRQ_PRINTERACK		2
+#define IRQ_FLOPPYCHANGED	12
+#endif
+
 #define IRQ_VSYNCPULSE		3
 #define IRQ_POWERON		4
 #define IRQ_TIMER0		5
@@ -16,15 +30,20 @@
 #define IRQ_SOUNDCHANGE		9
 #define IRQ_SERIALPORT		10
 #define IRQ_HARDDISK		11
-#define IRQ_FLOPPYCHANGED	12
 #define IRQ_EXPANSIONCARD	13
 #define IRQ_KEYBOARDTX		14
 #define IRQ_KEYBOARDRX		15
 
-#define FIQ_FLOPPYDATA		0
+#if defined(CONFIG_ARCH_A5K)
+#define FIQ_SERIALPORT		4
+#elif defined(CONFIG_ARCH_ARC)
 #define FIQ_FLOPPYIRQ		1
+#define FIQ_FD1772		FIQ_FLOPPYIRQ
+#endif
+
+#define FIQ_FLOPPYDATA		0
 #define FIQ_ECONET		2
 #define FIQ_EXPANSIONCARD	6
 #define FIQ_FORCE		7
 
-#define FIQ_FD1772		FIQ_FLOPPYIRQ
+#define IRQ_TIMER		IRQ_TIMER0
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/keyboard.h linux/include/asm-arm/arch-arc/keyboard.h
--- v2.1.95/linux/include/asm-arm/arch-arc/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-arc/keyboard.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-arc/keyboard.h
+ *
+ * Keyboard driver definitions for Acorn Archimedes/A5000
+ * architecture
+ *
+ * Copyright (C) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+extern int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
+extern void a5kkbd_leds(unsigned char leds);
+extern void a5kkbd_init_hw(void);
+extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
+
+#define kbd_setkeycode(sc,kc)		(-EINVAL)
+#define kbd_getkeycode(sc)		(-EINVAL)
+
+/* Prototype: int kbd_pretranslate(scancode, raw_mode)
+ * Returns  : 0 to ignore scancode
+ */
+#define kbd_pretranslate(sc,rm)	(1)
+
+/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
+ * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
+ *            set to 0200 if scancode indicates release
+ */
+#define kbd_translate(sc, kcp, ufp, rm)	a5kkbd_translate(sc, kcp, ufp)
+#define kbd_unexpected_up(kc)		(0200)
+#define kbd_leds(leds)			a5kkbd_leds(leds)
+#define kbd_init_hw()			a5kkbd_init_hw()
+#define kbd_sysrq_xlate			a5kkbd_sysrq_xlate
+#define kbd_disable_irq()		disable_irq(IRQ_KEYBOARDRX)
+#define kbd_enable_irq()		enable_irq(IRQ_KEYBOARDRX)
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/mmu.h linux/include/asm-arm/arch-arc/mmu.h
--- v2.1.95/linux/include/asm-arm/arch-arc/mmu.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/mmu.h	Sun Apr 12 11:42:15 1998
@@ -9,7 +9,21 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
+#define __virt_to_phys__is_a_macro
 #define __virt_to_phys(vpage) vpage
+#define __phys_to_virt__is_a_macro
 #define __phys_to_virt(ppage) ppage
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	(x)
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/oldlatches.h linux/include/asm-arm/arch-arc/oldlatches.h
--- v2.1.95/linux/include/asm-arm/arch-arc/oldlatches.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/oldlatches.h	Sun Apr 12 11:42:15 1998
@@ -1,6 +1,19 @@
-#ifndef _ASM_ARM_ARCHARC_OLDLATCH_H
-#define _ASM_ARM_ARCHARC_OLDLATCH_H
+/*
+ * linux/include/asm-arm/arch-arc/oldlatches.h
+ *
+ * Copyright (C) 1996 Russell King, Dave Gilbert
+ *
+ * Dummy oldlatches.h
+ *
+ * Modifications:
+ *  04-04-1998	PJB/RMK	Merged arc and a5k versions
+ */
+#ifndef _ASM_ARCH_OLDLATCH_H
+#define _ASM_ARCH_OLDLATCH_H
 
+#include <linux/config.h>
+
+#if defined(CONFIG_ARCH_ARC)
 #define LATCHA_FDSEL0    (1<<0)
 #define LATCHA_FDSEL1    (1<<1)
 #define LATCHA_FDSEL2    (1<<2)
@@ -21,4 +34,12 @@
 /* newval=(oldval & mask)|newdata */
 void oldlatch_aupdate(unsigned char mask,unsigned char newdata);
 
+#elif defined(CONFIG_ARCH_A5K)
+
+#ifdef __need_oldlatches
+#error "Old latches not present in this (a5k) machine"
+#endif
+
+#endif
 #endif
+
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/processor.h linux/include/asm-arm/arch-arc/processor.h
--- v2.1.95/linux/include/asm-arm/arch-arc/processor.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/processor.h	Sun Apr 12 11:42:15 1998
@@ -29,6 +29,6 @@
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/serial.h linux/include/asm-arm/arch-arc/serial.h
--- v2.1.95/linux/include/asm-arm/arch-arc/serial.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/serial.h	Sun Apr 12 11:42:15 1998
@@ -5,10 +5,13 @@
  *
  * Changelog:
  *  15-10-1996	RMK	Created
+ *  04-04-1998	PJB	Merged `arc' and `a5k' architectures
  */
 #ifndef __ASM_ARCH_SERIAL_H
 #define __ASM_ARCH_SERIAL_H
 
+#include <linux/config.h>
+
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
  *
@@ -20,6 +23,26 @@
 
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
+#if defined(CONFIG_ARCH_A5K)
+     /* UART CLK        PORT  IRQ     FLAGS        */
+#define RS_UARTS \
+	{ 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS3 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS }, 	/* ttyS4 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS5 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS6 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS7 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS8 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS9 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS10 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS11 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS12 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
+
+#elif defined(CONFIG_ARCH_ARC)
+
      /* UART CLK        PORT  IRQ     FLAGS        */
 #define RS_UARTS \
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS0 */	\
@@ -37,4 +60,5 @@
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS12 */	\
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
 
+#endif
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- v2.1.95/linux/include/asm-arm/arch-arc/system.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/system.h	Mon Apr 13 17:03:04 1998
@@ -6,6 +6,10 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
+#include <linux/config.h>
+
+#ifdef CONFIG_ARCH_ARC
+
 #define cliIF()				\
 	do {				\
 	  unsigned long temp;		\
@@ -16,6 +20,8 @@
 	  : "=r" (temp)	\
     : );	\
   } while(0)
+
+#endif
 
 extern __inline__ void arch_hard_reset (void)
 {
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/timex.h linux/include/asm-arm/arch-arc/timex.h
--- v2.1.95/linux/include/asm-arm/arch-arc/timex.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/timex.h	Sun Apr 12 11:42:15 1998
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-arc/timex.h
  *
- * Archimedes architecture timex specifications
+ * Acorn Archimedes/A5000 architecture timex specifications
  *
  * Copyright (C) 1997, 1998 Russell King
  */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-arc/uncompress.h linux/include/asm-arm/arch-arc/uncompress.h
--- v2.1.95/linux/include/asm-arm/arch-arc/uncompress.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/uncompress.h	Sun Apr 12 11:42:15 1998
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-a5k/uncompress.h
+ * linux/include/asm-arm/arch-arc/uncompress.h
  *
  * Copyright (C) 1996 Russell King
  */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/a.out.h linux/include/asm-arm/arch-ebsa110/a.out.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/a.out.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/a.out.h	Sun Apr 12 11:42:15 1998
@@ -8,7 +8,7 @@
 #define __ASM_ARCH_A_OUT_H
 
 #ifdef __KERNEL__
-#define STACK_TOP		(0xc0000000)
+#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
 #define LIBRARY_START_TEXT	(0x00c00000)
 #endif
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/dma.h linux/include/asm-arm/arch-ebsa110/dma.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/dma.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/dma.h	Sun Apr 12 11:42:15 1998
@@ -8,93 +8,22 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    printk (dma_str, "disable_dma", dmanr);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    printk (dma_str, "clear_dma_ff", dmanr);
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
  */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
+#define MAX_DMA_ADDRESS		0xd0000000
 
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
+/*
+ * DMA modes - we have two, IN and OUT
  */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
+typedef enum {
+	DMA_MODE_READ,
+	DMA_MODE_WRITE
+} dmamode_t;
 
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#define MAX_DMA_CHANNELS	8
 
 #endif /* _ASM_ARCH_DMA_H */
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/hardware.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Sun Apr 12 11:42:15 1998
@@ -39,6 +39,7 @@
 #define MAPTOPHYS(a)		((unsigned long)(a) - PAGE_OFFSET)
 #define KERNTOPHYS(a)		((unsigned long)(&a))
 #define KERNEL_BASE		(0xc0008000)
+#define SAFE_ADDR		0x40000000
 
 #else
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/io.h linux/include/asm-arm/arch-ebsa110/io.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/io.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/io.h	Sun Apr 12 11:42:15 1998
@@ -10,16 +10,6 @@
 #define __ASM_ARM_ARCH_IO_H
 
 /*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x)	((unsigned long)(x))
-#define bus_to_virt(x)	((void *)(x))
-
-/*
  * This architecture does not require any delayed IO, and
  * has the constant-optimised IO
  */
@@ -146,7 +136,18 @@
 	result & 0xffff;							\
 })
 
-#define __outlc(v,p) __outwc((v),(p))
+#define __outlc(v,p)								\
+({										\
+	unsigned long v = value;						\
+	if (__PORT_PCIO((port)))						\
+		__asm__ __volatile__(						\
+		"str	%0, [%1, %2]"						\
+		: : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2));		\
+	else									\
+		__asm__ __volatile__(						\
+		"str	%0, [%1, %2]"						\
+		: : "r" (v), "r" (IO_BASE), "r" ((port) << 2));			\
+})
 
 #define __inlc(port)								\
 ({										\
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/irqs.h linux/include/asm-arm/arch-ebsa110/irqs.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/irqs.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/irqs.h	Sun Apr 12 11:42:15 1998
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-arm/arch-sa100eval/irqs.h
+ * linux/include/asm-arm/arch-ebsa110/irqs.h
  *
  * Copyright (C) 1996 Russell King
  */
@@ -12,3 +12,5 @@
 #define IRQ_TIMER1		5
 #define IRQ_PCMCIA		6
 #define IRQ_IMMEDIATE		7
+
+#define IRQ_TIMER		IRQ_TIMER0
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/mm-init.h linux/include/asm-arm/arch-ebsa110/mm-init.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/mm-init.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/mm-init.h	Sun Apr 12 11:42:15 1998
@@ -1,11 +1,6 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/mm-init.h
+ * linux/include/asm-arm/arch-ebsa110/mmap.h
  *
- * Copyright (C) 1997,1998 Russell King
- *
- * Description of the initial memory map for EBSA-110
+ * Copyright (C) 1996,1997,1998 Russell King
  */
 
-static init_mem_map_t init_mem_map[] = {
-	INIT_MEM_MAP_SENTINEL
-};
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/mmap.h linux/include/asm-arm/arch-ebsa110/mmap.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/mmap.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/mmap.h	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR	0x40000000
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/mmu.h linux/include/asm-arm/arch-ebsa110/mmu.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/mmu.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/mmu.h	Sun Apr 12 11:42:15 1998
@@ -13,7 +13,14 @@
 /*
  * On ebsa, the dram is contiguous
  */
+#define __virt_to_phys__is_a_macro
 #define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
 #define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	__phys_to_virt(x)
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa110/processor.h linux/include/asm-arm/arch-ebsa110/processor.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa110/processor.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/processor.h	Sun Apr 12 11:42:15 1998
@@ -26,6 +26,6 @@
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0xc0000000, 0xc2000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/a.out.h linux/include/asm-arm/arch-ebsa285/a.out.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/a.out.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/a.out.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/a.out.h
+ *
+ * Copyright (C) 1996 Russell King
+ */
+
+#ifndef __ASM_ARCH_A_OUT_H
+#define __ASM_ARCH_A_OUT_H
+
+#ifdef __KERNEL__
+#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
+#define LIBRARY_START_TEXT	(0x00c00000)
+#endif
+
+#endif
+
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/dma.h linux/include/asm-arm/arch-ebsa285/dma.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/dma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/dma.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,29 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/dma.h
+ *
+ * Architecture DMA routes
+ *
+ * Copyright (C) 1997.1998 Russell King
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
+ */
+#define MAX_DMA_ADDRESS		0xd0000000
+
+/*
+ * DMA modes - we have two, IN and OUT
+ */
+typedef enum {
+	DMA_MODE_READ,
+	DMA_MODE_WRITE
+} dmamode_t;
+
+#define MAX_DMA_CHANNELS	8
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/hardware.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,114 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/hardware.h
+ *
+ * Copyright (C) 1998 Russell King.
+ *
+ * This file contains the hardware definitions of the EBSA-285.
+ */
+
+
+/*    Logical    Physical
+ * 0xfff00000	0x40000000	X-Bus
+ * 0xffe00000	0x7c000000	PCI I/O space
+ *
+ * 0xfe000000	0x42000000	CSR
+ * 0xfd000000	0x78000000	Outbound write flush
+ * 0xfc000000	0x79000000	PCI IACK/special space
+ *
+ * 0xf9030000	0x7a080000	PCI Config type 1 card 4
+ * 0xf9020000	0x7a040000	PCI Config type 1 card 3
+ * 0xf9010000	0x7a020000	PCI Config type 1 card 2
+ * 0xf9000000	0x7a010000	PCI Config type 1 card 1
+ *
+ * 0xf8030000	0x7b080000	PCI Config type 0 card 4
+ * 0xf8020000	0x7b040000	PCI Config type 0 card 3
+ * 0xf8010000	0x7b020000	PCI Config type 0 card 2
+ * 0xf8000000	0x7b010000	PCI Config type 0 card 1
+ * 
+ */
+ 
+#define IO_END			0xffffffff
+#define IO_BASE			0xe0000000
+#define IO_SIZE			(IO_END - IO_BASE)
+
+#define HAS_PCIO
+
+#define XBUS_LEDS		((volatile unsigned char *)0xfff12000)
+#define XBUS_LED_AMBER		(1 << 0)
+#define XBUS_LED_GREEN		(1 << 1)
+#define XBUS_LED_RED		(1 << 2)
+#define XBUS_LED_TOGGLE		(1 << 8)
+
+#define XBUS_SWITCH		((volatile unsigned char *)0xfff12000)
+#define XBUS_SWITCH_SWITCH	((*XBUS_SWITCH) & 15)
+#define XBUS_SWITCH_J17_13	((*XBUS_SWITCH) & (1 << 4))
+#define XBUS_SWITCH_J17_11	((*XBUS_SWITCH) & (1 << 5))
+#define XBUS_SWITCH_J17_9	((*XBUS_SWITCH) & (1 << 6))
+
+#define PCIO_BASE		0xffe00000
+ 
+#define CSR_SA110_CNTL		((volatile unsigned long *)0xfe00013c)
+#define CSR_PCIADDR_EXTN	((volatile unsigned long *)0xfe000140)
+#define CSR_PREFETCHMEMRANGE	((volatile unsigned long *)0xfe000144)
+#define CSR_XBUS_CYCLE		((volatile unsigned long *)0xfe000148)
+#define CSR_XBUS_IOSTROBE	((volatile unsigned long *)0xfe00014c)
+#define CSR_DOORBELL_PCI	((volatile unsigned long *)0xfe000150)
+#define CSR_DOORBELL_SA110	((volatile unsigned long *)0xfe000154)
+
+
+#define CSR_UARTDR		((volatile unsigned long *)0xfe000160)
+#define CSR_RXSTAT		((volatile unsigned long *)0xfe000164)
+#define CSR_H_UBRLCR		((volatile unsigned long *)0xfe000168)
+#define CSR_M_UBRLCR		((volatile unsigned long *)0xfe00016c)
+#define CSR_L_UBRLCR		((volatile unsigned long *)0xfe000170)
+#define CSR_UARTCON		((volatile unsigned long *)0xfe000174)
+#define CSR_UARTFLG		((volatile unsigned long *)0xfe000178)
+
+#define CSR_IRQ_STATUS		((volatile unsigned long *)0xfe000180)
+#define CSR_IRQ_RAWSTATUS	((volatile unsigned long *)0xfe000184)
+#define CSR_IRQ_ENABLE		((volatile unsigned long *)0xfe000188)
+#define CSR_IRQ_DISABLE		((volatile unsigned long *)0xfe00018c)
+#define CSR_IRQ_SOFT		((volatile unsigned long *)0xfe000190)
+
+#define CSR_FIQ_STATUS		((volatile unsigned long *)0xfe000280)
+#define CSR_FIQ_RAWSTATUS	((volatile unsigned long *)0xfe000284)
+#define CSR_FIQ_ENABLE		((volatile unsigned long *)0xfe000288)
+#define CSR_FIQ_DISABLE		((volatile unsigned long *)0xfe00028c)
+#define CSR_FIQ_SOFT		((volatile unsigned long *)0xfe000290)
+
+#define CSR_TIMER1_LOAD		((volatile unsigned long *)0xfe000300)
+#define CSR_TIMER1_VALUE	((volatile unsigned long *)0xfe000304)
+#define CSR_TIMER1_CNTL		((volatile unsigned long *)0xfe000308)
+#define CSR_TIMER1_CLR		((volatile unsigned long *)0xfe00030c)
+
+#define CSR_TIMER2_LOAD		((volatile unsigned long *)0xfe000320)
+#define CSR_TIMER2_VALUE	((volatile unsigned long *)0xfe000324)
+#define CSR_TIMER2_CNTL		((volatile unsigned long *)0xfe000328)
+#define CSR_TIMER2_CLR		((volatile unsigned long *)0xfe00032c)
+
+#define CSR_TIMER3_LOAD		((volatile unsigned long *)0xfe000340)
+#define CSR_TIMER3_VALUE	((volatile unsigned long *)0xfe000344)
+#define CSR_TIMER3_CNTL		((volatile unsigned long *)0xfe000348)
+#define CSR_TIMER3_CLR		((volatile unsigned long *)0xfe00034c)
+
+#define CSR_TIMER4_LOAD		((volatile unsigned long *)0xfe000360)
+#define CSR_TIMER4_VALUE	((volatile unsigned long *)0xfe000364)
+#define CSR_TIMER4_CNTL		((volatile unsigned long *)0xfe000368)
+#define CSR_TIMER4_CLR		((volatile unsigned long *)0xfe00036c)
+
+
+#define TIMER_CNTL_ENABLE	(1 << 7)
+#define TIMER_CNTL_AUTORELOAD	(1 << 6)
+#define TIMER_CNTL_DIV1		(0)
+#define TIMER_CNTL_DIV16	(1 << 2)
+#define TIMER_CNTL_DIV256	(2 << 2)
+#define TIMER_CNTL_CNTEXT	(3 << 2)
+
+
+#define KERNTOPHYS(a)		((unsigned long)(&a))
+
+#define PARAMS_OFFSET		0x0100
+#define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
+
+#define SAFE_ADDR		0x50000000
+
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/ide.h linux/include/asm-arm/arch-ebsa285/ide.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/ide.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/ide.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1 @@
+/* no ide */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/io.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,143 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/io.h
+ *
+ * Copyright (C) 1997,1998 Russell King
+ *
+ * Modifications:
+ *  06-Dec-1997	RMK	Created.
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/*
+ * This architecture does not require any delayed IO, and
+ * has the constant-optimised IO
+ */
+#undef	ARCH_IO_DELAY
+
+/*
+ * Dynamic IO functions - let the compiler
+ * optimize the expressions
+ */
+#define DECLARE_DYN_OUT(fnsuffix,instr,typ)					\
+extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
+{										\
+	__asm__ __volatile__(							\
+	"str" ##instr## "	%0, [%1, %2]"					\
+	: 									\
+	: "r" (value), "r" (PCIO_BASE), typ (port));				\
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)					\
+extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
+{										\
+	unsigned long value;							\
+	__asm__ __volatile__(							\
+	"ldr" ##instr## "	%0, [%1, %2]"					\
+	: "=&r" (value)								\
+	: "r" (PCIO_BASE), typ (port));						\
+	return (unsigned sz)value;						\
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port)			\
+{										\
+	return (unsigned int)(PCIO_BASE + port);				\
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr,typ)	\
+	DECLARE_DYN_OUT(fnsuffix,instr,typ)	\
+	DECLARE_DYN_IN(sz,fnsuffix,instr,typ)
+
+DECLARE_IO(char,b,"b","Jr")
+DECLARE_IO(short,w,"h","r")
+DECLARE_IO(long,l,"","Jr")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_OUT
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port)							\
+({										\
+	__asm__ __volatile__(							\
+	"strb	%0, [%1, %2]"							\
+	:									\
+	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
+})
+
+#define __inbc(port)								\
+({										\
+	unsigned char result;							\
+	__asm__ __volatile__(							\
+	"ldrb	%0, [%1, %2]"							\
+	: "=r" (result)								\
+	: "r" (PCIO_BASE), "Jr" (port));					\
+	result;									\
+})
+
+#define __outwc(value,port)							\
+({										\
+	__asm__ __volatile__(							\
+	"strh	%0, [%1, %2]"							\
+	:									\
+	: "r" (value), "r" (PCIO_BASE), "r" (port));				\
+})
+
+#define __inwc(port)								\
+({										\
+	unsigned short result;							\
+	__asm__ __volatile__(							\
+	"ldrh	%0, [%1, %2]"							\
+	: "=r" (result)								\
+	: "r" (PCIO_BASE), "r" (port));						\
+	result & 0xffff;							\
+})
+
+#define __outlc(value,port)							\
+({										\
+	__asm__ __volatile__(							\
+	"str	%0, [%1, %2]"							\
+	:									\
+	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
+})
+
+#define __inlc(port)								\
+({										\
+	unsigned long result;							\
+	__asm__ __volatile__(							\
+	"ldr	%0, [%1, %2]"							\
+	: "=r" (result)								\
+	: "r" (PCIO_BASE), "Jr" (port));					\
+	result;									\
+})
+
+#define __ioaddrc(port)								\
+({										\
+	unsigned long addr;							\
+	addr = PCIO_BASE + port;						\
+	addr;									\
+})
+
+/*
+ * Translated address IO functions
+ *
+ * IO address has already been translated to a virtual address
+ */
+#define outb_t(v,p)								\
+	(*(volatile unsigned char *)(p) = (v))
+
+#define inb_t(p)								\
+	(*(volatile unsigned char *)(p))
+
+#define outl_t(v,p)								\
+	(*(volatile unsigned long *)(p) = (v))
+
+#define inl_t(p)								\
+	(*(volatile unsigned long *)(p))
+
+#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/irq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,34 @@
+/*
+ * include/asm-arm/arch-ebsa110/irq.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+static __inline__ void mask_and_ack_irq(unsigned int irq)
+{
+	if (irq < 32)
+		*CSR_IRQ_DISABLE = 1 << irq;
+}
+
+static __inline__ void mask_irq(unsigned int irq)
+{
+	if (irq < 32)
+		*CSR_IRQ_DISABLE = 1 << irq;
+}
+
+static __inline__ void unmask_irq(unsigned int irq)
+{
+	if (irq < 32)
+		*CSR_IRQ_ENABLE = 1 << irq;
+}
+ 
+static __inline__ unsigned long get_enabled_irqs(void)
+{
+	return 0;
+}
+
+static __inline__ void irq_init_irq(void)
+{
+	*CSR_IRQ_DISABLE = -1;
+	*CSR_FIQ_DISABLE = -1;
+}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/irqs.h linux/include/asm-arm/arch-ebsa285/irqs.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/irqs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/irqs.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,45 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/irqs.h
+ *
+ * Copyright (C) 1998 Russell King
+ */
+
+#define NR_IRQS			32
+
+/*
+ * This is a list of all interrupts that the 21285
+ * can generate
+ */
+#define IRQ_RESERVED		0
+#define IRQ_SOFTIRQ		1
+#define IRQ_CONRX		2
+#define IRQ_CONTX		3
+#define IRQ_TIMER1		4
+#define IRQ_TIMER2		5
+#define IRQ_TIMER3		6
+#define IRQ_TIMER4		7
+#define IRQ_IN0			8
+#define IRQ_IN1			9
+#define IRQ_IN2			10
+#define IRQ_IN3			11
+#define IRQ_XCS0		12
+#define IRQ_XCS1		13
+#define IRQ_XCS2		14
+#define IRQ_DOORBELLHOST	15
+#define IRQ_DMA1		16
+#define IRQ_DMA2		17
+#define IRQ_PCI			18
+#define IRQ_BIST		22
+#define IRQ_SERR		23
+#define IRQ_SDRAMPARITY		24
+#define IRQ_I2OINPOST		25
+#define IRQ_DISCARDTIMER	27
+#define IRQ_PCIDATAPARITY	28
+#define IRQ_PCIMASTERABORT	29
+#define IRQ_PCITARGETABORT	30
+#define IRQ_PCIPARITY		31
+
+/*
+ * Now map them to the Linux interrupts
+ */
+#define IRQ_TIMER		IRQ_TIMER1
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/keyboard.h linux/include/asm-arm/arch-ebsa285/keyboard.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/keyboard.h	Mon Apr 13 17:03:04 1998
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/keyboard.h
+ *
+ * Keyboard driver definitions for EBSA285 architecture
+ *
+ * (C) 1998 Russell King
+ */
+
+#include <linux/config.h>
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static unsigned char kbd_sysrq_xlate[NR_SCANCODES];
+#endif
+
+#define kbd_setkeycode(sc,kc)		(-EINVAL)
+#define kbd_getkeycode(sc)		(-EINVAL)
+
+/* Prototype: int kbd_pretranslate(scancode, raw_mode)
+ * Returns  : 0 to ignore scancode
+ */
+#define kbd_pretranslate(sc,rm)		(1)
+
+/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
+ * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
+ *            set to 0200 if scancode indicates release
+ */
+#define kbd_translate(sc, kcp, ufp, rm)	(1)
+#define kbd_unexpected_up(kc)		(0200)
+#define kbd_leds(leds)
+#define kbd_init_hw()
+//#define kbd_sysrq_xlate			ps2kbd_sysrq_xlate
+#define kbd_disable_irq()
+#define kbd_enable_irq()
+
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/mm-init.h linux/include/asm-arm/arch-ebsa285/mm-init.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/mm-init.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/mm-init.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/mmap.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/mmu.h linux/include/asm-arm/arch-ebsa285/mmu.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/mmu.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/mmu.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/mmu.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ *
+ * Changelog:
+ *  20-10-1996	RMK	Created
+ *  31-12-1997	RMK	Fixed definitions to reduce warnings
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * On ebsa, the dram is contiguous
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	__phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/oldlatches.h linux/include/asm-arm/arch-ebsa285/oldlatches.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/oldlatches.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/oldlatches.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,9 @@
+/*
+ * Dummy oldlatches.h
+ *
+ * Copyright (C) 1996 Russell King
+ */
+
+#ifdef __need_oldlatches
+#error "Old latches not present in this (rpc) machine"
+#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/processor.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/processor.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,31 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/processor.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+#ifndef __ASM_ARCH_PROCESSOR_H
+#define __ASM_ARCH_PROCESSOR_H
+
+/*
+ * Bus types
+ */
+#define EISA_bus 0
+#define EISA_bus__is_a_macro /* for versions in ksyms.c */
+#define MCA_bus 0
+#define MCA_bus__is_a_macro /* for versions in ksyms.c */
+
+/*
+ * User space: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+
+#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/shmparam.h linux/include/asm-arm/arch-ebsa285/shmparam.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/shmparam.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/shmparam.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/shmparam.h
+ *
+ * Copyright (c) 1996 Russell King.
+ */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/system.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/system.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,24 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/system.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ */
+#include <asm/hardware.h>
+#include <asm/leds.h>
+
+/* To reboot, we set up the 21285 watchdog and enable it.
+ * We then wait for it to timeout.
+ */
+extern __inline__ void arch_hard_reset (void)
+{
+	cli();
+	*CSR_TIMER4_LOAD = 0x8000;
+	*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+	*CSR_SA110_CNTL |= 1 << 13;
+	while(1);
+}
+
+#define ARCH_IDLE_OK
+
+#define arch_start_idle()	leds_event(led_idle_start)
+#define arch_end_idle()		leds_event(led_idle_end)
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/time.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/time.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,57 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/time.h
+ *
+ * Copyright (c) 1998 Russell King.
+ *
+ * No real time clock on the evalulation board!
+ *
+ * Changelog:
+ *  21-Mar-1998	RMK	Created
+ */
+
+#include <asm/leds.h>
+
+extern __inline__ unsigned long gettimeoffset (void)
+{
+	return 0;
+}
+
+extern __inline__ int reset_timer (void)
+{
+	static unsigned int count = 50;
+	static int last_pid;
+
+	*CSR_TIMER1_CLR = 0;
+
+	if (current->pid != last_pid) {
+		last_pid = current->pid;
+		if (last_pid)
+			leds_event(led_idle_end);
+		else
+			leds_event(led_idle_start);
+	}
+
+	if (--count == 0) {
+		count = 50;
+		leds_event(led_timer);
+	}
+
+	return 1;
+}
+
+/*
+ * We don't have a RTC to update!
+ */
+#define update_rtc()
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+extern __inline__ unsigned long setup_timer (void)
+{
+	*CSR_TIMER1_CLR  = 0;
+	*CSR_TIMER1_LOAD = LATCH;
+	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+
+	return mktime(1970, 1, 1, 0, 0, 0);
+}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/timex.h linux/include/asm-arm/arch-ebsa285/timex.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/timex.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/timex.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,14 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/timex.h
+ *
+ * EBSA285 architecture timex specifications
+ *
+ * Copyright (C) 1998 Russell King
+ */
+
+/*
+ * On the EBSA, the clock ticks at weird rates.
+ * This is therefore not used to calculate the
+ * divisor.
+ */
+#define CLOCK_TICK_RATE		(50000000 / 16)
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h
--- v2.1.95/linux/include/asm-arm/arch-ebsa285/uncompress.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/uncompress.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,33 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ *
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+	__asm__ __volatile__("
+	ldrb	%0, [%2], #1
+	teq	%0, #0
+	beq	3f
+1:	strb	%0, [%3]
+2:	ldrb	%1, [%3, #0x14]
+	and	%1, %1, #0x60
+	teq	%1, #0x60
+	bne	2b
+	teq	%0, #'\n'
+	moveq	%0, #'\r'
+	beq	1b
+	ldrb	%0, [%2], #1
+	teq	%0, #0
+	bne	1b
+3:	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/a.out.h linux/include/asm-arm/arch-nexuspci/a.out.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/a.out.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/a.out.h	Sun Apr 12 11:42:15 1998
@@ -8,7 +8,7 @@
 #define __ASM_ARCH_A_OUT_H
 
 #ifdef __KERNEL__
-#define STACK_TOP		(0xc0000000)
+#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
 #define LIBRARY_START_TEXT	(0x00c00000)
 #endif
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/dma.h linux/include/asm-arm/arch-nexuspci/dma.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/dma.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/dma.h	Sun Apr 12 11:42:15 1998
@@ -1,100 +1,17 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/dma.h
+ * linux/include/asm-arm/arch-nexuspci/dma.h
  *
- * Architecture DMA routes
+ * Architecture DMA routines
  *
- * Copyright (C) 1997.1998 Russell King
+ * Copyright (C) 1998 Philip Blundell
  */
+
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
-    printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
-    printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
-    printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
-    printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
-    printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-    printk (dma_str, "arch_dma_count", dmanr);
-    return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    printk (dma_str, "disable_dma", dmanr);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-    printk (dma_str, "clear_dma_ff", dmanr);
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
+/* NexusPCI has no DMA */
 
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#warning No DMA on this platform
 
 #endif /* _ASM_ARCH_DMA_H */
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/hardware.h linux/include/asm-arm/arch-nexuspci/hardware.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/hardware.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/hardware.h	Sun Apr 12 11:42:15 1998
@@ -30,6 +30,7 @@
 #define MAPTOPHYS(a)		((unsigned long)(a) - PAGE_OFFSET + RAM_BASE)
 #define KERNTOPHYS(a)		((unsigned long)(&a))
 #define KERNEL_BASE		(0xc0008000)
+#define SAFE_ADDR		0x40000000
 
 #else
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/irqs.h linux/include/asm-arm/arch-nexuspci/irqs.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/irqs.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/irqs.h	Sun Apr 12 11:42:15 1998
@@ -5,10 +5,12 @@
  */
 
 #define IRQ_DUART		0
-#define IRQ_TIMER0		0	/* timer is part of the DUART */
 #define IRQ_PLX 		1
 #define IRQ_PCI_D		2
 #define IRQ_PCI_C		3
 #define IRQ_PCI_B		4
 #define IRQ_PCI_A		5
-#define IRQ_SYSERR		6	/* must ask JB about this one */
+#define IRQ_SYSERR		6
+
+/* timer is part of the DUART */
+#define IRQ_TIMER		IRQ_DUART
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/mm-init.h linux/include/asm-arm/arch-nexuspci/mm-init.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/mm-init.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-nexuspci/mm-init.h	Sun Apr 12 11:42:15 1998
@@ -0,0 +1,5 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/mmap.h
+ *
+ * Copyright (C) 1998 Philip Blundell
+ */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/mmap.h linux/include/asm-arm/arch-nexuspci/mmap.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/mmap.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/mmap.h	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR	0x40000000
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/processor.h linux/include/asm-arm/arch-nexuspci/processor.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/processor.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/processor.h	Sun Apr 12 11:42:15 1998
@@ -1,5 +1,6 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/processor.h
+ *  from linux/include/asm-arm/arch-ebsa110/processor.h
  *
  * Copyright (C) 1996,1997,1998 Russell King
  */
@@ -26,6 +27,6 @@
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0xc0000000, 0xc2000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/serial.h linux/include/asm-arm/arch-nexuspci/serial.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/serial.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/serial.h	Wed Dec 31 16:00:00 1969
@@ -1,41 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/serial.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  15-10-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define RS_UARTS \
-	{ 0, BASE_BAUD, 0x3F8,  1, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8,  2, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS3 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS }, 	/* ttyS4 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS5 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS6 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS7 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS8 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS9 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS10 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS11 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS12 */	\
-	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
-
-#endif
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-nexuspci/uncompress.h linux/include/asm-arm/arch-nexuspci/uncompress.h
--- v2.1.95/linux/include/asm-arm/arch-nexuspci/uncompress.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-nexuspci/uncompress.h	Sun Apr 12 11:42:15 1998
@@ -1,5 +1,6 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ * linux/include/asm-arm/arch-nexuspci/uncompress.h
+ *  from linux/include/asm-arm/arch-ebsa110/uncompress.h
  *
  * Copyright (C) 1996,1997,1998 Russell King
  */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/a.out.h linux/include/asm-arm/arch-rpc/a.out.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/a.out.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/a.out.h	Sun Apr 12 11:42:15 1998
@@ -8,7 +8,7 @@
 #define __ASM_ARCH_A_OUT_H
 
 #ifdef __KERNEL__
-#define STACK_TOP		(0xc0000000)
+#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
 #define LIBRARY_START_TEXT	(0x00c00000)
 #endif
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/dma.h linux/include/asm-arm/arch-rpc/dma.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/dma.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/dma.h	Sun Apr 12 11:42:15 1998
@@ -1,128 +1,33 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-#define MAX_DMA_ADDRESS		0xd0000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static unsigned char arch_dma_setup;
-unsigned char arch_dma_ctrl[8];
-unsigned long arch_dma_addr[8];
-unsigned long arch_dma_cnt[8];
-
-static inline void arch_enable_dma(int dmanr)
-{
-  if (!(arch_dma_setup & (1 << dmanr))) {
-    arch_dma_setup |= 1 << dmanr;
-/*    dma_interrupt (16 + dmanr);*/
-  }
-  arch_dma_ctrl[dmanr] |= DMA_CR_E;
-  switch (dmanr) {
-    case 0: outb (arch_dma_ctrl[0], IOMD_IO0CR); break;
-    case 1: outb (arch_dma_ctrl[1], IOMD_IO1CR); break;
-    case 2: outb (arch_dma_ctrl[2], IOMD_IO2CR); break;
-    case 3: outb (arch_dma_ctrl[3], IOMD_IO3CR); break;
-    case 4: outb (arch_dma_ctrl[4], IOMD_SD0CR); break;
-    case 5: outb (arch_dma_ctrl[5], IOMD_SD1CR); break;
-  }
-}
-
-static inline void arch_disable_dma(int dmanr)
-{
-  arch_dma_ctrl[dmanr] &= ~DMA_CR_E;
-  switch (dmanr) {
-    case 0: outb (arch_dma_ctrl[0], IOMD_IO0CR); break;
-    case 1: outb (arch_dma_ctrl[1], IOMD_IO1CR); break;
-    case 2: outb (arch_dma_ctrl[2], IOMD_IO2CR); break;
-    case 3: outb (arch_dma_ctrl[3], IOMD_IO3CR); break;
-    case 4: outb (arch_dma_ctrl[4], IOMD_SD0CR); break;
-    case 5: outb (arch_dma_ctrl[5], IOMD_SD1CR); break;
-  }
-}
-
-static inline void arch_set_dma_addr(int dmanr, unsigned int addr)
-{
-  arch_dma_setup &= ~dmanr;
-  arch_dma_addr[dmanr] = addr;
-}
-
-static inline void arch_set_dma_count(int dmanr, unsigned int count)
-{
-  arch_dma_setup &= ~dmanr;
-  arch_dma_cnt[dmanr] = count;
-}
-
-static inline void arch_set_dma_mode(int dmanr, char mode)
-{
-  switch (mode) {
-  case DMA_MODE_READ:
-    arch_dma_ctrl[dmanr] |= DMA_CR_D;
-    break;
-  case DMA_MODE_WRITE:
-    arch_dma_ctrl[dmanr] &= ~DMA_CR_D;
-    break;
-  }
-}
-
-static inline int arch_dma_count (int dmanr)
-{
-  return arch_dma_cnt[dmanr];
-}
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-    switch(dmanr) {
-    	case 1:  break;
-	case 2:  disable_irq(64); break;
-	default: printk(dma_str, "disable_dma", dmanr); break;
-    }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-#define clear_dma_ff(dmanr)
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
  */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
-    printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
+#define MAX_DMA_ADDRESS		0xd0000000
 
-/* Set transfer size for a specific DMA channel.
+/*
+ * DMA modes - we have two, IN and OUT
  */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
+typedef enum {
+	DMA_MODE_READ,
+	DMA_MODE_WRITE
+} dmamode_t;
+
+#define MAX_DMA_CHANNELS	8
+
+#define DMA_0			0
+#define DMA_1			1
+#define DMA_2			2
+#define DMA_3			3
+#define DMA_S0			4
+#define DMA_S1			5
+#define DMA_VIRTUAL_FLOPPY	6
+#define DMA_VIRTUAL_SOUND	7
 
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
+#define DMA_FLOPPY		DMA_VIRTUAL_FLOPPY
 
 #endif /* _ASM_ARCH_DMA_H */
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/hardware.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/hardware.h	Sun Apr 12 11:42:15 1998
@@ -85,6 +85,7 @@
 #define KERNEL_BASE		(PAGE_OFFSET + KERNEL_OFFSET)
 #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
 #define Z_PARAMS_BASE		(RAM_START + PARAMS_OFFSET)
+#define SAFE_ADDR		0x00000000	/* ROM */
 
 #else
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/io.h linux/include/asm-arm/arch-rpc/io.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/io.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/io.h	Sun Apr 12 11:42:16 1998
@@ -10,16 +10,6 @@
 #define __ASM_ARM_ARCH_IO_H
 
 /*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define virt_to_bus(x)	((unsigned long)(x))
-#define bus_to_virt(x)	((void *)(x))
-
-/*
  * This architecture does not require any delayed IO, and
  * has the constant-optimised IO
  */
@@ -174,14 +164,7 @@
 })
 
 #define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	if (__PORT_PCIO((port)))						\
-		addr = PCIO_BASE + ((port) << 2);				\
-	else									\
-		addr = IO_BASE + ((port) << 2);					\
-	addr;									\
-})
+	(__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2))
 
 /*
  * Translated address IO functions
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/irq.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/irq.h	Sun Apr 12 11:42:16 1998
@@ -131,8 +131,4 @@
 	outb(0, IOMD_IRQMASKB);
 	outb(0, IOMD_FIQMASK);
 	outb(0, IOMD_DMAMASK);
-	outb(0, IOMD_IO0CR);
-	outb(0, IOMD_IO1CR);
-	outb(0, IOMD_IO2CR);
-	outb(0, IOMD_IO3CR);
 }
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/irqs.h linux/include/asm-arm/arch-rpc/irqs.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/irqs.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/irqs.h	Sun Apr 12 11:42:16 1998
@@ -21,8 +21,17 @@
 #define IRQ_KEYBOARDTX		14
 #define IRQ_KEYBOARDRX		15
 
+#define IRQ_DMA0		16
+#define IRQ_DMA1		17
+#define IRQ_DMA2		18
+#define IRQ_DMA3		19
+#define IRQ_DMAS0		20
+#define IRQ_DMAS1		21
+
 #define FIQ_FLOPPYDATA		0
 #define FIQ_ECONET		2
 #define FIQ_SERIALPORT		4
 #define FIQ_EXPANSIONCARD	6
 #define FIQ_FORCE		7
+
+#define IRQ_TIMER		IRQ_TIMER0
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/keyboard.h linux/include/asm-arm/arch-rpc/keyboard.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/keyboard.h	Sun Apr 12 11:42:16 1998
@@ -0,0 +1,38 @@
+/*
+ * linux/include/asm-arm/arch-rpc/keyboard.h
+ *
+ * Keyboard driver definitions for RiscPC architecture
+ *
+ * (C) 1998 Russell King
+ */
+
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+extern int ps2kbd_pretranslate(unsigned char scancode);
+extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
+extern void ps2kbd_leds(unsigned char leds);
+extern void ps2kbd_init_hw(void);
+extern unsigned char ps2kbd_sysrq_xlate[NR_SCANCODES];
+
+#define kbd_setkeycode(sc,kc)		(-EINVAL)
+#define kbd_getkeycode(sc)		(-EINVAL)
+
+/* Prototype: int kbd_pretranslate(scancode, raw_mode)
+ * Returns  : 0 to ignore scancode
+ */
+#define kbd_pretranslate(sc,rm)		ps2kbd_pretranslate(sc)
+
+/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
+ * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
+ *            set to 0200 if scancode indicates release
+ */
+#define kbd_translate(sc, kcp, ufp, rm)	ps2kbd_translate(sc, kcp, ufp)
+#define kbd_unexpected_up(kc)		(0200)
+#define kbd_leds(leds)			ps2kbd_leds(leds)
+#define kbd_init_hw()			ps2kbd_init_hw()
+#define kbd_sysrq_xlate			ps2kbd_sysrq_xlate
+#define kbd_disable_irq()		disable_irq(IRQ_KEYBOARDRX)
+#define kbd_enable_irq()		enable_irq(IRQ_KEYBOARDRX)
+
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/mm-init.h linux/include/asm-arm/arch-rpc/mm-init.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/mm-init.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/mm-init.h	Sun Apr 12 11:42:16 1998
@@ -0,0 +1,47 @@
+/*
+ * linux/include/asm-arm/arch-rpc/mmap.h
+ *
+ * Copyright (C) 1996 Russell King
+ */
+
+#define HAVE_MAP_VID_MEM
+
+unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
+{
+	static int updated = 0;
+	unsigned long address;
+	pgd_t *pgd;
+
+	if (updated)
+		return 0;
+	updated = update;
+
+	address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
+	pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
+	pgd_val(pgd[0]) = address;
+	pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
+
+	if (update) {
+		unsigned long pgtable = PAGE_ALIGN(kmem), *p;
+		int i;
+
+		memzero ((void *)pgtable, 4096);
+		
+		pgd_val(pgd[-2]) = __virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
+		pgd_val(pgd[-1]) = __virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
+		p = (unsigned long *)pgtable;
+
+		i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
+		address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
+
+		while (i < PTRS_PER_PTE * 2) {
+			p[i++] = address;
+			address += PAGE_SIZE;
+		}
+
+		flush_page_to_ram(pgtable);
+
+		kmem = pgtable + PAGE_SIZE;
+	}
+	return kmem;
+}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/mmap.h linux/include/asm-arm/arch-rpc/mmap.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/mmap.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/mmap.h	Wed Dec 31 16:00:00 1969
@@ -1,48 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmap.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define HAVE_MAP_VID_MEM
-#define SAFE_ADDR 0x00000000	/* ROM */
-
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-	static int updated = 0;
-	unsigned long address;
-	pgd_t *pgd;
-
-	if (updated)
-		return 0;
-	updated = update;
-
-	address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-	pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
-	pgd_val(pgd[0]) = address;
-	pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
-
-	if (update) {
-		unsigned long pgtable = PAGE_ALIGN(kmem), *p;
-		int i;
-
-		memzero ((void *)pgtable, 4096);
-		
-		pgd_val(pgd[-2]) = virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-		pgd_val(pgd[-1]) = virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
-		p = (unsigned long *)pgtable;
-
-		i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
-		address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
-
-		while (i < PTRS_PER_PTE * 2) {
-			p[i++] = address;
-			address += PAGE_SIZE;
-		}
-
-		flush_page_to_ram(pgtable);
-
-		kmem = pgtable + PAGE_SIZE;
-	}
-	return kmem;
-}
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/mmu.h linux/include/asm-arm/arch-rpc/mmu.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/mmu.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/mmu.h	Sun Apr 12 11:42:16 1998
@@ -7,11 +7,21 @@
  *  20-10-1996	RMK	Created
  *  31-12-1997	RMK	Fixed definitions to reduce warnings
  *  11-01-1998	RMK	Uninlined to reduce hits on cache
+ *  08-02-1998	RMK	Added __virt_to_bus and __bus_to_virt
  */
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
 extern unsigned long __virt_to_phys(unsigned long vpage);
 extern unsigned long __phys_to_virt(unsigned long ppage);
+
+/*
+ * These are exactly the same on the RiscPC as the
+ * physical memory view.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) __phys_to_virt(x)
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/processor.h linux/include/asm-arm/arch-rpc/processor.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/processor.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/processor.h	Sun Apr 12 11:42:16 1998
@@ -29,6 +29,6 @@
 #define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
 
 #define INIT_MMAP \
-{ &init_mm, 0xc0000000, 0xc2000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
+{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/arch-rpc/uncompress.h linux/include/asm-arm/arch-rpc/uncompress.h
--- v2.1.95/linux/include/asm-arm/arch-rpc/uncompress.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/uncompress.h	Sun Apr 12 11:42:16 1998
@@ -77,7 +77,7 @@
 			}
 		} else {
 			ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
-			ll_write_char(ptr, c|(white<<8));
+			ll_write_char(ptr, c|(white<<16));
 			if ( ++x >= video_num_columns ) {
 				x = 0;
 				if ( ++y >= video_num_lines ) {
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h
--- v2.1.95/linux/include/asm-arm/dma.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/dma.h	Sun Apr 12 11:42:16 1998
@@ -1,28 +1,105 @@
 #ifndef __ASM_ARM_DMA_H
 #define __ASM_ARM_DMA_H
 
-#include <asm/irq.h>
+typedef unsigned int dmach_t;
 
-#define MAX_DMA_CHANNELS	14
-#define DMA_0			8
-#define DMA_1			9
-#define DMA_2			10
-#define DMA_3			11
-#define DMA_S0			12
-#define DMA_S1			13
+#include <asm/irq.h>
+#include <asm/arch/dma.h>
 
-#define DMA_MODE_READ		0x44
-#define DMA_MODE_WRITE		0x48
+typedef struct {
+	unsigned long address;
+	unsigned long length;
+} dmasg_t;
 
 extern const char dma_str[];
 
-#include <asm/arch/dma.h>
-
-/* These are in kernel/dma.c: */
-/* reserve a DMA channel */
-extern int request_dma(unsigned int dmanr, const char * device_id);
-/* release it again */
-extern void free_dma(unsigned int dmanr);
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ *
+ * NOTE: This is an architecture specific function, and should
+ *       be hidden from the drivers.
+ */
+#define clear_dma_ff(channel)
+
+/* Set only the page register bits of the transfer address.
+ *
+ * NOTE: This is an architecture specific function, and should
+ *       be hidden from the drivers
+ */
+static __inline__ void set_dma_page(dmach_t channel, char pagenr)
+{
+	printk(dma_str, "set_dma_page", channel);
+}
+
+/* Request a DMA channel
+ *
+ * Some architectures may need to do allocate an interrupt
+ */
+extern int  request_dma(dmach_t channel, const char * device_id);
+
+/* Free a DMA channel
+ *
+ * Some architectures may need to do free an interrupt
+ */
+extern void free_dma(dmach_t channel);
+
+/* Enable DMA for this channel
+ *
+ * On some architectures, this may have other side effects like
+ * enabling an interrupt and setting the DMA registers.
+ */
+extern void enable_dma(dmach_t channel);
+
+/* Disable DMA for this channel
+ *
+ * On some architectures, this may have other side effects like
+ * disabling an interrupt or whatever.
+ */
+extern void disable_dma(dmach_t channel);
+
+/* Set the DMA scatter gather list for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA address immediately, but defer it to the enable_dma().
+ */
+extern void set_dma_sg(dmach_t channel, dmasg_t *sg, int nr_sg);
+
+/* Set the DMA address for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA address immediately, but defer it to the enable_dma().
+ */
+extern void set_dma_addr(dmach_t channel, unsigned long physaddr);
+
+/* Set the DMA byte count for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA count immediately, but defer it to the enable_dma().
+ */
+extern void set_dma_count(dmach_t channel, unsigned long count);
+
+/* Set the transfer direction for this channel
+ *
+ * This should not be called if a DMA channel is enabled,
+ * especially since some DMA architectures don't update the
+ * DMA transfer direction immediately, but defer it to the
+ * enable_dma().
+ */
+extern void set_dma_mode(dmach_t channel, dmamode_t mode);
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ */
+extern int  get_dma_residue(dmach_t channel);
+
+#ifndef NO_DMA
+#define NO_DMA	255
+#endif
 
 #endif /* _ARM_DMA_H */
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/ecard.h linux/include/asm-arm/ecard.h
--- v2.1.95/linux/include/asm-arm/ecard.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/ecard.h	Sun Apr 12 11:42:16 1998
@@ -16,7 +16,8 @@
 #define __ASM_ECARD_H
 
 /*
- * Currently understood cards
+ * Currently understood cards (but not necessarily
+ * supported):
  *                        Manufacturer  Product ID
  */
 #define MANU_ACORN		0x0000
@@ -60,6 +61,8 @@
 #define MANU_MCS		0x0063
 #define PROD_MCS_CONNECT32		0x0125
 
+#define MANU_EESOX		0x0064
+#define PROD_EESOX_SCSI2		0x008c
 
 
 #ifdef ECARD_C
@@ -72,8 +75,9 @@
 
 /* Type of card's address space */
 typedef enum {
-	ECARD_IOC  = 0,
-	ECARD_MEMC = 1
+	ECARD_IOC,
+	ECARD_MEMC,
+	ECARD_DEBI
 } card_type_t;
 
 /* Speed of card for ECARD_IOC address space */
@@ -124,10 +128,12 @@
 	unsigned char		irqmask;	/* IRQ mask			*/
 	unsigned char		fiqmask;	/* FIQ mask			*/
 	unsigned char  		claimed;	/* Card claimed?		*/
+
 	CONST unsigned char	slot_no;	/* Slot number			*/
+	CONST unsigned char	dma;		/* DMA number (for request_dma)	*/
 	CONST unsigned char	irq;		/* IRQ number (for request_irq)	*/
 	CONST unsigned char	fiq;		/* FIQ number (for request_irq)	*/
-	CONST unsigned short	unused;
+
 	CONST struct in_ecld	cld;		/* Card Identification		*/
 	void			*irq_data;	/* Data for use for IRQ by card	*/
 	void			*fiq_data;	/* Data for use for FIQ by card	*/
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/elf.h linux/include/asm-arm/elf.h
--- v2.1.95/linux/include/asm-arm/elf.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/elf.h	Sun Apr 12 11:42:16 1998
@@ -38,6 +38,23 @@
 
 #define ELF_ET_DYN_BASE	(2 * TASK_SIZE / 3)
 
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  This could be done in userspace,
+   but it's not easy, and we've already done it here.  */
+
+#define ELF_HWCAP	(0)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo. */
+
+#define ELF_PLATFORM	(NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex,ibcs2) \
+	current->personality = PER_LINUX_32BIT
+#endif
+
 #define R_ARM_NONE	(0)
 #define R_ARM_32	(1)	/* => ld 32 */
 #define R_ARM_PC26	(2)	/* => ld b/bl branches */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.1.95/linux/include/asm-arm/hardirq.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/hardirq.h	Sun Apr 12 11:42:16 1998
@@ -4,7 +4,6 @@
 #include <linux/tasks.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
 
 #ifndef __SMP__
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h
--- v2.1.95/linux/include/asm-arm/hardware.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/hardware.h	Sun Apr 12 11:42:16 1998
@@ -140,6 +140,11 @@
 #define IOMD_ECTCR	__IOMD(0x0C8)
 #define IOMD_DMAEXT	__IOMD(0x0CC)
 
+#define DMA_EXT_IO0	1
+#define DMA_EXT_IO1	2
+#define DMA_EXT_IO2	4
+#define DMA_EXT_IO3	8
+
 #define IOMD_IO0CURA	__IOMD(0x100)
 #define IOMD_IO0ENDA	__IOMD(0x104)
 #define IOMD_IO0CURB	__IOMD(0x108)
@@ -194,6 +199,9 @@
 #define IOMD_DMASTAT	__IOMD(0x1F0)
 #define IOMD_DMAREQ	__IOMD(0x1F4)
 #define IOMD_DMAMASK	__IOMD(0x1F8)
+
+#define DMA_END_S	(1 << 31)
+#define DMA_END_L	(1 << 30)
 
 #define DMA_CR_C	0x80
 #define DMA_CR_D	0x40
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.1.95/linux/include/asm-arm/io.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/io.h	Sun Apr 12 11:42:16 1998
@@ -17,10 +17,20 @@
 #include <asm/arch/io.h>
 
 /* unsigned long virt_to_phys(void *x) */
-#define virt_to_phys(x)		__virt_to_phys((unsigned long)(x))
+#define virt_to_phys(x)		(__virt_to_phys((unsigned long)(x)))
 
 /* void *phys_to_virt(unsigned long x) */
 #define phys_to_virt(x)		((void *)(__phys_to_virt((unsigned long)(x))))
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define virt_to_bus(x)	(__virt_to_bus((unsigned long)(x)))
+#define bus_to_virt(x)	((void *)(__bus_to_virt(x)))
 
 /*
  * These macros actually build the multi-value IO function prototypes
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/irq-no.h linux/include/asm-arm/irq-no.h
--- v2.1.95/linux/include/asm-arm/irq-no.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/irq-no.h	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-/*
- * linux/include/asm-arm/irq-no.h
- *
- * Machine independent interrupt numbers
- */
-
-#include <asm/arch/irqs.h>
-
-#ifndef NR_IRQS
-#define NR_IRQS		128
-#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/irq.h linux/include/asm-arm/irq.h
--- v2.1.95/linux/include/asm-arm/irq.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/irq.h	Sun Apr 12 11:42:16 1998
@@ -1,7 +1,19 @@
 #ifndef __ASM_ARM_IRQ_H
 #define __ASM_ARM_IRQ_H
 
-#include <asm/irq-no.h>
+#include <asm/arch/irqs.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS	128
+#endif
+
+/*
+ * Use this value to indicate lack of interrupt
+ * capability
+ */
+#ifndef NO_IRQ
+#define NO_IRQ	255
+#endif
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/keyboard.h linux/include/asm-arm/keyboard.h
--- v2.1.95/linux/include/asm-arm/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/keyboard.h	Sun Apr 12 11:42:16 1998
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/keyboard.h
+ *
+ * Keyboard driver definitions for ARM
+ *
+ * (C) 1998 Russell King
+ */
+#ifndef __ASM_ARM_KEYBOARD_H
+#define __ASM_ARM_KEYBOARD_H
+
+/*
+ * We provide a unified keyboard interface when in VC_MEDIUMRAW
+ * mode.  This means that all keycodes must be common between
+ * all supported keyboards.  This unfortunately puts us at odds
+ * with the PC keyboard interface chip... but we can't do anything
+ * about that now.
+ */
+#ifdef __KERNEL__
+
+#include <asm/arch/keyboard.h>
+
+#define SYSRQ_KEY 13
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_ARM_KEYBOARD_H */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/leds.h linux/include/asm-arm/leds.h
--- v2.1.95/linux/include/asm-arm/leds.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/leds.h	Sun Apr 12 11:42:16 1998
@@ -0,0 +1,20 @@
+/*
+ * include/asm-arm/leds.h
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * Event-driven interface for LEDs on machines
+ */
+#ifndef ASM_ARM_LEDS_H
+#define ASM_ARM_LEDS_H
+
+typedef enum {
+	led_idle_start,
+	led_idle_end,
+	led_timer
+} led_event_t;
+
+/* Use this routine to handle LEDs */
+extern void leds_event(led_event_t);
+
+#endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h
--- v2.1.95/linux/include/asm-arm/proc-armo/processor.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/processor.h	Sun Apr 12 11:42:16 1998
@@ -113,6 +113,15 @@
 	flush_tlb_mm(current->mm);					\
 })
 
+/* Allocation and freeing of basic task resources. */
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+	((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define free_task_struct(p)    free_pages((unsigned long)(p),1)
+
+
 #endif
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/mm-init.h linux/include/asm-arm/proc-armv/mm-init.h
--- v2.1.95/linux/include/asm-arm/proc-armv/mm-init.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/mm-init.h	Sun Apr 12 11:42:16 1998
@@ -35,76 +35,120 @@
  *
  * We set it up using the section page table entries.
  */
-
-#include <asm/arch/mmap.h>
 #include <asm/pgtable.h>
  
-#define V2P(x)	virt_to_phys(x)
 #define PTE_SIZE (PTRS_PER_PTE * 4)
 
-#define PMD_SECT	(PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_CACHEABLE)
+extern unsigned long setup_io_pagetables(unsigned long start_mem);
 
-static inline void setup_swapper_dir (int index, unsigned long entry)
+/*
+ * Add a SECTION mapping between VIRT and PHYS in domain DOMAIN with protection PROT
+ */
+static inline void
+alloc_init_section(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
 {
-	pmd_t pmd;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+
+	pgdp = pgd_offset_k(virt);
+	pmdp = pmd_offset(pgdp, virt);
 
-	pmd_val(pmd) = entry;
-	set_pmd (pmd_offset (swapper_pg_dir + index, 0), pmd);
+	pmd_val(*pmdp) = phys | PMD_TYPE_SECT | PMD_DOMAIN(domain) | prot;
 }
 
-static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem)
+/*
+ * Clear any mapping
+ */
+static inline void
+free_init_section(unsigned long virt)
 {
-	unsigned long address;
-	unsigned int spi;
-	union { unsigned long l; unsigned long *p; } u;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+
+	pgdp = pgd_offset_k(virt);
+	pmdp = pmd_offset(pgdp, virt);
+
+	pmd_clear(pmdp);
+}
+
+/*
+ * Add a PAGE mapping between VIRT and PHYS in domain DOMAIN with protection PROT
+ */
+static inline void
+alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	pgdp = pgd_offset_k(virt);
+	pmdp = pmd_offset(pgdp, virt);
 
-	/* map in zero page */
-	u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1));
-	start_mem = u.l + PTE_SIZE;
-	memzero (u.p, PTE_SIZE);
-	*u.p = V2P(PAGE_OFFSET) | PTE_CACHEABLE | PTE_TYPE_SMALL;
-	setup_swapper_dir (0, V2P(u.l) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER));
-
-	for (spi = 1; spi < (PAGE_OFFSET >> PGDIR_SHIFT); spi++)
-		pgd_val(swapper_pg_dir[spi]) = 0;
-
-	/* map in physical ram & kernel */
-	address = PAGE_OFFSET;
-	while (spi < end_mem >> PGDIR_SHIFT) {
-		setup_swapper_dir (spi++,
-				V2P(address) | PMD_SECT |
-				PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
-		address += PGDIR_SIZE;
+	if (pmd_none(*pmdp)) {
+		unsigned long memory = *mem;
+
+		memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1);
+
+		ptep = (pte_t *)memory;
+		memzero(ptep, PTE_SIZE);
+
+		pmd_val(*pmdp) = __virt_to_phys(memory) | PMD_TYPE_TABLE | PMD_DOMAIN(domain);
+
+		*mem = memory + PTE_SIZE;
 	}
-	while (spi < PTRS_PER_PGD)
-		pgd_val(swapper_pg_dir[spi++]) = 0;
+
+	ptep = pte_offset(pmdp, virt);
+
+	pte_val(*ptep) = phys | prot | PTE_TYPE_SMALL;
+}
+
+static inline unsigned long
+setup_pagetables(unsigned long start_mem, unsigned long end_mem)
+{
+	unsigned long address;
 
 	/*
-	 * An area to invalidate the cache
+	 * map in zero page
 	 */
-	setup_swapper_dir (0xdf0, SAFE_ADDR | PMD_SECT | PMD_SECT_AP_READ);
+	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET), DOMAIN_USER, PTE_CACHEABLE);
 
-	/* map in IO */
-	address = IO_START;
-	spi = IO_BASE >> PGDIR_SHIFT;
-	pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT |
-					 PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
-	while (address < IO_START + IO_SIZE && address) {
-		pgd_val(swapper_pg_dir[spi++]) = address |
-						PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_IO) |
-						PMD_SECT_AP_WRITE;
-		address += PGDIR_SIZE;
-	}
+	/*
+	 * ensure no mappings in user space
+	 */
+	for (address = PGDIR_SIZE; address < PAGE_OFFSET; address += PGDIR_SIZE)
+		free_init_section(address);
+
+	/*
+	 * map in physical ram & kernel
+	 */
+	for (address = PAGE_OFFSET; address < end_mem; address += PGDIR_SIZE)
+		alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
+				   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
+
+	/*
+	 * unmap everything else
+	 */
+	for (address = end_mem; address; address += PGDIR_SIZE)
+		free_init_section(address);
 
-#ifdef HAVE_MAP_VID_MEM
-	map_screen_mem(0, 0, 0);
-#endif
+	/*
+	 * An area to invalidate the cache
+	 */
+	alloc_init_section(&start_mem, 0xdf000000, SAFE_ADDR, DOMAIN_KERNEL,
+			   PMD_SECT_CACHEABLE | PMD_SECT_AP_READ);
+
+	/*
+	 * Now set up our IO mappings
+	 */
+	start_mem = setup_io_pagetables(start_mem);
 
 	flush_cache_all();
+
 	return start_mem;
 }
 
-static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
+static inline
+void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
 {
 	unsigned long smem;
 
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.1.95/linux/include/asm-arm/proc-armv/pgtable.h	Wed Apr  8 19:36:28 1998
+++ linux/include/asm-arm/proc-armv/pgtable.h	Sun Apr 12 11:42:16 1998
@@ -178,17 +178,29 @@
 
 /*
  * We define the bits in the page tables as follows:
- *  PTE_BUFFERABLE	page is dirty
- *  PTE_AP_WRITE	page is writable
+ *  PTE_BUFFERABLE	page is writable
+ *  PTE_AP_WRITE	page is dirty
  *  PTE_AP_READ		page is a young (unsetting this causes faults for any access)
  *
  * Any page that is mapped in is assumed to be readable...
  */
-#define PAGE_NONE       __pgprot(PTE_TYPE_SMALL)
-#define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_AP_READ | PTE_AP_WRITE)
-#define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_AP_READ)
-#define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_AP_READ)
-#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | PTE_CACHEABLE | PTE_BUFFERABLE | PTE_AP_WRITE)
+#if 0
+#define _PTE_YOUNG	PTE_AP_READ
+#define _PTE_DIRTY	PTE_AP_WRITE
+#define _PTE_READ	PTE_CACHEABLE
+#define _PTE_WRITE	PTE_BUFFERABLE
+#else
+#define _PTE_YOUNG	PTE_CACHEABLE
+#define _PTE_DIRTY	PTE_BUFFERABLE
+#define _PTE_READ	PTE_AP_READ
+#define _PTE_WRITE	PTE_AP_WRITE
+#endif
+
+#define PAGE_NONE       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG)
+#define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ | _PTE_WRITE)
+#define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
+#define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
+#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_DIRTY | _PTE_WRITE)
 
 #define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
 #define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
@@ -249,7 +261,7 @@
 /* to set the page-dir */
 #define SET_PAGE_DIR(tsk,pgdir)					\
 do {								\
-	tsk->tss.memmap = __virt_to_phys(pgdir);		\
+	tsk->tss.memmap = __virt_to_phys((unsigned long)pgdir);	\
 	if ((tsk) == current)					\
 		__asm__ __volatile__(				\
 		"mcr%?	p15, 0, %0, c2, c0, 0\n"		\
@@ -276,7 +288,7 @@
 		return 0;
 	}
 #else
-	return ((pte_val(pmd) + 1) & PMD_TYPE_MASK);
+	return ((pte_val(pte) + 1) & 2);
 #endif
 }
 
@@ -300,18 +312,24 @@
 		return 1;
 	}
 #else
-	return (pmd_val(pmd) & PMD_TYPE_SECT);
+	return pmd_val(pmd) & 2;
 #endif
 }
 
 extern __inline__ int pmd_present(pmd_t pmd)
 {
+#if 0
+	/* This is what it really does, the else
+	   part is just to make it easier for the compiler */
 	switch (pmd_val(pmd) & PMD_TYPE_MASK) {
 	case PMD_TYPE_TABLE:
 		return 1;
 	default:
 		return 0;
 	}
+#else
+	return ((pmd_val(pmd) + 1) & 2);
+#endif
 }
 
 /*
@@ -336,19 +354,14 @@
 	return pte_val(pte) & PTE_AP_WRITE;
 }
 
-extern __inline__ int pte_cacheable(pte_t pte)
-{
-	return pte_val(pte) & PTE_CACHEABLE;
-}
-
 extern __inline__ int pte_dirty(pte_t pte)
 {
-	return pte_val(pte) & PTE_BUFFERABLE;
+	return pte_val(pte) & _PTE_DIRTY;
 }
 
 extern __inline__ int pte_young(pte_t pte)
 {
-	return pte_val(pte) & PTE_AP_READ;
+	return pte_val(pte) & _PTE_YOUNG;
 }
 
 extern __inline__ pte_t pte_wrprotect(pte_t pte)
@@ -455,7 +468,7 @@
 
 extern __inline__ unsigned long pte_page(pte_t pte)
 {
-	return (unsigned long)phys_to_virt(pte_val(pte) & PAGE_MASK);
+	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
 }
 
 extern __inline__ pmd_t mk_user_pmd(pte_t *ptep)
@@ -484,7 +497,7 @@
 
 extern __inline__ unsigned long pmd_page(pmd_t pmd)
 {
-	return (unsigned long)phys_to_virt(pmd_val(pmd) & 0xfffffc00);
+	return __phys_to_virt(pmd_val(pmd) & 0xfffffc00);
 }
 
 /* to find an entry in a kernel page-table-directory */
@@ -513,13 +526,14 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
- 
+
 #ifndef __SMP__
 extern struct pgtable_cache_struct {
 	unsigned long *pgd_cache;
 	unsigned long *pte_cache;
 	unsigned long pgtable_cache_sz;
 } quicklists;
+
 #define pgd_quicklist (quicklists.pgd_cache)
 #define pmd_quicklist ((unsigned long *)0)
 #define pte_quicklist (quicklists.pte_cache)
@@ -596,8 +610,8 @@
 {
 }
 
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pte_kernel(pmd_t *pmd);
+extern void __bad_pmd(pmd_t *pmd);
+extern void __bad_pmd_kernel(pmd_t *pmd);
 
 #define pte_free_kernel(pte)	free_pte_fast(pte)
 #define pte_free(pte)		free_pte_fast(pte)
@@ -616,7 +630,7 @@
 		return page + address;
 	}
 	if (pmd_bad(*pmd)) {
-		__bad_pte_kernel(pmd);
+		__bad_pmd_kernel(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -628,14 +642,14 @@
 
 	if (pmd_none(*pmd)) {
 		pte_t *page = (pte_t *) get_pte_fast();
-		
+
 		if (!page)
 			return get_pte_slow(pmd, address);
-		set_pmd(pmd, mk_user_pmd(page);
+		set_pmd(pmd, mk_user_pmd(page));
 		return page + address;
 	}
 	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
+		__bad_pmd(pmd);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -654,9 +668,10 @@
 	return (pmd_t *) pgd;
 }
 
-#define pmd_free_kernel         pmd_free
-#define pmd_alloc_kernel        pmd_alloc
+#define pmd_free_kernel		pmd_free
+#define pmd_alloc_kernel	pmd_alloc
 
+#if 0
 extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
 {
 	struct task_struct * p;
@@ -672,6 +687,7 @@
 	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
 		pgd[address >> PGDIR_SHIFT] = entry;
 }
+#endif
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
@@ -689,4 +705,3 @@
 #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
 
 #endif /* __ASM_PROC_PAGE_H */
-
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h
--- v2.1.95/linux/include/asm-arm/proc-armv/processor.h	Wed Apr  8 19:36:28 1998
+++ linux/include/asm-arm/proc-armv/processor.h	Sun Apr 12 11:42:16 1998
@@ -82,7 +82,10 @@
 	unsigned long *stack = (unsigned long *)sp;			\
 	set_fs(USER_DS);						\
 	memzero(regs->uregs, sizeof(regs->uregs));			\
-	regs->ARM_cpsr = sp <= 0x04000000 ? USR26_MODE : USR_MODE;	\
+	if (current->personality == PER_LINUX_32BIT)			\
+		regs->ARM_cpsr = USR_MODE;				\
+	else								\
+		regs->ARM_cpsr = USR26_MODE;				\
 	regs->ARM_pc = pc;		/* pc */			\
 	regs->ARM_sp = sp;		/* sp */			\
 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h
--- v2.1.95/linux/include/asm-arm/proc-armv/system.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/system.h	Sun Apr 12 11:42:16 1998
@@ -33,16 +33,13 @@
 /*
  * We can wait for an interrupt...
  */
-#if 0
 #define proc_idle()			\
 	do {				\
 	__asm__ __volatile__(		\
 "	mcr	p15, 0, %0, c15, c8, 2"	\
 	  : : "r" (0));			\
 	} while (0)
-#else
-#define proc_idle()
-#endif
+
 /*
  * A couple of speedups for the ARM
  */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/smp.h linux/include/asm-arm/smp.h
--- v2.1.95/linux/include/asm-arm/smp.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/smp.h	Sun Apr 12 11:42:16 1998
@@ -3,5 +3,10 @@
 
 #ifdef __SMP__
 #error SMP not supported
+#else
+
+#define cpu_logical_map(cpu) (cpu)
+
 #endif
+
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/socket.h linux/include/asm-arm/socket.h
--- v2.1.95/linux/include/asm-arm/socket.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/socket.h	Sun Apr 12 11:42:16 1998
@@ -28,6 +28,11 @@
 #define SO_RCVTIMEO	20
 #define SO_SNDTIMEO	21
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION		22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT	23
+#define SO_SECURITY_ENCRYPTION_NETWORK		24
+
 #define SO_BINDTODEVICE 25
 
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/softirq.h linux/include/asm-arm/softirq.h
--- v2.1.95/linux/include/asm-arm/softirq.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/softirq.h	Sun Apr 12 11:42:16 1998
@@ -4,6 +4,9 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
+extern unsigned int local_bh_count[NR_CPUS];
+#define in_bh()			(local_bh_count[smp_processor_id()] != 0)
+
 #define get_active_bhs()	(bh_mask & bh_active)
 #define clear_active_bhs(x)	atomic_clear_mask((int)(x),&bh_active)
 
@@ -25,44 +28,44 @@
 	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;
-}
-
 #ifdef __SMP__
 #error SMP not supported
 #else
 
-extern int __arm_bh_counter;
-
 extern inline void start_bh_atomic(void)
 {
-	__arm_bh_counter++;
+	local_bh_count[smp_processor_id()]++;
 	barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
 	barrier();
-	__arm_bh_counter--;
+	local_bh_count[smp_processor_id()]--;
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock()	(__arm_bh_counter ? 0 : (__arm_bh_counter=1))
-#define softirq_endlock()	(__arm_bh_counter = 0)
+#define softirq_trylock(cpu)	(in_bh() ? 0 : (local_bh_count[smp_processor_id()]=1))
+#define softirq_endlock(cpu)	(local_bh_count[smp_processor_id()] = 0)
+#define synchronize_bh()	do { } while (0)
 
 #endif	/* SMP */
+
+/*
+ * 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]++;
+	synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+}
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.1.95/linux/include/asm-arm/types.h linux/include/asm-arm/types.h
--- v2.1.95/linux/include/asm-arm/types.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/types.h	Sun Apr 12 11:42:16 1998
@@ -39,6 +39,8 @@
 typedef signed long long s64;
 typedef unsigned long long u64;
 
+#define BITS_PER_LONG 32
+
 #endif /* __KERNEL__ */
 
 #endif
diff -u --recursive --new-file v2.1.95/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.1.95/linux/include/asm-i386/processor.h	Wed Apr  1 20:11:54 1998
+++ linux/include/asm-i386/processor.h	Tue Apr 14 12:54:05 1998
@@ -189,8 +189,15 @@
 	regs->esp = new_esp; \
 } while (0)
 
+/* Forward declaration, a strange C thing */
+struct mm_struct;
+
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
+
+/* Copy and release all segment info associated with a VM */
+extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
+extern void release_segments(struct mm_struct * mm);
 
 /*
  * Return saved PC of a blocked thread.
diff -u --recursive --new-file v2.1.95/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.95/linux/include/asm-i386/system.h	Fri Apr 10 13:03:49 1998
+++ linux/include/asm-i386/system.h	Fri Apr 10 13:04:39 1998
@@ -138,8 +138,8 @@
 	 "d" (limit) \
 	:"dx")
 
-#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
-#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
+#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
 
 static inline unsigned long _get_base(char * addr)
 {
diff -u --recursive --new-file v2.1.95/linux/include/linux/cyclades.h linux/include/linux/cyclades.h
--- v2.1.95/linux/include/linux/cyclades.h	Tue Nov 11 11:04:15 1997
+++ linux/include/linux/cyclades.h	Fri Apr 10 15:35:00 1998
@@ -1,11 +1,21 @@
-/* $Revision: 2.1 $$Date: 1997/10/24 16:03:00 $
+/* $Revision: 2.3 $$Date: 1998/03/16 18:01:12 $
  * linux/include/linux/cyclades.h
  *
- * This file is maintained by Marcio Saito <marcio@cyclades.com> and
+ * This file is maintained by Ivan Passos <ivan@cyclades.com>, 
+ * Marcio Saito <marcio@cyclades.com> and
  * Randolph Bentson <bentson@grieg.seaslug.org>.
  *
  * This file contains the general definitions for the cyclades.c driver
  *$Log: cyclades.h,v $
+ *Revision 2.3  1998/03/16 18:01:12  ivan
+ *changes in the cyclades_port structure to get it closer to the 
+ *standard serial port structure;
+ *added constants for new ioctls;
+ *Revision 2.2  1998/02/17 16:50:00  ivan
+ *changes in the cyclades_port structure (addition of shutdown_wait and 
+ *chip_rev variables);
+ *added constants for new ioctls and for CD1400 rev. numbers.
+ *
  *Revision 2.1	1997/10/24 16:03:00  ivan
  *added rflow (which allows enabling the CD1400 special flow control 
  *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to 
@@ -58,10 +68,14 @@
 #define CYGETDEFTIMEOUT         0x435908
 #define CYSETDEFTIMEOUT         0x435909
 #define CYSETRFLOW		0x43590a
-#define CYRESETRFLOW		0x43590b
+#define CYGETRFLOW		0x43590b
 #define CYSETRTSDTR_INV		0x43590c
-#define CYRESETRTSDTR_INV	0x43590d
+#define CYGETRTSDTR_INV		0x43590d
 #define CYZPOLLCYCLE		0x43590e
+#define CYGETCD1400VER		0x43590f
+#define CYGETCARDINFO		0x435910
+#define	CYSETWAIT		0x435911
+#define	CYGETWAIT		0x435912
 
 /*************** CYCLOM-Z ADDITIONS ***************/
 
@@ -78,6 +92,8 @@
 #define MAX_PORT        128     /* Max number of ports per board */
 #define MAX_DEV         256     /* Max number of ports total */
 
+#define	CYZ_FIFO_SIZE	16
+
 #define CYZ_BOOT_NWORDS 0x100
 struct CYZ_BOOT_CTRL {
         unsigned short  nboard;
@@ -473,12 +489,13 @@
 
 struct cyclades_port {
 	int                     magic;
-	int                     type;
 	int			card;
 	int			line;
 	int			flags; 		/* defined in tty.h */
+	int                     type;		/* UART type */
 	struct tty_struct 	*tty;
 	int			read_status_mask;
+	int			ignore_status_mask;
 	int			timeout;
 	int			xmit_fifo_size;
 	int                     cor1,cor2,cor3,cor4,cor5;
@@ -486,13 +503,15 @@
 	int			baud;
 	int			rflow;
 	int			rtsdtr_inv;
-	int			ignore_status_mask;
+	int			chip_rev;
+	int			custom_divisor;
+	int                     x_char; /* to be pushed out ASAP */
 	int			close_delay;
-	int			IER; 	/* Interrupt Enable Register */
-	int			event;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
 	unsigned long		last_active;
 	int			count;	/* # of fd on device */
-	int                     x_char; /* to be pushed out ASAP */
 	int                     x_break;
 	int			blocked_open; /* # of blocked opens */
 	long			session; /* Session of opening process */
@@ -508,6 +527,7 @@
 	struct termios		callout_termios;
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
+	struct wait_queue	*shutdown_wait;
         struct cyclades_monitor mon;
 	unsigned long		jiffies[3];
 	unsigned long		rflush_count;
@@ -517,13 +537,14 @@
  * Events are used to schedule things to happen at timer-interrupt
  * time, instead of at cy interrupt time.
  */
-#define Cy_EVENT_READ_PROCESS	0
-#define Cy_EVENT_WRITE_WAKEUP	1
-#define Cy_EVENT_HANGUP		2
-#define Cy_EVENT_BREAK		3
-#define Cy_EVENT_OPEN_WAKEUP	4
-
+#define Cy_EVENT_READ_PROCESS		0
+#define Cy_EVENT_WRITE_WAKEUP		1
+#define Cy_EVENT_HANGUP			2
+#define Cy_EVENT_BREAK			3
+#define Cy_EVENT_OPEN_WAKEUP		4
+#define Cy_EVENT_SHUTDOWN_WAKEUP	5
 
+#define	CLOSING_WAIT_DELAY	30
 
 #define CyMAX_CHIPS_PER_CARD	8
 #define CyMAX_CHAR_FIFO		12
@@ -538,10 +559,13 @@
 
 /**** CD1400 registers ****/
 
-#define CyRegSize  0x0400
-#define Cy_HwReset 0x1400
-#define Cy_ClrIntr 0x1800
-#define Cy_EpldRev 0x1e00
+#define CD1400_REV_G	0x46
+#define CD1400_REV_J	0x48
+
+#define CyRegSize  	0x0400
+#define Cy_HwReset 	0x1400
+#define Cy_ClrIntr 	0x1800
+#define Cy_EpldRev 	0x1e00
 
 /* Global Registers */
 
diff -u --recursive --new-file v2.1.95/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.1.95/linux/include/linux/if_arp.h	Fri Feb  6 15:33:34 1998
+++ linux/include/linux/if_arp.h	Tue Apr 14 13:01:03 1998
@@ -64,6 +64,7 @@
 #define ARPHRD_PIMREG	779		/* PIMSM register interface	*/
 #define ARPHRD_HIPPI	780		/* High Performance Parallel Interface */
 #define ARPHRD_ASH	781		/* Nexus 64Mbps Ash		*/
+#define ARPHRD_ECONET	782		/* Acorn Econet			*/
 
 /* ARP protocol opcodes. */
 #define	ARPOP_REQUEST	1		/* ARP request			*/
diff -u --recursive --new-file v2.1.95/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.1.95/linux/include/linux/kernel.h	Tue Jan 20 16:51:56 1998
+++ linux/include/linux/kernel.h	Mon Apr 13 16:57:10 1998
@@ -69,10 +69,10 @@
  */
 
 #define NIPQUAD(addr) \
-	(((addr) >> 0)  & 0xff), \
-	(((addr) >> 8)  & 0xff), \
-	(((addr) >> 16) & 0xff), \
-	(((addr) >> 24) & 0xff)
+	(int)(((addr) >> 0)  & 0xff), \
+	(int)(((addr) >> 8)  & 0xff), \
+	(int)(((addr) >> 16) & 0xff), \
+	(int)(((addr) >> 24) & 0xff)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.95/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.1.95/linux/include/linux/parport.h	Tue Mar 10 10:03:35 1998
+++ linux/include/linux/parport.h	Sun Apr 12 11:39:20 1998
@@ -14,6 +14,7 @@
 #define PARPORT_IRQ_AUTO  -2
 #define PARPORT_DMA_AUTO  -2
 #define PARPORT_DISABLE   -2
+#define PARPORT_IRQ_PROBEONLY -3
 
 #define PARPORT_CONTROL_STROBE    0x1
 #define PARPORT_CONTROL_AUTOFD    0x2
@@ -291,6 +292,7 @@
 
 #define PARPORT_FLAG_COMA		1
 
+extern void parport_parse_irqs(int, const char *, int irqval[]);
 extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
 extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
 				   char);
diff -u --recursive --new-file v2.1.95/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.95/linux/include/linux/pci.h	Fri Apr 10 13:03:49 1998
+++ linux/include/linux/pci.h	Sat Apr 11 11:19:34 1998
@@ -935,6 +935,7 @@
 #define PCI_DEVICE_ID_KTI_ET32P2	0x3000
 
 #define PCI_VENDOR_ID_ADAPTEC		0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810	0x1078
 #define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
 #define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
diff -u --recursive --new-file v2.1.95/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.95/linux/include/linux/sched.h	Wed Apr  1 20:11:54 1998
+++ linux/include/linux/sched.h	Tue Apr 14 13:00:12 1998
@@ -168,6 +168,11 @@
 	unsigned long rss, total_vm, locked_vm;
 	unsigned long def_flags;
 	unsigned long cpu_vm_mask;
+	/*
+	 * This is an architecture-specific pointer: the portable
+	 * part of Linux does not know about any segments.
+	 */
+	void * segments;
 };
 
 #define INIT_MM {					\
@@ -178,7 +183,7 @@
 		0, 0, 0, 				\
 		0, 0, 0, 0,				\
 		0, 0, 0,				\
-		0, 0 }
+		0, 0, NULL }
 
 struct signal_struct {
 	atomic_t		count;
@@ -267,8 +272,6 @@
 /* ipc stuff */
 	struct sem_undo *semundo;
 	struct sem_queue *semsleeping;
-/* ldt for this task - used by Wine.  If NULL, default_ldt is used */
-	struct desc_struct *ldt;
 /* tss for this task */
 	struct thread_struct tss;
 /* filesystem information */
@@ -357,7 +360,6 @@
 /* comm */	"swapper", \
 /* fs info */	0,NULL, \
 /* ipc */	NULL, NULL, \
-/* ldt */	NULL, \
 /* tss */	INIT_TSS, \
 /* fs */	&init_fs, \
 /* files */	&init_files, \
diff -u --recursive --new-file v2.1.95/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.95/linux/include/linux/socket.h	Thu Mar 26 15:57:06 1998
+++ linux/include/linux/socket.h	Sat Apr 11 17:18:15 1998
@@ -150,6 +150,7 @@
 #define AF_ROUTE	AF_NETLINK /* Alias to emulate 4.4BSD */
 #define AF_PACKET	17	/* Packet family		*/
 #define AF_ASH		18	/* Ash				*/
+#define AF_ECONET	19	/* Acorn Econet			*/
 #define AF_MAX		32	/* For now.. */
 
 /* Protocol families, same as address families. */
diff -u --recursive --new-file v2.1.95/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.95/linux/include/linux/sysctl.h	Wed Apr  1 20:11:54 1998
+++ linux/include/linux/sysctl.h	Sat Apr 11 17:18:15 1998
@@ -153,6 +153,7 @@
 	NET_IPV4_TCP_TIMESTAMPS,
 	NET_IPV4_TCP_WINDOW_SCALING,
 	NET_IPV4_TCP_SACK,
+	NET_IPV4_TCP_RETRANS_COLLAPSE,
 	NET_IPV4_DEFAULT_TTL,
 	NET_IPV4_AUTOCONFIG,
 	NET_IPV4_NO_PMTU_DISC,
diff -u --recursive --new-file v2.1.95/linux/include/linux/tcp.h linux/include/linux/tcp.h
--- v2.1.95/linux/include/linux/tcp.h	Fri Feb  6 15:33:34 1998
+++ linux/include/linux/tcp.h	Tue Apr 14 13:01:03 1998
@@ -65,8 +65,13 @@
   TCP_CLOSE_WAIT,
   TCP_LAST_ACK,
   TCP_LISTEN,
-  TCP_CLOSING	/* now a valid state */
+  TCP_CLOSING,	 /* now a valid state */
+
+  TCP_MAX_STATES /* Leave at the end! */
 };
+
+#define TCP_STATE_MASK	0xF
+#define TCP_ACTION_FIN	1 << 7
 
 enum {
   TCPF_ESTABLISHED = (1 << 1),
diff -u --recursive --new-file v2.1.95/linux/include/net/ipx.h linux/include/net/ipx.h
--- v2.1.95/linux/include/net/ipx.h	Mon Feb 23 18:12:12 1998
+++ linux/include/net/ipx.h	Tue Apr 14 13:01:06 1998
@@ -34,7 +34,7 @@
 #define IPX_TYPE_UNKNOWN	0x00
 #define IPX_TYPE_RIP		0x01	/* may also be 0 */
 #define IPX_TYPE_SAP		0x04	/* may also be 0 */
-#define IPX_TYPE_SPX		0x05	/* Not yet implemented */
+#define IPX_TYPE_SPX		0x05	/* SPX protocol */
 #define IPX_TYPE_NCP		0x11	/* $lots for docs on this (SPIT) */
 #define IPX_TYPE_PPROP		0x14	/* complicated flood fill brdcast [Not supported] */
 	ipx_address	ipx_dest __attribute__ ((packed));
@@ -75,5 +75,8 @@
 
 #define IPX_MIN_EPHEMERAL_SOCKET	0x4000
 #define IPX_MAX_EPHEMERAL_SOCKET	0x7fff
+
+extern int ipx_register_spx(struct proto_ops **, struct net_proto_family *);
+extern int ipx_unregister_spx(void);
 
 #endif /* def _NET_INET_IPX_H_ */
diff -u --recursive --new-file v2.1.95/linux/include/net/netrom.h linux/include/net/netrom.h
--- v2.1.95/linux/include/net/netrom.h	Thu Dec  4 13:36:25 1997
+++ linux/include/net/netrom.h	Sat Apr 11 17:18:15 1998
@@ -126,6 +126,11 @@
 /* nr_in.c */
 extern int  nr_process_rx_frame(struct sock *, struct sk_buff *);
 
+/* nr_loopback.c */
+extern void nr_loopback_init(void);
+extern void nr_loopback_clear(void);
+extern int  nr_loopback_queue(struct sk_buff *);
+
 /* nr_out.c */
 extern void nr_output(struct sock *, struct sk_buff *);
 extern void nr_send_nak_frame(struct sock *);
@@ -153,7 +158,7 @@
 extern int  nr_validate_nr(struct sock *, unsigned short);
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
-extern void nr_transmit_dm(struct sk_buff *);
+extern void nr_transmit_refusal(struct sk_buff *, int);
 extern void nr_disconnect(struct sock *, int);
 
 /* nr_timer.c */
diff -u --recursive --new-file v2.1.95/linux/include/net/rose.h linux/include/net/rose.h
--- v2.1.95/linux/include/net/rose.h	Thu Dec  4 13:36:25 1997
+++ linux/include/net/rose.h	Sat Apr 11 17:18:15 1998
@@ -87,6 +87,7 @@
 	unsigned int		number;
 	char			restarted;
 	char			dce_mode;
+	char			loopback;
 	struct sk_buff_head	queue;
 	struct timer_list	t0timer;
 	struct timer_list	ftimer;
@@ -97,6 +98,7 @@
 	rose_address		address;
 	unsigned short		mask;
 	unsigned char		count;
+	char			loopback;
 	struct rose_neigh	*neighbour[3];
 };
 
@@ -179,11 +181,21 @@
 extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char, unsigned char);
 extern void rose_transmit_link(struct sk_buff *, struct rose_neigh *);
 
+/* rose_loopback.c */
+extern void rose_loopback_init(void);
+extern void rose_loopback_clear(void);
+extern int  rose_loopback_queue(struct sk_buff *, struct rose_neigh *);
+
 /* rose_out.c */
 extern void rose_kick(struct sock *);
 extern void rose_enquiry_response(struct sock *);
 
 /* rose_route.c */
+extern struct rose_neigh *rose_loopback_neigh;
+
+extern int  rose_add_loopback_neigh(void);
+extern int  rose_add_loopback_node(rose_address *);
+extern void rose_del_loopback_node(rose_address *);
 extern void rose_rt_device_down(struct device *);
 extern void rose_link_device_down(struct device *);
 extern struct device *rose_dev_first(void);
diff -u --recursive --new-file v2.1.95/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.95/linux/include/net/sock.h	Mon Apr  6 17:41:01 1998
+++ linux/include/net/sock.h	Tue Apr 14 13:01:06 1998
@@ -66,8 +66,12 @@
 #endif
 
 #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
+#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
+#include <net/spx.h>
+#else
 #include <net/ipx.h>
-#endif
+#endif /* CONFIG_SPX */
+#endif /* CONFIG_IPX */
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
 #include <linux/atalk.h>
@@ -413,7 +417,11 @@
 #endif
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 		struct raw6_opt		tp_raw;
-#endif
+#endif /* CONFIG_IPV6 */
+#if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+		struct spx_opt		af_spx;
+#endif /* CONFIG_SPX */
+
 	} tp_pinfo;
 
 	int			err, err_soft;	/* Soft holds errors that don't
diff -u --recursive --new-file v2.1.95/linux/include/net/spx.h linux/include/net/spx.h
--- v2.1.95/linux/include/net/spx.h	Thu Aug  1 05:43:05 1996
+++ linux/include/net/spx.h	Tue Apr 14 13:01:06 1998
@@ -1,38 +1,93 @@
 #ifndef __NET_SPX_H
 #define __NET_SPX_H
 
-/*
- *	Internal definitions for the SPX protocol.
- */
- 
-/*
- *	The SPX header following an IPX header.
- */
- 
+#include <net/ipx.h>
+
 struct spxhdr
-{
-	__u8 cctl;	
-#define CCTL_SPXII_XHD	0x01	/* SPX2 extended header */
-#define CCTL_SPX_UNKNOWN 0x02	/* Unknown (unused ??) */
-#define CCTL_SPXII_NEG	0x04	/* Negotiate size */
-#define CCTL_SPXII	0x08	/* Set for SPX2 */
-#define CCTL_EOM	0x10	/* End of message marker */
-#define CCTL_URG	0x20	/* Urgent marker in SPP (not used in SPX?) */
-#define CCTL_ACK	0x40	/* Send me an ACK */
-#define CCTL_CTL	0x80	/* Control message */
-	__u8 dtype;
+{	__u8	cctl;	
+	__u8	dtype;
 #define SPX_DTYPE_ECONN	0xFE	/* Finished */
 #define SPX_DTYPE_ECACK	0xFF	/* Ok */
-	__u16 sconn;	/* Connection ID */
-	__u16 dconn;	/* Connection ID */
-	__u16 sequence;
-	__u16 ackseq;
-	__u16 allocseq;
+	__u16	sconn;	/* Connection ID */
+	__u16	dconn;	/* Connection ID */
+	__u16	sequence;
+	__u16	ackseq;
+	__u16	allocseq;
 };
 
-#define IPXTYPE_SPX	5
+struct ipxspxhdr
+{	struct ipxhdr	ipx;
+	struct spxhdr	spx;
+};
+
+#define	SPX_SYS_PKT_LEN	(sizeof(struct ipxspxhdr))
+
+#ifdef __KERNEL__
+struct spx_opt
+{	int	state;
+	int	sndbuf;
+	int	retries;	/* Number of WD retries */
+	int	retransmits;	/* Number of retransmits */
+	int	max_retries;
+	int	wd_interval;
+	void	*owner;
+	__u16	dest_connid;	/* Net order */
+	__u16	source_connid;	/* Net order */
+	__u16	sequence;	/* Host order - our current pkt # */
+	__u16	alloc;		/* Host order - max seq we can rcv now */
+	__u16	rmt_ack;	/* Host order - last pkt ACKd by remote */
+	__u16	rmt_seq;
+	__u16	acknowledge;
+	__u16	rmt_alloc;	/* Host order - max seq remote can handle now */
+	ipx_address	dest_addr;
+	ipx_address	source_addr;
+	struct timer_list	watchdog;	/* Idle watch */
+	struct timer_list	retransmit;	/* Retransmit timer */
+	struct sk_buff_head     rcv_queue;
+	struct sk_buff_head	transmit_queue;
+	struct sk_buff_head     retransmit_queue;
+};
+
+/* Packet connectino control defines */
+#define CCTL_SPXII_XHD  0x01    /* SPX2 extended header */
+#define CCTL_SPX_UNKNOWN 0x02   /* Unknown (unused ??) */
+#define CCTL_SPXII_NEG  0x04    /* Negotiate size */
+#define CCTL_SPXII      0x08    /* Set for SPX2 */
+#define CCTL_EOM        0x10    /* End of message marker */
+#define CCTL_URG        0x20    /* Urgent marker in SPP (not used in SPX?) */
+#define CCTL_ACK        0x40    /* Send me an ACK */
+#define CCTL_CTL        0x80    /* Control message */
+#define CCTL_SYS        CCTL_CTL        /* Spec uses CCTL_SYS */
+
+/* Connection state defines */
+#define SPX_CLOSED	7
+#define	SPX_CONNECTING	8
+#define SPX_CONNECTED	9
+
+/* Packet transmit types - Internal */
+#define DATA	0	/* Data */
+#define ACK	1	/* Data ACK */
+#define WDACK	2	/* WD ACK */
+#define CONACK	3	/* Connection Request ACK */
+#define	CONREQ	4	/* Connection Request */
+#define WDREQ	5	/* WD Request */
+#define	DISCON	6	/* Informed Disconnect */
+#define	DISACK	7	/* Informed Disconnect ACK */
+#define RETRAN	8	/* Int. Retransmit of packet */
+#define TQUEUE	9	/* Int. Transmit of a queued packet */
+
+/*
+ * These are good canidates for IOcontrol calls
+ */
+
+/* Watchdog defines */
+#define VERIFY_TIMEOUT  3 * HZ
+#define ABORT_TIMEOUT   30 * HZ
+
+/* Packet retransmit defines */
+#define RETRY_COUNT     10
+#define RETRY_TIME      1 * HZ
+#define MAX_RETRY_DELAY 5 * HZ
 
-	
-	
-	
-#endif
+#endif /* __KERNEL__ */
+#endif /* def __NET_SPX_H */
diff -u --recursive --new-file v2.1.95/linux/include/net/spxcall.h linux/include/net/spxcall.h
--- v2.1.95/linux/include/net/spxcall.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/spxcall.h	Sat Apr 11 17:18:15 1998
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void spx_proto_init(struct net_proto *pro);
diff -u --recursive --new-file v2.1.95/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.95/linux/include/net/tcp.h	Mon Apr  6 17:41:01 1998
+++ linux/include/net/tcp.h	Tue Apr 14 13:03:33 1998
@@ -218,17 +218,6 @@
 	 !ipv6_addr_cmp(&(__sk)->net_pinfo.af_inet6.rcv_saddr, (__daddr))	&& \
 	 (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
 
-/* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
- * because the v6 tcp code to intialize a connection needs to interoperate
- * with the v4 code using the same variables.
- * FIXME: It would be better to rewrite the connection code to be
- * address family independent and just leave one copy in the ipv4 section.
- * This would also clean up some code duplication. -- erics
- */
-extern int sysctl_tcp_timestamps;
-extern int sysctl_tcp_window_scaling;
-extern int sysctl_tcp_sack;
-
 /* These can have wildcards, don't try too hard. */
 static __inline__ int tcp_lhashfn(unsigned short num)
 {
@@ -718,9 +707,9 @@
 #define TCP_CWND_SHIFT	1
 
 /* This determines how many packets are "in the network" to the best
- * or our knowledge.  In many cases it is conservative, but where
+ * of our knowledge.  In many cases it is conservative, but where
  * detailed information is available from the receiver (via SACK
- * blocks etc.) we can make more agressive calculations.
+ * blocks etc.) we can make more aggressive calculations.
  *
  * Use this for decisions involving congestion control, use just
  * tp->packets_out to determine if the send queue is empty or not.
@@ -809,7 +798,6 @@
 
 static __inline__ void tcp_set_state(struct sock *sk, int state)
 {
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	int oldstate = sk->state;
 
 	sk->state = state;
@@ -825,10 +813,13 @@
 		break;
 
 	case TCP_CLOSE:
+	    {
+		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 		/* Should be about 2 rtt's */
 		net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME));
 		sk->prot->unhash(sk);
 		/* fall through */
+	    }
 	default:
 		if (oldstate==TCP_ESTABLISHED)
 			tcp_statistics.TcpCurrEstab--;
@@ -940,9 +931,6 @@
 	/* Set the clamp no higher than max representable value */
 	(*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
 }
-
-/* Do new listen semantics */
-#define TCP_NEW_LISTEN
 
 extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev)
 {
diff -u --recursive --new-file v2.1.95/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.1.95/linux/include/scsi/sg.h	Wed May  1 21:48:55 1996
+++ linux/include/scsi/sg.h	Fri Apr 10 15:22:21 1998
@@ -30,6 +30,12 @@
 #define SG_SET_TIMEOUT 0x2201  /* set timeout *(int *)arg==timeout */
 #define SG_GET_TIMEOUT 0x2202  /* get timeout return timeout */
 
+#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
+
+/* Used to configure SCSI command transformation layer for ATAPI devices */
+#define SG_SET_TRANSFORM 0x2204
+#define SG_GET_TRANSFORM 0x2205
+
 #define SG_DEFAULT_TIMEOUT (60*HZ) /* 1 minute timeout */
 #define SG_DEFAULT_RETRIES 1
 
diff -u --recursive --new-file v2.1.95/linux/init/main.c linux/init/main.c
--- v2.1.95/linux/init/main.c	Wed Apr  8 19:36:29 1998
+++ linux/init/main.c	Mon Apr 13 18:11:17 1998
@@ -1093,7 +1093,7 @@
 	 *	Like idlers init is an unlocked kernel thread, which will
 	 *	make syscalls (and thus be locked).
 	 */
-	kernel_thread(init, NULL, 0);
+	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 /*
  * task[0] is meant to be used as an "idle" task: it may not sleep, but
  * it might do some general things like count free pages or it could be
@@ -1132,16 +1132,16 @@
 #endif
 
 	/* Launch bdflush from here, instead of the old syscall way. */
-	kernel_thread(bdflush, NULL, 0);
+	kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	/* Start the background pageout daemon. */
 	kswapd_setup();
-	kernel_thread(kswapd, NULL, 0);
+	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 
 #if CONFIG_AP1000
 	/* Start the async paging daemon. */
 	{
 	  extern int asyncd(void *);	 
-	  kernel_thread(asyncd, NULL, 0);
+	  kernel_thread(asyncd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	}
 #endif
 
diff -u --recursive --new-file v2.1.95/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.95/linux/kernel/fork.c	Wed Apr  1 20:11:54 1998
+++ linux/kernel/fork.c	Tue Apr 14 12:54:18 1998
@@ -300,13 +300,14 @@
 void mmput(struct mm_struct *mm)
 {
 	if (!--mm->count) {
+		release_segments(mm);
 		exit_mmap(mm);
 		free_page_tables(mm);
 		kmem_cache_free(mm_cachep, mm);
 	}
 }
 
-static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
+static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct mm_struct * mm;
 	int retval;
@@ -326,6 +327,7 @@
 	tsk->min_flt = tsk->maj_flt = 0;
 	tsk->cmin_flt = tsk->cmaj_flt = 0;
 	tsk->nswap = tsk->cnswap = 0;
+	copy_segments(nr, tsk, mm);
 	retval = new_page_tables(tsk);
 	if (retval)
 		goto free_mm;
@@ -542,7 +544,7 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
-	if (copy_mm(clone_flags, p))
+	if (copy_mm(nr, clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	error = copy_thread(nr, clone_flags, usp, p, regs);
 	if (error)
diff -u --recursive --new-file v2.1.95/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.1.95/linux/kernel/kmod.c	Wed Apr  8 19:36:29 1998
+++ linux/kernel/kmod.c	Mon Apr 13 18:11:38 1998
@@ -108,7 +108,12 @@
 {
 	printk("Starting kmod\n");
 
-	kernel_thread(kmod_thread, NULL, 0);
+	/*
+	 * CLONE_FS means that our "cwd" will follow that of init.
+	 * CLONE_FILES just saves some space (we don't need any
+	 * new file descriptors). Ditto for CLONE_SIGHAND.
+	 */
+	kernel_thread(kmod_thread, NULL, CLONE_FILES | CLONE_FS | CLONE_SIGHAND);
 
 	kmod_unload_timer.next = NULL;
 	kmod_unload_timer.prev = NULL;
diff -u --recursive --new-file v2.1.95/linux/kernel/printk.c linux/kernel/printk.c
--- v2.1.95/linux/kernel/printk.c	Wed Apr  1 20:11:54 1998
+++ linux/kernel/printk.c	Mon Apr 13 14:41:53 1998
@@ -358,7 +358,8 @@
 		if (console->index >= 0 &&
 		    console->index != console_cmdline[i].index)
 			continue;
-		if (console->index < 0) console->index = 0;
+		if (console->index < 0)
+			console->index = console_cmdline[i].index;
 		if (console->setup &&
 		    console->setup(console, console_cmdline[i].options) != 0)
 			break;
diff -u --recursive --new-file v2.1.95/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.95/linux/kernel/signal.c	Tue Mar 17 22:18:15 1998
+++ linux/kernel/signal.c	Mon Apr 13 16:47:48 1998
@@ -788,6 +788,7 @@
 
 	if (act) {
 		*k = *act;
+		sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
 
 		/*
 		 * POSIX 3.3.1.3:
diff -u --recursive --new-file v2.1.95/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.95/linux/net/ax25/af_ax25.c	Tue Mar 17 22:18:16 1998
+++ linux/net/ax25/af_ax25.c	Sat Apr 11 17:18:16 1998
@@ -1622,7 +1622,7 @@
 
 	cli();
 
-	len += sprintf(buffer, "dest_addr src_addr   dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr src_addr   dev  st  vs  vr  va    t1     t2     t3      idle   n2  rtt wnd paclen   Snd-Q Rcv-Q inode\n");
 
 	for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
 		if (ax25->ax25_dev == NULL)
@@ -1658,9 +1658,10 @@
 			ax25->paclen);
 
 		if (ax25->sk != NULL) {
-			len += sprintf(buffer + len, " %5d %5d\n",
+			len += sprintf(buffer + len, " %5d %5d %ld\n",
 				atomic_read(&ax25->sk->wmem_alloc),
-				atomic_read(&ax25->sk->rmem_alloc));
+				atomic_read(&ax25->sk->rmem_alloc),
+				ax25->sk->socket != NULL ? ax25->sk->socket->inode->i_ino : 0L);
 		} else {
 			len += sprintf(buffer + len, "\n");
 		}
diff -u --recursive --new-file v2.1.95/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v2.1.95/linux/net/ax25/ax25_out.c	Thu Feb 12 20:56:14 1998
+++ linux/net/ax25/ax25_out.c	Sat Apr 11 17:18:16 1998
@@ -362,7 +362,7 @@
 
 	ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-	skb->dev      = ax25->ax25_dev->dev;
+	skb->dev = ax25->ax25_dev->dev;
 
 	ax25_queue_xmit(skb);
 }
diff -u --recursive --new-file v2.1.95/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.1.95/linux/net/core/iovec.c	Thu Mar 26 15:57:10 1998
+++ linux/net/core/iovec.c	Sat Apr 11 17:18:16 1998
@@ -29,7 +29,8 @@
 #include <net/checksum.h>
 
 /*
- *	Verify iovec
+ *	Verify iovec. The caller must ensure that the iovec is big enough
+ *	to hold the message iovec.
  *
  *	Save time not doing verify_area. copy_*_user will make this work
  *	in any case.
@@ -37,8 +38,7 @@
 
 int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
 {
-	int size = m->msg_iovlen * sizeof(struct iovec);
-	int err, ct;
+	int size, err, ct;
 	
 	if(m->msg_namelen)
 	{
@@ -53,28 +53,16 @@
 	} else
 		m->msg_name = NULL;
 
-	if (m->msg_iovlen > UIO_FASTIOV)
-	{
-		err = -ENOMEM;
-		iov = kmalloc(size, GFP_KERNEL);
-		if (!iov)
-			goto out;
-	}
-	
+	err = -EFAULT;
+	size = m->msg_iovlen * sizeof(struct iovec);
 	if (copy_from_user(iov, m->msg_iov, size))
-		goto out_free;
+		goto out;
 	m->msg_iov=iov;
 
 	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++)
 		err += iov[ct].iov_len;
 out:
 	return err;
-
-out_free:
-	err = -EFAULT;
-	if (m->msg_iovlen > UIO_FASTIOV)
-		kfree(iov);
-	goto out;
 }
 
 /*
diff -u --recursive --new-file v2.1.95/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.95/linux/net/core/sock.c	Thu Mar 26 15:57:10 1998
+++ linux/net/core/sock.c	Sat Apr 11 17:18:16 1998
@@ -589,38 +589,37 @@
  */
 unsigned long sock_rspace(struct sock *sk)
 {
-	int amt;
+	int amt = 0;
 
 	if (sk != NULL) {
-		/* This used to have some bizzare complications that
+		/* This used to have some bizarre complications that
 		 * to attempt to reserve some amount of space. This doesn't
 	 	 * make sense, since the number returned here does not
 		 * actually reflect allocated space, but rather the amount
 		 * of space we committed to. We gamble that we won't
 		 * run out of memory, and returning a smaller number does
-		 * not change the gamble. If we loose the gamble tcp still
+		 * not change the gamble. If we lose the gamble tcp still
 		 * works, it may just slow down for retransmissions.
 		 */
 		amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc);
 		if (amt < 0) 
-			return(0);
-		return(amt);
+			amt = 0;
 	}
-	return(0);
+	return amt;
 }
 
 
 /* FIXME: this is also insane. See above comment */
 unsigned long sock_wspace(struct sock *sk)
 {
-	if (sk != NULL) {
-		if (sk->shutdown & SEND_SHUTDOWN)
-			return(0);
-		if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf) 
-			return(0);
-		return sk->sndbuf - atomic_read(&sk->wmem_alloc);
+	int amt = 0;
+
+	if (sk != NULL && !(sk->shutdown & SEND_SHUTDOWN)) {
+		amt = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+		if (amt < 0) 
+			amt = 0;
 	}
-	return(0);
+	return amt;
 }
 
 /* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
@@ -653,13 +652,17 @@
  *	Generic send/receive buffer handlers
  */
 
-struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode)
+struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
+			unsigned long fallback, int noblock, int *errcode)
 {
 	int err;
 	struct sk_buff *skb;
 
-	do {
-		if ((err = xchg(&sk->err,0)) != 0)
+	while (1) {
+		unsigned long try_size = size;
+
+		err = sock_error(sk);
+		if (err != 0)
 			goto failure;
 
 		/*
@@ -676,33 +679,32 @@
 		if (sk->shutdown&SEND_SHUTDOWN)
 			goto failure;
 
-		if (!fallback)
-			skb = sock_wmalloc(sk, size, 0, sk->allocation);
-		else {
-			/* The buffer get won't block, or use the atomic queue. It does
-			   produce annoying no free page messages still.... */
+		if (fallback) {
+			/* The buffer get won't block, or use the atomic queue.
+			 * It does produce annoying no free page messages still.
+			 */
 			skb = sock_wmalloc(sk, size, 0, GFP_BUFFER);
-			if (!skb)
-				skb=sock_wmalloc(sk, fallback, 0, sk->allocation);
+			if (skb)
+				break;
+			try_size = fallback;
 		}
+		skb = sock_wmalloc(sk, try_size, 0, sk->allocation);
+		if (skb)
+			break;
 
 		/*
 		 *	This means we have too many buffers for this socket already.
 		 */
 
-		/* The following code is stolen "as is" from tcp.c */
-
-		if (skb==NULL) {
-			sk->socket->flags |= SO_NOSPACE;
-			err = -EAGAIN;
-			if (noblock)
-				goto failure;
-			err = -ERESTARTSYS;
-			if (signal_pending(current))
-				goto failure;
-			sock_wait_for_wmem(sk);
-		}
-	} while (skb==NULL);
+		sk->socket->flags |= SO_NOSPACE;
+		err = -EAGAIN;
+		if (noblock)
+			goto failure;
+		err = -ERESTARTSYS;
+		if (signal_pending(current))
+			goto failure;
+		sock_wait_for_wmem(sk);
+	}
 
 	return skb;
 
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.95/linux/net/ipv4/icmp.c	Tue Mar 17 22:18:16 1998
+++ linux/net/ipv4/icmp.c	Sat Apr 11 17:18:16 1998
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@cymru.net>
  *
- *	Version: $Id: icmp.c,v 1.39 1998/03/08 05:56:19 davem Exp $
+ *	Version: $Id: icmp.c,v 1.40 1998/04/11 09:38:24 freitag Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -1026,7 +1026,6 @@
  *	dst_entry gets expired too early. The same should happen when
  *	the cache grows too big.
  */
-int sysctl_icmp_sourcequench_time = 1*HZ; 
 int sysctl_icmp_destunreach_time = 1*HZ;
 int sysctl_icmp_timeexceed_time = 1*HZ;
 int sysctl_icmp_paramprob_time = 1*HZ;
@@ -1044,7 +1043,7 @@
 /* DEST UNREACH (3) */
  { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time },
 /* SOURCE QUENCH (4) */
- { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, &sysctl_icmp_sourcequench_time },
+ { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, },
 /* REDIRECT (5) */
  { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, },
  { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.1.95/linux/net/ipv4/sysctl_net_ipv4.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv4/sysctl_net_ipv4.c	Sat Apr 11 17:18:16 1998
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.32 1998/04/03 09:49:47 freitag Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.34 1998/04/11 09:38:26 freitag Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -48,6 +48,7 @@
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
+extern int sysctl_tcp_retrans_collapse;
 extern int sysctl_tcp_keepalive_time;
 extern int sysctl_tcp_keepalive_probes;
 extern int sysctl_tcp_max_ka_probes;
@@ -62,7 +63,6 @@
 extern int sysctl_max_syn_backlog; 
 
 /* From icmp.c */
-extern int sysctl_icmp_sourcequench_time; 
 extern int sysctl_icmp_destunreach_time;
 extern int sysctl_icmp_timeexceed_time;
 extern int sysctl_icmp_paramprob_time;
@@ -105,6 +105,9 @@
         {NET_IPV4_TCP_SACK, "tcp_sack",
          &sysctl_tcp_sack, sizeof(int), 0644, NULL,
          &proc_dointvec},
+        {NET_IPV4_TCP_RETRANS_COLLAPSE, "tcp_retrans_collapse",
+         &sysctl_tcp_retrans_collapse, sizeof(int), 0644, NULL,
+         &proc_dointvec},
         {NET_IPV4_FORWARD, "ip_forward",
          &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
          &ipv4_sysctl_forward},
@@ -166,8 +169,6 @@
 	{NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, "icmp_echo_ignore_broadcasts",
 	 &sysctl_icmp_echo_ignore_broadcasts, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
-	{NET_IPV4_ICMP_SOURCEQUENCH_RATE, "icmp_sourcequench_rate",
-	 &sysctl_icmp_sourcequench_time, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_IPV4_ICMP_DESTUNREACH_RATE, "icmp_destunreach_rate",
 	 &sysctl_icmp_destunreach_time, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_IPV4_ICMP_TIMEEXCEED_RATE, "icmp_timeexceed_rate",
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.95/linux/net/ipv4/tcp.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv4/tcp.c	Sat Apr 11 17:18:16 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.110 1998/04/03 09:49:51 freitag Exp $
+ * Version:	$Id: tcp.c,v 1.111 1998/04/06 16:09:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -197,7 +197,7 @@
  *	Stefan Magdalinski	:	adjusted tcp_readable() to fix FIONREAD
  *	Willy Konynenberg	:	Transparent proxying support.
  *	Mike McLagan		:	Routing by source
- *		Keith Owens	:	Do proper meging with partial SKB's in
+ *		Keith Owens	:	Do proper merging with partial SKB's in
  *					tcp_do_sendmsg to avoid burstiness.
  *		Eric Schenk	:	Fix fast close down bug with
  *					shutdown() followed by close().
@@ -451,35 +451,6 @@
 }
 
 /*
- *	This routine closes sockets which have been at least partially
- *	opened, but not yet accepted. Currently it is only called by
- *	tcp_close, and timeout mirrors the value there.
- */
-
-static void tcp_close_pending (struct sock *sk)
-{
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct open_request *req = tp->syn_wait_queue;
-
-	while(req) {
-		struct open_request *iter;
-		
-		if (req->sk)
-			tcp_close(req->sk, 0);
-
-		iter = req;
-		req = req->dl_next;
-		
-		(*iter->class->destructor)(iter);
-		tcp_dec_slow_timer(TCP_SLT_SYNACK);
-		sk->ack_backlog--;
-		tcp_openreq_free(iter);
-	}
-
-	tcp_synq_init(tp);
-}
-
-/*
  *	Walk down the receive queue counting readable data.
  *
  *	Must be called with the socket lock held.
@@ -513,14 +484,12 @@
 		 * avoid overlaps.
 		 */
 		sum = skb->len - (counted - TCP_SKB_CB(skb)->seq);
-		if (skb->h.th->syn)
-			sum++;
-		if (sum > 0) {
+		if (sum >= 0) {
 			/* Add it up, move on. */
 			amount += sum;
-			if (skb->h.th->syn)
-				amount--;
 			counted += sum;
+			if (skb->h.th->syn)
+				counted++;
 		}
 
 		/* Don't count urg data ... but do it in the right place!
@@ -608,7 +577,7 @@
 		/* More than half of the socket queue free? */
 		space = atomic_read(&sk->wmem_alloc) / 2;
 #endif
-		/* Always wake the user up when an error occured */
+		/* Always wake the user up when an error occurred */
 		if (sock_wspace(sk) >= space || sk->err)
 			mask |= POLLOUT | POLLWRNORM;
 		if (tp->urg_data)
@@ -619,44 +588,41 @@
 
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
+	int answ;
+
 	switch(cmd) {
-		case TIOCINQ:
+	case TIOCINQ:
 #ifdef FIXME	/* FIXME: */
-		case FIONREAD:
+	case FIONREAD:
 #endif
-		{
-			unsigned long amount;
-
-			if (sk->state == TCP_LISTEN)
-				return(-EINVAL);
-
-			lock_sock(sk);
-			amount = tcp_readable(sk);
-			release_sock(sk);
-			return put_user(amount, (int *)arg);
-		}
-		case SIOCATMARK:
+		if (sk->state == TCP_LISTEN)
+			return(-EINVAL);
+		lock_sock(sk);
+		answ = tcp_readable(sk);
+		release_sock(sk);
+		break;
+	case SIOCATMARK:
 		{
 			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-			int answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
-			return put_user(answ,(int *) arg);
-		}
-		case TIOCOUTQ:
-		{
-			unsigned long amount;
-
-			if (sk->state == TCP_LISTEN)
-				return(-EINVAL);
-			amount = sock_wspace(sk);
-			return put_user(amount, (int *)arg);
+			answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
+			break;
 		}
-		default:
-			return(-ENOIOCTLCMD);
+	case TIOCOUTQ:
+		if (sk->state == TCP_LISTEN)
+			return(-EINVAL);
+		answ = sock_wspace(sk);
+		break;
+	default:
+		return(-ENOIOCTLCMD);
 	};
+
+	return put_user(answ, (int *)arg);
 }
 
 /*
  *	Wait for a socket to get into the connected state
+ *
+ *	Note: must be called with the socket locked.
  */
 static int wait_for_tcp_connect(struct sock * sk, int flags)
 {
@@ -729,6 +695,8 @@
 /*
  *	This routine copies from a user buffer into a socket,
  *	and starts the transmit system.
+ *
+ *	Note: must be called with the socket locked.
  */
 
 int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
@@ -738,6 +706,10 @@
 	int err = 0;
 	int copied  = 0;
 
+	/* Verify that the socket is locked */
+	if (!sk->sock_readers)
+		printk("tcp_do_sendmsg: socket not locked!\n");
+
 	/* Wait for a connection to finish. */
 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
 		if((err = wait_for_tcp_connect(sk, flags)) != 0)
@@ -951,7 +923,6 @@
 			struct msghdr *msg, int len, int flags, 
 			int *addr_len)
 {
-	int err=0; 
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	/* No URG data to read. */
@@ -961,22 +932,19 @@
 	if (sk->err)
 		return sock_error(sk);
 
-	if (sk->state == TCP_CLOSE || sk->done) {
-		if (!sk->done) {
-			sk->done = 1;
-			return 0;
-		}
+	if (sk->done)
 		return -ENOTCONN;
-	}
 
-	if (sk->shutdown & RCV_SHUTDOWN) {
+	if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) {
 		sk->done = 1;
 		return 0;
 	}
 
 	lock_sock(sk);
 	if (tp->urg_data & URG_VALID) {
+		int err = 0; 
 		char c = tp->urg_data;
+
 		if (!(flags & MSG_PEEK))
 			tp->urg_data = URG_READ;
 			
@@ -994,11 +962,13 @@
 		if(len>0)
 		{
 			err = memcpy_toiovec(msg->msg_iov, &c, 1);
+			/* N.B. already set above ... */
 			msg->msg_flags|=MSG_OOB;
 		}
 		else
 			msg->msg_flags|=MSG_TRUNC;
 			
+		/* N.B. Is this right?? If len == 0 we didn't read any data */ 
 		return err ? -EFAULT : 1;
 	}
 	release_sock(sk);
@@ -1286,43 +1256,43 @@
 }
 
 /*
+ * Check whether to renew the timer.
+ */
+static inline void tcp_check_fin_timer(struct sock *sk)
+{
+	if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev)
+		tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+}
+
+/*
  *	State processing on a close. This implements the state shift for
  *	sending our FIN frame. Note that we only send a FIN for some
  *	states. A shutdown() may have already sent the FIN, or we may be
  *	closed.
  */
 
+static unsigned char new_state[16] = {
+  /* current state:        new state:      action:	*/
+  /* (Invalid)		*/ TCP_CLOSE,
+  /* TCP_ESTABLISHED	*/ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
+  /* TCP_SYN_SENT	*/ TCP_CLOSE,
+  /* TCP_SYN_RECV	*/ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
+  /* TCP_FIN_WAIT1	*/ TCP_FIN_WAIT1,
+  /* TCP_FIN_WAIT2	*/ TCP_FIN_WAIT2,
+  /* TCP_TIME_WAIT	*/ TCP_CLOSE,
+  /* TCP_CLOSE		*/ TCP_CLOSE,
+  /* TCP_CLOSE_WAIT	*/ TCP_LAST_ACK  | TCP_ACTION_FIN,
+  /* TCP_LAST_ACK	*/ TCP_LAST_ACK,
+  /* TCP_LISTEN		*/ TCP_CLOSE,
+  /* TCP_CLOSING	*/ TCP_CLOSING,
+};
+
 static int tcp_close_state(struct sock *sk, int dead)
 {
-	int ns=TCP_CLOSE;
-	int send_fin=0;
-	switch(sk->state) {
-		case TCP_SYN_SENT:	/* No SYN back, no FIN needed */
-			break;
-		case TCP_SYN_RECV:
-		case TCP_ESTABLISHED:	/* Closedown begin */
-			ns=TCP_FIN_WAIT1;
-			send_fin=1;
-			break;
-		case TCP_FIN_WAIT1:	/* Already closing, or FIN sent: no change */
-		case TCP_FIN_WAIT2:
-		case TCP_CLOSING:
-			ns=sk->state;
-			break;
-		case TCP_CLOSE:
-		case TCP_LISTEN:
-			break;
-		case TCP_LAST_ACK:	/* Could have shutdown() then close()
-					 * (but don't do send_fin again!) */
-			ns=TCP_LAST_ACK;
-			break;
-		case TCP_CLOSE_WAIT:	/* They have FIN'd us. We send our FIN and
-					   wait only for the ACK */
-			ns=TCP_LAST_ACK;
-			send_fin=1;
-	};
+	int next = (int) new_state[sk->state];
+	int ns = (next & TCP_STATE_MASK);
 
-	tcp_set_state(sk,ns);
+	tcp_set_state(sk, ns);
 
 	/*	This is a (useful) BSD violating of the RFC. There is a
 	 *	problem with TCP as specified in that the other end could
@@ -1332,10 +1302,10 @@
 	 *	that we won't make the old 4*rto = almost no time - whoops
 	 *	reset mistake.
 	 */
-	if(dead && ns == TCP_FIN_WAIT2 && !sk->timer.prev)
-		tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+	if (dead)
+		tcp_check_fin_timer(sk);
 
-	return send_fin;
+	return (next & TCP_ACTION_FIN);
 }
 
 /*
@@ -1378,12 +1348,47 @@
 	return ((1 << sk->state) & (TCPF_FIN_WAIT1|TCPF_CLOSING|TCPF_LAST_ACK));
 }
 
+/*
+ *	This routine closes sockets which have been at least partially
+ *	opened, but not yet accepted. Currently it is only called by
+ *	tcp_close, and timeout mirrors the value there.
+ */
+
+static void tcp_close_pending (struct sock *sk)
+{
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	struct open_request *req = tp->syn_wait_queue;
+
+	while(req) {
+		struct open_request *iter;
+		
+		if (req->sk)
+			tcp_close(req->sk, 0);
+
+		iter = req;
+		req = req->dl_next;
+		
+		(*iter->class->destructor)(iter);
+		tcp_dec_slow_timer(TCP_SLT_SYNACK);
+		sk->ack_backlog--;
+		tcp_openreq_free(iter);
+	}
+
+	tcp_synq_init(tp);
+}
 
 void tcp_close(struct sock *sk, unsigned long timeout)
 {
 	struct sk_buff *skb;
 	int data_was_unread = 0;
 
+	/*
+	 * Check whether the socket is locked ... supposedly
+	 * it's impossible to tcp_close() a locked socket.
+	 */
+	if (sk->sock_readers)
+		printk("tcp_close: socket already locked!\n");
+
 	/* We need to grab some memory, and put together a FIN,
 	 * and then put it into the queue to be sent.
 	 */
@@ -1436,12 +1441,14 @@
 		struct task_struct *tsk = current;
 		struct wait_queue wait = { tsk, NULL };
 
-		tsk->state = TASK_INTERRUPTIBLE;
 		tsk->timeout = timeout;
 		add_wait_queue(sk->sleep, &wait);
 		release_sock(sk);
 
-		while (closing(sk)) {
+		while (1) {
+			tsk->state = TASK_INTERRUPTIBLE;
+			if (!closing(sk))
+				break;
 			schedule();
 			if (signal_pending(tsk) || !tsk->timeout)
 				break;
@@ -1457,8 +1464,7 @@
 	/* Now that the socket is dead, if we are in the FIN_WAIT2 state
 	 * we may need to set up a timer.
          */
-	if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev)
-		tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+	tcp_check_fin_timer(sk);
 
 	sk->dead = 1;
 	release_sock(sk);
@@ -1472,7 +1478,7 @@
 					      struct open_request **pprev)
 {
 	struct wait_queue wait = { current, NULL };
-	struct open_request *req = NULL;
+	struct open_request *req;
 
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
@@ -1486,6 +1492,7 @@
 		if (signal_pending(current))
 			break;
 	}
+	current->state = TASK_RUNNING;
 	remove_wait_queue(sk->sleep, &wait);
 	return req;
 }
@@ -1515,14 +1522,14 @@
 	/* Find already established connection */
 	req = tcp_find_established(tp, &prev);
 	if (!req) {
-	    /* If this is a non blocking socket don't sleep */
-	    error = EAGAIN;
-	    if (flags & O_NONBLOCK)
+		/* If this is a non blocking socket don't sleep */
+		error = EAGAIN;
+		if (flags & O_NONBLOCK)
 			goto out;
 	    
-	    error = ERESTARTSYS;
-	    req = wait_for_connect(sk, &prev);
-	    if (!req) 
+		error = ERESTARTSYS;
+		req = wait_for_connect(sk, &prev);
+		if (!req) 
 			goto out;
 	}
 
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.95/linux/net/ipv4/tcp_input.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv4/tcp_input.c	Sat Apr 11 17:18:16 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.104 1998/04/01 07:41:24 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.106 1998/04/10 23:56:19 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -42,6 +42,11 @@
  *		Andi Kleen	:	Moved open_request checking here
  *					and process RSTs for open_requests.
  *		Andi Kleen	:	Better prune_queue, and other fixes.
+ *		Andrey Savochkin:	Fix RTT measurements in the presnce of
+ *					timestamps.
+ *		Andrey Savochkin:	Check sequence numbers correctly when
+ *					removing SACKs due to in sequence incoming
+ *					data segments.
  */
 
 #include <linux/config.h>
@@ -667,7 +672,20 @@
 static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
 			       u32 seq, u32 ack, int flag)
 {
-	__u32 seq_rtt = (jiffies-tp->rcv_tsecr);
+	__u32 seq_rtt;
+
+	/* RTTM Rule: A TSecr value received in a segment is used to
+	 * update the averaged RTT measurement only if the segment
+	 * acknowledges some new data, i.e., only if it advances the
+	 * left edge of the send window.
+	 *
+	 * See draft-ietf-tcplw-high-performance-00, section 3.3.
+	 * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
+	 */
+	if (!(flag & FLAG_DATA_ACKED))
+		return;
+
+	seq_rtt = jiffies-tp->rcv_tsecr;
 	tcp_rtt_estimator(tp, seq_rtt);
 	if (tp->retransmits) {
 		if (tp->packets_out == 0) {
@@ -683,8 +701,7 @@
 		}
 	} else {
 		tcp_set_rto(tp);
-		if (flag & FLAG_DATA_ACKED)
-			tcp_cong_avoid(tp, seq, ack, seq_rtt);
+		tcp_cong_avoid(tp, seq, ack, seq_rtt);
 	}
 	/* NOTE: safe here so long as cong_ctl doesn't use rto */
 	tcp_bound_rto(tp);
@@ -1224,7 +1241,8 @@
 	 * from the front of a SACK.
 	 */
 	for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
-		if(!after(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
+		/* Check if the start of the sack is covered by skb. */
+		if(!before(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
 		   before(sp->start_seq, TCP_SKB_CB(skb)->end_seq))
 			break;
 	}
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.95/linux/net/ipv4/tcp_ipv4.c	Wed Apr  8 19:36:29 1998
+++ linux/net/ipv4/tcp_ipv4.c	Sat Apr 11 17:18:16 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.131 1998/04/03 10:52:04 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.133 1998/04/06 08:42:28 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -38,13 +38,12 @@
  *					open_request handling and moved
  *					most of it into the af independent code.
  *					Added tail drop and some other bugfixes.
- *					Added new listen sematics (ifdefed by
- *					TCP_NEW_LISTEN for now)
+ *					Added new listen sematics.
  *		Mike McLagan	:	Routing by source
  *	Juan Jose Ciarlante:		ip_dynaddr bits
  *		Andi Kleen:		various fixes.
  *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
- *	Andi Kleen		:	Fix TCP_NEW_LISTEN and make it the default.
+ *	Andi Kleen		:	Fix new listen.
  */
 
 #include <linux/config.h>
@@ -337,9 +336,6 @@
 	return result;
 }
 
-/* Until this is verified... -DaveM */
-/* #define USE_QUICKSYNS */
-
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
  * It is assumed that this code only gets called from within NET_BH.
@@ -354,12 +350,6 @@
 	struct sock *sk;
 	int hash;
 
-#ifdef USE_QUICKSYNS
-	/* Incomming connection short-cut. */
-	if (th && th->syn == 1 && th->ack == 0)
-		goto listener_shortcut;
-#endif
-
 	/* Check TCP register quick cache first. */
 	sk = TCP_RHASH(sport);
 	if(sk && TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
@@ -380,9 +370,6 @@
 	for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
 		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
 			goto hit;
-#ifdef USE_QUICKSYNS
-listener_shortcut:
-#endif
 	sk = tcp_v4_lookup_listener(daddr, hnum, dif);
 hit:
 	return sk;
@@ -813,11 +800,7 @@
 		if (req->sk) {	/* not yet accept()ed */
 			sk = req->sk; /* report error in accept */
 		} else {
-#ifdef TCP_NEW_LISTEN
 			tp->syn_backlog--;
-#else
-			sk->ack_backlog--;
-#endif
 			tcp_synq_unlink(tp, req, prev);
 			req->class->destructor(req);
 			tcp_openreq_free(req);
@@ -1030,13 +1013,8 @@
 	tcp_v4_send_reset
 };
 
-#ifdef TCP_NEW_LISTEN
 #define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
 #define BACKLOGMAX(sk) sysctl_max_syn_backlog
-#else
-#define BACKLOG(sk) ((sk)->ack_backlog)
-#define BACKLOGMAX(sk) ((sk)->max_ack_backlog)
-#endif
 
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, 
 						__u32 isn)
@@ -1068,10 +1046,9 @@
 	} else { 
 		if (isn == 0)
 			isn = tcp_v4_init_sequence(sk, skb);
+		BACKLOG(sk)++;
 	}
 
-	BACKLOG(sk)++;
-
 	req = tcp_openreq_alloc();
 	if (req == NULL) {
 		goto dropbacklog;
@@ -1289,10 +1266,8 @@
 	int snd_mss;
 	int mtu;
 
-#ifdef TCP_NEW_LISTEN
 	if (sk->ack_backlog > sk->max_ack_backlog)
 		goto exit; /* head drop */
-#endif
 	if (dst == NULL) { 
 		struct rtable *rt;
 		
@@ -1303,10 +1278,8 @@
 	        dst = &rt->u.dst;
 	}
 
-#ifdef TCP_NEW_LISTEN
 	sk->tp_pinfo.af_tcp.syn_backlog--;
 	sk->ack_backlog++;
-#endif
 
 	mtu = dst->pmtu;
 	if (mtu < 68)
@@ -1353,11 +1326,7 @@
 	    after(TCP_SKB_CB(skb)->seq, req->snt_isn+1))
 		return;
 	tcp_synq_unlink(tp, req, prev);
-#ifdef TCP_NEW_LISTEN
 	(req->sk ? sk->ack_backlog : tp->syn_backlog)--;
-#else
-	sk->ack_backlog--;
-#endif
 	req->class->destructor(req);
 	tcp_openreq_free(req); 
 }
@@ -1483,7 +1452,7 @@
 		skb->csum = csum_partial((char *)th, len, 0);
 	case CHECKSUM_HW:
 		if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) {
-			printk(KERN_DEBUG "TCPv4 bad checksum from %ld.%ld.%ld.%ld:%04x to %ld.%ld.%ld.%ld:%04x, "
+			printk(KERN_DEBUG "TCPv4 bad checksum from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, "
 			       "len=%d/%d/%d\n",
  			       NIPQUAD(ntohl(skb->nh.iph->saddr)),
 			       ntohs(th->source), 
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.95/linux/net/ipv4/tcp_output.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv4/tcp_output.c	Sat Apr 11 17:18:16 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.83 1998/04/03 08:10:45 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.84 1998/04/06 08:48:29 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -37,6 +37,10 @@
 
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
+extern int sysctl_tcp_sack;
+
+/* People can turn this off for buggy TCP's found in printers etc. */
+int sysctl_tcp_retrans_collapse = 1;
 
 /* Get rid of any delayed acks, we sent one already.. */
 static __inline__ void clear_delayed_acks(struct sock * sk)
@@ -494,7 +498,8 @@
 	if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
 	   (skb->len < (current_mss >> 1)) &&
 	   (skb->next != tp->send_head) &&
-	   (skb->next != (struct sk_buff *)&sk->write_queue))
+	   (skb->next != (struct sk_buff *)&sk->write_queue) &&
+	   (sysctl_tcp_retrans_collapse != 0))
 		tcp_retrans_try_collapse(sk, skb, current_mss);
 
 	if(tp->af_specific->rebuild_header(sk))
diff -u --recursive --new-file v2.1.95/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.1.95/linux/net/ipv4/tcp_timer.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv4/tcp_timer.c	Sat Apr 11 17:18:16 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.47 1998/04/03 10:52:05 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.48 1998/04/06 08:42:30 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -460,11 +460,7 @@
 #endif
 						(*conn->class->destructor)(conn);
 						tcp_dec_slow_timer(TCP_SLT_SYNACK);
-#ifdef TCP_NEW_LISTEN
-					tp->syn_backlog--;
-#else
-					sk->ack_backlog--;
-#endif
+						tp->syn_backlog--;
 						tcp_openreq_free(conn);
 
 						if (!tp->syn_wait_queue)
diff -u --recursive --new-file v2.1.95/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.95/linux/net/ipv6/tcp_ipv6.c	Mon Apr  6 17:41:01 1998
+++ linux/net/ipv6/tcp_ipv6.c	Sat Apr 11 17:18:16 1998
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.74 1998/04/03 09:50:01 freitag Exp $
+ *	$Id: tcp_ipv6.c,v 1.76 1998/04/06 08:42:34 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -42,6 +42,8 @@
 
 #include <asm/uaccess.h>
 
+extern int sysctl_max_syn_backlog;
+
 static void	tcp_v6_send_reset(struct sk_buff *skb);
 static void	tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, 
 				  struct sk_buff *skb);
@@ -225,9 +227,6 @@
 	return result;
 }
 
-/* Until this is verified... -DaveM */
-/* #define USE_QUICKSYNS */
-
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
  * It is assumed that this code only gets called from within NET_BH.
@@ -242,12 +241,6 @@
 	__u32 ports = TCP_COMBINED_PORTS(sport, hnum);
 	int hash;
 
-#ifdef USE_QUICKSYNS
-	/* Incomming connection short-cut. */
-	if (th && th->syn == 1 && th->ack == 0)
-		goto listener_shortcut;
-#endif
-
 	/* Check TCP register quick cache first. */
 	sk = TCP_RHASH(sport);
 	if(sk && TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif))
@@ -276,9 +269,6 @@
 				goto hit;
 		}
 	}
-#ifdef USE_QUICKSYNS
-listener_shortcut:
-#endif
 	sk = tcp_v6_lookup_listener(daddr, hnum, dif);
 hit:
 	return sk;
@@ -638,6 +628,7 @@
 		if (req->sk) {
 			sk = req->sk; /* report error in accept */
 		} else {
+			tp->syn_backlog--;
 			tcp_synq_unlink(tp, req, prev);
 			req->class->destructor(req);
 			tcp_openreq_free(req);
@@ -717,6 +708,9 @@
 	tcp_v6_send_reset
 };
 
+#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
+#define BACKLOGMAX(sk) sysctl_max_syn_backlog
+
 /* FIXME: this is substantially similar to the ipv4 code.
  * Can some kind of merge be done? -- erics
  */
@@ -742,9 +736,9 @@
 	/*
 	 *	There are no SYN attacks on IPv6, yet...
 	 */
-	if (sk->ack_backlog >= sk->max_ack_backlog) {
+	if (BACKLOG(sk) >= BACKLOGMAX(sk)) {
 		printk(KERN_DEBUG "droping syn ack:%d max:%d\n",
-		       sk->ack_backlog, sk->max_ack_backlog);
+		       BACKLOG(sk), BACKLOGMAX(sk));
 		goto drop;		
 	}
 
@@ -753,7 +747,7 @@
 		goto drop;
 	}
 
-	sk->ack_backlog++;
+	BACKLOG(sk)++;
 
 	req->rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
 
@@ -820,7 +814,7 @@
 	struct tcp_opt *newtp;
 	struct sock *newsk;
 	int mss;
-
+      
 	if (skb->protocol == __constant_htons(ETH_P_IP)) {
 		/*
 		 *	v6 mapped
@@ -848,6 +842,9 @@
 	}
 
 
+	if (sk->ack_backlog > sk->max_ack_backlog)
+		return NULL; 
+
 	if (dst == NULL) {
 		/*
 		 *	options / mss / route cache
@@ -866,6 +863,8 @@
 	if (dst->error || dst->pmtu < 576)
 		goto out;
 	
+	sk->tp_pinfo.af_tcp.syn_backlog--;
+	sk->ack_backlog++;
 
 	mss = dst->pmtu - sizeof(struct ipv6hdr);
 #if 0
@@ -1005,6 +1004,10 @@
 	if (before(TCP_SKB_CB(skb)->seq, req->snt_isn) ||
 	    after(TCP_SKB_CB(skb)->seq, req->snt_isn+1))
 		return;
+	if(req->sk)
+		sk->ack_backlog--;
+	else
+		tp->syn_backlog--;
 	tcp_synq_unlink(tp, req, prev);
 	req->class->destructor(req);
 	tcp_openreq_free(req); 
diff -u --recursive --new-file v2.1.95/linux/net/ipx/Config.in linux/net/ipx/Config.in
--- v2.1.95/linux/net/ipx/Config.in	Mon Feb 23 18:12:14 1998
+++ linux/net/ipx/Config.in	Sat Apr 11 17:18:16 1998
@@ -2,5 +2,7 @@
 # IPX configuration
 #
 
-comment 'IPX options'
-bool 'Full internal IPX network' CONFIG_IPX_INTERN
+bool 'IPX: Full internal IPX network' CONFIG_IPX_INTERN
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  dep_tristate 'IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
+fi
diff -u --recursive --new-file v2.1.95/linux/net/ipx/Makefile linux/net/ipx/Makefile
--- v2.1.95/linux/net/ipx/Makefile	Mon Feb 23 18:12:14 1998
+++ linux/net/ipx/Makefile	Sat Apr 11 17:18:16 1998
@@ -17,6 +17,14 @@
   O_OBJS += sysctl_net_ipx.o
 endif
 
+ifeq ($(CONFIG_SPX),y)
+OX_OBJS += af_spx.o
+else
+  ifeq ($(CONFIG_SPX),m)
+  MX_OBJS += af_spx.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 tar:
diff -u --recursive --new-file v2.1.95/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.95/linux/net/ipx/af_ipx.c	Tue Mar 17 22:18:16 1998
+++ linux/net/ipx/af_ipx.c	Sat Apr 11 17:18:16 1998
@@ -1,5 +1,5 @@
 /*
- *	Implements an IPX socket layer (badly - but I'm working on it).
+ *	Implements an IPX socket layer.
  *
  *	This code is derived from work by
  *		Ross Biro	: 	Writing the original IP stack
@@ -47,6 +47,7 @@
  *	Revision 0.36:	Internal bump up for 2.1
  *	Revision 0.37:	Began adding POSIXisms.
  *	Revision 0.38:  Asynchronous socket stuff made current.
+ *	Revision 0.39: 	SPX interfaces
  *
  *	Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
  *	pair. Also, now usage count is managed this way
@@ -111,6 +112,8 @@
 
 static struct proto_ops ipx_dgram_ops;
 
+static struct net_proto_family *spx_family_ops;
+
 static ipx_route 	*ipx_routes = NULL;
 static ipx_interface	*ipx_interfaces = NULL;
 static ipx_interface	*ipx_primary_net = NULL;
@@ -163,7 +166,7 @@
  *	use this facility.
  */
 
-static void ipx_remove_socket(struct sock *sk)
+void ipx_remove_socket(struct sock *sk)
 {
 	struct sock	*s;
 	ipx_interface	*intrfc;
@@ -762,8 +765,8 @@
 					if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)==FW_ACCEPT)
 					{
 					        skb2 = skb_clone(skb, GFP_ATOMIC);
-					ipxrtr_route_skb(skb2);
-				}
+						ipxrtr_route_skb(skb2);
+					}
 				}
 			}
 			/*
@@ -1264,6 +1267,9 @@
 	 */
 
 	__u32 i=length>>1;
+	char    hops = packet->ipx_tctrl;
+
+	packet->ipx_tctrl = 0;     /* hop count excluded from checksum calc */
 
 	/*
 	 *	Loop through all complete words except the checksum field
@@ -1279,6 +1285,7 @@
 	if(packet->ipx_pktsize&htons(1))
 		sum+=ntohs(0xff00)&*p;
 
+	packet->ipx_tctrl = hops;
 	/*
 	 *	Do final fixup
 	 */
@@ -1713,19 +1720,24 @@
 static int ipx_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	sk=sk_alloc(AF_IPX, GFP_KERNEL, 1);
-	if(sk==NULL)
-		return(-ENOMEM);
 	switch(sock->type)
 	{
 		case SOCK_DGRAM:
+			sk=sk_alloc(AF_IPX, GFP_KERNEL, 1);
+			if(sk==NULL)
+				return(-ENOMEM);
                         sock->ops = &ipx_dgram_ops;
                         break;
-		case SOCK_STREAM:	/* Allow higher levels to piggyback */
 		case SOCK_SEQPACKET:
-			printk(KERN_CRIT "IPX: _create-ing non_DGRAM socket\n");
+			/*
+			 *	From this point on SPX sockets are handled
+			 *	by af_spx.c and the methods replaced.
+			 */
+			if(spx_family_ops)
+				return spx_family_ops->create(sock,protocol);
+			/* Fall through if SPX is not loaded */			
+		case SOCK_STREAM:	/* Allow higher levels to piggyback */
 		default:
-			sk_free(sk);
 			return(-ESOCKTNOSUPPORT);
 	}
 	sock_init_data(sock,sk);
@@ -2249,6 +2261,34 @@
 	return(0);
 }
 
+/*
+ *	SPX interface support
+ */
+
+int ipx_register_spx(struct proto_ops **p, struct net_proto_family *spx)
+{
+	if(spx_family_ops!=NULL)
+		return -EBUSY;
+	cli();
+	MOD_INC_USE_COUNT;
+	*p=&ipx_dgram_ops;
+	spx_family_ops=spx;
+	sti();
+	return 0;
+}
+
+int ipx_unregister_spx(void)
+{
+	spx_family_ops=NULL;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+/*
+ *	Socket family declarations
+ */
+ 
 static struct net_proto_family ipx_family_ops = {
 	AF_IPX,
 	ipx_create
@@ -2256,7 +2296,6 @@
 
 static struct proto_ops ipx_dgram_ops = {
 	AF_IPX,
-
 	sock_no_dup,
 	ipx_release,
 	ipx_bind,
@@ -2280,7 +2319,7 @@
 static struct packet_type ipx_8023_packet_type =
 
 {
-	0,	/* MUTTER ntohs(ETH_P_8023),*/
+	0,	/* MUTTER ntohs(ETH_P_802_3),*/
 	NULL,		/* All devices */
 	ipx_rcv,
 	NULL,
@@ -2371,6 +2410,10 @@
 /* Export symbols for higher layers */
 EXPORT_SYMBOL(ipxrtr_route_skb);
 EXPORT_SYMBOL(ipx_if_offset);
+EXPORT_SYMBOL(ipx_remove_socket);
+EXPORT_SYMBOL(ipx_register_spx);
+EXPORT_SYMBOL(ipx_unregister_spx);
+
 
 #ifdef MODULE
 /* Note on MOD_{INC,DEC}_USE_COUNT:
@@ -2387,7 +2430,8 @@
  */
 
 __initfunc(static void ipx_proto_finito(void))
-{	ipx_interface	*ifc;
+{
+	ipx_interface	*ifc;
 
 	while (ipx_interfaces) {
 		ifc = ipx_interfaces;
diff -u --recursive --new-file v2.1.95/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- v2.1.95/linux/net/ipx/af_spx.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipx/af_spx.c	Sat Apr 11 17:18:16 1998
@@ -0,0 +1,872 @@
+/*
+ *	This module implements the (SPP-derived) Sequenced Packet eXchange
+ *	(SPX) protocol for Linux 2.1.X as specified in
+ *		NetWare SPX Services Specification, Semantics and API
+ *		 Revision:       1.00
+ *		 Revision Date:  February 9, 1993
+ *
+ *	Developers:
+ *      Jay Schulist    <Jay.Schulist@spacs.k12.wi.us>
+ *	Jim Freeman	<jfree@caldera.com>
+ *
+ *	Changes:
+ *	Alan Cox	:	Fixed an skb_unshare check for NULL
+ *				that crashed it under load. Renamed and
+ *				made static the ipx ops. Removed the hack
+ *				ipx methods interface. Dropped AF_SPX - its
+ *				the wrong abstraction.
+ *
+ *	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.
+ *
+ *	None of the authors or maintainers or their employers admit
+ *	liability nor provide warranty for any of this software.
+ *	This material is provided "as is" and at no charge.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
+#include <linux/module.h>
+#include <net/ipx.h>
+#include <net/spx.h>
+#include <net/sock.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <linux/uio.h>
+#include <linux/unistd.h>
+#include <linux/firewall.h>
+
+static struct proto_ops *ipx_operations;
+static struct proto_ops spx_operations;
+static __u16  connids;
+
+/* Functions needed for SPX connection start up */
+static int spx_transmit(struct sock *sk,struct sk_buff *skb,int type,int len);
+static void spx_retransmit(unsigned long data);
+static void spx_watchdog(unsigned long data);
+void spx_rcv(struct sock *sk, int bytes);
+
+/* Create the SPX specific data */
+static int spx_sock_init(struct sock *sk)
+{
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+        pdata->state            = SPX_CLOSED;
+        pdata->sequence         = 0;
+	pdata->acknowledge	= 0;
+        pdata->source_connid    = htons(connids);
+	pdata->rmt_seq		= 0;
+        connids++;
+
+        pdata->owner            = (void *)sk;
+        pdata->sndbuf           = sk->sndbuf;
+
+        pdata->watchdog.function = spx_watchdog;
+        pdata->watchdog.data    = (unsigned long)sk;
+        pdata->wd_interval      = VERIFY_TIMEOUT;
+	pdata->retransmit.function = spx_retransmit;
+	pdata->retransmit.data	= (unsigned long)sk;
+	pdata->retransmits	= 0;
+        pdata->retries          = 0;
+        pdata->max_retries      = RETRY_COUNT;
+
+	skb_queue_head_init(&pdata->rcv_queue);
+	skb_queue_head_init(&pdata->transmit_queue);
+	skb_queue_head_init(&pdata->retransmit_queue);
+
+        return (0);
+}
+
+static int spx_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	sk = sk_alloc(AF_IPX, GFP_KERNEL, 1);
+	if(sk == NULL)
+                return (-ENOMEM);
+
+	switch(sock->type)
+        {
+                case SOCK_SEQPACKET:
+			sock->ops = &spx_operations;
+			break;
+		default:
+			sk_free(sk);
+                        return (-ESOCKTNOSUPPORT);
+        }
+
+	sock_init_data(sock, sk);
+	spx_sock_init(sk);
+	sk->data_ready  = spx_rcv;
+	sk->destruct 	= NULL;
+        sk->mtu 	= IPX_MTU;
+        sk->no_check 	= 1;
+
+        MOD_INC_USE_COUNT;
+
+	return (0);
+}
+
+static int spx_shutdown(struct socket *sk,int how)
+{
+        return (-EOPNOTSUPP);
+}
+
+void spx_close_socket(struct sock *sk)
+{
+	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+	pdata->state	= SPX_CLOSED;
+	sk->state 	= TCP_CLOSE;
+	del_timer(&pdata->retransmit);
+	del_timer(&pdata->watchdog);
+}
+
+void spx_destroy_socket(struct sock *sk)
+{
+	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+	struct sk_buff *skb;
+
+        ipx_remove_socket(sk);
+        while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+                kfree_skb(skb);
+	while((skb = skb_dequeue(&pdata->transmit_queue)) != NULL)
+                kfree_skb(skb);
+	while((skb = skb_dequeue(&pdata->retransmit_queue)) != NULL)
+		kfree_skb(skb);
+	while((skb = skb_dequeue(&pdata->rcv_queue)) != NULL)
+                kfree_skb(skb);
+
+        sk_free(sk);
+	MOD_DEC_USE_COUNT;
+}
+
+/* Release an SPX socket */
+static int spx_release(struct socket *sock, struct socket *peer)
+{
+ 	struct sock *sk = sock->sk;
+	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+	if(sk == NULL)
+		return (0);
+	if(!sk->dead)
+                sk->state_change(sk);
+        sk->dead = 1;
+
+	if(pdata->state != SPX_CLOSED)
+	{
+		spx_transmit(sk, NULL, DISCON, 0);
+		spx_close_socket(sk);
+	}
+
+	sock->sk	= NULL;
+	sk->socket 	= NULL;
+	spx_destroy_socket(sk);
+
+        return (0);
+}
+
+/* Move a socket into listening state. */
+static int spx_listen(struct socket *sock, int backlog)
+{
+        struct sock *sk = sock->sk;
+
+        if(sock->state != SS_UNCONNECTED)
+                return (-EINVAL);
+	if(sock->type != SOCK_SEQPACKET)
+		return (-EOPNOTSUPP);
+        if(sk->zapped != 0)
+                return (-EAGAIN);
+
+        if((unsigned) backlog == 0)     /* BSDism */
+                backlog = 1;
+        if((unsigned) backlog > SOMAXCONN)
+                backlog = SOMAXCONN;
+        sk->max_ack_backlog = backlog;
+        if(sk->state != TCP_LISTEN)
+        {
+                sk->ack_backlog = 0;
+                sk->state = TCP_LISTEN;
+        }
+        sk->socket->flags |= SO_ACCEPTCON;
+
+        return (0);
+}
+
+/* Accept a pending SPX connection */
+static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+        struct sock *sk;
+        struct sock *newsk;
+        struct sk_buff *skb;
+	int err;
+
+	if(newsock->sk != NULL)
+		spx_destroy_socket(newsock->sk);
+        newsock->sk = NULL;
+
+	if(sock->sk == NULL)
+		return (-EINVAL);
+	sk = sock->sk;
+
+        if((sock->state != SS_UNCONNECTED) || !(sock->flags & SO_ACCEPTCON))
+                return (-EINVAL);
+        if(sock->type != SOCK_SEQPACKET)
+		return (-EOPNOTSUPP);
+	if(sk->state != TCP_LISTEN)
+                return (-EINVAL);
+
+	cli();
+	do {
+		skb = skb_dequeue(&sk->receive_queue);
+		if(skb == NULL)
+		{
+                	if(flags & O_NONBLOCK)
+			{
+                                sti();
+                                return (-EWOULDBLOCK);
+                        }
+                	interruptible_sleep_on(sk->sleep);
+                	if(signal_pending(current))
+                	{
+                        	sti();
+                        	return (-ERESTARTSYS);
+                	}
+		}
+	} while (skb == NULL);
+
+	newsk 		= skb->sk;
+        newsk->pair 	= NULL;
+	sti();
+
+	err = spx_transmit(newsk, skb, CONACK, 0);   /* Connection ACK */
+	if(err)
+		return (err);
+
+	/* Now attach up the new socket */
+	sock->sk 	= NULL;
+        sk->ack_backlog--;
+        newsock->sk 	= newsk;
+	newsk->state 	= TCP_ESTABLISHED;
+	newsk->protinfo.af_ipx.dest_addr = newsk->tp_pinfo.af_spx.dest_addr;
+
+	return (0);
+}
+
+/* Build a connection to an SPX socket */
+static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
+                int addr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+        struct sockaddr_ipx src;
+	struct sk_buff *skb;
+	int size, err;
+
+	size = sizeof(src);
+	err  = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0);
+	if(err)
+		return (err);
+
+        pdata->source_addr.net	= src.sipx_network;
+        memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
+        pdata->source_addr.sock = (unsigned short)src.sipx_port;
+
+	err = ipx_operations->connect(sock, uaddr, addr_len, flags);
+        if(err)
+                return (err);
+
+        pdata->dest_addr = sk->protinfo.af_ipx.dest_addr;
+	pdata->state	 = SPX_CONNECTING;
+	sock->state	 = SS_CONNECTING;
+        sk->state	 = TCP_SYN_SENT;
+
+        /* Send Connection request */
+	err = spx_transmit(sk, NULL, CONREQ, 0);
+        if(err)
+                return (err);
+
+	cli();
+        do {
+                skb = skb_dequeue(&sk->receive_queue);
+                if(skb == NULL)
+                {
+                        if(flags & O_NONBLOCK)
+                        {
+                                sti();
+                                return (-EWOULDBLOCK);
+                        }
+                        interruptible_sleep_on(sk->sleep);
+                        if(signal_pending(current))
+                        {
+                                sti();
+                                return (-ERESTARTSYS);
+                        }
+                }
+        } while (skb == NULL);
+
+        if(pdata->state == SPX_CLOSED)
+        {
+		sti();
+                del_timer(&pdata->watchdog);
+                return (-ETIMEDOUT);
+        }
+
+	sock->state	= SS_CONNECTED;
+	sk->state 	= TCP_ESTABLISHED;
+	kfree_skb(skb);
+	sti();
+
+        return (0);
+}
+
+/*
+ * Calculate the timeout for a packet. Thankfully SPX has a large
+ * fudge factor (3/4 secs) and does not pay much attention to RTT.
+ * As we simply have a default retry time of 1*HZ and a max retry
+ * time of 5*HZ. Between those values we increase the timeout based
+ * on the number of retransmit tries.
+ */
+static inline unsigned long spx_calc_rtt(int tries)
+{
+        if(tries < 1)
+                return (RETRY_TIME);
+        if(tries > 5)
+                return (MAX_RETRY_DELAY);
+        return (tries * HZ);
+}
+
+static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
+{
+	struct sk_buff *skb2;
+	int err = 0;
+
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if(skb==NULL)
+		return -ENOBUFS;
+
+	switch(type)
+	{
+		case (DATA):
+			if(!skb_queue_empty(&pdata->retransmit_queue))
+			{
+				skb_queue_tail(&pdata->transmit_queue, skb);
+				return 0;
+			}
+
+		case (TQUEUE):
+			pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
+			add_timer(&pdata->retransmit);
+
+			skb2 = skb_clone(skb, GFP_BUFFER);
+	                if(skb2 == NULL)
+        	                return -ENOBUFS;
+        	        skb_queue_tail(&pdata->retransmit_queue, skb2);
+
+		case (ACK):
+		case (CONREQ):
+		case (CONACK):
+		case (WDREQ):
+		case (WDACK):
+		case (DISCON):
+		case (DISACK):
+		case (RETRAN):
+		default:
+			/* Send data */
+        		err = ipxrtr_route_skb(skb);
+        		if(err)
+                		kfree_skb(skb);
+	}
+
+	return (err);
+}
+
+/* SPX packet transmit engine */
+static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
+{
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+        struct ipxspxhdr *ipxh;
+	int flags, err;
+
+	if(skb == NULL)
+	{
+		int offset  = ipx_if_offset(pdata->dest_addr.net);
+        	int size    = offset + sizeof(struct ipxspxhdr);
+
+		save_flags(flags);
+		cli();
+        	skb = sock_alloc_send_skb(sk, size, 0, 0, &err);
+        	if(skb == NULL)
+                	return (-ENOMEM);
+        	skb_reserve(skb, offset);
+        	skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
+		restore_flags(flags);
+	}
+
+	/* IPX header */
+	ipxh = (struct ipxspxhdr *)skb->nh.raw;
+	ipxh->ipx.ipx_checksum  = 0xFFFF;
+	ipxh->ipx.ipx_pktsize   = htons(SPX_SYS_PKT_LEN);
+        ipxh->ipx.ipx_tctrl     = 0;
+	ipxh->ipx.ipx_type 	= IPX_TYPE_SPX;
+        ipxh->ipx.ipx_dest      = pdata->dest_addr;
+        ipxh->ipx.ipx_source    = pdata->source_addr;
+
+	/* SPX header */
+        ipxh->spx.dtype         = 0;
+	ipxh->spx.sequence      = htons(pdata->sequence);
+	ipxh->spx.ackseq        = htons(pdata->rmt_seq);
+	ipxh->spx.sconn         = pdata->source_connid;
+        ipxh->spx.dconn         = pdata->dest_connid;
+        ipxh->spx.allocseq      = htons(pdata->alloc);
+
+	/* Reset/Set WD timer */
+        del_timer(&pdata->watchdog);
+        pdata->watchdog.expires = jiffies + VERIFY_TIMEOUT;
+        add_timer(&pdata->watchdog);
+
+	switch(type)
+	{
+		case (DATA):	/* Data */
+			ipxh->ipx.ipx_pktsize 	= htons(SPX_SYS_PKT_LEN + len);
+			ipxh->spx.cctl 		= (CCTL_ACK | CCTL_EOM);
+                	pdata->sequence++;
+			break;
+
+		case (ACK):	/* Connection/WD/Data ACK */
+			pdata->rmt_seq++;
+		case (WDACK):
+		case (CONACK):
+			ipxh->spx.cctl 		= CCTL_SYS;
+			ipxh->spx.ackseq 	= htons(pdata->rmt_seq);
+			break;
+
+		case (CONREQ):	/* Connection Request */
+			del_timer(&pdata->watchdog);
+		case (WDREQ):	/* WD Request */
+			pdata->source_connid    = htons(connids++);
+                	pdata->dest_connid      = 0xFFFF;
+                	pdata->alloc 		= 3 + pdata->rmt_seq;
+			ipxh->spx.cctl          = (CCTL_ACK | CCTL_SYS);
+			ipxh->spx.sconn         = pdata->source_connid;
+		        ipxh->spx.dconn         = pdata->dest_connid;
+		        ipxh->spx.allocseq      = htons(pdata->alloc);
+			break;
+
+		case (DISCON):	/* Informed Disconnect */
+			ipxh->spx.cctl 		= CCTL_ACK;
+			ipxh->spx.dtype 	= SPX_DTYPE_ECONN;
+			break;
+
+		case (DISACK):	/* Informed Disconnect ACK */
+			ipxh->spx.cctl  	= 0;
+			ipxh->spx.dtype 	= SPX_DTYPE_ECACK;
+			ipxh->spx.sequence 	= 0;
+			ipxh->spx.ackseq 	= htons(pdata->rmt_seq++);
+			break;
+
+		default:
+			return (-EOPNOTSUPP);
+	}
+
+	/* Send data */
+	spx_route_skb(pdata, skb, type);
+
+        return (0);
+}
+
+/* Check the state of the connection and send a WD request if needed. */
+static void spx_watchdog(unsigned long data)
+{
+	struct sock *sk = (struct sock*)data;
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+        del_timer(&pdata->watchdog);
+	if(pdata->retries > pdata->max_retries)
+        {
+		spx_close_socket(sk);	/* Unilateral Abort */
+                return;
+        }
+
+        /* Send WD request */
+	spx_transmit(sk, NULL, WDREQ, 0);
+	pdata->retries++;
+
+        return;
+}
+
+static void spx_retransmit(unsigned long data)
+{
+	struct sock *sk = (struct sock*)data;
+        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+	struct sk_buff *skb;
+	int err;
+
+	del_timer(&pdata->retransmit);
+	if(pdata->retransmits > RETRY_COUNT)
+	{
+		spx_close_socket(sk);   /* Unilateral Abort */
+                return;
+        }
+
+	/* need to leave skb on the queue! */
+	skb = skb_peek(&pdata->retransmit_queue);
+	if(skb_cloned(skb))
+                skb = skb_copy(skb, GFP_ATOMIC);
+        else
+                skb = skb_clone(skb, GFP_ATOMIC);
+
+	pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
+	add_timer(&pdata->retransmit);
+
+	err = spx_route_skb(pdata, skb, RETRAN);
+	pdata->retransmits++;
+
+	return;
+}
+
+/* SPX packet receive engine */
+void spx_rcv(struct sock *sk, int bytes)
+{
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	struct ipxspxhdr *ipxh;
+	struct ipxspxhdr *ipxh2;
+	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+
+	skb = skb_dequeue(&sk->receive_queue);
+	if(skb == NULL)
+		return;
+	ipxh = (struct ipxspxhdr *)skb->nh.raw;
+
+	/* Can't receive on a closed connection */
+        if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0))
+		return;
+	if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN)
+		return;
+        if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)
+		return;
+
+	/* insanity - rcv'd ACK of unsent data ?? */
+        if(ntohs(ipxh->spx.ackseq) > pdata->sequence)
+		return;
+
+	/* Reset WD timer on any received packet */
+	del_timer(&pdata->watchdog);
+	pdata->retries = 0;
+	pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
+        add_timer(&pdata->watchdog);
+
+	switch(ipxh->spx.cctl)
+	{
+		case (CCTL_SYS | CCTL_ACK):
+			if((ipxh->spx.sequence == 0)	/* ConReq */
+				&& (ipxh->spx.ackseq == 0)
+				&& (ipxh->spx.dconn == 0xFFFF))
+			{
+				pdata->state		= SPX_CONNECTED;
+				pdata->dest_addr        = ipxh->ipx.ipx_source;
+				pdata->source_addr      = ipxh->ipx.ipx_dest;
+				pdata->dest_connid      = ipxh->spx.sconn;
+				pdata->alloc = 3 + ntohs(ipxh->spx.sequence);
+
+				skb_queue_tail(&sk->receive_queue, skb);
+				wake_up_interruptible(sk->sleep);
+			}
+			else	/* WD Request */
+				spx_transmit(sk, skb, WDACK, 0);
+			break;
+
+		case CCTL_SYS:	/* ACK */
+			if((ipxh->spx.dtype == 0)       /* ConReq ACK */
+                                && (ipxh->spx.sconn != 0xFFFF)
+                                && (ipxh->spx.dconn != 0xFFFF)
+                                && (ipxh->spx.sequence == 0)
+                                && (ipxh->spx.ackseq == 0)
+                                && (pdata->state != SPX_CONNECTED))
+                        {
+                                pdata->state = SPX_CONNECTED;
+
+                                skb_queue_tail(&sk->receive_queue, skb);
+                                wake_up_interruptible(sk->sleep);
+                                break;
+                        }
+
+			/* Check Data/ACK seq */
+                        skb2 = skb_dequeue(&pdata->retransmit_queue);
+                        if(skb2)
+                        {
+				ipxh2 = (struct ipxspxhdr *)skb2->nh.raw;
+                                if((ntohs(ipxh2->spx.sequence)
+                                        == (ntohs(ipxh->spx.ackseq) - 1))
+					|| (ntohs(ipxh2->spx.sequence) == 65535
+					&& ntohs(ipxh->spx.ackseq) == 0))
+                                {
+					del_timer(&pdata->retransmit);
+					pdata->retransmits = 0;
+                                        kfree_skb(skb2);
+					if(skb_queue_empty(&pdata->retransmit_queue))
+					{
+						skb2 = skb_dequeue(&pdata->transmit_queue);
+						if(skb2 != NULL)
+							spx_route_skb(pdata, skb2, TQUEUE);
+					}
+                                }
+                                else    /* Out of Seq - ERROR! */
+				skb_queue_head(&pdata->retransmit_queue, skb2);
+                        }
+
+			kfree_skb(skb);
+			break;
+
+		case (CCTL_ACK):	/* Informed Disconnect */
+			if(ipxh->spx.dtype == SPX_DTYPE_ECONN)
+			{
+				spx_transmit(sk, skb, DISACK, 0);
+				spx_close_socket(sk);
+			}
+			break;
+
+		default:
+			if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)
+			{
+				pdata->rmt_seq = ntohs(ipxh->spx.sequence);
+				skb_queue_tail(&pdata->rcv_queue, skb);
+				wake_up_interruptible(sk->sleep);
+				spx_transmit(sk, NULL, ACK, 0);
+				break;
+			}
+
+			/* Catch All */
+			kfree_skb(skb);
+			break;
+	}
+
+        return;
+}
+
+/* Get message/packet data from user-land */
+static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int flags = msg->msg_flags;
+	struct sk_buff *skb;
+	int err, offset, size;
+
+	if(len > 534)
+                return (-EMSGSIZE);
+        if(sk->zapped)
+                return (-ENOTCONN); /* Socket not bound */
+	if(flags&~MSG_DONTWAIT)
+                return (-EINVAL);
+
+	offset	= ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);
+        size 	= offset + sizeof(struct ipxspxhdr) + len;
+        skb  	= sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
+        if(skb == NULL)
+                return (err);
+
+	skb->sk = sk;
+        skb_reserve(skb, offset);
+	skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
+
+	err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+	if(err)
+        {
+                kfree_skb(skb);
+                return (-EFAULT);
+        }
+
+	err = spx_transmit(sk, skb, DATA, len);
+	if(err)
+		return (-EAGAIN);
+
+        return (len);
+}
+
+/* Send message/packet data to user-land */
+static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			int flags, struct scm_cookie *scm)
+{
+	struct sk_buff *skb;
+	struct ipxspxhdr *ispxh;
+	struct sock *sk = sock->sk;
+	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
+	struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
+	int copied, err;
+
+        if(sk->zapped)
+                return (-ENOTCONN); /* Socket not bound */
+
+	lock_sock(sk);
+restart:
+        while(skb_queue_empty(&pdata->rcv_queue))      /* No data */
+        {
+                /* Socket errors? */
+                err = sock_error(sk);
+                if(err)
+			return (err);
+
+                /* Socket shut down? */
+                if(sk->shutdown & RCV_SHUTDOWN)
+			return (-ESHUTDOWN);
+
+                /* handle signals */
+                if(signal_pending(current))
+			return (-ERESTARTSYS);
+
+                /* User doesn't want to wait */
+                if(flags&MSG_DONTWAIT)
+			return (-EAGAIN);
+
+		release_sock(sk);
+        	save_flags(flags);
+        	cli();
+        	if(skb_peek(&pdata->rcv_queue) == NULL)
+                	interruptible_sleep_on(sk->sleep);
+        	restore_flags(flags);
+        	lock_sock(sk);
+        }
+
+        skb = skb_dequeue(&pdata->rcv_queue);
+        if(skb == NULL) 
+		goto restart;
+
+	ispxh 	= (struct ipxspxhdr *)skb->nh.raw;
+	copied 	= ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
+        if(copied > size)
+	{
+                copied = size;
+                msg->msg_flags |= MSG_TRUNC;
+        }
+
+	err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);
+        if(err)
+                return (-EFAULT);
+
+	msg->msg_namelen = sizeof(*sipx);
+	if(sipx)
+	{
+		sipx->sipx_family	= AF_IPX;
+                sipx->sipx_port		= ispxh->ipx.ipx_source.sock;
+                memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
+                sipx->sipx_network	= ispxh->ipx.ipx_source.net;
+                sipx->sipx_type 	= ispxh->ipx.ipx_type;
+        }
+	kfree_skb(skb);
+        release_sock(sk);
+
+	return (copied);
+}
+
+/*
+ * Functions which just wrap their IPX cousins
+ */
+
+static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+        int err;
+        err = ipx_operations->bind(sock, uaddr, addr_len);
+        return (err);
+}
+
+static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
+                         int *usockaddr_len, int peer)
+{
+	int err;
+	err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
+	return (err);
+}
+
+static int spx_ioctl (struct socket *sock, unsigned int cmd,
+                         unsigned long arg)
+{
+	int err;
+	err = ipx_operations->ioctl(sock, cmd, arg);
+	return (err);
+}
+
+static int spx_setsockopt(struct socket *sock, int level, int optname,
+                         char *optval, int optlen)
+{
+	int err;
+	err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
+	return (err);
+}
+
+static int spx_getsockopt(struct socket *sock, int level, int optname,
+                         char *optval, int *optlen)
+{
+	int err;
+	err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
+	return (err);
+}
+
+static struct proto_ops spx_operations = {
+        AF_IPX,
+        sock_no_dup,
+        spx_release,
+        spx_bind,
+        spx_connect,
+        sock_no_socketpair,
+        spx_accept,
+	spx_getname,
+        datagram_poll,  /* this does seqpacket too */
+	spx_ioctl,
+        spx_listen,
+        spx_shutdown,
+	spx_setsockopt,
+	spx_getsockopt,
+        sock_no_fcntl,
+        spx_sendmsg,
+        spx_recvmsg
+};
+
+static struct net_proto_family spx_family_ops=
+{
+	AF_IPX,
+	spx_create
+};
+
+
+void spx_proto_init(void)
+{
+	int error;
+
+	connids = (__u16)jiffies;	/* initalize random */
+
+	error = ipx_register_spx(&ipx_operations, &spx_family_ops);
+        if (error)
+                printk(KERN_ERR "SPX: unable to register with IPX.\n");
+
+	/* route socket(AF_IPX, SOCK_SEQPACKET) calls through spx_create() */
+
+	printk(KERN_INFO "Sequenced Packet eXchange (SPX) 0.01 for Linux NET3.037\n");
+	return;
+}
+
+void spx_proto_finito(void)
+{
+	ipx_unregister_spx();
+	return;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+        spx_proto_init();
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        spx_proto_finito();
+        return;
+}
+
+#endif /* MODULE */
+#endif /* CONFIG_SPX || CONFIG_SPX_MODULE */
diff -u --recursive --new-file v2.1.95/linux/net/netrom/Makefile linux/net/netrom/Makefile
--- v2.1.95/linux/net/netrom/Makefile	Mon Apr  7 11:35:33 1997
+++ linux/net/netrom/Makefile	Sat Apr 11 17:18:16 1998
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := netrom.o
-O_OBJS	 := af_netrom.o nr_dev.o nr_in.o nr_out.o nr_route.o nr_subr.o nr_timer.o
+O_OBJS	 := af_netrom.o nr_dev.o nr_in.o nr_loopback.o nr_out.o nr_route.o \
+	    nr_subr.o nr_timer.o
 M_OBJS   := $(O_TARGET)
 
 ifeq ($(CONFIG_SYSCTL),y)
diff -u --recursive --new-file v2.1.95/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.95/linux/net/netrom/af_netrom.c	Tue Mar 17 22:18:16 1998
+++ linux/net/netrom/af_netrom.c	Sat Apr 11 17:18:16 1998
@@ -259,6 +259,28 @@
 }
 
 /*
+ *	Find next free circuit ID.
+ */
+static unsigned short nr_find_next_circuit(void)
+{
+	unsigned short id = circuit;
+	unsigned char i, j;
+
+	for (;;) {
+		i = id / 256;
+		j = id % 256;
+
+		if (i != 0 && j != 0)
+			if (nr_find_socket(i, j) == NULL)
+				break;
+
+		id++;
+	}
+
+	return id;
+}
+
+/*
  *	Deferred destroy.
  */
 void nr_destroy_socket(struct sock *);
@@ -535,12 +557,12 @@
 	switch (sk->protinfo.nr->state) {
 
 		case NR_STATE_0:
+		case NR_STATE_1:
 		case NR_STATE_2:
 			nr_disconnect(sk, 0);
 			nr_destroy_socket(sk);
 			break;
 
-		case NR_STATE_1:
 		case NR_STATE_3:
 			nr_clear_queues(sk);
 			sk->protinfo.nr->n2count = 0;
@@ -670,8 +692,7 @@
 
 	sk->protinfo.nr->dest_addr = addr->sax25_call;
 
-	while (nr_find_socket((unsigned char)circuit / 256, (unsigned char)circuit % 256) != NULL)
-		circuit++;
+	circuit = nr_find_next_circuit();
 
 	sk->protinfo.nr->my_index = circuit / 256;
 	sk->protinfo.nr->my_id    = circuit % 256;
@@ -764,7 +785,6 @@
 	sti();
 
 	/* Now attach up the new socket */
-	skb->sk = NULL;
 	kfree_skb(skb);
 	sk->ack_backlog--;
 	newsock->sk = newsk;
@@ -802,7 +822,8 @@
 	struct sock *make;	
 	ax25_address *src, *dest, *user;
 	unsigned short circuit_index, circuit_id;
-	unsigned short frametype, window, timeout;
+	unsigned short peer_circuit_index, peer_circuit_id;
+	unsigned short frametype, flags, window, timeout;
 
 	skb->sk = NULL;		/* Initially we don't know who it's for */
 
@@ -813,28 +834,46 @@
 	src  = (ax25_address *)(skb->data + 0);
 	dest = (ax25_address *)(skb->data + 7);
 
-	circuit_index = skb->data[15];
-	circuit_id    = skb->data[16];
-	frametype     = skb->data[19] & 0x0F;
+	circuit_index      = skb->data[15];
+	circuit_id         = skb->data[16];
+	peer_circuit_index = skb->data[17];
+	peer_circuit_id    = skb->data[18];
+	frametype          = skb->data[19] & 0x0F;
+	flags              = skb->data[19] & 0xF0;
 
 #ifdef CONFIG_INET
 	/*
 	 * Check for an incoming IP over NET/ROM frame.
 	 */
-	 if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+	if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
 		skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-	 	skb->h.raw = skb->data;
+		skb->h.raw = skb->data;
 
 		return nr_rx_ip(skb, dev);
-	 }
+	}
 #endif
 
 	/*
 	 * Find an existing socket connection, based on circuit ID, if it's
 	 * a Connect Request base it on their circuit ID.
+	 *
+	 * Circuit ID 0/0 is not valid but it could still be a "reset" for a
+	 * circuit that no longer exists at the other end ...
 	 */
-	if ((frametype != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
-	    (frametype == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id)) != NULL)) {
+
+	sk = NULL;
+
+	if (circuit_index == 0 && circuit_id == 0) {
+		if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG)
+			sk = nr_find_peer(peer_circuit_index, peer_circuit_id);
+	} else {
+		if (frametype == NR_CONNREQ)
+			sk = nr_find_peer(circuit_index, circuit_id);
+		else
+			sk = nr_find_socket(circuit_index, circuit_id);
+	}
+
+	if (sk != NULL) {
 		skb->h.raw = skb->data;
 
 		if (frametype == NR_CONNACK && skb->len == 22)
@@ -845,15 +884,17 @@
 		return nr_process_rx_frame(sk, skb);
 	}
 
-	switch (frametype) {
-		case NR_CONNREQ:
-			break;
-		case NR_DISCREQ:
-		case NR_DISCACK:
-			return 0;
-		default:
-			nr_transmit_dm(skb);
-			return 0;
+	/*
+	 * Now it should be a CONNREQ.
+	 */
+	if (frametype != NR_CONNREQ) {
+		/*
+		 * Never reply to a CONNACK/CHOKE.
+		 */
+		if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
+			nr_transmit_refusal(skb, 1);
+
+		return 0;
 	}
 
 	sk = nr_find_listener(dest);
@@ -861,7 +902,7 @@
 	user = (ax25_address *)(skb->data + 21);
 
 	if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = nr_make_new(sk)) == NULL) {
-		nr_transmit_dm(skb);
+		nr_transmit_refusal(skb, 0);
 		return 0;
 	}
 
@@ -878,6 +919,8 @@
 	make->protinfo.nr->your_index  = circuit_index;
 	make->protinfo.nr->your_id     = circuit_id;
 
+	circuit = nr_find_next_circuit();
+
 	make->protinfo.nr->my_index    = circuit / 256;
 	make->protinfo.nr->my_id       = circuit % 256;
 
@@ -1131,7 +1174,7 @@
 
 	cli();
 
-	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2     t4      idle   n2  wnd Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2     t4      idle   n2  wnd Snd-Q Rcv-Q inode\n");
 
 	for (s = nr_list; s != NULL; s = s->next) {
 		if ((dev = s->protinfo.nr->device) == NULL)
@@ -1143,7 +1186,7 @@
 			ax2asc(&s->protinfo.nr->user_addr));
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&s->protinfo.nr->dest_addr));
-		len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d\n",
+		len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n",
 			ax2asc(&s->protinfo.nr->source_addr),
 			devname,
 			s->protinfo.nr->my_index,
@@ -1166,7 +1209,8 @@
 			s->protinfo.nr->n2,
 			s->protinfo.nr->window,
 			atomic_read(&s->wmem_alloc),
-			atomic_read(&s->rmem_alloc));
+			atomic_read(&s->rmem_alloc),
+			s->socket != NULL ? s->socket->inode->i_ino : 0L);
 
 		pos = begin + len;
 
@@ -1273,6 +1317,8 @@
 	nr_register_sysctl();
 #endif
 
+	nr_loopback_init();
+
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&proc_net_nr);
 	proc_net_register(&proc_net_nr_neigh);
@@ -1305,6 +1351,8 @@
 	proc_net_unregister(PROC_NET_NR_NEIGH);
 	proc_net_unregister(PROC_NET_NR_NODES);
 #endif
+	nr_loopback_clear();
+
 	nr_rt_free();
 
 	ax25_protocol_release(AX25_P_NETROM);
diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- v2.1.95/linux/net/netrom/nr_in.c	Thu Feb 12 20:56:15 1998
+++ linux/net/netrom/nr_in.c	Sat Apr 11 17:18:16 1998
@@ -129,6 +129,10 @@
 {
 	switch (frametype) {
 
+		case NR_CONNACK | NR_CHOKE_FLAG:
+			nr_disconnect(sk, ECONNRESET);
+			break;
+
 		case NR_DISCREQ:
 			nr_write_internal(sk, NR_DISCACK);
 
@@ -170,6 +174,7 @@
 			nr_disconnect(sk, 0);
 			break;
 
+		case NR_CONNACK | NR_CHOKE_FLAG:
 		case NR_DISCACK:
 			nr_disconnect(sk, ECONNRESET);
 			break;
diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_loopback.c linux/net/netrom/nr_loopback.c
--- v2.1.95/linux/net/netrom/nr_loopback.c	Wed Dec 31 16:00:00 1969
+++ linux/net/netrom/nr_loopback.c	Sat Apr 11 17:18:16 1998
@@ -0,0 +1,107 @@
+/*
+ *	NET/ROM release 007
+ *
+ *	This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	NET/ROM 007	Tomi(OH2BNS)	Created this file.
+ *
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/skbuff.h>
+#include <net/netrom.h>
+
+static struct sk_buff_head loopback_queue;
+static struct timer_list loopback_timer;
+
+static void nr_set_loopback_timer(void);
+
+void nr_loopback_init(void)
+{
+	skb_queue_head_init(&loopback_queue);
+
+	init_timer(&loopback_timer);
+}
+
+static int nr_loopback_running(void)
+{
+	return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+}
+
+int nr_loopback_queue(struct sk_buff *skb)
+{
+	struct sk_buff *skbn;
+
+	skbn = skb_clone(skb, GFP_ATOMIC);
+
+	kfree_skb(skb);
+
+	if (skbn != NULL) {
+		skb_queue_tail(&loopback_queue, skbn);
+
+		if (!nr_loopback_running())
+			nr_set_loopback_timer();
+	}
+
+	return 1;
+}
+
+static void nr_loopback_timer(unsigned long);
+
+static void nr_set_loopback_timer(void)
+{
+	del_timer(&loopback_timer);
+
+	loopback_timer.data     = 0;
+	loopback_timer.function = &nr_loopback_timer;
+	loopback_timer.expires  = jiffies + 10;
+
+	add_timer(&loopback_timer);
+}
+
+static void nr_loopback_timer(unsigned long param)
+{
+	struct sk_buff *skb;
+	ax25_address *nr_dest;
+	struct device *dev;
+
+	while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+		nr_dest = (ax25_address *)(skb->data + 7);
+
+		if ((dev = nr_dev_get(nr_dest)) == NULL) {
+			kfree_skb(skb);
+			continue;
+		}
+
+		if (nr_rx_frame(skb, dev) == 0)
+			kfree_skb(skb);
+	}
+}
+
+#ifdef MODULE
+
+void nr_loopback_clear(void)
+{
+	struct sk_buff *skb;
+
+	del_timer(&loopback_timer);
+
+	while ((skb = skb_dequeue(&loopback_queue)) != NULL)
+		kfree_skb(skb);
+}
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c
--- v2.1.95/linux/net/netrom/nr_route.c	Mon Jul  7 08:20:00 1997
+++ linux/net/netrom/nr_route.c	Sat Apr 11 17:18:16 1998
@@ -697,8 +697,12 @@
 		nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
 			    ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser);
 
-	if ((dev = nr_dev_get(nr_dest)) != NULL)	/* Its for me */
-		return nr_rx_frame(skb, dev);
+	if ((dev = nr_dev_get(nr_dest)) != NULL) {	/* Its for me */
+		if (ax25 == NULL)			/* Its from me */
+			return nr_loopback_queue(skb);
+		else
+			return nr_rx_frame(skb, dev);
+	}
 
 	if (!sysctl_netrom_routing_control && ax25 != NULL)
 		return 0;
diff -u --recursive --new-file v2.1.95/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- v2.1.95/linux/net/netrom/nr_subr.c	Thu Feb 12 20:56:15 1998
+++ linux/net/netrom/nr_subr.c	Sat Apr 11 17:18:16 1998
@@ -229,7 +229,7 @@
  * This routine is called when a Connect Acknowledge with the Choke Flag
  * set is needed to refuse a connection.
  */
-void nr_transmit_dm(struct sk_buff *skb)
+void nr_transmit_refusal(struct sk_buff *skb, int mine)
 {
 	struct sk_buff *skbn;
 	unsigned char *dptr;
@@ -258,10 +258,18 @@
 
 	*dptr++ = sysctl_netrom_network_ttl_initialiser;
 
-	*dptr++ = skb->data[15];
-	*dptr++ = skb->data[16];
-	*dptr++ = 0;
-	*dptr++ = 0;
+	if (mine) {
+		*dptr++ = 0;
+		*dptr++ = 0;
+		*dptr++ = skb->data[15];
+		*dptr++ = skb->data[16];
+	} else {
+		*dptr++ = skb->data[15];
+		*dptr++ = skb->data[16];
+		*dptr++ = 0;
+		*dptr++ = 0;
+	}
+
 	*dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
 	*dptr++ = 0;
 
diff -u --recursive --new-file v2.1.95/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.95/linux/net/netsyms.c	Wed Apr  1 20:11:55 1998
+++ linux/net/netsyms.c	Mon Apr 13 16:57:53 1998
@@ -66,10 +66,18 @@
 extern void destroy_8023_client(struct datalink_proto *);
 #endif
 
+#ifdef CONFIG_IPV6_MODULE
+#ifdef CONFIG_SYSCTL
+extern int sysctl_max_syn_backlog;
+#endif
+#endif
+
 #ifdef CONFIG_ATALK_MODULE
 #include <net/sock.h>
 #endif
 
+EXPORT_SYMBOL(dev_lockct);
+
 /* Skbuff symbols. */
 EXPORT_SYMBOL(skb_push_errstr);
 EXPORT_SYMBOL(skb_put_errstr);
@@ -177,17 +185,10 @@
 EXPORT_SYMBOL(destroy_EII_client);
 #endif
 
-#ifdef CONFIG_ATALK_MODULE
 EXPORT_SYMBOL(sklist_destroy_socket);
-#endif
-
-#if defined(CONFIG_ATALK_MODULE) || defined(CONFIG_PACKET_MODULE)
 EXPORT_SYMBOL(sklist_insert_socket);
-#endif
 
-#ifdef CONFIG_SMB_FS_MODULE
 EXPORT_SYMBOL(scm_detach_fds);
-#endif
 
 #ifdef CONFIG_INET
 /* Internet layer registration */
@@ -211,6 +212,7 @@
 EXPORT_SYMBOL(ip_mc_dec_group);
 EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
+EXPORT_SYMBOL(__release_sock);
 
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
@@ -242,11 +244,8 @@
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(memcpy_fromiovecend);
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
-EXPORT_SYMBOL(__release_sock);
 EXPORT_SYMBOL(net_timer);
 /* UDP/TCP exported functions for TCPv6 */
-EXPORT_SYMBOL(sysctl_tcp_timestamps);
-EXPORT_SYMBOL(sysctl_tcp_window_scaling);
 EXPORT_SYMBOL(sock_rspace);
 EXPORT_SYMBOL(udp_ioctl);
 EXPORT_SYMBOL(udp_connect);
@@ -301,6 +300,9 @@
 EXPORT_SYMBOL(dev_loopback_xmit);
 EXPORT_SYMBOL(tcp_regs);
 
+#ifdef CONFIG_SYSCTL
+EXPORT_SYMBOL(sysctl_max_syn_backlog);
+#endif
 #endif
 
 #ifdef CONFIG_NETLINK
@@ -328,18 +330,16 @@
 EXPORT_SYMBOL(neigh_dump_info);
 #endif
 
-#ifdef CONFIG_PACKET_MODULE
 EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
 EXPORT_SYMBOL(sklist_remove_socket);
 EXPORT_SYMBOL(rtnl_wait);
 EXPORT_SYMBOL(rtnl_rlockct);
-#endif
+EXPORT_SYMBOL(rtnl_lock);
+EXPORT_SYMBOL(rtnl_unlock);
 
-#if defined(CONFIG_IPV6_MODULE) || defined(CONFIG_PACKET_MODULE)
-EXPORT_SYMBOL(dev_lockct);
 EXPORT_SYMBOL(sock_wmalloc);
-#endif
+EXPORT_SYMBOL(sock_rmalloc);
 
 #if	defined(CONFIG_ULTRA)	||	defined(CONFIG_WD80x3)		|| \
 	defined(CONFIG_EL2)	||	defined(CONFIG_NE2000)		|| \
@@ -424,9 +424,6 @@
 EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(arp_rcv);
 EXPORT_SYMBOL(dev_mc_delete);
-
-EXPORT_SYMBOL(rtnl_lock);
-EXPORT_SYMBOL(rtnl_unlock);
 
 EXPORT_SYMBOL(if_port_text);
 
diff -u --recursive --new-file v2.1.95/linux/net/rose/Makefile linux/net/rose/Makefile
--- v2.1.95/linux/net/rose/Makefile	Mon Apr  7 11:35:33 1997
+++ linux/net/rose/Makefile	Sat Apr 11 17:18:16 1998
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := rose.o
-O_OBJS	 := af_rose.o rose_dev.o rose_in.o rose_link.o rose_out.o rose_route.o rose_subr.o rose_timer.o
+O_OBJS	 := af_rose.o rose_dev.o rose_in.o rose_link.o rose_loopback.o \
+	    rose_out.o rose_route.o rose_subr.o rose_timer.o
 M_OBJS   := $(O_TARGET)
 
 ifeq ($(CONFIG_SYSCTL),y)
diff -u --recursive --new-file v2.1.95/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.95/linux/net/rose/af_rose.c	Tue Mar 17 22:18:16 1998
+++ linux/net/rose/af_rose.c	Sat Apr 11 17:18:16 1998
@@ -1261,7 +1261,7 @@
 
 	cli();
 
-	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
 
 	for (s = rose_list; s != NULL; s = s->next) {
 		if ((dev = s->protinfo.rose->device) == NULL)
@@ -1278,7 +1278,7 @@
 		else
 			callsign = ax2asc(&s->protinfo.rose->source_call);
 
-		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d\n",
+		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
 			rose2asc(&s->protinfo.rose->source_addr),
 			callsign,
 			devname, 
@@ -1295,7 +1295,8 @@
 			ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ),
 			s->protinfo.rose->idle / (60 * HZ),
 			atomic_read(&s->wmem_alloc),
-			atomic_read(&s->rmem_alloc));
+			atomic_read(&s->rmem_alloc),
+			s->socket != NULL ? s->socket->inode->i_ino : 0L);
 
 		pos = begin + len;
 
@@ -1408,6 +1409,9 @@
 #ifdef CONFIG_SYSCTL
 	rose_register_sysctl();
 #endif
+	rose_loopback_init();
+
+	rose_add_loopback_neigh();
 
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&proc_net_rose);
@@ -1443,6 +1447,8 @@
 	proc_net_unregister(PROC_NET_RS_NODES);
 	proc_net_unregister(PROC_NET_RS_ROUTES);
 #endif
+	rose_loopback_clear();
+
 	rose_rt_free();
 
 	ax25_protocol_release(AX25_P_ROSE);
diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.1.95/linux/net/rose/rose_dev.c	Thu Feb 12 20:56:15 1998
+++ linux/net/rose/rose_dev.c	Sat Apr 11 17:18:16 1998
@@ -134,11 +134,11 @@
 {
 	struct sockaddr *sa = addr;
 
-	ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+	rose_del_loopback_node((rose_address *)dev->dev_addr);
 
 	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
 
-	ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+	rose_add_loopback_node((rose_address *)dev->dev_addr);
 
 	return 0;
 }
@@ -150,7 +150,7 @@
 
 	MOD_INC_USE_COUNT;
 
-	ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+	rose_add_loopback_node((rose_address *)dev->dev_addr);
 
 	return 0;
 }
@@ -162,7 +162,7 @@
 
 	MOD_DEC_USE_COUNT;
 
-	ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+	rose_del_loopback_node((rose_address *)dev->dev_addr);
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
--- v2.1.95/linux/net/rose/rose_in.c	Sun Nov 30 14:00:40 1997
+++ linux/net/rose/rose_in.c	Sat Apr 11 17:18:16 1998
@@ -141,10 +141,6 @@
 
 		case ROSE_RR:
 		case ROSE_RNR:
-			if (frametype == ROSE_RNR)
-				sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
-			else
-				sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
 			if (!rose_validate_nr(sk, nr)) {
 				rose_write_internal(sk, ROSE_RESET_REQUEST);
 				sk->protinfo.rose->condition = 0x00;
@@ -157,8 +153,11 @@
 				rose_stop_idletimer(sk);
 			} else {
 				rose_frames_acked(sk, nr);
-				if (frametype == ROSE_RNR)
-					rose_requeue_frames(sk);
+				if (frametype == ROSE_RNR) {
+					sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
+				} else {
+					sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
+				}
 			}
 			break;
 
@@ -177,16 +176,26 @@
 				break;
 			}
 			rose_frames_acked(sk, nr);
-			if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
-				break;
 			if (ns == sk->protinfo.rose->vr) {
 				rose_start_idletimer(sk);
 				if (sock_queue_rcv_skb(sk, skb) == 0) {
 					sk->protinfo.rose->vr = (sk->protinfo.rose->vr + 1) % ROSE_MODULUS;
 					queued = 1;
 				} else {
-					sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
+					/* Should never happen ! */
+					rose_write_internal(sk, ROSE_RESET_REQUEST);
+					sk->protinfo.rose->condition = 0x00;
+					sk->protinfo.rose->vs        = 0;
+					sk->protinfo.rose->vr        = 0;
+					sk->protinfo.rose->va        = 0;
+					sk->protinfo.rose->vl        = 0;
+					sk->protinfo.rose->state     = ROSE_STATE_4;
+					rose_start_t2timer(sk);
+					rose_stop_idletimer(sk);
+					break;
 				}
+				if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
+					sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
 			}
 			/*
 			 * If the window is full, ack the frame, else start the
diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.1.95/linux/net/rose/rose_link.c	Thu Feb 12 20:56:15 1998
+++ linux/net/rose/rose_link.c	Sat Apr 11 17:18:16 1998
@@ -113,7 +113,7 @@
 	else
 		rose_call = &rose_callsign;
 
-	neigh->ax25 = ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+	neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 
 	return (neigh->ax25 != NULL);
 }
@@ -293,6 +293,11 @@
 
 	if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) {
 		kfree_skb(skb);
+		return;
+	}
+
+	if (neigh->loopback) {
+		rose_loopback_queue(skb, neigh);
 		return;
 	}
 
diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_loopback.c linux/net/rose/rose_loopback.c
--- v2.1.95/linux/net/rose/rose_loopback.c	Wed Dec 31 16:00:00 1969
+++ linux/net/rose/rose_loopback.c	Sat Apr 11 17:18:16 1998
@@ -0,0 +1,126 @@
+/*
+ *	ROSE release 003
+ *
+ *	This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	ROSE 003	Jonathan(G4KLX)	Created this file from nr_loopback.c.
+ *
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/skbuff.h>
+#include <net/rose.h>
+
+static struct sk_buff_head loopback_queue;
+static struct timer_list loopback_timer;
+
+static void rose_set_loopback_timer(void);
+
+void rose_loopback_init(void)
+{
+	skb_queue_head_init(&loopback_queue);
+
+	init_timer(&loopback_timer);
+}
+
+static int rose_loopback_running(void)
+{
+	return (loopback_timer.prev != NULL || loopback_timer.next != NULL);
+}
+
+int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh)
+{
+	struct sk_buff *skbn;
+
+	skbn = skb_clone(skb, GFP_ATOMIC);
+
+	kfree_skb(skb);
+
+	if (skbn != NULL) {
+		skb_queue_tail(&loopback_queue, skbn);
+
+		if (!rose_loopback_running())
+			rose_set_loopback_timer();
+	}
+
+	return 1;
+}
+
+static void rose_loopback_timer(unsigned long);
+
+static void rose_set_loopback_timer(void)
+{
+	del_timer(&loopback_timer);
+
+	loopback_timer.data     = 0;
+	loopback_timer.function = &rose_loopback_timer;
+	loopback_timer.expires  = jiffies + 10;
+
+	add_timer(&loopback_timer);
+}
+
+static void rose_loopback_timer(unsigned long param)
+{
+	struct sk_buff *skb;
+	struct device *dev;
+	rose_address *dest;
+	struct sock *sk;
+	unsigned short frametype;
+	unsigned int lci_i, lci_o;
+
+	while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+		lci_i     = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+		frametype = skb->data[2];
+		dest      = (rose_address *)(skb->data + 4);
+		lci_o     = sysctl_rose_maximum_vcs - lci_i + 1;
+
+		skb->h.raw = skb->data;
+
+		if ((sk = rose_find_socket(lci_o, rose_loopback_neigh)) != NULL) {
+			if (rose_process_rx_frame(sk, skb) == 0)
+				kfree_skb(skb);
+			continue;
+		}
+
+		if (frametype == ROSE_CALL_REQUEST) {
+			if ((dev = rose_dev_get(dest)) != NULL) {
+				if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0)
+					kfree_skb(skb);
+			} else {
+				kfree_skb(skb);
+			}
+		} else {
+			kfree_skb(skb);
+		}
+	}
+}
+
+#ifdef MODULE
+
+void rose_loopback_clear(void)
+{
+	struct sk_buff *skb;
+
+	del_timer(&loopback_timer);
+
+	while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+		skb->sk = NULL;
+		kfree_skb(skb);
+	}
+}
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.95/linux/net/rose/rose_route.c linux/net/rose/rose_route.c
--- v2.1.95/linux/net/rose/rose_route.c	Thu Feb 12 20:56:15 1998
+++ linux/net/rose/rose_route.c	Sat Apr 11 17:18:16 1998
@@ -55,6 +55,8 @@
 static struct rose_neigh *rose_neigh_list = NULL;
 static struct rose_route *rose_route_list = NULL;
 
+struct rose_neigh *rose_loopback_neigh = NULL;
+
 static void rose_remove_neigh(struct rose_neigh *);
 
 /*
@@ -72,6 +74,9 @@
 		if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
 			break;
 
+	if (rose_node != NULL && rose_node->loopback)
+		return -EINVAL;
+
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
 		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
 			break;
@@ -87,6 +92,7 @@
 		rose_neigh->count     = 0;
 		rose_neigh->use       = 0;
 		rose_neigh->dce_mode  = 0;
+		rose_neigh->loopback  = 0;
 		rose_neigh->number    = rose_neigh_no++;
 		rose_neigh->restarted = 0;
 
@@ -123,6 +129,7 @@
 		rose_node->address      = rose_route->address;
 		rose_node->mask         = rose_route->mask;
 		rose_node->count        = 1;
+		rose_node->loopback     = 0;
 		rose_node->neighbour[0] = rose_neigh;
 
 		save_flags(flags); cli();
@@ -263,6 +270,8 @@
 
 	if (rose_node == NULL) return -EINVAL;
 
+	if (rose_node->loopback) return -EINVAL;
+
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
 		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
 			break;
@@ -299,6 +308,86 @@
 }
 
 /*
+ *	Add the loopback neighbour.
+ */
+int rose_add_loopback_neigh(void)
+{
+	unsigned long flags;
+
+	if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+	rose_loopback_neigh->callsign  = null_ax25_address;
+	rose_loopback_neigh->digipeat  = NULL;
+	rose_loopback_neigh->ax25      = NULL;
+	rose_loopback_neigh->dev       = NULL;
+	rose_loopback_neigh->count     = 0;
+	rose_loopback_neigh->use       = 0;
+	rose_loopback_neigh->dce_mode  = 1;
+	rose_loopback_neigh->loopback  = 1;
+	rose_loopback_neigh->number    = rose_neigh_no++;
+	rose_loopback_neigh->restarted = 1;
+
+	save_flags(flags); cli();
+	rose_loopback_neigh->next = rose_neigh_list;
+	rose_neigh_list           = rose_loopback_neigh;
+	restore_flags(flags);
+
+	return 0;
+}
+
+/*
+ *	Add a loopback node.
+ */
+int rose_add_loopback_node(rose_address *address)
+{
+	struct rose_node *rose_node;
+	unsigned long flags;
+
+	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
+		if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+			break;
+
+	if (rose_node != NULL) return 0;
+
+	if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+	rose_node->address      = *address;
+	rose_node->mask         = 10;
+	rose_node->count        = 1;
+	rose_node->loopback     = 1;
+	rose_node->neighbour[0] = rose_loopback_neigh;
+
+	save_flags(flags); cli();
+	rose_node->next = rose_node_list;
+	rose_node_list  = rose_node;
+	restore_flags(flags);
+
+	rose_loopback_neigh->count++;
+
+	return 0;
+}
+
+/*
+ *	Delete a loopback node.
+ */
+void rose_del_loopback_node(rose_address *address)
+{
+	struct rose_node *rose_node;
+
+	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
+		if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+			break;
+
+	if (rose_node == NULL) return;
+
+	rose_remove_node(rose_node);
+
+	rose_loopback_neigh->count--;
+}
+
+/*
  *	A device has been removed. Remove its routes and neighbours.
  */
 void rose_rt_device_down(struct device *dev)
@@ -723,16 +812,12 @@
 		    rosecmp(src_addr, &rose_route->src_addr) == 0 &&
 		    ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
 		    ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
-			printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr));
-			printk(KERN_DEBUG "ROSE:                to %s\n", rose2asc(dest_addr));
 			rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
 			return 0;
 		}
 	}
 
 	if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
-		if (cause == ROSE_NOT_OBTAINABLE)
-			printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr));
 		rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
 		return 0;
 	}
@@ -788,16 +873,22 @@
 	len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
 
 	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next) {
-		len += sprintf(buffer + len, "%-10s %04d %d",
-			rose2asc(&rose_node->address),
-			rose_node->mask,
-			rose_node->count);			
-
-		for (i = 0; i < rose_node->count; i++)
-			len += sprintf(buffer + len, " %05d",
-				rose_node->neighbour[i]->number);
+		if (rose_node->loopback) {
+			len += sprintf(buffer + len, "%-10s %04d 1 loopback\n",
+				rose2asc(&rose_node->address),
+				rose_node->mask);
+		} else {
+			len += sprintf(buffer + len, "%-10s %04d %d",
+				rose2asc(&rose_node->address),
+				rose_node->mask,
+				rose_node->count);
+
+			for (i = 0; i < rose_node->count; i++)
+				len += sprintf(buffer + len, " %05d",
+					rose_node->neighbour[i]->number);
 
-		len += sprintf(buffer + len, "\n");
+			len += sprintf(buffer + len, "\n");
+		}
 
 		pos = begin + len;
 
@@ -834,33 +925,35 @@
 	len += sprintf(buffer, "addr  callsign  dev  count use mode restart  t0  tf digipeaters\n");
 
 	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
-		len += sprintf(buffer + len, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3lu %3lu",
-			rose_neigh->number,
-			ax2asc(&rose_neigh->callsign),
-			rose_neigh->dev ? rose_neigh->dev->name : "???",
-			rose_neigh->count,
-			rose_neigh->use,
-			(rose_neigh->dce_mode) ? "DCE" : "DTE",
-			(rose_neigh->restarted) ? "yes" : "no",
-			ax25_display_timer(&rose_neigh->t0timer) / HZ,
-			ax25_display_timer(&rose_neigh->ftimer)  / HZ);
-
-		if (rose_neigh->digipeat != NULL) {
-			for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
-				len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
-		}
+		if (!rose_neigh->loopback) {
+			len += sprintf(buffer + len, "%05d %-9s %-4s   %3d %3d  %3s     %3s %3lu %3lu",
+				rose_neigh->number,
+				ax2asc(&rose_neigh->callsign),
+				rose_neigh->dev ? rose_neigh->dev->name : "???",
+				rose_neigh->count,
+				rose_neigh->use,
+				(rose_neigh->dce_mode) ? "DCE" : "DTE",
+				(rose_neigh->restarted) ? "yes" : "no",
+				ax25_display_timer(&rose_neigh->t0timer) / HZ,
+				ax25_display_timer(&rose_neigh->ftimer)  / HZ);
+
+			if (rose_neigh->digipeat != NULL) {
+				for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
+					len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+			}
 
-		len += sprintf(buffer + len, "\n");
+			len += sprintf(buffer + len, "\n");
 
-		pos = begin + len;
+			pos = begin + len;
 
-		if (pos < offset) {
-			len   = 0;
-			begin = pos;
-		}
+			if (pos < offset) {
+				len   = 0;
+				begin = pos;
+			}
 
-		if (pos > offset + length)
-			break;
+			if (pos > offset + length)
+				break;
+		}
 	}
 
 	sti();
diff -u --recursive --new-file v2.1.95/linux/net/socket.c linux/net/socket.c
--- v2.1.95/linux/net/socket.c	Wed Apr  1 20:11:55 1998
+++ linux/net/socket.c	Sat Apr 11 17:18:16 1998
@@ -547,20 +547,19 @@
 		return -1;
 	switch (how)
 	{
-		case 0:
-			kill_fasync(sock->fasync_list, SIGIO);
-			break;
-		case 1:
-			if (!(sock->flags & SO_WAITDATA))
-				kill_fasync(sock->fasync_list, SIGIO);
-			break;
-		case 2:
-			if (sock->flags & SO_NOSPACE)
-			{
-				kill_fasync(sock->fasync_list, SIGIO);
-				sock->flags &= ~SO_NOSPACE;
-			}
+	case 1:
+		if (sock->flags & SO_WAITDATA)
 			break;
+		goto call_kill;
+	case 2:
+		if (!(sock->flags & SO_NOSPACE))
+			break;
+		sock->flags &= ~SO_NOSPACE;
+		/* fall through */
+	case 0:
+	call_kill:
+		kill_fasync(sock->fasync_list, SIGIO);
+		break;
 	}
 	return 0;
 }
@@ -827,6 +826,7 @@
 			sys_close(err);
 			goto restart;
 		}
+		/* N.B. Should check for errors here */
 		move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
 	}
 
@@ -912,13 +912,13 @@
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
-	int len;
-	int err;
+	int len, err;
 
 	lock_kernel();
 	if ((sock = sockfd_lookup(fd, &err))!=NULL)
 	{
-		if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1))==0)
+		err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
+		if (!err)
 			err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
 		sockfd_put(sock);
 	}
@@ -940,28 +940,22 @@
 
 	lock_kernel();
 	sock = sockfd_lookup(fd, &err);
-	if (!sock)
-		goto out;
-	err = -EINVAL;
-	if (len < 0)
-		goto out_put;
-
-	iov.iov_base=buff;
-	iov.iov_len=len;
-	msg.msg_name=NULL;
-	msg.msg_namelen=0;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	msg.msg_control=NULL;
-	msg.msg_controllen=0;
-	if (sock->file->f_flags & O_NONBLOCK)
-		flags |= MSG_DONTWAIT;
-	msg.msg_flags = flags;
-	err = sock_sendmsg(sock, &msg, len);
+	if (sock) {
+		iov.iov_base=buff;
+		iov.iov_len=len;
+		msg.msg_name=NULL;
+		msg.msg_namelen=0;
+		msg.msg_iov=&iov;
+		msg.msg_iovlen=1;
+		msg.msg_control=NULL;
+		msg.msg_controllen=0;
+		if (sock->file->f_flags & O_NONBLOCK)
+			flags |= MSG_DONTWAIT;
+		msg.msg_flags = flags;
+		err = sock_sendmsg(sock, &msg, len);
 
-out_put:
-	sockfd_put(sock);
-out:
+		sockfd_put(sock);
+	}
 	unlock_kernel();
 	return err;
 }
@@ -1140,11 +1134,11 @@
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
-	struct iovec iov[UIO_FASTIOV];
+	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
 	unsigned char ctl[sizeof(struct cmsghdr) + 20];	/* 20 is size of ipv6_pktinfo */
 	unsigned char *ctl_buf = ctl;
 	struct msghdr msg_sys;
-	int err, ctl_len, total_len;
+	int err, ctl_len, iov_size, total_len;
 	
 	lock_kernel();
 
@@ -1152,20 +1146,29 @@
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
 		goto out; 
 
+	sock = sockfd_lookup(fd, &err);
+	if (!sock) 
+		goto out;
+
 	/* do not move before msg_sys is valid */
 	err = -EINVAL;
 	if (msg_sys.msg_iovlen > UIO_MAXIOV)
-		goto out;
+		goto out_put;
+
+	/* Check whether to allocate the iovec area*/
+	err = -ENOMEM;
+	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+	if (msg_sys.msg_iovlen > 1 /* UIO_FASTIOV */) {
+		iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+		if (!iov)
+			goto out_put;
+	}
 
 	/* This will also move the address data into kernel space */
 	err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
 	if (err < 0) 
-		goto out;
-	total_len=err;
-
-	sock = sockfd_lookup(fd, &err);
-	if (!sock) 
 		goto out_freeiov;
+	total_len = err;
 
 	ctl_len = msg_sys.msg_controllen; 
 	if (ctl_len) 
@@ -1181,7 +1184,7 @@
 			err = -ENOBUFS;
 			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
 			if (ctl_buf == NULL) 
-				goto out_put;
+				goto out_freeiov;
 		}
 		err = -EFAULT;
 		if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len))
@@ -1197,11 +1200,11 @@
 out_freectl:
 	if (ctl_buf != ctl)    
 		sock_kfree_s(sock->sk, ctl_buf, ctl_len);
+out_freeiov:
+	if (iov != iovstack)
+		sock_kfree_s(sock->sk, iov, iov_size);
 out_put:
 	sockfd_put(sock);
-out_freeiov:
-	if (msg_sys.msg_iov != iov)
-		kfree(msg_sys.msg_iov);
 out:       
 	unlock_kernel();
 	return err;
@@ -1218,9 +1221,7 @@
 	struct iovec *iov=iovstack;
 	struct msghdr msg_sys;
 	unsigned long cmsg_ptr;
-	int err;
-	int total_len;
-	int len = 0;
+	int err, iov_size, total_len, len;
 
 	/* kernel mode address */
 	char addr[MAX_SOCK_ADDR];
@@ -1234,10 +1235,23 @@
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
 		goto out;
 
-	err=-EINVAL;
-	if (msg_sys.msg_iovlen > UIO_MAXIOV)
+	sock = sockfd_lookup(fd, &err);
+	if (!sock)
 		goto out;
+
+	err = -EINVAL;
+	if (msg_sys.msg_iovlen > UIO_MAXIOV)
+		goto out_put;
 	
+	/* Check whether to allocate the iovec area*/
+	err = -ENOMEM;
+	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+	if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+		iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+		if (!iov)
+			goto out_put;
+	}
+
 	/*
 	 *	Save the user-mode address (verify_iovec will change the
 	 *	kernel msghdr to use the kernel address space)
@@ -1245,41 +1259,43 @@
 	 
 	uaddr = msg_sys.msg_name;
 	uaddr_len = &msg->msg_namelen;
-	err=verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
-	if (err<0)
-		goto out;
-
+	err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out_freeiov;
 	total_len=err;
 
 	cmsg_ptr = (unsigned long)msg_sys.msg_control;
 	msg_sys.msg_flags = 0;
 	
-	if ((sock = sockfd_lookup(fd, &err))!=NULL)
-	{
-		if (sock->file->f_flags & O_NONBLOCK)
-			flags |= MSG_DONTWAIT;
-		err=sock_recvmsg(sock, &msg_sys, total_len, flags);
-		if(err>=0)
-			len=err;
-		sockfd_put(sock);
-	}
-	if (msg_sys.msg_iov != iov)
-		kfree(msg_sys.msg_iov);
+	if (sock->file->f_flags & O_NONBLOCK)
+		flags |= MSG_DONTWAIT;
+	err = sock_recvmsg(sock, &msg_sys, total_len, flags);
+	if (err < 0)
+		goto out_freeiov;
+	len = err;
 
-	if (uaddr != NULL && err>=0)
+	if (uaddr != NULL) {
 		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
-	if (err < 0)
-		goto out;
+		if (err < 0)
+			goto out_freeiov;
+	}
 	err = __put_user(msg_sys.msg_flags, &msg->msg_flags);
 	if (err)
-		goto out;
+		goto out_freeiov;
 	err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, 
 							 &msg->msg_controllen);
+	if (err)
+		goto out_freeiov;
+	err = len;
+
+out_freeiov:
+	if (iov != iovstack)
+		sock_kfree_s(sock->sk, iov, iov_size);
+out_put:
+	sockfd_put(sock);
 out:
 	unlock_kernel();
-	if(err<0)
-		return err;
-	return len;
+	return err;
 }
 
 
@@ -1462,10 +1478,13 @@
 	 
 	sk_init();
 
+#ifdef SLAB_SKB
 	/*
 	 *	Initialize skbuff SLAB cache 
 	 */
 	skb_init();
+#endif
+
 
 	/*
 	 *	Wan router layer. 
diff -u --recursive --new-file v2.1.95/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.95/linux/net/x25/af_x25.c	Tue Mar 17 22:18:16 1998
+++ linux/net/x25/af_x25.c	Sun Apr 12 11:42:16 1998
@@ -1118,13 +1118,14 @@
 			struct x25_facilities facilities;
 			if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
 				return -EFAULT;
-			if (sk->state != TCP_LISTEN)
+			if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE)
 				return -EINVAL;
 			if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
 				return -EINVAL;
 			if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
 				return -EINVAL;
-			if (sk->protinfo.x25->neighbour->extended) {
+			if (sk->state == TCP_CLOSE || sk->protinfo.x25->neighbour->extended) 
+			{
 				if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
 					return -EINVAL;
 				if (facilities.winsize_out < 1 || facilities.winsize_out > 127)
@@ -1188,7 +1189,7 @@
 
 	cli();
 
-	len += sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   t  t2 t21 t22 t23 Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   t  t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
 
 	for (s = x25_list; s != NULL; s = s->next) {
 		if (s->protinfo.x25->neighbour == NULL || (dev = s->protinfo.x25->neighbour->dev) == NULL)
@@ -1196,7 +1197,7 @@
 		else
 			devname = s->protinfo.x25->neighbour->dev->name;
 
-		len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %5d %5d\n",
+		len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %5d %5d %ld\n",
 			(s->protinfo.x25->dest_addr.x25_addr[0] == '\0')   ? "*" : s->protinfo.x25->dest_addr.x25_addr,
 			(s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr,
 			devname, 
@@ -1211,7 +1212,8 @@
 			s->protinfo.x25->t22 / HZ,
 			s->protinfo.x25->t23 / HZ,
 			atomic_read(&s->wmem_alloc),
-			atomic_read(&s->rmem_alloc));
+			atomic_read(&s->rmem_alloc),
+			s->socket != NULL ? s->socket->inode->i_ino : 0L);
 
 		pos = begin + len;
 
diff -u --recursive --new-file v2.1.95/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.1.95/linux/net/x25/x25_in.c	Thu Feb 12 20:56:15 1998
+++ linux/net/x25/x25_in.c	Sat Apr 11 17:18:16 1998
@@ -184,11 +184,6 @@
 
 		case X25_RR:
 		case X25_RNR:
-			if (frametype == X25_RNR) {
-				sk->protinfo.x25->condition |= X25_COND_PEER_RX_BUSY;
-			} else {
-				sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
-			}
 			if (!x25_validate_nr(sk, nr)) {
 				x25_clear_queues(sk);
 				x25_write_internal(sk, X25_RESET_REQUEST);
@@ -201,8 +196,11 @@
 				sk->protinfo.x25->state     = X25_STATE_4;
 			} else {
 				x25_frames_acked(sk, nr);
-				if (frametype == X25_RNR)
-					x25_requeue_frames(sk);
+				if (frametype == X25_RNR) {
+					sk->protinfo.x25->condition |= X25_COND_PEER_RX_BUSY;
+				} else {
+					sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
+				}
 			}
 			break;
 
@@ -221,15 +219,25 @@
 				break;
 			}
 			x25_frames_acked(sk, nr);
-			if (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)
-				break;
 			if (ns == sk->protinfo.x25->vr) {
 				if (x25_queue_rx_frame(sk, skb, m) == 0) {
 					sk->protinfo.x25->vr = (sk->protinfo.x25->vr + 1) % modulus;
 					queued = 1;
 				} else {
-					sk->protinfo.x25->condition |= X25_COND_OWN_RX_BUSY;
+					/* Should never happen */
+					x25_clear_queues(sk);
+					x25_write_internal(sk, X25_RESET_REQUEST);
+					x25_start_t22timer(sk);
+					sk->protinfo.x25->condition = 0x00;
+					sk->protinfo.x25->vs        = 0;
+					sk->protinfo.x25->vr        = 0;
+					sk->protinfo.x25->va        = 0;
+					sk->protinfo.x25->vl        = 0;
+					sk->protinfo.x25->state     = X25_STATE_4;
+					break;
 				}
+				if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
+					sk->protinfo.x25->condition |= X25_COND_OWN_RX_BUSY;
 			}
 			/*
 			 *	If the window is full Ack it immediately, else
diff -u --recursive --new-file v2.1.95/linux/scripts/Configure linux/scripts/Configure
--- v2.1.95/linux/scripts/Configure	Wed Apr  1 20:11:55 1998
+++ linux/scripts/Configure	Fri Apr 10 15:18:55 1998
@@ -53,6 +53,10 @@
 #
 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
 # texts.
+#
+# 100498 Riley Williams (rhw@bigfoot.com) - added ability to display
+# blank lines in help texts: Any line consisting only of a single dot
+# will be displayed blank.
 
 #
 # Make sure we're really running bash.
@@ -103,7 +107,7 @@
      then
 	  echo; echo "  Sorry, no help available for this option yet.";echo
      else
-	  (echo; echo "$text") | ${PAGER:-more}
+	  (echo; echo "$text") | sed 's/^\.$//' | ${PAGER:-more}
      fi
   else
      echo;
diff -u --recursive --new-file v2.1.95/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.1.95/linux/scripts/Menuconfig	Wed Apr  1 20:11:55 1998
+++ linux/scripts/Menuconfig	Fri Apr 10 15:16:56 1998
@@ -48,6 +48,12 @@
 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
 # texts.
 #----------------------------------------------------------------------------
+#
+# 10 Apr 1998 - Added ability to display blank lines in help text: Any line
+#               which only contains a single dot will be displayed blank.
+#               Author: Riley Williams <rhw@bigfoot.com>
+#
+#----------------------------------------------------------------------------
 
 
 #
@@ -295,7 +301,7 @@
           echo "There is no help available for this kernel option."
 	  return 1
      else
-	  echo "$text"
+	  echo "$text" | sed 's/^\.$//'
      fi
   else
 	 echo "There is no help available for this kernel option."
