diff -u --recursive --new-file v1.3.63/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.63/linux/Documentation/Configure.help	Wed Feb 14 14:37:06 1996
+++ linux/Documentation/Configure.help	Thu Feb 15 09:20:41 1996
@@ -2041,6 +2041,20 @@
   want), say M here and read Documentation/modules.txt. Note that the
   filesystem of your root partition cannot be compiled as a module.
 
+fat fs support
+CONFIG_FAT_FS
+  If you want to use one of the FAT-based filesystems (the MS-DOS,
+  VFAT (Windows'95) and UMSDOS filesystems), then you must include
+  FAT support. This is not a filesystem in itself, but it provides
+  the foundation for the other filesystems. This option will enlarge
+  your kernel about 24 kB. If unsure, say Y. If you want to compile
+  this as a module however ( = code which can be inserted in and 
+  removed from the running kernel whenever you want), say M here and
+  read Documentation/modules.txt. Note that if you compile the FAT
+  support as a module, you cannot compile any of the FAT-based file-
+  systems into the kernel - they will have to be modules as well.
+  The filesystem of your root partition cannot be a module.
+
 msdos fs support
 CONFIG_MSDOS_FS
   This allows you to mount MSDOS partitions of your harddrive (unless
@@ -2056,14 +2070,30 @@
   which doesn't require the msdos filesystem support.  If you want to
   use umsdos, the Unix-like filesystem on top of DOS, which allows you
   to run Linux from within a DOS partition without repartitioning,
-  you'll have to say Y here. This option will enlarge your kernel by
-  about 25 kB. If unsure, say Y.  If you want to compile this as a
-  module however ( = code which can be inserted in and removed from
-  the running kernel whenever you want), say M here and read
-  Documentation/modules.txt. Note that the filesystem of your root
+  you'll have to say Y or M here. If your have Windows'95 or Windows NT 
+  installed on your MSDOS partitions, you should use the VFAT 
+  filesystem instead, or you will not be able to see the long filenames 
+  generated by Windows'95 / Windows NT. This option will enlarge your 
+  kernel by about 7 kB. If unsure, say Y.  If you want to compile this 
+  as a module however ( = code which can be inserted in and removed from 
+  the running kernel whenever you want), say M here and read 
+  Documentation/modules.txt. Note that the filesystem of your root 
   partition cannot be a module.
 
-umsdos: Unix like fs on top of std MSDOS FAT fs
+vfat fs support
+CONFIG_VFAT_FS
+  This allows you to mount MSDOS partitions of your harddrive. It
+  will let you use filenames in a way compatible with the long 
+  filenames used by Windows'95 and Windows NT fat-based (not NTFS)
+  partitions. It does not support Windows'95 compressed filesystems.
+  You cannot use the VFAT filesystem for your root partition; use
+  UMSDOS instead. This option enlarges your kernel by about 10 kB. 
+  If unsure, say N. If you want to compile this 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. Note that 
+  the filesystem of your root partition cannot be a module.
+
+umsdos: Unix like fs on top of std MSDOS fs
 CONFIG_UMSDOS_FS
   Say Y here if you want to run Linux from within an existing DOS
   partition of your harddrive. The advantage of this is that you can
diff -u --recursive --new-file v1.3.63/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt
--- v1.3.63/linux/Documentation/networking/arcnet-hardware.txt	Sun Jan 14 16:30:09 1996
+++ linux/Documentation/networking/arcnet-hardware.txt	Thu Feb 15 09:21:21 1996
@@ -1,4 +1,4 @@
-
+ 
 -----------------------------------------------------------------------------
 1) This file is a supplement to arcnet.txt.  Please read that for general
    driver configuration help.
@@ -26,7 +26,8 @@
 types, as far as I'm aware, are not compatible and so you cannot wire a
 100Mbps card to a 2.5Mbps card, and so on.  From what I hear, my driver does
 work with 100Mbps cards, but I haven't been able to verify this myself,
-since I only have the 2.5Mbps variety.
+since I only have the 2.5Mbps variety.  It is probably not going to saturate
+your 100Mbps card.  Stop complaining :)
 
 You also cannot connect an ARCnet card to any kind of ethernet card and
 expect it to work.  
@@ -46,6 +47,10 @@
 break, or because the destination computer does not exist) it will at least
 tell the sender about it.
 
+Because of the carefully defined action of the "token", it will always make
+a pass around the "ring" within a maximum length of time.  This makes it
+useful for realtime networks.
+
 In addition, all known ARCnet cards have an (almost) identical programming
 interface.  This means that with one "arcnet" driver you can support any
 card; whereas, with ethernet, each manufacturer uses what is sometimes a
@@ -60,9 +65,14 @@
 up to 508 bytes in length.  This is smaller than the internet "bare minimum"
 of 576 bytes, let alone the ethernet MTU of 1500.  To compensate, an extra
 level of encapsulation is defined by RFC1201, which I call "packet
-splitting," which allows "virtual packets" to grow as large as 64K each,
+splitting," that allows "virtual packets" to grow as large as 64K each,
 although they are generally kept down to the ethernet-style 1500 bytes.
 
+For more information on the advantages and disadvantages (mostly the
+advantages) of ARCnet networks, you might try the "ARCnet Trade Association"
+WWW page:
+	http://www.arcnet.com
+
 
 CABLING ARCNET NETWORKS
 -----------------------
@@ -260,7 +270,7 @@
     that IRQ2 is the same as IRQ9, as far as Linux is concerned.  You can
     "cat /proc/interrupts" for a somewhat complete list of which ones are in
     use at any given time.  Here is a list of common usages from Vojtech
-    Pavlik <vpav4328@diana.troja.mff.cuni.cz>:
+    Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>:
     	("Not on bus" means there is no way for a card to generate this
 	interrupt)
 	IRQ  0 - Timer 0 (Not on bus)
@@ -268,9 +278,9 @@
 	IRQ  2 - IRQ Controller 2 (Not on bus, nor does interrupt the CPU)
 	IRQ  3 - COM2
 	IRQ  4 - COM1
-	IRQ  5 - FREE (LPT2 if you have it; sometimes COM3)
+	IRQ  5 - FREE (LPT2 if you have it; sometimes COM3; maybe PLIP)
 	IRQ  6 - Floppy disk controller
-	IRQ  7 - FREE (LPT1 if you don't use the polling driver or PLIP) 
+	IRQ  7 - FREE (LPT1 if you don't use the polling driver; PLIP) 
 	IRQ  8 - Realtime Clock Interrupt (Not on bus)
 	IRQ  9 - FREE (VGA vertical sync interrupt if enabled)
 	IRQ 10 - FREE
@@ -279,6 +289,19 @@
 	IRQ 13 - Numeric Coprocessor (Not on bus)
 	IRQ 14 - Fixed Disk Controller
 	IRQ 15 - FREE (Fixed Disk Controller 2 if you have it) 
+	
+	Note: IRQ 9 is used on some video cards for the "vertical retrace"
+	interrupt.  This interrupt would have been handy for things like
+	video games, as it occurs exactly once per screen refresh, but
+	unfortunately IBM cancelled this feature starting with the original
+	VGA and thus many VGA/SVGA cards do not support it.  For this
+	reason, no modern software uses this interrupt and it can almost
+	always be safely disabled, if your video card supports it at all.
+	
+	If your card for some reason CANNOT disable this IRQ (usually there
+	is a jumper), one solution would be to clip the printed circuit
+	contact on the board: it's the fourth contact from the left on the
+	back side.  I take no responsibility if you try this.
 
 	- Avery's favourite: IRQ2 (actually IRQ9).  Watch that VGA, though.
 
@@ -324,7 +347,7 @@
     network.
     
 Also, on many cards (not mine, though) there are red and green LED's. 
-Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz> tells me this is what they
+Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz> tells me this is what they
 mean:
 	GREEN           RED             Status
 	-----		---		------
@@ -368,7 +391,7 @@
 	SMC		PC550Longboard		16
 	SMC		PC600			16
 	SMC		PC710			8
-	SMC?		LCS-8830-T		16?
+	SMC?		LCS-8830(-T)		8/16
 	Puredata	PDI507			8
 	CNet Tech	CN120-Series		8
 	CNet Tech	CN160-Series		16
@@ -974,9 +997,12 @@
 *****************************************************************************
 
 ** Possibly SMC **
-LCS-8830-T (16-bit card)
-------------------------
+LCS-8830(-T) (8 and 16-bit cards)
+---------------------------------
   - from Mathias Katzer <mkatzer@HRZ.Uni-Bielefeld.DE>
+  - Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl> says the
+    LCS-8830 is slightly different from LCS-8830-T.  These are 8 bit, BUS
+    only (the JP0 jumper is hardwired), and BNC only.
 	
 This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC,
 nowhere else, not even on the few xeroxed sheets from the manual).
@@ -1709,7 +1735,7 @@
 ** Acer **
 8-bit card, Model 5210-003
 --------------------------
-  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz> using portions of
+  - from Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz> using portions of
     the existing arcnet-hardware file.
 
 This is a 90C26 based card.  Its configuration seems similar to 
@@ -1877,7 +1903,7 @@
 ** Datapoint? **
 LAN-ARC-8, an 8-bit card
 ------------------------
-  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz>
+  - from Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
 
 This is another SMC 90C65 based arcnet card. I couldn't identify the
 manufacturer, but it might be DataPoint, becsuse the card has the
@@ -2017,7 +2043,7 @@
 ** Topware **
 8-bit card, TA-ARC/10
 -------------------------
-  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz>
+  - from Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
 
 This is another very similar 90C65 card. Most of the switches and jumpers
 are the same as on other clones.
@@ -2726,7 +2752,7 @@
 ** No Name **
 8-bit cards ("Made in Taiwan R.O.C.")
 -----------
-  - from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz>
+  - from Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
 
 I have named this ARCnet card "NONAME", since I got only the card with
 no manual at all and the only text identifying the manufacturer is 
diff -u --recursive --new-file v1.3.63/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt
--- v1.3.63/linux/Documentation/networking/arcnet.txt	Sun Jan 14 16:30:09 1996
+++ linux/Documentation/networking/arcnet.txt	Thu Feb 15 09:21:15 1996
@@ -7,8 +7,8 @@
 
 Since no one seems to listen to me otherwise, perhaps a poem will get your
 attention:
-			This is scary software
-			If it works I DO CARE.
+		This driver's getting fat and beefy,
+		But my cat is still named Fifi.
 
 Hmm, I think I'm allowed to call that a poem, even though it's only two
 lines.  Hey, I'm in Computer Science, not English.  Give me a break.
@@ -46,16 +46,16 @@
 These are the ARCnet drivers for Linux.
 
 This new release has resulted from many months of on-and-off effort from me
-(Avery Pennarun), many bug reports from users, and in particular a lot of
-input and coding from Tomasz Motylewski.  Starting with ARCnet 2.10 ALPHA,
-Tomasz's all-new-and-improved RFC1051 support has been included and seems to
-be working fine!
+(Avery Pennarun), many bug reports/fixes and suggestions from others, and in
+particular a lot of input and coding from Tomasz Motylewski.  Starting with
+ARCnet 2.10 ALPHA, Tomasz's all-new-and-improved RFC1051 support has been
+included and seems to be working fine!
 
 
 Where do I discuss these drivers?
 ---------------------------------
 
-BOINGY - the linux-arcnet@807-city.on.ca mailing list is now so unstable
+HEY!! - the linux-arcnet@807-city.on.ca mailing list is now so unstable
 that I can't recommend people even bother with it.  I no longer have an
 account on 807-CITY (though they still graciously forward my mail to me) so
 there's not much I can do.
@@ -65,12 +65,9 @@
 linux-arcnet YOUR REAL NAME" to listserv@tichy.ch.uj.edu.pl.  Then, to
 submit messages to the list, mail to linux-arcnet@tichy.ch.uj.edu.pl.
 
-There are mailing list archives at:
+There are archives of the mailing list at:
 	http://tichy.ch.uj.edu.pl/lists/linux-arcnet
 
-Send all bug (or success) reports to me, then, not the list, since (as I
-mentioned) the list doesn't work.
-
 The people on linux-net@vger.rutgers.edu have also been known to be very
 helpful, especially when we're talking about ALPHA Linux kernels that may or
 may not work right in the first place.
@@ -264,10 +261,14 @@
 		The arc0s support was contributed by Tomasz Motylewski
 		and modified somewhat by me.  Bugs are probably my fault.
 
+You can choose not to compile arc0e and arc0s into the driver if you want -
+this will save you a bit of memory and avoid confusion when eg. trying to
+use the "NFS-root" stuff in recent Linux kernels.
+
 The arc0e and arc0s devices are created automatically when you first
-'ifconfig' the arc0 device.  To actually use them, though, you need to also
-'ifconfig' the other virtual devices you need.  There are a number of ways
-you can set up your network then:
+ifconfig the arc0 device.  To actually use them, though, you need to also
+ifconfig the other virtual devices you need.  There are a number of ways you
+can set up your network then:
 
 
 1. Single Protocol.
@@ -308,7 +309,7 @@
    its own IP address and needs to use freedom as its default gateway.  The
    XT (patience), however, does not have its own internet IP address and so
    I assigned it one on a "private subnet" (as defined by RFC1597).
-   
+
    To start with, take a simple network with just insight and freedom. 
    Insight needs to:
    	- talk to freedom via RFC1201 (arc0) protocol, because I like it
@@ -330,7 +331,7 @@
    	ifconfig arc0 freedom
    	route add freedom arc0
    	route add insight arc0
-   	/* and default gateway is configured by PPP */
+   	/* and default gateway is configured by pppd */
    	
    Great, now insight talks to freedom directly on arc0, and sends packets
    to the internet through freedom.  If you didn't know how to do the above,
@@ -374,16 +375,15 @@
    both insight and patience are using freedom as their default gateway, the
    two can already talk to each other.
    
-   It's quite fortunate that I set things up like this the first time
-   through (cough cough) because it's really handy when I boot insight into
-   DOS.  There, it runs the Novell ODI protocol stack, which only works with
-   RFC1201 ARCnet.  In this mode it would be impossible for insight to
-   communicate directly with patience, since the Novell stack is
-   incompatible with Microsoft's Ethernet-Encap.  Without changing any
-   settings on freedom or patience, I simply set freedom as the default
-   gateway for insight (now in DOS, remember) and all the forwarding happens
-   "automagically" between the two hosts that would normally not be able to
-   communicate at all.
+   It's quite fortunate that I set things up like this the first time (cough
+   cough) because it's really handy when I boot insight into DOS.  There, it
+   runs the Novell ODI protocol stack, which only works with RFC1201 ARCnet. 
+   In this mode it would be impossible for insight to communicate directly
+   with patience, since the Novell stack is incompatible with Microsoft's
+   Ethernet-Encap.  Without changing any settings on freedom or patience, I
+   simply set freedom as the default gateway for insight (now in DOS,
+   remember) and all the forwarding happens "automagically" between the two
+   hosts that would normally not be able to communicate at all.
    
    For those who like diagrams, I have created two "virtual subnets" on the
    same physical ARCnet wire.  You can picture it like this:
@@ -397,15 +397,13 @@
           |               |         *            |               |
           |               +-Freedom-*-Gatekeeper-+               |
           |               |    |    *            |               |
-          \-------+-------/    |                 \-------+-------/
+          \-------+-------/    |    *            \-------+-------/
                   |            |                         |
                Insight         |                      Patience
                            (Internet)
-                        
 
 
 
-                                                    
 It works: what now?
 -------------------
 
@@ -424,31 +422,37 @@
 --------------------------
 
 Do the same as above, but also include the output of the ifconfig and route
-commands, as well as any pertinent log entries (ie: anything that starts
+commands, as well as any pertinent log entries (ie. anything that starts
 with "arcnet:" and has shown up since the last reboot) in your mail.
 
 If you want to try fixing it yourself (I strongly recommend that you mail me
 about the problem first, since it might already have been solved) you may
 want to try some of the debug levels available.  For heavy testing on
 D_DURING or more, it would be a REALLY good idea to kill your klogd daemon
-first!  D_DURING displays 4-5 lines for each packet sent or received.  D_TX
-and RX actually DISPLAY each packet as it is sent or received, which is
-obviously quite big.
-
-You can run the arcdump shell script (available from me or in the full
-ARCnet package if you got it) as root to list the contents of the arcnet
-buffers at any time.  To make any sense at all out of this, you should grab
-the pertinent RFC's. (some are listed near the top of arcnet.c).  arcdump
-assumes your card is at 0xD0000.  If it isn't, edit the script.
-
-Buffers #0 and 1 are used for receiving, and Buffers #2 and 3 are for
-sending.  Ping-pong buffers are implemented both ways.
-
-If your debug level includes D_DURING, the buffers are cleared to a constant
-value of 0x42 every time the card is reset (which should only happen when
-you do an ifconfig up, or when Linux decides that the driver is broken). 
-This is to make it easier to figure out which bytes are being used by a
-packet.
+first!  D_DURING displays 4-5 lines for each packet sent or received.  D_TX,
+D_RX, and D_SKB actually DISPLAY each packet as it is sent or received,
+which is obviously quite big.
+
+Starting with v2.40 ALPHA, the autoprobe routines have changed
+significantly.  In particular, they won't tell you why the card was not
+found unless you turn on the D_INIT_REASONS debugging flag.
+
+Once the driver is running, you can run the arcdump shell script (available
+from me or in the full ARCnet package, if you have it) as root to list the
+contents of the arcnet buffers at any time.  To make any sense at all out of
+this, you should grab the pertinent RFC's. (some are listed near the top of
+arcnet.c).  arcdump assumes your card is at 0xD0000.  If it isn't, edit the
+script.
+
+Buffers 0 and 1 are used for receiving, and Buffers 2 and 3 are for sending. 
+Ping-pong buffers are implemented both ways.
+
+If your debug level includes D_DURING and you did NOT define SLOW_XMIT_COPY,
+the buffers are cleared to a constant value of 0x42 every time the card is
+reset (which should only happen when you do an ifconfig up, or when Linux
+decides that the driver is broken).  During a transmit, unused parts of the
+buffer will be cleared to 0x42 as well.  This is to make it easier to figure
+out which bytes are being used by a packet.
 
 You can change the debug level without recompiling the kernel by typing:
 	ifconfig arc0 down metric 1xxx
@@ -456,10 +460,10 @@
 where "xxx" is the debug level you want.  For example, "metric 1015" would put
 you at debug level 15.  Debug level 7 is currently the default.
 
-Note that the debug level is (as of v1.90 ALPHA) a binary combination of
-different debug flags; so debug level 7 is really 1+2+4 or
-D_NORMAL+D_INIT+D_EXTRA.  To reach D_DURING, you would add 8 to this,
-resulting in debug level 15.
+Note that the debug level is (starting with v1.90 ALPHA) a binary
+combination of different debug flags; so debug level 7 is really 1+2+4 or
+D_NORMAL+D_EXTRA+D_INIT.  To include D_DURING, you would add 16 to this,
+resulting in debug level 23.
 
 If you don't understand that, you probably don't want to know anyway. 
 E-mail me about your problem.
diff -u --recursive --new-file v1.3.63/linux/Makefile linux/Makefile
--- v1.3.63/linux/Makefile	Wed Feb 14 14:37:06 1996
+++ linux/Makefile	Thu Feb 15 14:55:36 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 63
+SUBLEVEL = 64
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.63/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v1.3.63/linux/arch/alpha/kernel/bios32.c	Thu Jan  4 21:54:53 1996
+++ linux/arch/alpha/kernel/bios32.c	Thu Feb 15 09:20:41 1996
@@ -581,7 +581,7 @@
 		{ 0,  0,  2,  1,  0}, /* idsel 11 (slot furthest from ISA) KN25_PCI_SLOT0 */
 		{ 1,  1,  0,  2,  1}, /* idsel 12 (middle slot) KN25_PCI_SLOT1 */
 #ifdef CONFIG_ALPHA_AVANTI
-		{ 1,  1, -1, -1, -1}, /* idsel 13 KN25_PCI_SLOT2 */
+		{ 1,  2,  1,  0,  2}, /* idsel 13 KN25_PCI_SLOT2 */
 #endif /* CONFIG_ALPHA_AVANTI */
 	};
 	/*
diff -u --recursive --new-file v1.3.63/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v1.3.63/linux/arch/alpha/kernel/irq.c	Sun Jan 14 16:30:09 1996
+++ linux/arch/alpha/kernel/irq.c	Thu Feb 15 09:20:41 1996
@@ -622,6 +622,8 @@
 			cabriolet_and_eb66p_device_interrupt(vector, &regs);
 #elif NR_IRQS == 32
 			eb66_and_eb64p_device_interrupt(vector, &regs);
+#elif NR_IRQS == 16
+			isa_device_interrupt(vector, &regs);
 #endif
 			return;
 		case 4:
diff -u --recursive --new-file v1.3.63/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- v1.3.63/linux/arch/i386/kernel/ksyms.c	Fri Feb  9 17:52:57 1996
+++ linux/arch/i386/kernel/ksyms.c	Thu Feb 15 07:13:13 1996
@@ -1,10 +1,16 @@
 #include <linux/module.h>
 #include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
 
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(elf_fpregset_t *);
 
 static struct symbol_table arch_symbol_table = {
 #include <linux/symtab_begin.h>
 	/* platform dependent support */
+	X(dump_thread),
+	X(dump_fpu),
 #ifdef __SMP__
 	X(apic_reg),		/* Needed internally for the I386 inlines */
 	X(cpu_data),
diff -u --recursive --new-file v1.3.63/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.63/linux/drivers/block/floppy.c	Fri Feb  9 17:53:00 1996
+++ linux/drivers/block/floppy.c	Thu Feb 15 09:20:58 1996
@@ -107,7 +107,7 @@
 
 /* do print messages for unexpected interrupts */
 static int print_unex=1;
-
+#include <linux/utsname.h>
 #include <linux/module.h>
 
 /* the following is the mask of allowed drives. By default units 2 and
@@ -3118,30 +3118,15 @@
 
 static inline int normalize_0x02xx_ioctl(int *cmd, int *size)
 {
-	int i, orig_size, ocmd;
+	int i;
 
-	orig_size = _IOC_SIZE(*cmd);
-	ocmd = *cmd;
 	for (i=0; i < ARRAY_SIZE(translation_table); i++) {
-		if ((*cmd & 0xff3f) == (translation_table[i].newcmd & 0xff3f)){
+		if ((*cmd & 0xffff) == (translation_table[i].newcmd & 0xffff)){
+			*size = _IOC_SIZE(*cmd);
 			*cmd = translation_table[i].newcmd;
-			if (!orig_size && _IOC_SIZE(*cmd)) {
-				/* kernels 1.3.34 to 1.3.39 : */
-				*size = _IOC_SIZE(*cmd); 
-				DPRINT1("warning: obsolete ioctl 0x%x\n",ocmd);
-				DPRINT("please recompile your program\n");
-				/* these ioctls only existed
-				 * in six (development)
-				 * kernels anyways. That's why we
-				 * complain about these, and not about
-				 * the much older 0x00xx ioctl's
-				 */
-			} else {
-				*size = orig_size;
-				if (*size > _IOC_SIZE(*cmd)) {
-					printk("ioctl not yet supported\n");
-					return -EFAULT;
-				}
+			if (*size > _IOC_SIZE(*cmd)) {
+				printk("ioctl not yet supported\n");
+				return -EFAULT;
 			}
 			return 0;
 		}
@@ -3152,14 +3137,18 @@
 static inline int xlate_0x00xx_ioctl(int *cmd, int *size)
 {
 	int i;
-	/* kernels <= 1.3.33 */
-	/* we might want to start warning in 1.4.x (by then, no user
-	 * programs will have an excuse to use the old ioctls: there
-	 * will be a stable kernel supporting them :)
-	 *
-	 * when the first 1.5.x kernel will come out, this loop will
-	 * be removed as well.
-	 */
+	/* old ioctls' for kernels <= 1.3.33 */
+	/* When the next even release will come around, we'll start
+	 * warning against these.
+	 * When the next odd release will come around, we'll fail with
+	 * -EINVAL */
+	if(strcmp(system_utsname.version, "1.4.0") >= 0)
+		printk("obsolete floppy ioctl %x\n", *cmd);
+	if((system_utsname.version[0] == '1' &&
+	    strcmp(system_utsname.version, "1.5.0") >= 0) ||
+	   (system_utsname.version[0] >= '2' &&
+	    strcmp(system_utsname.version, "2.1.0") >= 0))
+		return -EINVAL;
 	for (i=0; i < ARRAY_SIZE(translation_table); i++) {
 		if (*cmd == translation_table[i].oldcmd) {
 			*size = translation_table[i].oldsize;
diff -u --recursive --new-file v1.3.63/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.63/linux/drivers/block/ll_rw_blk.c	Wed Feb 14 14:37:09 1996
+++ linux/drivers/block/ll_rw_blk.c	Thu Feb 15 12:09:57 1996
@@ -29,7 +29,7 @@
  * NOTE that writes may use only the low 2/3 of these: reads
  * take precedence.
  */
-#define NR_REQUEST	16
+#define NR_REQUEST	64
 static struct request all_requests[NR_REQUEST];
 
 /*
diff -u --recursive --new-file v1.3.63/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v1.3.63/linux/drivers/block/rd.c	Sat Jan  6 19:10:39 1996
+++ linux/drivers/block/rd.c	Thu Feb 15 09:20:51 1996
@@ -431,7 +431,7 @@
 		outfile.f_op->write(outfile.f_inode, &outfile, buf,
 				    BLOCK_SIZE);
 		if (!(i % 16)) {
-			printk("%c\b", rotator[rotate & 0x3]);
+			printk(KERN_NOTICE "%c\b", rotator[rotate & 0x3]);
 			rotate++;
 		}
 	}
diff -u --recursive --new-file v1.3.63/linux/drivers/char/README.stallion linux/drivers/char/README.stallion
--- v1.3.63/linux/drivers/char/README.stallion	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/README.stallion	Thu Feb 15 12:07:35 1996
@@ -0,0 +1,320 @@
+
+Stallion Multiport Serial Drivers
+---------------------------------
+
+Version: 1.0.2
+Date:    01FEB96
+Author:  Greg Ungerer (gerg@stallion.oz.au)
+
+
+1. INTRODUCTION
+
+There are two drivers that work with the different families of Stallion
+multiport serial boards. One is for the Stallion smart boards - that is
+EasyIO and EasyConnection 8/32, the other for the true Stallion intelligent
+multiport boards - Stallion, Brumby, ONboard and EasyConnection 8/64.
+
+If you are using any of the Stallion intelligent multiport boards (Brumby,
+ONboard, Stallion, EasyConnection 8/64) with Linux you will need to get the
+driver utility package. This package is available at most of the Linux
+archive sites (and on CD's that contain these archives). The file will be
+called stallion-X.X.X.tar.gz where X.X.X will be the version number. In
+particular this package contains the board embedded executable images that
+are required for these boards. It also contains the downloader program.
+These boards cannot be used without this.
+
+The following ftp sites (and their mirrors) definately have the stallion
+driver utility package: ftp.stallion.com, tsx-11.mit.edu, sunsite.unc.edu.
+
+ftp.stallion.com:/drivers/ata5/Linux/stallion-1.0.1.tar.gz
+tsx-11.mit.edu:/pub/linux/BETA/serial/stallion/stallion-1.0.1.tar.gz
+sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-1.0.1.tar.gz
+
+If you are using the EasyIO or EasyConnection 8/32 boards then you don't
+need this package. Although it does have a handy script to create the
+/dev device nodes for these boards.
+
+If you require DIP switch settings, EISA/MCA configuration files, or any
+other information related to Stallion boards then have a look at
+http://www.stallion.com.
+
+
+
+2. INSTALLATION
+
+The drivers can be used as loadable modules or compiled into the kernel.
+You can choose which when doing a "make config" on the kernel.
+
+All ISA, EISA and MCA boards that you want to use need to be entered into
+the driver(s) configuration structures. All PCI boards will be automatically
+detected when you load the driver - so they do not need to be entered into
+the driver(s) configuration structure. (Note that kernel PCI BIOS32 support
+is required to use PCI boards.)
+
+Entering ISA, EISA and MCA boards into the driver(s) configuration structure
+involves editing the driver(s) source file. It's pretty easy if you follow
+the instructions below. Both drivers can support up to 4 boards. The smart
+card driver (the stallion.c driver) supports any combination of EasyIO and
+EasyConnection 8/32 boards (up to a total of 4). The intelligent driver
+supports any combination of ONboards, Brumbys, Stallions and EasyConnection
+8/64 boards (up to a total of 4).
+
+To set up the driver(s) for the boards that you want to use you need to
+edit the appropriate driver file and add configuration entries.
+
+If using EasyIO or EasyConnection 8/32 ISA or MCA boards, do:
+   vi stallion.c
+      - find the definition of the stl_brdconf array (of structures)
+        near the top of the file
+      - modify this to match the boards you are going to install
+	(the comments before this structure should help)
+      - save and exit
+
+If using ONboard, Brumby, Stallion or EasyConnection 8/64 boards then do:
+   vi istallion.c
+      - find the definition of the stli_brdconf array (of structures)
+        near the top of the file
+      - modify this to match the boards you are going to install
+	(the comments before this structure should help)
+      - save and exit
+
+Once you have set up the board configurations then you are ready to build
+the kernel or modules.
+
+When the new kernel is booted, or the loadable module loaded then the
+driver will emit some kernel trace messages about whether the configured
+boards where detected or not. Depending on how your system logger is set
+up these may come out on the console, or just be logged to
+/usr/adm/messages. You should check the messages to confirm that all is well.
+
+
+2.1 SHARING INTERRUPTS
+
+It is possible to share interrupts between multiple EasyIO and
+EasyConnection 8/32 boards in an EISA system. To do this you will need to
+do a couple of things:
+
+1. When entering the board resources into the stallion.c file you need to
+   mark the boards as using level triggered interrupts. Do this by replacing
+   the "0" entry at field position 6 (the last field) in the board
+   configuration structure with a "1". (This is the structure that defines
+   the board type, I/O locations, etc. for each board). All boards that are
+   sharing an interrupt must be set this way, and each board should have the
+   same interrupt number specified here as well. Now build the module or
+   kernel as you would normally.
+
+2. When physically installing the boards into the system you must enter
+   the system EISA configuration utility. You will need to install the EISA
+   configuration files for *all* the EasyIO and EasyConnection 8/32 boards
+   that are sharing interrupts. The Stallion EasyIO and EasyConnection 8/32
+   EISA configuration files required are supplied by Stallion Technologies
+   on the DOS Utilities floppy (usually supplied in the box with the board
+   when purchased. If not, you can pick it up from Stallion's FTP site,
+   ftp.stallion.com). You will need to edit the board resources to choose
+   level triggered interrupts, and make sure to set each board's interrupt
+   to the same IRQ number.
+
+You must complete both the above steps for this to work. When you reboot
+or load the driver your EasyIO and EasyConnection 8/32 boards will be
+sharing interrupts.
+
+
+2.2 USING HIGH SHARED MEMORY
+
+The EasyConnection 8/64-EI, ONboard and Stallion boards are capable of
+using shared memory addresses above the usual 640K - 1Mb range. The ONboard
+ISA and the Stallion boards can be programmed to use memory addresses up to
+16Mb (the ISA bus addressing limit), and the EasyConnection 8/64-EI and
+ONboard/E can be programmed for memory addresses up to 4Gb (the EISA bus
+addressing limit).
+
+The istallion intelligent driver does offer support for these higher memory
+addresses with a couple of limitations. The higher memory support can only
+be used in the loadable module form of the driver, since the kernel memory
+management routines it relies on can not be run from the drivers static
+kernel init routine.
+
+By default, support for these higher memory addresses is not compiled into
+the driver. This is because it relies on kernel functions that are not
+normally exported as part of the Linux loadable module system.
+
+To add the appropriate symbols into the kernel export code you need to:
+
+1. cd /usr/src/linux/kernel
+   (assuming your Linux kernel code is in /usr/src/linux)
+2. vi ksyms.c
+   - find the line that reads
+        X(vfree),
+   - after this line insert the following line
+        X(remap_page_range),
+   - save and exit
+3. cd ..
+4. build a new kernel (usually just make)
+
+This will export the "remap_page_range" function for loadable modules
+which is required for the higher memory support code.
+
+Finally you need to enable the code in the istallion driver. To do this
+edit the istallion.c file and search for the symbol STLI_HIMEMORY. It is
+near the top of the file in a line that looks like:
+
+#define	STLI_HIMEMORY	0
+
+Change the "0" to a "1". This enables the high memory support code in
+the driver. You will then need to rebuild the module or rebuild the
+kernel to incorporate the change. You will also need to modify
+the board resource configuration information to use a higher memory
+address.
+
+Once these changes are in place the driver will work as it did before.
+Note that the physical memory address range is software programmed on the
+EasyConnection 8/64-EI and ONboards, but must be set via DIP switches on
+the original Stallion boards.
+
+
+2.3 TROUBLE SHOOTING
+
+If a board is not found by the driver but is actually in the system then the
+most likely problem is that the I/O address is wrong. Change it in the driver
+stallion.c or istallion.c configuration structure and rebuild the kernel or
+modules, or change it on the board. On EasyIO and EasyConnection 8/32 boards
+the IRQ is software programmable, so if there is a conflict you may need to
+change the IRQ used for a board in the stallion.c configuration structure.
+There are no interrupts to worry about for ONboard, Brumby, Stallion or
+EasyConnection 8/64 boards. The memory region on EasyConnection 8/64 and
+ONboard boards is software programmable, but not on the Brumbys or Stallions.
+
+
+
+3. USING THE DRIVERS
+
+3.1 INTELLIGENT DRIVER OPERATION
+
+The intelligent boards also need to have their "firmware" code downloaded
+to them. This is done via a user level application supplied in the driver
+package called "stlload". Compile this program where ever you dropped the
+package files, by typing "make". In its simplest form you can then type
+    ./stlload -i cdk.sys
+in this directory and that will download board 0 (assuming board 0 is an
+EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do:
+    ./stlload -i 2681.sys
+
+Normally you would want all boards to be downloaded as part of the standard
+system startup. To achieve this, add one of the lines above into the
+/etc/rc.d/rc.S or /etc/rc.d/rc.serial file. To download each board just add
+the "-b <brd-number>" option to the line. You will need to download code for
+every board. You should probably move the stlload program into a system
+directory, such as /usr/sbin. Also, the default location of the cdk.sys image
+file in the stlload down-loader is /usr/lib/stallion. Create that directory
+and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put
+them anyway). As an example your /etc/rc.d/rc.S file might have the
+following lines added to it (if you had 3 boards):
+    /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys
+    /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys
+    /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys
+
+The image files cdk.sys and 2681.sys are specific to the board types. The
+cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly
+the 2681.sys image fill only operate on ONboard, Brumby and Stallion boards.
+If you load the wrong image file into a board it will fail to start up, and
+of course the ports will not be operational!
+
+If you are using the modularized version of the driver you might want to put
+the insmod calls in the startup script as well (before the download lines
+obviously).
+
+
+3.2 USING THE SERIAL PORTS
+
+Once the driver is installed you will need to setup some device nodes to
+access the serial ports. The simplest method is to use the stallion utility
+"mkdevnods" script. It will automatically create all possible device entries
+required for all 4 boards. This will create the normal serial port devices as
+/dev/ttyE# where # is the port number starting from 0. A bank of 64 minor
+device numbers is allocated to each board, so the first port on the second
+board is port 64, etc. A set of callout type devices is also created. They
+are created as the devices /dev/cue# where # is the same as for the ttyE
+devices.
+
+For the most part the Stallion driver tries to emulate the standard PC system
+COM ports and the standard Linux serial driver. The idea is that you should
+be able to use Stallion board ports and COM ports interchangeably without
+modifying anything but the device name. Anything that doesn't work like that
+should be considered a bug in this driver!
+
+If you look at the driver code you will notice that it is fairly closely
+based on the Linux serial driver (linux/drivers/char/serial.c). This is
+intentional, obviously this is the easiest way to emulate its behavior!
+
+Since this driver tries to emulate the standard serial ports as much as
+possible, most system utilities should work as they do for the standard
+COM ports. Most importantly "stty" works as expected and "setserial" can be
+also be used (excepting the ability to auto-configure the I/O and IRQ
+addresses of boards). Higher baud rates are supported in the
+usual fashion through setserial or using the CBAUDEX extensions. Note that
+the EasyIO and EasyConnection (all types) support 57600 and 115200 baud. The
+older boards including ONboard, Brumby and the original Stallion support a
+maximum baud rate of 38400.
+
+If you are unfamiliar with how to use serial ports, then get the Serial-HOWTO
+by Greg Hankins. It will explain everything you need to know!
+
+
+
+4. NOTES
+
+You can use both drivers at once if you have a mix of board types installed
+in a system. However to do this you will need to change the major numbers
+used by one of the drivers. Currently both drivers use major numbers 24 and
+25 for their port devices. Change one driver to use some other major numbers,
+and then modify the mkdevnods script to make device nodes based on those new
+major numbers. For example, you could change the stallion.c driver to use
+major numbers 30 and 31 (don't use 28, it's used by istallion.c driver for its
+sio memory device!). You will also need to create device nodes with different
+names for the ports...
+
+Finding a free physical memory address range can be a problem. The older
+boards like the Stallion and ONboard need large areas (64K or even 128K), so
+they can be very difficult to get into a system. If you have 16 Mb of RAM
+then you have no choice but to put them somewhere in the 640K -> 1Mb range.
+ONboards require 64K, so typically 0xd0000 is good, or 0xe0000 on some
+systems. If you have an original Stallion board, "V4.0" or Rev.O,
+then you need a 64K memory address space, so again 0xd0000 and 0xe0000 are
+good. Older Stallion boards are a much bigger problem. They need 128K of
+address space and must be on a 128K boundary. If you don't have a VGA card
+then 0xc0000 might be usable - there is really no other place you can put
+them below 1Mb.
+
+Both the ONboard and old Stallion boards can use higher memory addresses as
+well, but you must have less than 16Mb of RAM to be able to use them. Usual
+high memory addresses used include 0xec0000 and 0xf00000.
+
+The Brumby boards only require 16Kb of address space, so you can usually
+squeeze them in somewhere. Common addresses are 0xc8000, 0xcc000, or in
+the 0xd0000 range. EasyConnection 8/64 boards are even better, they only
+require 4Kb of address space, again usually 0xc8000, 0xcc000 or 0xd0000
+are good.
+
+If you are using an EasyConnection 8/64-EI or ONboard/E then usually the
+0xd0000 or 0xe0000 ranges are the best options below 1Mb. If neither of
+them can be used then the high memory support to use the really high address
+ranges is the best option. Typically the 2Gb range is convenient for them,
+and gets them well out of the way.
+
+There is a new utility program in the stallion utility package called
+"stlstty". Most people will not need to use this. If you have an ONboard/16
+which has partial signals on the upper 12 ports then this program can be used
+to set the upper ports to have modem control instead of hardware flow control.
+Use the "mapcts maprts" flag options to this utility on the port(s) that you
+wish to do this mapping on, eg
+    ./stlstty maprts mapcts < /dev/cue0
+This enables RTS to act like DTR and CTS to act like DCD on the specified
+port.
+
+
+
+5. DISCLAIMER
+
+I do not speak for Stallion Technologies in any capacity, officially or
+unofficially.
+
diff -u --recursive --new-file v1.3.63/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v1.3.63/linux/drivers/char/istallion.c	Wed Nov  8 07:11:31 1995
+++ linux/drivers/char/istallion.c	Thu Feb 15 12:07:35 1996
@@ -3,7 +3,7 @@
 /*
  *	istallion.c  -- stallion intelligent multiport serial driver.
  *
- *	Copyright (C) 1994,1995  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *	This code is loosely based on the Linux serial driver, written by
  *	Linus Torvalds, Theodore T'so and others.
@@ -26,7 +26,6 @@
 /*****************************************************************************/
 
 #include <linux/module.h>
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -141,6 +140,13 @@
 #include <asm/pgtable.h>
 #endif
 
+/*
+ *	There is some experimental EISA board detection code in this driver.
+ *	By default it is disabled, but for those that want to try it out,
+ *	then set the define below to be 1.
+ */
+#define	STLI_EISAPROBE	0
+
 /*****************************************************************************/
 
 /*
@@ -173,7 +179,7 @@
  *	all the local structures required by a serial tty driver.
  */
 static char	*stli_drvname = "Stallion Intelligent Multiport Serial Driver";
-static char	*stli_drvversion = "1.0.0";
+static char	*stli_drvversion = "1.0.2";
 static char	*stli_serialname = "ttyE";
 static char	*stli_calloutname = "cue";
 
@@ -267,9 +273,10 @@
 	unsigned long		addr;
 	unsigned long		rxoffset;
 	unsigned long		txoffset;
+	unsigned long		sigs;
+	unsigned long		pflag;
 	unsigned int		rxsize;
 	unsigned int		txsize;
-	unsigned long		sigs;
 	unsigned char		reqbit;
 	unsigned char		portidx;
 	unsigned char		portbit;
@@ -287,6 +294,7 @@
 	int		nrports;
 	int		nrdevs;
 	unsigned int	iobase;
+	unsigned long	memaddr;
 	void		*membase;
 	int		memsize;
 	int		pagesize;
@@ -304,7 +312,7 @@
 	stliport_t	*ports[STL_MAXPORTS];
 } stlibrd_t;
 
-static stlibrd_t	*stli_brds;
+static stlibrd_t	*stli_brds[STL_MAXBRDS];
 
 static int		stli_shared = 0;
 
@@ -369,6 +377,30 @@
 	"EC8/32-PCI",
 };
 
+/*
+ *	Set up a default memory address table for EISA board probing.
+ *	The default addresses are all bellow 1Mbyte, which has to be the
+ *	case anyway. They should be safe, since we only read values from
+ *	them, and interrupts are disabled while we do it. If the higher
+ *	memory support is compiled in then we also try probing around
+ *	the 1Gb, 2Gb and 3Gb areas as well...
+ */
+static unsigned long	stli_eisamemprobeaddrs[] = {
+	0xc0000, 0xd0000, 0xe0000, 0xf0000,
+	0x80000000, 0x80010000, 0x80020000, 0x80030000,
+	0x40000000, 0x40010000, 0x40020000, 0x40030000,
+	0xc0000000, 0xc0010000, 0xc0020000, 0xc0030000,
+	0xff000000, 0xff010000, 0xff020000, 0xff030000,
+};
+
+#if STLI_HIMEMORY
+static int	stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long);
+#else
+static int	stli_eisamempsize = 4;
+#endif
+
+int		stli_eisaprobe = STLI_EISAPROBE;
+
 /*****************************************************************************/
 
 /*
@@ -382,6 +414,8 @@
 #define	ECP_EIPAGESIZE	(64 * 1024)
 #define	ECP_MCPAGESIZE	(4 * 1024)
 
+#define	STL_EISAID	0x8c4e
+
 /*
  *	Important defines for the ISA class of ECP board.
  */
@@ -414,6 +448,8 @@
 #define	ECP_EIADDRSHFTH	24
 #define	ECP_EIBRDENAB	0xc84
 
+#define	ECP_EISAID	0x4
+
 /*
  *	Important defines for the Micro-channel class of ECP board.
  *	(It has a lot in common with the ISA boards.)
@@ -471,6 +507,8 @@
 #define	ONB_EIADDRSHFTH	24
 #define	ONB_EIBRDENAB	0xc84
 
+#define	ONB_EISAID	0x1
+
 /*
  *	Important defines for the Brumby boards. They are pretty simple,
  *	there is not much that is programmably configurable.
@@ -535,7 +573,7 @@
 	(* brdp->getmemptr)(brdp, offset, __LINE__)
 
 /*
- *	Define the maximal baud rate, and he default baud base for ports.
+ *	Define the maximal baud rate, and the default baud base for ports.
  */
 #define	STL_MAXBAUD	230400
 #define	STL_BAUDBASE	115200
@@ -576,7 +614,6 @@
 int		init_module(void);
 void		cleanup_module(void);
 #endif
-static void	*stli_memalloc(int len);
 
 int		stli_init(void);
 static int	stli_open(struct tty_struct *tty, struct file *filp);
@@ -595,9 +632,12 @@
 static void	stli_flushbuffer(struct tty_struct *tty);
 static void	stli_hangup(struct tty_struct *tty);
 
-static int	stli_brdinit(void);
-static int	stli_initecp(stlibrd_t *brdp, stlconf_t *confp);
-static int	stli_initonb(stlibrd_t *brdp, stlconf_t *confp);
+static int	stli_initbrds(void);
+static int	stli_brdinit(stlibrd_t *brdp);
+static int	stli_initecp(stlibrd_t *brdp);
+static int	stli_initonb(stlibrd_t *brdp);
+static int	stli_eisamemprobe(stlibrd_t *brdp);
+static int	stli_findeisabrds(void);
 static int	stli_initports(stlibrd_t *brdp);
 static int	stli_startbrd(stlibrd_t *brdp);
 static int	stli_memread(struct inode *ip, struct file *fp, char *buf, int count);
@@ -621,6 +661,7 @@
 static void	stli_read(stlibrd_t *brdp, stliport_t *portp);
 static void	stli_getserial(stliport_t *portp, struct serial_struct *sp);
 static int	stli_setserial(stliport_t *portp, struct serial_struct *sp);
+static void	*stli_memalloc(int len);
 
 static void	stli_ecpinit(stlibrd_t *brdp);
 static void	stli_ecpenable(stlibrd_t *brdp);
@@ -695,19 +736,18 @@
 static int	stli_timeron = 0;
 
 /*
- *	This is hack to allow for the kernel changes made to add_timer
- *	in the newer 1.3.X kernels (changed around 1.3.1X).
+ *	Define the calculation for the timeout routine.
  */
-#ifdef LINUX_1_2_X_COMPAT
-#define	STLI_TIMEOUT	0
-#else
 #define	STLI_TIMEOUT	(jiffies + 1)
-#endif
 
 /*****************************************************************************/
 
 #ifdef MODULE
 
+/*
+ *	Loadable module initialization stuff.
+ */
+
 int init_module()
 {
 	unsigned long	flags;
@@ -767,7 +807,9 @@
 		kfree_s(stli_txcookbuf, STLI_TXBUFSIZE);
 
 	for (i = 0; (i < stli_nrbrds); i++) {
-		brdp = &stli_brds[i];
+		brdp = stli_brds[i];
+		if (brdp == (stlibrd_t *) NULL)
+			continue;
 		for (j = 0; (j < STL_MAXPORTS); j++) {
 			portp = brdp->ports[j];
 			if (portp != (stliport_t *) NULL) {
@@ -785,8 +827,9 @@
 			release_region(brdp->iobase, ECP_IOSIZE);
 		else
 			release_region(brdp->iobase, ONB_IOSIZE);
+		kfree_s(brdp, sizeof(stlibrd_t));
+		stli_brds[i] = (stlibrd_t *) NULL;
 	}
-	kfree_s(stli_brds, (sizeof(stlibrd_t) * stli_nrbrds));
 
 	restore_flags(flags);
 }
@@ -796,17 +839,12 @@
 /*****************************************************************************/
 
 /*
- *	Local memory allocation routines. These are used so we can deal with
- *	memory allocation at init time and during run-time in a consistent
- *	way. Everbody just calls the stli_memalloc routine to allocate
- *	memory and it will do the right thing. There is no common memory
- *	deallocation code - since this is only done is special cases, all of
- *	which are tightly controlled.
+ *	Local driver kernel malloc routine.
  */
 
 static void *stli_memalloc(int len)
 {
-	return (void *) kmalloc(len, GFP_KERNEL);
+	return((void *) kmalloc(len, GFP_KERNEL));
 }
 
 /*****************************************************************************/
@@ -826,9 +864,9 @@
 	brdnr = MKDEV2BRD(minordev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	if (stli_brds == (stlibrd_t *) NULL)
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
 	if ((brdp->state & BST_STARTED) == 0)
 		return(-ENODEV);
 	portnr = MKDEV2PORT(minordev);
@@ -877,7 +915,7 @@
 			clear_bit(TTY_IO_ERROR, &tty->flags);
 		}
 		clear_bit(ST_INITIALIZING, &portp->state);
-		wake_up_interruptible(&portp->open_wait);
+		wake_up_interruptible(&portp->raw_wait);
 		if (rc < 0)
 			return(rc);
 	}
@@ -985,11 +1023,14 @@
 	}
 
 	portp->flags &= ~ASYNC_INITIALIZED;
-	brdp = &stli_brds[portp->brdnr];
-	stli_rawclose(brdp, portp, 0, 1);
+	brdp = stli_brds[portp->brdnr];
+	stli_rawclose(brdp, portp, 0, 0);
 	if (tty->termios->c_cflag & HUPCL) {
 		stli_mkasysigs(&portp->asig, 0, 0);
-		stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+		if (test_bit(ST_CMDING, &portp->state))
+			set_bit(ST_DOSIGS, &portp->state);
+		else
+			stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
 	}
 	clear_bit(ST_TXBUSY, &portp->state);
 	clear_bit(ST_RXSTOP, &portp->state);
@@ -1284,7 +1325,9 @@
 		return(-ENODEV);
 	if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds))
 		return(-ENODEV);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 
 	stli_mkasyport(portp, &aport, portp->tty->termios);
 	return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
@@ -1400,7 +1443,9 @@
 		return(0);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 	chbuf = (unsigned char *) buf;
 
 /*
@@ -1562,7 +1607,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	save_flags(flags);
 	cli();
@@ -1645,7 +1692,9 @@
 		return(0);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 
 	save_flags(flags);
 	cli();
@@ -1698,7 +1747,9 @@
 		return(0);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 
 	save_flags(flags);
 	cli();
@@ -1726,6 +1777,7 @@
 static void stli_getserial(stliport_t *portp, struct serial_struct *sp)
 {
 	struct serial_struct	sio;
+	stlibrd_t		*brdp;
 
 #if DEBUG
 	printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
@@ -1734,8 +1786,7 @@
 	memset(&sio, 0, sizeof(struct serial_struct));
 	sio.type = PORT_UNKNOWN;
 	sio.line = portp->portnr;
-	sio.port = stli_brdconf[portp->brdnr].ioaddr1;
-	sio.irq = stli_brdconf[portp->brdnr].irq;
+	sio.irq = 0;
 	sio.flags = portp->flags;
 	sio.baud_base = portp->baud_base;
 	sio.close_delay = portp->close_delay;
@@ -1743,6 +1794,11 @@
 	sio.custom_divisor = portp->custom_divisor;
 	sio.xmit_fifo_size = 0;
 	sio.hub6 = 0;
+
+	brdp = stli_brds[portp->brdnr];
+	if (brdp != (stlibrd_t *) NULL)
+		sio.port = brdp->iobase;
+		
 	memcpy_tofs(sp, &sio, sizeof(struct serial_struct));
 }
 
@@ -1802,7 +1858,9 @@
 		return(-ENODEV);
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return(0);
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(0);
 
 	rc = 0;
 
@@ -1870,6 +1928,16 @@
 		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
 			rc = stli_setserial(portp, (struct serial_struct *) arg);
 		break;
+	case STL_GETPFLAG:
+		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long))) == 0)
+			put_fs_long(portp->pflag, (unsigned long *) arg);
+		break;
+	case STL_SETPFLAG:
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long))) == 0) {
+			portp->pflag = get_fs_long((unsigned long *) arg);
+			stli_setport(portp);
+		}
+		break;
 	case TIOCSERCONFIG:
 	case TIOCSERGWILD:
 	case TIOCSERSWILD:
@@ -1910,7 +1978,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	tiosp = tty->termios;
 	if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag))
@@ -2004,7 +2074,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	memset(&actrl, 0, sizeof(asyctrl_t));
 	actrl.txctrl = CT_STOPFLOW;
@@ -2036,7 +2108,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	memset(&actrl, 0, sizeof(asyctrl_t));
 	actrl.txctrl = CT_STARTFLOW;
@@ -2098,7 +2172,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	portp->flags &= ~ASYNC_INITIALIZED;
 
@@ -2154,7 +2230,9 @@
 		return;
 	if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
 		return;
-	brdp = &stli_brds[portp->brdnr];
+	brdp = stli_brds[portp->brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return;
 
 	save_flags(flags);
 	cli();
@@ -2188,8 +2266,8 @@
  *	carefull of data that will be copied out from shared memory -
  *	containing command results. The command completion is all done from
  *	a poll routine that does not have user coontext. Therefore you cannot
- *	copy back directly into user space, or to the kernel stack. This
- *	routine does not sleep, so can be called from anywhere.
+ *	copy back directly into user space, or to the kernel stack of a
+ *	process. This routine does not sleep, so can be called from anywhere.
  */
 
 static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
@@ -2203,13 +2281,15 @@
 	printk("stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, (int) arg, size, copyback);
 #endif
 
+	save_flags(flags);
+	cli();
+
 	if (test_bit(ST_CMDING, &portp->state)) {
 		printk("STALLION: command already busy, cmd=%x!\n", (int) cmd);
+		restore_flags(flags);
 		return;
 	}
 
-	save_flags(flags);
-	cli();
 	EBRDENABLE(brdp);
 	cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
 	if (size > 0) {
@@ -2520,7 +2600,9 @@
  *	Check each board and do any servicing required.
  */
 	for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
-		brdp = &stli_brds[brdnr];
+		brdp = stli_brds[brdnr];
+		if (brdp == (stlibrd_t *) NULL)
+			continue;
 		if ((brdp->state & BST_STARTED) == 0)
 			continue;
 
@@ -2691,6 +2773,11 @@
 		pp->iflag |= FI_1MARKRXERRS;
 	if (tiosp->c_iflag & BRKINT)
 		portp->rxmarkmsk |= BRKINT;
+
+/*
+ *	Transfer any persistent flags into the asyport structure.
+ */
+	pp->pflag = portp->pflag;
 }
 
 /*****************************************************************************/
@@ -2806,7 +2893,7 @@
 	outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
 	udelay(100);
 
-	memconf = (((unsigned long) brdp->membase) & ECP_ATADDRMASK) >> ECP_ATADDRSHFT;
+	memconf = (brdp->memaddr & ECP_ATADDRMASK) >> ECP_ATADDRSHFT;
 	outb(memconf, (brdp->iobase + ECP_ATMEMAR));
 }
 
@@ -2897,9 +2984,9 @@
 	outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR));
 	udelay(500);
 
-	memconf = (((unsigned long) brdp->membase) & ECP_EIADDRMASKL) >> ECP_EIADDRSHFTL;
+	memconf = (brdp->memaddr & ECP_EIADDRMASKL) >> ECP_EIADDRSHFTL;
 	outb(memconf, (brdp->iobase + ECP_EIMEMARL));
-	memconf = (((unsigned long) brdp->membase) & ECP_EIADDRMASKH) >> ECP_EIADDRSHFTH;
+	memconf = (brdp->memaddr & ECP_EIADDRMASKH) >> ECP_EIADDRSHFTH;
 	outb(memconf, (brdp->iobase + ECP_EIMEMARH));
 }
 
@@ -3018,10 +3105,10 @@
 	outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
 	udelay(10);
 	outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 
-	memconf = (((unsigned long) brdp->membase) & ONB_ATADDRMASK) >> ONB_ATADDRSHFT;
+	memconf = (brdp->memaddr & ONB_ATADDRMASK) >> ONB_ATADDRSHFT;
 	outb(memconf, (brdp->iobase + ONB_ATMEMAR));
 	outb(0x1, brdp->iobase);
 	udelay(1000);
@@ -3079,7 +3166,7 @@
 	outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
 	udelay(10);
 	outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3102,12 +3189,12 @@
 	outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
 	udelay(10);
 	outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 
-	memconf = (((unsigned long) brdp->membase) & ONB_EIADDRMASKL) >> ONB_EIADDRSHFTL;
+	memconf = (brdp->memaddr & ONB_EIADDRMASKL) >> ONB_EIADDRSHFTL;
 	outb(memconf, (brdp->iobase + ONB_EIMEMARL));
-	memconf = (((unsigned long) brdp->membase) & ONB_EIADDRMASKH) >> ONB_EIADDRSHFTH;
+	memconf = (brdp->memaddr & ONB_EIADDRMASKH) >> ONB_EIADDRSHFTH;
 	outb(memconf, (brdp->iobase + ONB_EIMEMARH));
 	outb(0x1, brdp->iobase);
 	udelay(1000);
@@ -3172,7 +3259,7 @@
 	outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
 	udelay(10);
 	outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3193,7 +3280,7 @@
 	outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
 	udelay(10);
 	outb(0, (brdp->iobase + BBY_ATCONFR));
-	for (i = 0; (i < 500); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 	outb(0x1, brdp->iobase);
 	udelay(1000);
@@ -3235,7 +3322,7 @@
 	outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
 	udelay(10);
 	outb(0, (brdp->iobase + BBY_ATCONFR));
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3254,7 +3341,7 @@
 #endif
 
 	outb(0x1, brdp->iobase);
-	for (i = 0; (i < 100); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3291,7 +3378,7 @@
 	vecp = (volatile unsigned long *) (brdp->membase + 0x30);
 	*vecp = 0xffff0000;
 	outb(0, brdp->iobase);
-	for (i = 0; (i < 500); i++)
+	for (i = 0; (i < 1000); i++)
 		udelay(1000);
 }
 
@@ -3336,7 +3423,7 @@
  *	board types.
  */
 
-static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
+static int stli_initecp(stlibrd_t *brdp)
 {
 	cdkecpsig_t	sig;
 	cdkecpsig_t	*sigsp;
@@ -3344,18 +3431,23 @@
 	int		panelnr;
 
 #if DEBUG
-	printk("stli_initecp(brdp=%x,confp=%x)\n", (int) brdp, (int) confp);
+	printk("stli_initecp(brdp=%x)\n", (int) brdp);
 #endif
 
 /*
+ *	Do a basic sanity check on the IO and memory addresses.
+ */
+	if ((brdp->iobase == 0) || (brdp->memaddr == 0))
+		return(-ENODEV);
+
+/*
  *	Based on the specific board type setup the common vars to access
  *	and enable shared memory. Set all board specific information now
  *	as well.
  */
 	switch (brdp->brdtype) {
 	case BRD_ECP:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ECP_MEMSIZE;
 		brdp->pagesize = ECP_ATPAGESIZE;
 		brdp->init = stli_ecpinit;
@@ -3368,8 +3460,7 @@
 		break;
 
 	case BRD_ECPE:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ECP_MEMSIZE;
 		brdp->pagesize = ECP_EIPAGESIZE;
 		brdp->init = stli_ecpeiinit;
@@ -3382,10 +3473,9 @@
 		break;
 
 	case BRD_ECPMC:
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ECP_MEMSIZE;
-		brdp->membase = (void *) confp->memaddr;
 		brdp->pagesize = ECP_MCPAGESIZE;
-		brdp->iobase = confp->ioaddr1;
 		brdp->init = NULL;
 		brdp->enable = stli_ecpmcenable;
 		brdp->reenable = stli_ecpmcenable;
@@ -3408,8 +3498,8 @@
 	EBRDINIT(brdp);
 
 #if STLI_HIMEMORY
-	if (confp->memaddr > 0x100000) {
-		brdp->membase = stli_mapbrdmem(confp->memaddr, brdp->memsize);
+	if (brdp->memaddr > 0x100000) {
+		brdp->membase = stli_mapbrdmem(brdp->memaddr, brdp->memsize);
 		if (brdp->membase == (void *) NULL)
 			return(-ENOMEM);
 	}
@@ -3418,7 +3508,7 @@
 /*
  *	Now that all specific code is set up, enable the shared memory and
  *	look for the a signature area that will tell us exactly what board
- *	this is, and what is connected to it.
+ *	this is, and what it is connected to it.
  */
 	EBRDENABLE(brdp);
 	sigsp = (cdkecpsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
@@ -3468,17 +3558,23 @@
  *	This handles only these board types.
  */
 
-static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
+static int stli_initonb(stlibrd_t *brdp)
 {
 	cdkonbsig_t	sig;
 	cdkonbsig_t	*sigsp;
 	int		i;
 
 #if DEBUG
-	printk("stli_initonb(brdp=%x,confp=%x)\n", (int) brdp, (int) confp);
+	printk("stli_initonb(brdp=%x)\n", (int) brdp);
 #endif
 
 /*
+ *	Do a basic sanity check on the IO and memory addresses.
+ */
+	if ((brdp->iobase == 0) || (brdp->memaddr == 0))
+		return(-ENODEV);
+
+/*
  *	Based on the specific board type setup the common vars to access
  *	and enable shared memory. Set all board specific information now
  *	as well.
@@ -3489,8 +3585,7 @@
 	case BRD_ONBOARD2:
 	case BRD_ONBOARD2_32:
 	case BRD_ONBOARDRS:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ONB_MEMSIZE;
 		brdp->pagesize = ONB_ATPAGESIZE;
 		brdp->init = stli_onbinit;
@@ -3503,8 +3598,7 @@
 		break;
 
 	case BRD_ONBOARDE:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = ONB_EIMEMSIZE;
 		brdp->pagesize = ONB_EIPAGESIZE;
 		brdp->init = stli_onbeinit;
@@ -3519,8 +3613,7 @@
 	case BRD_BRUMBY4:
 	case BRD_BRUMBY8:
 	case BRD_BRUMBY16:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = BBY_MEMSIZE;
 		brdp->pagesize = BBY_PAGESIZE;
 		brdp->init = stli_bbyinit;
@@ -3533,8 +3626,7 @@
 		break;
 
 	case BRD_STALLION:
-		brdp->iobase = confp->ioaddr1;
-		brdp->membase = (void *) confp->memaddr;
+		brdp->membase = (void *) brdp->memaddr;
 		brdp->memsize = STAL_MEMSIZE;
 		brdp->pagesize = STAL_PAGESIZE;
 		brdp->init = stli_stalinit;
@@ -3559,8 +3651,8 @@
 	EBRDINIT(brdp);
 
 #if STLI_HIMEMORY
-	if (confp->memaddr > 0x100000) {
-		brdp->membase = stli_mapbrdmem(confp->memaddr, brdp->memsize);
+	if (brdp->memaddr > 0x100000) {
+		brdp->membase = stli_mapbrdmem(brdp->memaddr, brdp->memsize);
 		if (brdp->membase == (void *) NULL)
 			return(-ENOMEM);
 	}
@@ -3720,75 +3812,297 @@
 /*****************************************************************************/
 
 /*
+ *	Probe and initialize the specified board.
+ */
+
+static int stli_brdinit(stlibrd_t *brdp)
+{
+#if DEBUG
+	printk("stli_brdinit(brdp=%x)\n", (int) brdp);
+#endif
+
+	stli_brds[brdp->brdnr] = brdp;
+
+	switch (brdp->brdtype) {
+	case BRD_ECP:
+	case BRD_ECPE:
+	case BRD_ECPMC:
+		stli_initecp(brdp);
+		break;
+	case BRD_ONBOARD:
+	case BRD_ONBOARDE:
+	case BRD_ONBOARD2:
+	case BRD_ONBOARD32:
+	case BRD_ONBOARD2_32:
+	case BRD_ONBOARDRS:
+	case BRD_BRUMBY4:
+	case BRD_BRUMBY8:
+	case BRD_BRUMBY16:
+	case BRD_STALLION:
+		stli_initonb(brdp);
+		break;
+	case BRD_EASYIO:
+	case BRD_ECH:
+	case BRD_ECHMC:
+	case BRD_ECHPCI:
+		printk("STALLION: %s board type not supported in this driver\n", stli_brdnames[brdp->brdtype]);
+		return(ENODEV);
+	default:
+		printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype);
+		return(ENODEV);
+	}
+
+	if ((brdp->state & BST_FOUND) == 0) {
+		printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr);
+		return(ENODEV);
+	}
+
+	stli_initports(brdp);
+	printk("STALLION: %s found, unit=%d io=%x mem=%x nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr, brdp->nrpanels, brdp->nrports);
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Probe around trying to find where the EISA boards shared memory
+ *	might be. This is a bit if hack, but it is the best we can do.
+ */
+
+static int stli_eisamemprobe(stlibrd_t *brdp)
+{
+	cdkecpsig_t	ecpsig, *ecpsigp;
+	cdkonbsig_t	onbsig, *onbsigp;
+	int		i, foundit;
+
+#if DEBUG
+	printk("stli_eisamemprobe(brdp=%x)\n", (int) brdp);
+#endif
+
+/*
+ *	First up we reset the board, to get it into a known state. There
+ *	is only 2 board types here we need to worry about. Don;t use the
+ *	standard board init routine here, it programs up the shared
+ *	memopry address, and we don't know it yet...
+ */
+	if (brdp->brdtype == BRD_ECPE) {
+		outb(0x1, (brdp->iobase + ECP_EIBRDENAB));
+		outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
+		udelay(10);
+		outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR));
+		udelay(500);
+		stli_ecpeienable(brdp);
+	} else if (brdp->brdtype == BRD_ONBOARDE) {
+		outb(0x1, (brdp->iobase + ONB_EIBRDENAB));
+		outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
+		udelay(10);
+		outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
+		for (i = 0; (i < 100); i++)
+			udelay(1000);
+		outb(0x1, brdp->iobase);
+		udelay(1000);
+		stli_onbeenable(brdp);
+	} else {
+		return(-ENODEV);
+	}
+
+	foundit = 0;
+	brdp->memsize = ECP_MEMSIZE;
+
+/*
+ *	Board shared memory is enabled, so now we have a poke around and
+ *	see if we can find it.
+ */
+	for (i = 0; (i < stli_eisamempsize); i++) {
+		brdp->memaddr = stli_eisamemprobeaddrs[i];
+		brdp->membase = (void *) brdp->memaddr;
+#if STLI_HIMEMORY
+		if (brdp->memaddr > 0x100000) {
+			brdp->membase = stli_mapbrdmem(brdp->memaddr, brdp->memsize);
+			if (brdp->membase == (void *) NULL)
+				continue;
+		}
+#endif
+		if (brdp->brdtype == BRD_ECPE) {
+			ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp, CDK_SIGADDR, __LINE__);
+			memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
+			if (ecpsig.magic == ECP_MAGIC)
+				foundit = 1;
+		} else {
+			onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp, CDK_SIGADDR, __LINE__);
+			memcpy(&onbsig, onbsigp, sizeof(cdkonbsig_t));
+			if ((onbsig.magic0 == ONB_MAGIC0) && (onbsig.magic1 == ONB_MAGIC1) &&
+					(onbsig.magic2 == ONB_MAGIC2) && (onbsig.magic3 == ONB_MAGIC3))
+				foundit = 1;
+		}
+#if STLI_HIMEMORY
+		if (brdp->memaddr >= 0x100000)
+			vfree(brdp->membase);
+#endif
+		if (foundit)
+			break;
+	}
+
+/*
+ *	Regardless of whether we found the shared memory or not we must
+ *	disable the region. After that return success or failure.
+ */
+	if (brdp->brdtype == BRD_ECPE)
+		stli_ecpeidisable(brdp);
+	else
+		stli_onbedisable(brdp);
+
+	if (! foundit) {
+		brdp->memaddr = 0;
+		brdp->membase = 0;
+		printk("STALLION: failed to probe shared memory region for %s in EISA slot=%d\n", stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
+		return(-ENODEV);
+	}
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *	Probe around and try to find any EISA boards in system. The biggest
+ *	problem here is finding out what memory address is associated with
+ *	an EISA board after it is found. The registers of the ECPE and
+ *	ONboardE are not readable - so we can't read them from there. We
+ *	don't have access to the EISA CMOS (or EISA BIOS) so we don't
+ *	actually have any way to find out the real value. The best we can
+ *	do is go probing around in the usual places hoping we can find it.
+ */
+
+static int stli_findeisabrds()
+{
+	stlibrd_t	*brdp;
+	unsigned int	iobase, eid;
+	int		i;
+
+#if DEBUG
+	printk("stli_findeisabrds()\n");
+#endif
+
+/*
+ *	Firstly check if this is an EISA system. Do this by probing for
+ *	the system board EISA ID. If this is not an EISA system then
+ *	don't bother going any further!
+ */
+	outb(0xff, 0xc80);
+	if (inb(0xc80) == 0xff)
+		return(0);
+
+/*
+ *	Looks like an EISA system, so go searching for EISA boards.
+ */
+	for (iobase = 0x1000; (iobase <= 0xc000); iobase += 0x1000) {
+		outb(0xff, (iobase + 0xc80));
+		eid = inb(iobase + 0xc80);
+		eid |= inb(iobase + 0xc81) << 8;
+		if (eid != STL_EISAID)
+			continue;
+
+/*
+ *		We have found a board. Need to check if this board was
+ *		statically configured already (just in case!).
+ */
+		for (i = 0; (i < STL_MAXBRDS); i++) {
+			brdp = stli_brds[i];
+			if (brdp == (stlibrd_t *) NULL)
+				continue;
+			if (brdp->iobase == iobase)
+				break;
+		}
+		if (i < STL_MAXBRDS)
+			continue;
+
+/*
+ *		Check that we have room for this new board in our board
+ *		info table.
+ */
+		if (stli_nrbrds >= STL_MAXBRDS) {
+			printk("STALLION: no room for more probed boards, maximum supported %d\n", STL_MAXBRDS);
+			break;
+		}
+
+/*
+ *		We have found a Stallion board and it is not configured already.
+ *		Allocate a board structure and initialize it.
+ */
+		brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
+		if (brdp == (stlibrd_t *) NULL) {
+			printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlibrd_t));
+			return(-ENOMEM);
+		}
+		memset(brdp, 0, sizeof(stlibrd_t));
+
+		brdp->brdnr = stli_nrbrds++;
+		eid = inb(iobase + 0xc82);
+		if (eid == ECP_EISAID)
+			brdp->brdtype = BRD_ECPE;
+		else if (eid == ONB_EISAID)
+			brdp->brdtype = BRD_ONBOARDE;
+		else
+			brdp->brdtype = BRD_UNKNOWN;
+		brdp->iobase = iobase;
+		outb(0x1, (iobase + 0xc84));
+		if (stli_eisamemprobe(brdp))
+			outb(0, (iobase + 0xc84));
+		stli_brdinit(brdp);
+	}
+
+	return(0);
+}
+
+/*****************************************************************************/
+
+/*
  *	Scan through all the boards in the configuration and see what we
  *	can find.
  */
 
-static int stli_brdinit()
+static int stli_initbrds()
 {
-	stlibrd_t	*brdp;
+	stlibrd_t	*brdp, *nxtbrdp;
 	stlconf_t	*confp;
 	int		i, j;
 
 #if DEBUG
-	printk("stli_brdinit()\n");
+	printk("stli_initbrds()\n");
 #endif
 
-	if (stli_nrbrds > STL_MAXBRDS)
-		return(-EINVAL);
-
-	stli_brds = (stlibrd_t *) stli_memalloc((sizeof(stlibrd_t) * stli_nrbrds));
-	if (stli_brds == (stlibrd_t *) NULL) {
-		printk("STALLION: failed to allocate board structures\n");
-		return(-ENOMEM);
+	if (stli_nrbrds > STL_MAXBRDS) {
+		printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS);
+		stli_nrbrds = STL_MAXBRDS;
 	}
-	memset(stli_brds, 0, (sizeof(stlibrd_t) * stli_nrbrds));
 
+/*
+ *	Firstly scan the list of static boards configured. Allocate
+ *	resources and initialize the boards as found.
+ */
 	for (i = 0; (i < stli_nrbrds); i++) {
-		brdp = &stli_brds[i];
 		confp = &stli_brdconf[i];
-		brdp->brdnr = i;
-		brdp->brdtype = confp->brdtype;
-
-		switch (confp->brdtype) {
-		case BRD_ECP:
-		case BRD_ECPE:
-		case BRD_ECPMC:
-			stli_initecp(brdp, confp);
-			break;
-		case BRD_ONBOARD:
-		case BRD_ONBOARDE:
-		case BRD_ONBOARD2:
-		case BRD_ONBOARD32:
-		case BRD_ONBOARD2_32:
-		case BRD_ONBOARDRS:
-		case BRD_BRUMBY4:
-		case BRD_BRUMBY8:
-		case BRD_BRUMBY16:
-		case BRD_STALLION:
-			stli_initonb(brdp, confp);
-			break;
-		case BRD_EASYIO:
-		case BRD_ECH:
-		case BRD_ECHMC:
-		case BRD_ECHPCI:
-			printk("STALLION: %s board type not supported in this driver\n", stli_brdnames[brdp->brdtype]);
-			break;
-		default:
-			printk("STALLION: unit=%d is unknown board type=%d\n", i, confp->brdtype);
-			break;
-		}
-
-		if ((brdp->state & BST_FOUND) == 0) {
-			printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n", stli_brdnames[brdp->brdtype], i, confp->ioaddr1, (int) confp->memaddr);
-			continue;
+		brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
+		if (brdp == (stlibrd_t *) NULL) {
+			printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlibrd_t));
+			return(-ENOMEM);
 		}
+		memset(brdp, 0, sizeof(stlibrd_t));
 
-		stli_initports(brdp);
-		printk("STALLION: %s found, unit=%d io=%x mem=%x nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], i, confp->ioaddr1, (int) confp->memaddr, brdp->nrpanels, brdp->nrports);
+		brdp->brdnr = i;
+		brdp->brdtype = confp->brdtype;
+		brdp->iobase = confp->ioaddr1;
+		brdp->memaddr = confp->memaddr;
+		stli_brdinit(brdp);
 	}
 
 /*
+ *	Now go probing for EISA boards if enabled.
+ */
+	if (stli_eisaprobe)
+		stli_findeisabrds();
+
+/*
  *	All found boards are initialized. Now for a little optimization, if
  *	no boards are sharing the "shared memory" regions then we can just
  *	leave them all enabled. This is in fact the usual case.
@@ -3796,10 +4110,14 @@
 	stli_shared = 0;
 	if (stli_nrbrds > 1) {
 		for (i = 0; (i < stli_nrbrds); i++) {
+			brdp = stli_brds[i];
+			if (brdp == (stlibrd_t *) NULL)
+				continue;
 			for (j = i + 1; (j < stli_nrbrds); j++) {
-				brdp = &stli_brds[i];
-				if ((brdp->membase >= stli_brds[j].membase) &&
-						(brdp->membase <= (stli_brds[j].membase + stli_brds[j].memsize - 1))) {
+				nxtbrdp = stli_brds[j];
+				if (nxtbrdp == (stlibrd_t *) NULL)
+					continue;
+				if ((brdp->membase >= nxtbrdp->membase) && (brdp->membase <= (nxtbrdp->membase + nxtbrdp->memsize - 1))) {
 					stli_shared++;
 					break;
 				}
@@ -3809,7 +4127,9 @@
 
 	if (stli_shared == 0) {
 		for (i = 0; (i < stli_nrbrds); i++) {
-			brdp = &stli_brds[i];
+			brdp = stli_brds[i];
+			if (brdp == (stlibrd_t *) NULL)
+				continue;
 			if (brdp->state & BST_FOUND) {
 				EBRDENABLE(brdp);
 				brdp->enable = NULL;
@@ -3843,7 +4163,9 @@
 	brdnr = MINOR(ip->i_rdev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 	if (brdp->state == 0)
 		return(-ENODEV);
 	if (fp->f_pos >= brdp->memsize)
@@ -3891,7 +4213,9 @@
 	brdnr = MINOR(ip->i_rdev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 	if (brdp->state == 0)
 		return(-ENODEV);
 	if (fp->f_pos >= brdp->memsize)
@@ -3937,7 +4261,9 @@
 	brdnr = MINOR(ip->i_rdev);
 	if (brdnr >= stli_nrbrds)
 		return(-ENODEV);
-	brdp = &stli_brds[brdnr];
+	brdp = stli_brds[brdnr];
+	if (brdp == (stlibrd_t *) NULL)
+		return(-ENODEV);
 	if (brdp->state == 0)
 		return(-ENODEV);
 
@@ -3971,11 +4297,11 @@
 
 /*****************************************************************************/
 
-int stli_init(void)
+int stli_init()
 {
 	printk("%s: version %s\n", stli_drvname, stli_drvversion);
 
-	stli_brdinit();
+	stli_initbrds();
 
 /*
  *	Allocate a temporary write buffer.
@@ -4039,7 +4365,7 @@
 	if (tty_register_driver(&stli_callout))
 		printk("STALLION: failed to register callout driver\n");
 
-	return 0;
+	return(0);
 }
 
 /*****************************************************************************/
diff -u --recursive --new-file v1.3.63/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v1.3.63/linux/drivers/char/stallion.c	Thu Nov  9 11:23:48 1995
+++ linux/drivers/char/stallion.c	Thu Feb 15 12:07:36 1996
@@ -3,7 +3,7 @@
 /*
  *	stallion.c  -- stallion multiport serial driver.
  *
- *	Copyright (C) 1994,1995  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *	This code is loosely based on the Linux serial driver, written by
  *	Linus Torvalds, Theodore T'so and others.
@@ -26,7 +26,6 @@
 /*****************************************************************************/
 
 #include <linux/module.h>
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
@@ -42,7 +41,6 @@
 #include <linux/malloc.h>
 #include <linux/ioport.h>
 #include <linux/config.h>	/* for CONFIG_PCI */
-
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -143,7 +141,7 @@
  *	all the local structures required by a serial tty driver.
  */
 static char	*stl_drvname = "Stallion Multiport Serial Driver";
-static char	*stl_drvversion = "1.0.0";
+static char	*stl_drvversion = "1.0.2";
 static char	*stl_serialname = "ttyE";
 static char	*stl_calloutname = "cue";
 
@@ -452,7 +450,6 @@
 int		init_module(void);
 void		cleanup_module(void);
 #endif
-static void	*stl_memalloc(int len);
 
 int		stl_init(void);
 static int	stl_open(struct tty_struct *tty, struct file *filp);
@@ -494,6 +491,7 @@
 static void	stl_delay(int len);
 static void	stl_intr(int irq, struct pt_regs *regs);
 static void	stl_offintr(void *private);
+static void	*stl_memalloc(int len);
 
 #ifdef	CONFIG_PCI
 static int	stl_findpcibrds(void);
@@ -504,8 +502,9 @@
 #ifdef MODULE
 
 /*
- *	Use the kernel version number for modules.
+ *	Loadable module initialization stuff.
  */
+
 int init_module()
 {
 	unsigned long	flags;
@@ -605,15 +604,12 @@
 /*****************************************************************************/
 
 /*
- *	Local memory allocation routines. These are used so we can deal with
- *	memory allocation at init time and during run-time in a consistent
- *	way. Everbody just calls the stl_memalloc routine to allocate
- *	memory and it will do the right thing.
+ *	Local driver kernel memory allocation routine.
  */
 
 static void *stl_memalloc(int len)
 {
-	return (void *) kmalloc(len, GFP_KERNEL);
+	return((void *) kmalloc(len, GFP_KERNEL));
 }
 
 /*****************************************************************************/
@@ -2782,18 +2778,6 @@
 			}
 			brdp->irq = irq;
 
-#if 0
-			ioaddr = 0x0c000001;
-			if ((rc = pcibios_write_config_dword(busnr, devnr, 0x40, ioaddr))) {
-				printk("STALLION: failed to write register on PCI board, errno=%x\n", rc);
-				continue;
-			}
-			if ((rc = pcibios_write_config_dword(busnr, devnr, 0x48, ioaddr))) {
-				printk("STALLION: failed to write register on PCI board, errno=%x\n", rc);
-				continue;
-			}
-#endif
-
 			stl_brdinit(brdp);
 		}
 	}
@@ -2919,7 +2903,7 @@
 	if (tty_register_driver(&stl_callout))
 		printk("STALLION: failed to register callout driver\n");
 
-	return 0;
+	return(0);
 }
 
 /*****************************************************************************/
diff -u --recursive --new-file v1.3.63/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.3.63/linux/drivers/net/arcnet.c	Wed Feb  7 15:11:25 1996
+++ linux/drivers/net/arcnet.c	Thu Feb 15 09:24:24 1996
@@ -1,4 +1,4 @@
-/* arcnet.c
+/* arcnet.c:
 	Written 1994-1996 by Avery Pennarun,
 	derived from skeleton.c by Donald Becker.
 
@@ -19,6 +19,45 @@
 	
 	This is ONLY A SUMMARY.  The complete ChangeLog is available in
 	the full Linux-ARCnet package.
+	
+	v2.41 ALPHA (96/02/10)
+	  - Incorporated changes someone made to arcnet_setup in 1.3.60.
+	  - Increased reset timeout to 3/10 of a second because some cards
+	    are too slow.
+	  - Removed a useless delay from autoprobe stage 4; I wonder
+	    how that got there!  (oops)
+	  - If FAST_IFCONFIG is defined, don't reset the card during
+	    arcnet_open; rather, do it in arcnet_close but don't delay. 
+	    This speeds up calls to ifconfig up/down.  (Thanks to Vojtech
+	    for the idea to speed this up.)
+	  - If FAST_PROBE is defined, don't bother to reset the card in
+	    autoprobe Stage 5 when there is only one io port and one shmem
+	    left in the list.  They "obviously" correspond to each other. 
+	    Another good idea from Vojtech.
+
+	v2.40 ALPHA (96/02/03)
+	  - Checked the RECON flag last in the interrupt handler (when
+	    enabled) so the flag will show up in "status" when reporting
+	    other errors.  (I had a cabling problem that was hard to notice
+	    until I saw the huge RECON count in /proc/net/dev.)
+	  - Moved "IRQ for unknown device" message to D_DURING.
+	  - "transmit timed out" and "not acknowledged" messages are
+	    now D_EXTRA, because they very commonly happen when things
+	    are working fine.  "transmit timed out" due to missed IRQ's
+	    is still D_NORMAL, because it's probably a bug.
+	  - "Transmit timed out" messages now include destination station id.
+	  - The virtual arc0e and arc0s devices can now be disabled. 
+	    Massive (but simple) code rearrangement to support this with
+	    fewer ifdef's.
+	  - SLOW_XMIT_COPY option so fast computers don't hog the bus.  It's
+	    weird, but it works.
+	  - Finally redesigned autoprobe after some discussion with Vojtech
+	    Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>.  It should be much safer
+	    and more reliable now, I think.  We now probe several more io
+	    ports and many more shmem addresses.
+	  - Rearranged D_* debugging flags slightly.  Watch out!  There is
+	    now a new flag, disabled by default, that will tell you the
+	    reason a particular port or shmem is discarded from the list.
 
 	v2.30 ALPHA (96/01/10)
 	  - Abandoned support for Linux 1.2 to simplify coding and allow me
@@ -82,27 +121,27 @@
          
 	TO DO: (it it just me, or does this list only get longer?)
 	
-         - Test in systems with NON-ARCnet network cards, just to see if
-           autoprobe kills anything.  Currently, we do cause some NE2000's
-           to die.  Autoprobe is also way too slow and verbose, particularly
-           if there aren't any ARCnet cards in the system.
-         - Rewrite autoprobe.  Try the Linux-generic-autoirq function instead
-           of the net-specific one.
-         - Make sure RESET flag is cleared during an IRQ even if dev->start==0;
-           mainly a portability fix.  This will confuse autoprobe a bit, so
-           test that too.
+	 - Make sure autoprobe puts TESTvalue back into shmem locations
+	   that it determines aren't ARCnet cards.
+	 - Probe for multiple devices in one shot (there's supposed to
+	   be a way to do that now, but I can't remember what it is!)
+         - Support printk's priority levels.
+         - Have people test the new autoprobe a bit more - then remove
+           D_INIT from the default debug level.
+         - Move the SKB and memory dump code into separate functions.
+	 - Debug level should be changed with a system call, not a hack to
+	   the "metric" flag.
          - What about cards with shared memory that can be "turned off?"
            (or that have none at all, like the SMC PC500longboard)
          - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play
-           with temporarily)
+           with temporarily.)  Update: yes, the Pure Data config program
+           for DOS works fine, but the PDI508Plus I have doesn't! :)
          - Try to implement promiscuous (receive-all-packets) mode available
            on some newer cards with COM20020 and similar chips.  I don't have
            one, but SMC sent me the specs.
          - Add support for the new 1.3.x IP header cache features.
-         - Support printk's priority levels.
          - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
            packet into ARCnet memory.
-         - Move the SKB and memory dump code into separate functions.
          - ATA protocol support?? 
          - VINES TCP/IP encapsulation?? (info needed)
 
@@ -125,7 +164,7 @@
 */
 
 static const char *version =
- "arcnet.c: v2.30 ALPHA 96/01/10 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.41 ALPHA 96/02/10 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -160,6 +199,36 @@
 
 /**************************************************************************/
 
+/* This driver supports three different "virtual ARCnet devices" running
+ * on the same adapter, in order to communicate with various different
+ * TCP/IP-over-ARCnet implementations.  They are:
+ *	arc0	- RFC1201 Internet-standard protocol
+ *	arc0e	- Ethernet-encapsulation protocol (as used by Windows)
+ *	arc0s	- "Simpler" (but outdated) RFC1051 internet standard.
+ *
+ * arc0e and arc0s are created when arc0 is ifconfig'ed up.  You can disable
+ * either or both of them by undefining CONFIG_ARCNET_ETH and/or
+ * CONFIG_ARCNET_1051.
+ */
+#define CONFIG_ARCNET_ETH
+#define CONFIG_ARCNET_1051
+
+/* On a fast computer, the buffer copy from memory to the ARCnet card during
+ * a transmit can hog the bus just a little too long.  SLOW_XMIT_COPY
+ * replaces the fast memcpy() with a slower for() loop that seems to solve
+ * my problems with ftape.
+ *
+ * Probably a better solution would be to use memcpy_toio (more portable
+ * anyway) and modify that routine to support REALLY_SLOW_IO-style
+ * defines; ARCnet probably is not the only driver that can screw up an
+ * ftape DMA transfer.
+ *
+ * Turn this off if you don't have timing-sensitive DMA (ie. a tape drive)
+ * and would like the little bit of speed back.  It's on by default because
+ * - trust me - it's very difficult to figure out that you need it!
+ */
+#define SLOW_XMIT_COPY
+
 /* The card sends the reconfiguration signal when it loses the connection to
  * the rest of its network. It is a 'Hello, is anybody there?' cry.  This
  * usually happens when a new computer on the network is powered on or when
@@ -189,24 +258,34 @@
  */
 #define RECON_THRESHOLD 30
 
-/* Define this if you want to make sure transmitted packets are "acknowledged"
- * by the destination host, as long as they're not to the broadcast address.
- *
- * That way, if one segment of a split packet doesn't get through, it can be
- * resent immediately rather than confusing the other end.  We don't
- * actually do that yet, though.
- *
- * Disable this to return to 1.02-style behaviour, if you have problems.
- */
-#define VERIFY_ACK
-
 /* Define this to the minimum "timeout" value.  If a transmit takes longer
  * than TX_TIMEOUT jiffies, Linux will abort the TX and retry.  On a large
  * network, or one with heavy network traffic, this timeout may need to be
- * increased.
+ * increased.  The larger it is, though, the longer it will be between
+ * necessary transmits - don't set this too large.
  */
 #define TX_TIMEOUT 20
 
+/* Define this to speed up the autoprobe by assuming if only one io port and
+ * shmem are left in the list at Stage 5, they must correspond to each
+ * other.
+ *
+ * This is undefined by default because it might not always be true.  Speed
+ * demons can turn it on - I think it should be fine if you only have one
+ * ARCnet card installed.
+ *
+ * If no ARCnet cards are installed, this delay never happens anyway and thus
+ * the option has no effect.
+ */
+#undef FAST_PROBE
+
+/* Define this to speed up "ifconfig up" by moving the card reset command
+ * around.  This is a new option in 2.41 ALPHA.  If it causes problems,
+ * undefine this to get the old behaviour; then send me email, because if
+ * there are no problems, this option will go away very soon.
+ */
+#define FAST_IFCONFIG
+
 /* Define this if you want to make it easier to use the "call trace" when
  * a kernel NULL pointer assignment occurs.  Hopefully unnecessary, most of
  * the time.  It will make all the function names (and other things) show
@@ -224,55 +303,66 @@
  *		and HOSTNAME is your hostname/ip address
  * and then resetting your routes.
  *
+ * An ioctl() should be used for this instead, someday.
+ *
  * Note: only debug flags included in the ARCNET_DEBUG_MAX define will
  *   actually be available.  GCC will (at least, GCC 2.7.0 will) notice
  *   lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
  *   them out.
  */
-#define D_NORMAL	1	/* D_NORMAL  normal operational info	*/
-#define	D_INIT		2	/* D_INIT    show init/probe messages	*/
-#define D_EXTRA		4	/* D_EXTRA   extra information		*/
-/* debug levels past this point give LOTS of output! */
-#define D_DURING	8	/* D_DURING  during normal use (irq's)	*/
-#define D_TX		16	/* D_TX	     show tx packets		*/
-#define D_RX		32	/* D_RX	     show rx packets		*/
-#define D_SKB		64	/* D_SKB     dump skb's			*/
+#define D_NORMAL	1	/* important operational info		*/
+#define D_EXTRA		2	/* useful, but non-vital information	*/
+#define	D_INIT		4	/* show init/probe messages		*/
+#define D_INIT_REASONS	8	/* show reasons for discarding probes	*/
+/* debug levels below give LOTS of output during normal operation! */
+#define D_DURING	16	/* trace operations (including irq's)	*/
+#define D_TX		32	/* show tx packets			*/
+#define D_RX		64	/* show rx packets			*/
+#define D_SKB		128	/* show skb's				*/
 
 #ifndef ARCNET_DEBUG_MAX
 #define ARCNET_DEBUG_MAX (~0)		/* enable ALL debug messages */
-/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_INIT|D_EXTRA) */
+/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS) */
 /*#define ARCNET_DEBUG_MAX 0	*/	/* enable NO debug messages */
 #endif
 
 #ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL|D_INIT|D_EXTRA)
-/*#define ARCNET_DEBUG (D_NORMAL|D_INIT)*/
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA|D_INIT)
+/*#define ARCNET_DEBUG (D_NORMAL)*/
 #endif
 int arcnet_debug = ARCNET_DEBUG;
 
 /* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
-#define BUGMSG(x,msg,args...) BUGLVL(x) printk("%6s: " msg, dev->name , ## args);
+#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg , ## args)
+#define BUGMSG(x,msg,args...) BUGMSG2(x,"%6s: " msg, dev->name , ## args)
+
+/* Some useful multiprotocol macros.  The idea here is that GCC will
+ * optimize away multiple tests or assignments to lp->adev.  Relying on this
+ * results in the cleanest mess possible.
+ */
+#define ADEV lp->adev
+ 
+#ifdef CONFIG_ARCNET_ETH
+ #define EDEV lp->edev
+#else
+ #define EDEV lp->adev
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+ #define SDEV lp->sdev
+#else
+ #define SDEV lp->adev
+#endif
+
+#define TBUSY ADEV->tbusy=EDEV->tbusy=SDEV->tbusy
+#define IF_TBUSY (ADEV->tbusy||EDEV->tbusy||SDEV->tbusy)
+
+#define INTERRUPT ADEV->interrupt=EDEV->interrupt=SDEV->interrupt
+#define IF_INTERRUPT (ADEV->interrupt||EDEV->interrupt||SDEV->interrupt)
+
+#define START ADEV->start=EDEV->start=SDEV->start
 
-/* Some useful multiprotocol macros */
-#define TBUSY lp->adev->tbusy \
-		=lp->edev->tbusy \
-		=lp->sdev->tbusy
-#define IF_TBUSY (lp->adev->tbusy \
-		|| lp->edev->tbusy \
-		|| lp->sdev->tbusy)
-
-#define INTERRUPT lp->adev->interrupt \
-		=lp->edev->interrupt \
-		=lp->sdev->interrupt
-#define IF_INTERRUPT (lp->adev->interrupt \
-		|| lp->edev->interrupt \
-		|| lp->sdev->interrupt)
-
-#define START lp->adev->start \
-		=lp->edev->start \
-		=lp->sdev->start
-		
 
 /* The number of low I/O ports used by the ethercard. */
 #define ARCNET_TOTAL_SIZE	16
@@ -287,9 +377,11 @@
 
 #define SETMASK outb(lp->intmask,INTMASK);
 
-	/* Time needed for various things (in clock ticks, 1/100 sec) */
-	/* We mostly don't bother with these - watch out. */
-#define RESETtime 30		/* reset */
+	/* Time needed to reset the card - in jiffies.  This works on my SMC
+	 * PC100.  I can't find a reference that tells me just how long I
+	 * should wait.
+	 */
+#define RESETtime (HZ * 3 / 10)		/* reset */
 
 	/* these are the max/min lengths of packet data. (including
 	 * ClientData header)
@@ -309,8 +401,8 @@
 #define RECONflag       0x04            /* system reconfigured */
 #define TESTflag        0x08            /* test flag */
 #define RESETflag       0x10            /* power-on-reset */
-#define RES1flag        0x20            /* unused */
-#define RES2flag        0x40            /* unused */
+#define RES1flag        0x20            /* reserved - usually set by jumper */
+#define RES2flag        0x40            /* reserved - usually set by jumper */
 #define NORXflag        0x80            /* receiver inhibited */
 
        /* in the command register, the following bits have these meanings:
@@ -455,12 +547,9 @@
 		intmask;	/* current value of INTMASK register */
 	short intx,		/* in TX routine? */
 	      in_txhandler,	/* in TX_IRQ handler? */
-	      sending;		/* transmit in progress? */
-
-#ifdef VERIFY_ACK
-	short lastload_dest,		/* can last loaded packet be acked? */
-	      lasttrans_dest;		/* can last TX'd packet be acked? */
-#endif
+	      sending,		/* transmit in progress? */
+	      lastload_dest,	/* can last loaded packet be acked? */
+	      lasttrans_dest;	/* can last TX'd packet be acked? */
 
 #if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
 	time_t first_recon,	/* time of "first" RECON message to count */
@@ -473,29 +562,29 @@
 	struct Incoming incoming[256];	/* one from each address */
 	struct Outgoing outgoing; /* packet currently being sent */
 	
-	struct device *adev,	/* RFC1201 protocol device */
-		 	*edev,	/* Ethernet-Encap device */
-		 	*sdev;	/* RFC1051 protocol device */
+	struct device *adev;	/* RFC1201 protocol device */
+
+#ifdef CONFIG_ARCNET_ETH
+	struct device *edev;	/* Ethernet-Encap device */
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+	struct device *sdev;	/* RFC1051 protocol device */
+#endif
 };
 
 
 /* Index to functions, as function prototypes. */
 extern int arcnet_probe(struct device *dev);
-static int arcnet_memprobe(struct device *dev,u_char *addr);
-static int arcnet_ioprobe(struct device *dev, short ioaddr);
+static int arcnet_found(struct device *dev,int port,int airq,u_long shmem);
 
 static void arcnet_setup(struct device *dev);
-static int arcnetE_init(struct device *dev);
-static int arcnetS_init(struct device *dev);
-
 static int arcnet_open(struct device *dev);
 static int arcnet_close(struct device *dev);
-static int arcnet_reset(struct device *dev);
+static int arcnet_reset(struct device *dev,int reset_delay);
 
 static int arcnet_send_packet_bad(struct sk_buff *skb,struct device *dev);
 static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev);
-static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev);
-static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev);
 static void arcnetA_continue_tx(struct device *dev);
 static void arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
 		char *data,int length,int daddr,int exceptA);
@@ -507,26 +596,35 @@
 static void arcnet_rx(struct device *dev,int recbuf);
 static void arcnetA_rx(struct device *dev,u_char *buf,
 	int length,u_char saddr, u_char daddr);
-static void arcnetE_rx(struct device *dev,u_char *arcsoft,
-	int length,u_char saddr, u_char daddr);
-static void arcnetS_rx(struct device *dev,u_char *buf,
-	int length,u_char saddr, u_char daddr);
 
 static struct enet_statistics *arcnet_get_stats(struct device *dev);
-/*
-static void set_multicast_list(struct device *dev);
-*/
-	/* functions for header/arp/etc building */
+
 int arcnetA_header(struct sk_buff *skb,struct device *dev,
 		unsigned short type,void *daddr,void *saddr,unsigned len);
-int arcnetS_header(struct sk_buff *skb,struct device *dev,
-		unsigned short type,void *daddr,void *saddr,unsigned len);
 int arcnetA_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
 		struct sk_buff *skb);
+unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev);
+
+#ifdef CONFIG_ARCNET_ETH
+	/* functions specific to Ethernet-Encap */
+static int arcnetE_init(struct device *dev);
+static int arcnetE_send_packet(struct sk_buff *skb, struct device *dev);
+static void arcnetE_rx(struct device *dev,u_char *arcsoft,
+	int length,u_char saddr, u_char daddr);
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+	/* functions specific to RFC1051 */
+static int arcnetS_init(struct device *dev);
+static int arcnetS_send_packet(struct sk_buff *skb, struct device *dev);
+static void arcnetS_rx(struct device *dev,u_char *buf,
+	int length,u_char saddr, u_char daddr);
+int arcnetS_header(struct sk_buff *skb,struct device *dev,
+		unsigned short type,void *daddr,void *saddr,unsigned len);
 int arcnetS_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
 		struct sk_buff *skb);
-unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev);
 unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev);
+#endif
 
 #ifdef MODULE
 int  init_module(void);
@@ -535,8 +633,7 @@
 
 #define tx_done(dev) 1
 
-#define JIFFER(time) for (delayval=0; delayval<(time*10); delayval++) \
-		udelay(1000);
+#define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ;
 		
 
 /****************************************************************************
@@ -545,63 +642,54 @@
  *                                                                          *
  ****************************************************************************/
  
-/* Check for a network adaptor of this type, and return '0' if one exists.
+/* Check for an ARCnet network adaptor, and return '0' if one exists.
  *  If dev->base_addr == 0, probe all likely locations.
  *  If dev->base_addr == 1, always return failure.
  *  If dev->base_addr == 2, allocate space for the device and return success
- *  (detachable devices only).
- */
-int
-arcnet_probe(struct device *dev)
-{
-	/* I refuse to probe anything less than 0x200, because anyone using
-	 * an address like that should probably be shot.
-	 */
-	int *port, ports[] = {/* first the suggested values! */
-			      0x300,0x2E0,0x2F0,0x2D0,
-			      /* ...now everything else possible. */
-			      0x200,0x210,0x220,0x230,0x240,0x250,0x260,0x270,
-			      0x280,0x290,0x2a0,0x2b0,0x2c0,
-			            0x310,0x320,0x330,0x340,0x350,0x360,0x370,
-			      0x380,0x390,0x3a0,/* video ports, */0x3e0,0x3f0,
-			      /* a null ends the list */
-			      0};
-	/* I'm not going to probe below 0xA0000 either, for similar reasons.
-	 */
-	unsigned long *addr, addrs[] = {0xD0000,0xE0000,0xA0000,0xB0000,
-					0xC0000,0xF0000,
-					/* from <mdrejhon@magi.com> */
-					0xE1000,
-					0xDD000,0xDC000,
-					0xD9000,0xD8000,0xD5000,0xD4000,0xD1000,
-					0xCD000,0xCC000,
-					0xC9000,0xC8000,0xC5000,0xC4000,
-					/* terminator */
-					0};
-	int base_addr=dev->base_addr, status=0;
-	int delayval,ioaddr;
-	struct arcnet_local *lp;
+ *  			    (detachable devices only).
+ *
+ * NOTE: the list of possible ports/shmems is static, so it is retained
+ * across calls to arcnet_probe.  So, if more than one ARCnet probe is made,
+ * values that were discarded once will not even be tried again.
+ */
+int arcnet_probe(struct device *dev)
+{
+	static int init_once = 0;
+	static int ports[(0x3f0 - 0x200) / 16 + 1];
+	static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1];
+	static int numports=sizeof(ports)/sizeof(ports[0]),
+	    	   numshmems=sizeof(shmems)/sizeof(shmems[0]);
 
-	printk(version);
+	int count,status,delayval,ioaddr,numprint,airq;
+	unsigned long airqmask;
+	int *port;
+	u_long *shmem;
 	
-#if 1
-	BUGLVL(D_NORMAL)
+	if (!init_once)
 	{
-		printk("arcnet: ***\n");
-		printk("arcnet: * Read README.arcnet for important release notes!\n");
-		printk("arcnet: *\n");
-		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.00)  E-mail me if\n");
-		printk("arcnet: * you have any questions, comments, or bug reports.\n");
-		printk("arcnet: ***\n");
+		for (count=0x200; count<=0x3f0; count+=16)
+			ports[(count-0x200)/16] = count;
+		for (count=0xA0000; count<=0xFF800; count+=2048)
+			shmems[(count-0xA0000)/2048] = count;
 	}
-#else
+	else
+		init_once=1;
+
+	BUGLVL(D_NORMAL) printk(version);
+
+	BUGMSG(D_DURING,"space used for probe buffers: %d+%d=%d bytes\n",
+		sizeof(ports),sizeof(shmems),
+		sizeof(ports)+sizeof(shmems));
+
+	
+#if 1
 	BUGLVL(D_EXTRA)
 	{
 		printk("arcnet: ***\n");
-		printk("arcnet: * Read README.arcnet for important release notes!\n");
+		printk("arcnet: * Read arcnet.txt for important release notes!\n");
 		printk("arcnet: *\n");
-		printk("arcnet: * This version should be stable, but please e-mail\n");
-		printk("arcnet: * me if you have any questions or comments.\n");
+		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.22)  E-mail me if\n");
+		printk("arcnet: * you have any questions, comments, or bug reports.\n");
 		printk("arcnet: ***\n");
 	}
 #endif
@@ -609,80 +697,367 @@
 	BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
 			dev->base_addr,dev->irq,dev->mem_start);
 
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		status=arcnet_ioprobe(dev, base_addr);
-	else if (base_addr > 0)		/* Don't probe at all. */
+	if (dev->base_addr > 0x1ff)	/* Check a single specified port */
+	{
+		ports[0]=dev->base_addr;
+		numports=1;
+	}
+	else if (dev->base_addr > 0)	/* Don't probe at all. */
 		return -ENXIO;
-	else for (port = &ports[0]; *port; port++)
+		
+	if (dev->mem_start)
+	{
+		shmems[0]=dev->mem_start;
+		numshmems=1;
+	}
+	
+
+	/* Stage 1: abandon any reserved ports, or ones with status==0xFF
+	 * (empty), and reset any others by reading the reset port.
+	 */
+	BUGMSG(D_INIT,"Stage 1: ");
+	numprint=0;
+	for (port = &ports[0]; port-ports<numports; port++)
 	{
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 1: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%Xh ",*port);
+		
+		ioaddr=*port;
+		
 		if (check_region(*port, ARCNET_TOTAL_SIZE))
 		{
-			BUGMSG(D_INIT,"Skipping %Xh because of check_region...\n",
-					*port);
+			BUGMSG2(D_INIT_REASONS,"(check_region)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 1: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
+			continue;
+		}
+		
+		if (inb(STATUS) == 0xFF)
+		{
+			BUGMSG2(D_INIT_REASONS,"(empty)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 1: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
 			continue;
 		}
+		
+		inb(RESET);	/* begin resetting card */
 
-		status=arcnet_ioprobe(dev, *port);
-		if (!status) break;
+		BUGMSG2(D_INIT_REASONS,"\n");
+		BUGMSG(D_INIT_REASONS,"Stage 1: ");
+		BUGLVL(D_INIT_REASONS) numprint=0;
 	}
+	BUGMSG2(D_INIT,"\n");
 	
-	if (status) return status;
+	if (!numports)
+	{
+		BUGMSG(D_INIT,"Stage 1: failed.  No ARCnet cards found.\n");
+		return -ENODEV;
+	}
 	
-	/* arcnet_ioprobe set this */
-	ioaddr=dev->base_addr;
 
-	/* ioprobe turned out okay.  Now reset the card, so we have
-	 * a test byte to look for in shared memory...
+	/* Stage 2: we have now reset any possible ARCnet cards, so we can't
+	 * do anything until they finish.  If D_INIT, print the list of
+	 * cards that are left.
 	 */
-	BUGMSG(D_INIT,"ioprobe okay!  Waiting for reset...\n");
-	inb(RESET);
+	BUGMSG(D_INIT,"Stage 2: ");
+	numprint=0;
+	for (port = &ports[0]; port-ports<numports; port++)
+	{
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 2: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%Xh ",*port);
+	}
+	BUGMSG2(D_INIT,"\n");
 	JIFFER(RESETtime);
+	
+
+	/* Stage 3: abandon any shmem addresses that don't have the signature
+	 * 0xD1 byte in the right place, or are read-only.
+	 */
+	BUGMSG(D_INIT,"Stage 3: ");
+	numprint=0;
+	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+	{
+		u_char *cptr;
+	
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 3: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%lXh ",*shmem);
+		
+		cptr=(u_char *)(*shmem);
+		
+		if (*cptr != TESTvalue)
+		{
+			BUGMSG2(D_INIT_REASONS,"(mem=%Xh, not %Xh)\n",
+				*cptr,TESTvalue);
+			BUGMSG(D_INIT_REASONS,"Stage 3: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*shmem=shmems[numshmems-1];
+			numshmems--;
+			shmem--;
+			continue;
+		}
+		
+		/* By writing 0x42 to the TESTvalue location, we also make
+		 * sure no "mirror" shmem areas show up - if they occur
+		 * in another pass through this loop, they will be discarded
+		 * because *cptr != TESTvalue.
+		 */
+		*cptr=0x42;
+		if (*cptr != 0x42)
+		{
+			BUGMSG2(D_INIT_REASONS,"(read only)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 3: ");
+			*shmem=shmems[numshmems-1];
+			numshmems--;
+			shmem--;
+			continue;
+		}
+		
+		BUGMSG2(D_INIT_REASONS,"\n");
+		BUGMSG(D_INIT_REASONS,"Stage 3: ");
+		BUGLVL(D_INIT_REASONS) numprint=0;
+	}
+	BUGMSG2(D_INIT,"\n");
 
-	/* okay, now we have to find the shared memory area. */
-	BUGMSG(D_INIT,"starting memory probe, given %lXh\n",
-			dev->mem_start);
-	if (dev->mem_start)	/* value given - probe just that one */
+	if (!numshmems)
 	{
-		status=arcnet_memprobe(dev,(u_char *)dev->mem_start);
-		if (status) return status;
+		BUGMSG(D_INIT,"Stage 3: failed.  No ARCnet cards found.\n");
+		return -ENODEV;
 	}
-	else			/* no value given - probe everything */
+
+	/* Stage 4: something of a dummy, to report the shmems that are
+	 * still possible after stage 3.
+	 */
+	BUGMSG(D_INIT,"Stage 4: ");
+	numprint=0;
+	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
 	{
-		for (addr = &addrs[0]; *addr; addr++) {
-			status=arcnet_memprobe(dev,(u_char *)(*addr));
-			if (!status) break;
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 4: ");
+			numprint=1;
 		}
-		
-		if (status) return status;
+		BUGMSG2(D_INIT,"%lXh ",*shmem);
 	}
+	BUGMSG2(D_INIT,"\n");
+	
+
+	/* Stage 5: for any ports that have the correct status, can disable
+	 * the RESET flag, and (if no irq is given) generate an autoirq,
+	 * register an ARCnet device.
+	 *
+	 * Currently, we can only register one device per probe, so quit
+	 * after the first one is found.
+	 */
+	BUGMSG(D_INIT,"Stage 5: ");
+	numprint=0;
+	for (port = &ports[0]; port-ports<numports; port++)
+	{
+		numprint++;
+		if (numprint>8)
+		{
+			BUGMSG2(D_INIT,"\n");
+			BUGMSG(D_INIT,"Stage 5: ");
+			numprint=1;
+		}
+		BUGMSG2(D_INIT,"%Xh ",*port);
+		
+		ioaddr=*port;
+		status=inb(STATUS);
+		
+		if ((status & 0x9F)
+			!= (NORXflag|RECONflag|TXFREEflag|RESETflag))
+		{
+			BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status);
+			BUGMSG(D_INIT_REASONS,"Stage 5: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
+			continue;
+		}
+
+		outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
+		status=inb(STATUS);
+		if (status & RESETflag)
+		{
+			BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n",
+					status);
+			BUGMSG(D_INIT_REASONS,"Stage 5: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+			*port=ports[numports-1];
+			numports--;
+			port--;
+			continue;
+		}
 
-	/* now reserve the irq... */
-	{	
-		int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
-			"arcnet");
-		if (irqval)
+		/* skip this if an IRQ was given, because maybe we're on a
+		 * machine that locks during autoirq!
+		 */
+		if (!dev->irq)
+		{
+			/* if we do this, we're sure to get an IRQ since the
+			 * card has just reset and the NORXflag is on until
+			 * we tell it to start receiving.
+			 */
+			airqmask = probe_irq_on();
+			outb(NORXflag,INTMASK);
+			/*udelay(1);*/
+			outb(0,INTMASK);
+			airq = probe_irq_off(airqmask);
+	
+			if (airq<=0)
+			{
+				BUGMSG2(D_INIT_REASONS,"(airq=%d)\n",airq);
+				BUGMSG(D_INIT_REASONS,"Stage 5: ");
+				BUGLVL(D_INIT_REASONS) numprint=0;
+				*port=ports[numports-1];
+				numports--;
+				port--;
+				continue;
+			}
+		}
+		else
 		{
-			BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
-				dev->irq, irqval);
-			return -EIO;
+			airq=dev->irq;
 		}
 		
-		irq2dev_map[dev->irq]=dev;
+		BUGMSG2(D_INIT,"(%d,", airq);
+		
+		/* Everything seems okay.  But which shmem, if any, puts
+		 * back its signature byte when the card is reset?
+		 *
+		 * If there are multiple cards installed, there might be
+		 * multiple shmems still in the list.
+		 */
+#ifdef FAST_PROBE
+		if (numports>1 || numshmems>1)
+		{
+			inb(RESET);
+			JIFFER(RESETtime);
+		}
+		else
+		{
+			*(u_char *)(shmems[0]) = TESTvalue;
+		}
+#else
+		inb(RESET);
+		JIFFER(RESETtime);
+#endif
+
+
+		for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+		{
+			u_char *cptr;
+			cptr=(u_char *)(*shmem);
+			
+			if (*cptr == TESTvalue)	/* found one */
+			{
+				BUGMSG2(D_INIT,"%lXh)\n", *shmem);
+
+				/* register the card */
+				status=arcnet_found(dev,*port,airq,*shmem);
+
+				/* remove port and shmem from the lists */
+				*port=ports[numports-1];
+				numports--;
+				*shmem=shmems[numshmems-1];
+				numshmems--;
+				
+				return status;
+			}
+			else
+			{
+				BUGMSG2(D_INIT_REASONS,"%Xh-", *cptr);
+			}
+		}
+
+		BUGMSG2(D_INIT,"no matching shmem)\n");
+		BUGMSG(D_INIT_REASONS,"Stage 5: ");
+		BUGLVL(D_INIT_REASONS) numprint=0;
+		*port=ports[numports-1];
+		numports--;
+		port--;
 	}
-	 
-	/* Grab the region so we can find another board if autoIRQ fails. */
-	request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
+	BUGMSG(D_INIT_REASONS,"\n");
+
+	return -ENODEV;
+}
+
+/* Set up the struct device associated with this card.  Called after
+ * probing succeeds.
+ */
+int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
+{
+	int irqval;
+	u_char *first_mirror,*last_mirror;
+	struct arcnet_local *lp;
+	
+	/* reserve the I/O region */
+	request_region(port,ARCNET_TOTAL_SIZE,"arcnet");
+	dev->base_addr=port;
+
+	/* reserve the irq */
+	irqval = request_irq(airq,&arcnet_interrupt,0,"arcnet");
+	if (irqval)
+	{
+		BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
+			airq, irqval);
+		return -ENODEV;
+	}
+	irq2dev_map[airq]=dev;
+	dev->irq=airq;
+	
+	/* find the real shared memory start/end points, including mirrors */
 	
-	BUGMSG(D_NORMAL,"ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
-		dev->base_addr, dev->irq, dev->mem_start);
+	#define BUFFER_SIZE (512)
+	#define MIRROR_SIZE (BUFFER_SIZE*4)
+	
+	first_mirror=last_mirror=(u_char *)shmem;
+	while (*first_mirror==TESTvalue) first_mirror-=MIRROR_SIZE;
+	first_mirror+=MIRROR_SIZE;
+
+	while (*last_mirror==TESTvalue) last_mirror+=MIRROR_SIZE;
+	last_mirror-=MIRROR_SIZE;
 
-	/* Initialize the device structure. */
+	dev->mem_start=(u_long)first_mirror;
+	dev->mem_end=(u_long)last_mirror+MIRROR_SIZE-1;
+	dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
+	dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
+	 
+	/* Initialize the rest of the device structure. */
+	
 	dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
-	memset(dev->priv, 0, sizeof(struct arcnet_local));
+	memset(dev->priv,0,sizeof(struct arcnet_local));
 	lp=(struct arcnet_local *)(dev->priv);
-
+	
 	dev->open=arcnet_open;
 	dev->stop=arcnet_close;
 	dev->hard_start_xmit=arcnetA_send_packet;
@@ -697,261 +1072,87 @@
 	/* And now fill particular fields with arcnet values */
 	dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
 	dev->hard_header_len=sizeof(struct ClientData);
+	dev->hard_header=arcnetA_header;
+	dev->rebuild_header=arcnetA_rebuild_header;
+	lp->sequence=1;
+	lp->recbuf=0;
+
 	BUGMSG(D_DURING,"ClientData header size is %d.\n",
 		sizeof(struct ClientData));
 	BUGMSG(D_DURING,"HardHeader size is %d.\n",
 		sizeof(struct HardHeader));
 
-		/* since we strip EXTRA_CLIENTDATA bytes off before sending,
-		 * we let Linux add that many bytes to the packet data...
-		 */
-	
-	BUGMSG(D_INIT,"arcnet_probe: resetting card.\n");
-	arcnet_reset(dev);
-	BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
-			lp->stationid,lp->stationid);
+	/* get and check the station ID from offset 1 in shmem */
+	lp->stationid = first_mirror[1];
 	if (lp->stationid==0)
-		BUGMSG(D_NORMAL,"WARNING!  Station address 0 is reserved for broadcasts!\n");
-	if (lp->stationid==255)
-		BUGMSG(D_NORMAL,"WARNING!  Station address 255 may confuse DOS networking programs!\n");
+		BUGMSG(D_NORMAL,"WARNING!  Station address 0 is reserved "
+			"for broadcasts!\n");
+	else if (lp->stationid==255)
+		BUGMSG(D_NORMAL,"WARNING!  Station address FF may confuse "
+			"DOS networking programs!\n");
 	dev->dev_addr[0]=lp->stationid;
-	lp->sequence=1;
-	lp->recbuf=0;
 
-	dev->hard_header=arcnetA_header;
-	dev->rebuild_header=arcnetA_rebuild_header;
-	
+	BUGMSG(D_NORMAL,"ARCnet station %02Xh found at %03lXh, IRQ %d, "
+		"ShMem %lXh (%ld bytes).\n",
+		lp->stationid,
+		dev->base_addr,dev->irq,dev->mem_start,
+		dev->mem_end-dev->mem_start+1);
+		
 	return 0;
 }
 
 
-int arcnet_ioprobe(struct device *dev, short ioaddr)
+/* Do a hardware reset on the card, and set up necessary registers.
+ *
+ * This should be called as little as possible, because it disrupts the
+ * token on the network (causes a RECON) and requires a significant delay.
+ *
+ * However, it does make sure the card is in a defined state.
+ */
+int arcnet_reset(struct device *dev,int reset_delay)
 {
-	int airq;
-	unsigned long airqmask;
-
-	BUGMSG(D_INIT,"probing address %Xh\n",ioaddr);
-	BUGMSG(D_INIT," status1=%Xh\n",inb(STATUS));
-
-		
-	/* very simple - all we have to do is reset the card, and if there's
-	 * no irq, it's not an ARCnet.  We can also kill two birds with
-	 * one stone because we detect the IRQ at the same time :)
-	 *
-	 * BUT: some newer cards don't seem to IRQ upon reset, or worse,
-	 * don't reset when BASE+0x08 is read.  This code is no longer
-	 * so simple, and in fact quite dangerous.  It should be redesigned.
-	 */
-	 
-#if 0
-	/* reset the card by reading the reset port */
-	inb(RESET);
-	JIFFER(RESETtime);
-#endif
-
-	/* if status port is FF, there's certainly no arcnet... give up. */
-	if (inb(STATUS)==0xFF)
-	{
-		BUGMSG(D_INIT," probe failed.  Status port empty.\n");
-		return -ENODEV;
-	}
+	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
+	short ioaddr=dev->base_addr;
+	int delayval,recbuf=lp->recbuf;
+	u_char *cardmem;
+	
+	/* no IRQ's, please! */
+	lp->intmask=0;
+	SETMASK;
+	
+	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
+			dev->name,inb(STATUS));
 
-#if 0
-	/* we'll try to be reasonably sure it's an arcnet by making sure
-	 * the value of the COMMAND port changes automatically once in a
-	 * while.  I have no idea what those values ARE, but at least
-	 * they work.
-	 */
+	if (reset_delay)
 	{
-		int initval,curval;
-		
-		curval=initval=inb(COMMAND);
-		delayval=jiffies+5;
-		while (delayval>=jiffies && curval==initval)
-			curval=inb(COMMAND);
-			
-		if (curval==initval)
-		{
-			BUGLVL(D_INIT," probe failed.  never-changing command port (%02Xh).\n",
-				initval);
-			return -ENODEV;
-		}
+		/* reset the card */
+		inb(RESET);
+		JIFFER(RESETtime);
 	}
-#endif
 
-	BUGMSG(D_INIT," status2=%Xh\n",inb(STATUS));
+	outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
+	outb(CFLAGScmd|CONFIGclear,COMMAND);
 
-	/* now we turn the reset bit off so we can IRQ next reset... */
-	outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-	if (inb(STATUS) & RESETflag) /* reset flag STILL on */
+	/* verify that the ARCnet signature byte is present */
+	cardmem = (u_char *) dev->mem_start;
+	if (cardmem[0] != TESTvalue)
 	{
-		BUGMSG(D_INIT," probe failed.  eternal reset flag1...(status=%Xh)\n",
-				inb(STATUS));
-		return -ENODEV;
+		BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
+		return 1;
 	}
-
-	outb(NORXcmd,COMMAND);
-	outb(0,INTMASK);
-	udelay(1);
-
-	/* set up automatic IRQ detection */
-	airqmask = probe_irq_on();
-	BUGMSG(D_INIT," airqmask=%lXh\n",airqmask);
-
-	/* if we do this, we're sure to get an IRQ since the card
-	 * has just reset and the NORXflag is on until we tell it to
-	 * start receiving.
-	 */
-	outb(NORXflag,INTMASK);
-	udelay(1);
-	outb(0,INTMASK);
-
-	/* and turn the reset flag back off.  On some systems, we NEED to do
-	 * this before we re-enable the IRQ!
-	 */
-	outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-
-	/* get autoirq results */
-	airq = probe_irq_off(airqmask);
-
-	if (airq>0)
-	{
-		BUGMSG(D_INIT," autoirq is %d\n", airq);
-	}
-	else if (airq<0)
-	{
-		BUGMSG(D_INIT," autoirq MAY be %d (please send mail to Avery)\n",
-			-airq);
-		airq=0;
-	}
-
-	/* if there was no autoirq AND the user hasn't set any defaults,
-	 * give up.
-	 */
-	if (!airq && !(dev->base_addr && dev->irq))
-	{
-		BUGMSG(D_INIT," probe failed.  no autoirq...\n");
-		return -ENODEV;
-	}
-
-	/* otherwise we probably have a card.  Let's make sure. */
-	
-#if 0
-	if (inb(STATUS) & RESETflag) /* reset flag on */
-	{
-		/* now we turn the reset bit off */
-		outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-	}
-#endif
-	
-	if (inb(STATUS) & RESETflag) /* reset flag STILL on */
-	{
-		BUGMSG(D_INIT," probe failed.  eternal reset flag...(status=%Xh)\n",
-				inb(STATUS));
-		return -ENODEV;
-	}
-	
-	/* okay, we've got a real, live ARCnet on our hands.
-	 * I hope.
-	 */
-	if (!dev->base_addr) dev->base_addr=ioaddr;
-	
-	if (dev->irq < 2)		/* "Auto-IRQ" */
-	{
-		/* we already did the autoirq above, so store the value */
-		dev->irq=airq;
-	}
-	else if (dev->irq == 2)
-	{
-		BUGMSG(D_NORMAL,"IRQ2 == IRQ9, don't worry.\n");
-		dev->irq = 9;
-	}
-
-	BUGMSG(D_INIT,"irq and base address seem okay. (%lXh, IRQ %d)\n",
-			dev->base_addr,dev->irq);
-	return 0;
-}
-
-
-/* A memory probe that is called after the card is reset.
- * It checks for the official TESTvalue in byte 0 and makes sure the buffer
- * has certain characteristics of an ARCnet.
- */
-int arcnet_memprobe(struct device *dev,u_char *addr)
-{
-	BUGMSG(D_INIT,"probing memory at %lXh\n",(u_long)addr);
-		
-	dev->mem_start=0;
-
-	/* ARCnet memory byte 0 is TESTvalue */
-	if (addr[0]!=TESTvalue)
-	{
-		BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not %Xh)\n",
-				(unsigned long)addr,addr[0],TESTvalue);
-		return -ENODEV;
-	}
-	
-	/* now verify the shared memory writability */
-	addr[0]=0x42;
-	if (addr[0]!=0x42)
-	{
-		BUGMSG(D_INIT," probe failed.  addr=%lXh, addr[0]=%Xh (not 42h)\n",
-				(unsigned long)addr,addr[0]);
-	 	return -ENODEV;
-	}
-
-	/* got it!  fill in dev */
-	dev->mem_start=(unsigned long)addr;
-	dev->mem_end=dev->mem_start+512*4-1;
-	dev->rmem_start=dev->mem_start+512*0;
-	dev->rmem_end=dev->mem_start+512*2-1;
-
-	return 0;
-}
-
-
-/* Do a hardware reset on the card.
- */
-int arcnet_reset(struct device *dev)
-{
-	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	short ioaddr=dev->base_addr;
-	int delayval,recbuf=lp->recbuf;
-	u_char *cardmem;
-	
-	lp->intmask=0;
-	SETMASK;		/* no IRQ's, please! */
-	
-	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
-			dev->name,inb(STATUS));
-
-	inb(RESET);		/* Reset by reading this port */
-	JIFFER(RESETtime);
-
-	outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
-	outb(CFLAGScmd|CONFIGclear,COMMAND);
-
-	/* after a reset, the first byte of shared mem is TESTvalue and the
-	 * second byte is our 8-bit ARCnet address.
-	 */
-	cardmem = (u_char *) dev->mem_start;
-	if (cardmem[0] != TESTvalue)
-	{
-		BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n");
-		return 1;
-	}
-	lp->stationid=cardmem[1];  /* save address for later use */
-	
-	/* clear out status variables */
-	recbuf=lp->recbuf=0;
-	lp->txbuf=2;
+	
+	/* clear out status variables */
+	recbuf=lp->recbuf=0;
+	lp->txbuf=2;
 
 	/* enable extended (512-byte) packets */
 	outb(CONFIGcmd|EXTconf,COMMAND);
 	
+#ifndef SLOW_XMIT_COPY
 	/* clean out all the memory to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)dev->mem_start,0x42,2048);
+#endif
 	
 	/* and enable receive of our first packet to the first buffer */
 	EnableReceiver();
@@ -968,8 +1169,7 @@
 }
 
 
-/*
- * Setup a struct device for ARCnet.  This should really be in net_init.c
+/* Setup a struct device for ARCnet.  This should really be in net_init.c
  * but since there are three different ARCnet devices ANYWAY... <gargle>
  *
  * Actually, the whole idea of having all this kernel-dependent stuff (ie.
@@ -977,17 +1177,18 @@
  *
  * Intelligent defaults?!  Nah.
  */
-
 void arcnet_setup(struct device *dev)
 {
 	int i;
 	for (i=0; i<DEV_NUMBUFFS; i++)
 		skb_queue_head_init(&dev->buffs[i]);
 
-	dev->broadcast[0]	= 0x00;	/* broadcasts on ARCnet are address 0 */
+	dev->broadcast[0]	= 0x00;	/* for us, broadcasts are address 0 */
 	dev->addr_len		= 1;
 	dev->type		= ARPHRD_ARCNET;
-	dev->tx_queue_len 	= 30;	/* Fairly long queue, arcnet is quite speedy */
+	dev->tx_queue_len	= 30;	/* fairly long queue - arcnet is
+					 * quite speedy.
+					 */
 
 	/* New-style flags. */
 	dev->flags		= IFF_BROADCAST;
@@ -999,49 +1200,6 @@
 }
 
 
-/* Initialize the arc0e device.
- */
-static int arcnetE_init(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	ether_setup(dev); /* we're emulating ether here, not ARCnet */
-	dev->dev_addr[0]=0;
-	dev->dev_addr[5]=lp->stationid;
-	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1;
-	dev->open=NULL;
-	dev->stop=NULL;
-	dev->hard_start_xmit=arcnetE_send_packet;
-
-	BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
-			
-	return 0;
-}
-
-/* Initialize the arc0s device.
- */
-static int arcnetS_init(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	arcnet_setup(dev);
-       
-	/* And now fill particular fields with arcnet values */
-	dev->dev_addr[0]=lp->stationid;
-	dev->hard_header_len=sizeof(struct S_ClientData);
-	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len
-		+ S_EXTRA_CLIENTDATA;
-	dev->open=NULL;
-	dev->stop=NULL;
-	dev->hard_start_xmit=arcnetS_send_packet;
-	dev->hard_header=arcnetS_header;
-	dev->rebuild_header=arcnetS_rebuild_header;
-	BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
-
-	return 0;
-}
-
-
 /****************************************************************************
  *                                                                          *
  * Open and close the driver                                                *
@@ -1069,13 +1227,20 @@
 		dev->metric=1;
 	}
 
-	BUGLVL(D_EXTRA) printk(version);
-
-	BUGMSG(D_EXTRA,"arcnet_open: resetting card.\n");
+	BUGMSG(D_INIT,"arcnet_open: resetting card.\n");
 	
-	/* try to reset - twice if it fails the first time */
-	if (arcnet_reset(dev) && arcnet_reset(dev))
+#ifdef FAST_IFCONFIG
+	/* try to put the card in a defined state - if it fails the first
+	 * time, actually reset it.
+	 */
+	if (arcnet_reset(dev,0) && arcnet_reset(dev,1))
+		return -ENODEV;
+#else
+	/* reset the card twice in case something goes wrong the first time.
+	 */
+	if (arcnet_reset(dev,1) && arcnet_reset(dev,1))
 		return -ENODEV;
+#endif
 	
 	dev->tbusy=0;
 	dev->interrupt=0;
@@ -1085,7 +1250,8 @@
 	/* The RFC1201 driver is the default - just store */
 	lp->adev=dev;
 	BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n");
-	
+
+#ifdef CONFIG_ARCNET_ETH	
 	/* Initialize the ethernet-encap protocol driver */
 	lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
 	if (lp->edev == NULL)
@@ -1100,7 +1266,11 @@
 	sprintf(lp->edev->name,"%se",dev->name);
 	lp->edev->init=arcnetE_init;
 	register_netdev(lp->edev);
+#else
+	BUGMSG(D_EXTRA,"Ethernet-Encap protocol not available (disabled).\n");
+#endif
 
+#ifdef CONFIG_ARCNET_1051
 	/* Initialize the RFC1051-encap protocol driver */
 	lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
 	memcpy(lp->sdev,dev,sizeof(struct device));
@@ -1108,6 +1278,9 @@
 	sprintf(lp->sdev->name,"%ss",dev->name);
 	lp->sdev->init=arcnetS_init;
 	register_netdev(lp->sdev);
+#else
+	BUGMSG(D_EXTRA,"RFC1051 protocol not available (disabled).\n");
+#endif
 
 	/* we're started */
 	START=1;
@@ -1140,11 +1313,15 @@
 	TBUSY=1;
 	START=0;
 
-	/* Flush TX and disable RX */
+	/* Shut down the card */
+#ifdef FAST_IFCONFIG
+	inb(RESET);	/* reset IRQ won't run if START=0 */
+#else
 	lp->intmask=0;
 	SETMASK;	/* no IRQ's (except RESET, of course) */
 	outb(NOTXcmd,COMMAND);  /* stop transmit */
 	outb(NORXcmd,COMMAND);	/* disable receive */
+#endif
 
 	/* reset more flags */
 	INTERRUPT=0;
@@ -1152,6 +1329,7 @@
 	/* do NOT free lp->adev!!  It's static! */
 	lp->adev=NULL;
 	
+#ifdef CONFIG_ARCNET_ETH
 	/* free the ethernet-encap protocol device */
 	lp->edev->priv=NULL;
 	dev_close(lp->edev);
@@ -1159,7 +1337,9 @@
 	kfree(lp->edev->name);
 	kfree(lp->edev);
 	lp->edev=NULL;
+#endif
 
+#ifdef CONFIG_ARCNET_1051
 	/* free the RFC1051-encap protocol device */
 	lp->sdev->priv=NULL;
 	dev_close(lp->sdev);
@@ -1167,6 +1347,7 @@
 	kfree(lp->sdev->name);
 	kfree(lp->sdev);
 	lp->sdev=NULL;
+#endif
 
 	/* Update the statistics here. (not necessary in ARCnet) */
 
@@ -1229,16 +1410,14 @@
 		
 		if (status&TXFREEflag)	/* transmit _DID_ finish */
 		{
-			BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, inTXh=%d, ticks=%d, mask=%Xh)\n",
-					status,lp->in_txhandler,tickssofar,
-					lp->intmask);
+			BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%d)\n",
+					status,tickssofar,lp->intmask,lp->lasttrans_dest);
 			lp->stats.tx_errors++;
 		}
 		else
 		{
-			BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTXh=%d, tickssofar=%d, intmask=%Xh)\n",
-					status,lp->in_txhandler,tickssofar,
-					lp->intmask);
+			BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%d)\n",
+					status,tickssofar,lp->intmask,lp->lasttrans_dest);
 			lp->stats.tx_errors++;
 			lp->stats.tx_aborted_errors++;
 
@@ -1418,289 +1597,99 @@
 }
 
 
-/* Called by the kernel in order to transmit an ethernet-type packet.
+/* After an RFC1201 split packet has been set up, this function calls
+ * arcnetAS_prepare_tx to load the next segment into the card.  This function
+ * does NOT automatically call arcnet_go_tx.
  */
-static int
-arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
+static void arcnetA_continue_tx(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad;
-	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
-	u_char *arcsoft,daddr;
-	short offset,length=skb->len+1;
-
-	lp->intx++;
+	int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
+	struct Outgoing *out=&(lp->outgoing);
 	
-	bad=arcnet_send_packet_bad(skb,dev);
-	if (bad)
+	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
+		inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
+	
+	if (lp->txready)
 	{
-		lp->intx--;
-		return bad;
+		BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
+		return;
 	}
-
-	TBUSY=1;
-		
-	if (length>XMTU)
+	
+	if (out->segnum>=out->numsegs)
 	{
-		BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
-			length);
-		BUGMSG(D_NORMAL,"transmit aborted.\n");
-
-		dev_kfree_skb(skb,FREE_WRITE);
-		lp->intx--;
-		return 0;
+		BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
+			out->segnum+1,out->numsegs);
 	}
+
+	if (!out->segnum)	/* first packet */
+		out->hdr->split_flag=((out->numsegs-2)<<1)+1;
+	else
+		out->hdr->split_flag=out->segnum<<1;
+
+	out->seglen=maxsegsize;
+	if (out->seglen>out->dataleft) out->seglen=out->dataleft;
+			
+	BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
+		out->segnum+1,out->seglen,out->numsegs,
+		out->length,out->hdr->split_flag);
+
+	arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
+		sizeof(struct ClientData)-EXTRA_CLIENTDATA,
+		out->data,out->seglen,out->hdr->daddr,1);
 		
-	BUGMSG(D_DURING,"starting tx sequence...\n");
+	out->dataleft-=out->seglen;
+	out->data+=out->seglen;
+	out->segnum++;
+}
 
-	lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
 
+/* Given an skb, copy a packet into the ARCnet buffers for later transmission
+ * by arcnet_go_tx.
+ */
+static void
+arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
+		char *data,int length,int daddr,int exceptA)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	struct ClientData *arcsoft;
+	union ArcPacket *arcpacket = 
+		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+	int offset;
+	
+#ifdef SLOW_XMIT_COPY
+	char *iptr,*iend,*optr;
+#endif
+	
+	lp->txbuf=lp->txbuf^1;	/* XOR with 1 to alternate between 2 and 3 */
+	
+	length+=hdrlen;
+
+	BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
+			hdr,length,data);
+
+#ifndef SLOW_XMIT_COPY
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+#endif
 
-	/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
-	if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
-		daddr=arcpacket->hardheader.destination=0;
-	else
-		daddr=arcpacket->hardheader.destination=
-			((struct ethhdr*)(skb->data))->h_dest[5];
+	arcpacket->hardheader.destination=daddr;
 
 	/* load packet into shared memory */
-	offset=512-length;
-	if (length>MTU)		/* long/exception packet */
+	if (length<=MTU)	/* Normal (256-byte) Packet */
 	{
-		if (length<MinTU) offset-=3;
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset;
+		arcpacket->hardheader.offset1=offset=256-length;
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset]);
 	}
-	else			/* short packet */
+	else if (length>=MinTU)	/* Extended (512-byte) Packet */
 	{
-		arcpacket->hardheader.offset1=(offset-=256);
-	}
-	
-	BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
-			length,offset,arcpacket->hardheader.offset1,
-			arcpacket->hardheader.offset2);
-	
-	arcsoft=&arcpacket->raw[offset];
-	arcsoft[0]=ARC_P_ETHER;
-	arcsoft++;
-		
-	/* copy the packet into ARCnet shmem
-	 *  - the first bytes of ClientData header are skipped
-	 */
-	BUGMSG(D_DURING,"ready to memcpy\n");
-	
-	memcpy(arcsoft,skb->data,skb->len);
-		
-	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
-			daddr,length);
-				
-	BUGLVL(D_TX)
-	{
-		int countx,county;
-			
-		printk("%6s: packet dump [tx] follows:",dev->name);
-
- 		for (county=0; county<16+(length>=240)*16; county++)
-		{
-			printk("\n[%04X] ",county*16);
-			for (countx=0; countx<16; countx++)
-				printk("%02X ",
-					arcpacket->raw[county*16+countx]);
-		}
-		
-		printk("\n");
-	}
-
-#ifdef VERIFY_ACK
-	lp->lastload_dest=daddr;
-#endif
-	lp->txready=lp->txbuf;	/* packet is ready for sending */
-
-	dev_kfree_skb(skb,FREE_WRITE);
-
-	if (arcnet_go_tx(dev,1))
-	{
-		/* inform upper layers */
-		TBUSY=0;
-		mark_bh(NET_BH);
-	}
-
-	dev->trans_start=jiffies;
-	lp->intx--;
-	
-	/* make sure we didn't ignore a TX IRQ while we were in here */
-	lp->intmask |= TXFREEflag;
-	SETMASK;
-
-	return 0;
-}
-
-
-/* Called by the kernel in order to transmit an RFC1051-type packet.
- */
-static int
-arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad,length;
-	struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
-
-	lp->intx++;
-	
-	bad=arcnet_send_packet_bad(skb,dev);
-	if (bad)
-	{
-		lp->intx--;
-		return bad;
-	}
-	
-	TBUSY=1;
-
-	length = 1 < skb->len ? skb->len : 1;
-
-	BUGLVL(D_SKB)
-	{
-		short i;
-		for(i=0; i<skb->len; i++)
-		{
-			if (i%16 == 0) printk("\n[%04hX] ",i);
-			printk("%02hX ",((unsigned char*)skb->data)[i]);
-		}
-		printk("\n");
-	}
-
-	/* fits in one packet? */
-	if (length-S_EXTRA_CLIENTDATA<=XMTU)
-	{
-		arcnetAS_prepare_tx(dev,
-			skb->data+S_EXTRA_CLIENTDATA,
-			sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
-			skb->data+sizeof(struct S_ClientData),
-			length-sizeof(struct S_ClientData),
-			hdr->daddr,0);
-
-		/* done right away */
-		dev_kfree_skb(skb,FREE_WRITE);
-				
-		if (arcnet_go_tx(dev,1))
-		{
-			/* inform upper layers */
-			TBUSY=0;
-			mark_bh(NET_BH);
-		}
-	}
-	else			/* too big for one - not accepted */
-	{
-		BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
-			length);
-		dev_kfree_skb(skb,FREE_WRITE);
-		lp->stats.tx_dropped++;
-		TBUSY=0;
-		mark_bh(NET_BH);	
-	}
-
-	dev->trans_start=jiffies;
-	lp->intx--;
-
-	/* make sure we didn't ignore a TX IRQ while we were in here */
-	lp->intmask |= TXFREEflag;
-	SETMASK;
-
-	return 0;
-}
-
-
-/* After an RFC1201 split packet has been set up, this function calls
- * arcnetAS_prepare_tx to load the next segment into the card.  This function
- * does NOT automatically call arcnet_go_tx.
- */
-static void arcnetA_continue_tx(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
-	struct Outgoing *out=&(lp->outgoing);
-	
-	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
-		inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
-	
-	if (lp->txready)
-	{
-		BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
-		return;
-	}
-	
-	if (out->segnum>=out->numsegs)
-	{
-		BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
-			out->segnum+1,out->numsegs);
-	}
-
-	if (!out->segnum)	/* first packet */
-		out->hdr->split_flag=((out->numsegs-2)<<1)+1;
-	else
-		out->hdr->split_flag=out->segnum<<1;
-
-	out->seglen=maxsegsize;
-	if (out->seglen>out->dataleft) out->seglen=out->dataleft;
-			
-	BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
-		out->segnum+1,out->seglen,out->numsegs,
-		out->length,out->hdr->split_flag);
-
-	arcnetAS_prepare_tx(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
-		sizeof(struct ClientData)-EXTRA_CLIENTDATA,
-		out->data,out->seglen,out->hdr->daddr,1);
-		
-	out->dataleft-=out->seglen;
-	out->data+=out->seglen;
-	out->segnum++;
-}
-
-
-/* Given an skb, copy a packet into the ARCnet buffers for later transmission
- * by arcnet_go_tx.
- */
-static void
-arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
-		char *data,int length,int daddr,int exceptA)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct ClientData *arcsoft;
-	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
-	int offset;
-	
-	lp->txbuf=lp->txbuf^1;	/* XOR with 1 to alternate between 2 and 3 */
-	
-	length+=hdrlen;
-
-	BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
-			hdr,length,data);
-
-	/* clean out the page to make debugging make more sense :) */
-	BUGLVL(D_DURING)
-		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
-
-	arcpacket->hardheader.destination=daddr;
-
-	/* load packet into shared memory */
-	if (length<=MTU)	/* Normal (256-byte) Packet */
-	{
-		arcpacket->hardheader.offset1=offset=256-length;
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset]);
-	}
-	else if (length>=MinTU)	/* Extended (512-byte) Packet */
-	{
-		arcpacket->hardheader.offset1=0;
-		arcpacket->hardheader.offset2=offset=512-length;
-		
-		arcsoft=(struct ClientData *)
-			(&arcpacket->raw[offset]);
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset=512-length;
+		
+		arcsoft=(struct ClientData *)
+			(&arcpacket->raw[offset]);
 	}
 	else if (exceptA)		/* RFC1201 Exception Packet */
 	{
@@ -1735,8 +1724,17 @@
 	 */
 	memcpy((u_char*)arcsoft,
 		(u_char*)hdr,hdrlen);
+#ifdef SLOW_XMIT_COPY
+	for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcsoft+hdrlen;
+		iptr<iend; iptr++,optr++)
+	{
+		*optr=*iptr;
+		/*udelay(5);*/
+	}
+#else
 	memcpy((u_char*)arcsoft+hdrlen,
 		data,length-hdrlen);
+#endif
 		
 	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
 			daddr,length);
@@ -1758,9 +1756,7 @@
 		printk("\n");
 	}
 
-#ifdef VERIFY_ACK
 	lp->lastload_dest=daddr;
-#endif
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
 }
 
@@ -1792,7 +1788,7 @@
 		}
 		return 0;
 	}
-
+	
 	/* start sending */
 	outb(TXcmd|(lp->txready<<3),COMMAND);
 
@@ -1800,10 +1796,8 @@
 	lp->txready=0;
 	lp->sending++;
 
-#ifdef VERIFY_ACK	
 	lp->lasttrans_dest=lp->lastload_dest;
 	lp->lastload_dest=0;
-#endif
 
 	lp->intmask |= TXFREEflag;
 
@@ -1829,18 +1823,29 @@
 arcnet_interrupt(int irq,struct pt_regs *regs)
 {
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	int ioaddr;
 	
-	BUGMSG(D_DURING,"in arcnet_interrupt\n");
-
 	if (dev==NULL)
 	{
-		BUGLVL(D_EXTRA)
+		BUGLVL(D_DURING)
 			printk("arcnet: irq %d for unknown device.\n", irq);
 		return;
 	}
 	
-	if (!dev->start) return;
+	BUGMSG(D_DURING,"in arcnet_interrupt\n");
 
+	/* RESET flag was enabled - if !dev->start, we must clear it right
+	 * away (but nothing else) since inthandler() is never called.
+	 */
+	ioaddr=dev->base_addr;
+	if (!dev->start)
+	{
+		if (inb(STATUS) & RESETflag)
+			outb(CFLAGScmd|RESETclear, COMMAND);
+		return;
+	}
+
+	/* Call the "real" interrupt handler. */
 	arcnet_inthandler(dev);
 }
 
@@ -1871,93 +1876,27 @@
 		status = inb(STATUS);
 		didsomething=0;
 	
+
 		/* RESET flag was enabled - card is resetting and if RX
 		 * is disabled, it's NOT because we just got a packet.
 		 */
 		if (status & RESETflag)
 		{
-			outb(CFLAGScmd|RESETclear,COMMAND);
-			BUGMSG(D_INIT,"reset irq (status=%Xh)\n",
+			BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
 					status);
+			arcnet_reset(dev,0);
+			
+			/* all other flag values are just garbage */
+			break;
 		}
-#ifdef DETECT_RECONFIGS
-		if (status & (lp->intmask) & RECONflag)
+		
+		
+		/* RX is inhibited - we must have received something. */
+		if (status & lp->intmask & NORXflag)
 		{
-			outb(CFLAGScmd|CONFIGclear,COMMAND);
-			lp->stats.tx_carrier_errors++;
-			
-			#ifdef SHOW_RECONFIGS
-			BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
-					status);
-			#endif /* SHOW_RECONFIGS */
-			
-			#ifdef RECON_THRESHOLD
-			/* is the RECON info empty or old? */
-			if (!lp->first_recon || !lp->last_recon || 
-				jiffies-lp->last_recon > HZ*10)
-			{
-				if (lp->network_down)
-					BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
-				lp->first_recon=lp->last_recon=jiffies;
-				lp->num_recons=lp->network_down=0;
-				
-				BUGMSG(D_DURING,"recon: clearing counters.\n");
-			}
-			else /* add to current RECON counter */
-			{
-				lp->last_recon=jiffies;
-				lp->num_recons++;
-				
-				BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
-					lp->num_recons,
-					(lp->last_recon-lp->first_recon)/HZ,
-					lp->network_down);
-
-				/* if network is marked up;
-				 * and first_recon and last_recon are 60+ sec
-				 *   apart;
-				 * and the average no. of recons counted is
-				 *   > RECON_THRESHOLD/min;
-				 * then print a warning message.
-				 */
-				if (!lp->network_down
-				    && (lp->last_recon-lp->first_recon)<=HZ*60
-				    && lp->num_recons >= RECON_THRESHOLD)
-				{
-					lp->network_down=1;
-					BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
-				}
-				else if (!lp->network_down
-				    && lp->last_recon-lp->first_recon > HZ*60)
-				{
-					/* reset counters if we've gone for
-					 * over a minute.
-					 */
-					lp->first_recon=lp->last_recon;
-					lp->num_recons=1;
-				}
-			}
-			#endif
-		}
-		#ifdef RECON_THRESHOLD
-		else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
-		{
-			if (lp->network_down)
-				BUGMSG(D_NORMAL,"cabling restored?\n");
-			lp->first_recon=lp->last_recon=0;
-			lp->num_recons=lp->network_down=0;
-			
-			BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
-		}
-		#endif
-#endif /* DETECT_RECONFIGS */
-
-		/* RX is inhibited - we must have received something. */
-		if (status & lp->intmask & NORXflag)
-		{
-			int recbuf=lp->recbuf=!lp->recbuf;
-
-			BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
+			int recbuf=lp->recbuf=!lp->recbuf;
+
+			BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
 					status);
 
 			/* enable receive of our next packet */
@@ -1983,12 +1922,11 @@
 			BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
 					status,out->numsegs,out->segnum,out->skb);
 					
-#ifdef VERIFY_ACK
 			if (was_sending && !(status&TXACKflag))
 			{
 				if (lp->lasttrans_dest != 0)
 				{
-					BUGMSG(D_NORMAL,"transmit was not acknowledged! (status=%Xh, dest=%d)\n",
+					BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%d)\n",
 						status,lp->lasttrans_dest);
 					lp->stats.tx_errors++;
 					lp->stats.tx_carrier_errors++;
@@ -2000,7 +1938,7 @@
 							lp->lasttrans_dest);
 				}
 			}
-#endif
+
 			/* send packet if there is one */
 			arcnet_go_tx(dev,0);
 			didsomething++;
@@ -2063,6 +2001,78 @@
 			arcnet_go_tx(dev,0);
 			didsomething++;
 		}
+
+#ifdef DETECT_RECONFIGS
+		if (status & (lp->intmask) & RECONflag)
+		{
+			outb(CFLAGScmd|CONFIGclear,COMMAND);
+			lp->stats.tx_carrier_errors++;
+			
+			#ifdef SHOW_RECONFIGS
+			BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
+					status);
+			#endif /* SHOW_RECONFIGS */
+			
+			#ifdef RECON_THRESHOLD
+			/* is the RECON info empty or old? */
+			if (!lp->first_recon || !lp->last_recon || 
+				jiffies-lp->last_recon > HZ*10)
+			{
+				if (lp->network_down)
+					BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
+				lp->first_recon=lp->last_recon=jiffies;
+				lp->num_recons=lp->network_down=0;
+				
+				BUGMSG(D_DURING,"recon: clearing counters.\n");
+			}
+			else /* add to current RECON counter */
+			{
+				lp->last_recon=jiffies;
+				lp->num_recons++;
+				
+				BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
+					lp->num_recons,
+					(lp->last_recon-lp->first_recon)/HZ,
+					lp->network_down);
+
+				/* if network is marked up;
+				 * and first_recon and last_recon are 60+ sec
+				 *   apart;
+				 * and the average no. of recons counted is
+				 *   > RECON_THRESHOLD/min;
+				 * then print a warning message.
+				 */
+				if (!lp->network_down
+				    && (lp->last_recon-lp->first_recon)<=HZ*60
+				    && lp->num_recons >= RECON_THRESHOLD)
+				{
+					lp->network_down=1;
+					BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
+				}
+				else if (!lp->network_down
+				    && lp->last_recon-lp->first_recon > HZ*60)
+				{
+					/* reset counters if we've gone for
+					 * over a minute.
+					 */
+					lp->first_recon=lp->last_recon;
+					lp->num_recons=1;
+				}
+			}
+			#endif
+		}
+		#ifdef RECON_THRESHOLD
+		else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
+		{
+			if (lp->network_down)
+				BUGMSG(D_NORMAL,"cabling restored?\n");
+			lp->first_recon=lp->last_recon=0;
+			lp->num_recons=lp->network_down=0;
+			
+			BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
+		}
+		#endif
+#endif /* DETECT_RECONFIGS */
 	} while (--boguscount && didsomething);
 
 	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
@@ -2138,13 +2148,17 @@
 	case ARC_P_NOVELL_EC:
 		arcnetA_rx(lp->adev,arcsoft,length,saddr,daddr);
 		break;
+#ifdef CONFIG_ARCNET_ETH
 	case ARC_P_ETHER:
 		arcnetE_rx(lp->edev,arcsoft,length,saddr,daddr);
-		break;		
+		break;
+#endif
+#ifdef CONFIG_ARCNET_1051
 	case ARC_P_IP_RFC1051:
 	case ARC_P_ARP_RFC1051:
 		arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
 		break;
+#endif
 	case ARC_P_LANSOFT: /* don't understand.  fall through. */
 	default:
 		BUGMSG(D_NORMAL,"received unknown protocol %d (%Xh) from station %d.\n",
@@ -2172,9 +2186,11 @@
        	}
 
 
+#ifndef SLOW_XMIT_COPY
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
 		memset((void *)arcpacket->raw,0x42,512);
+#endif
 
 
 	/* If any worth-while packets have been received, a mark_bh(NET_BH)
@@ -2328,7 +2344,7 @@
 
 		if (in->skb && in->sequence!=arcsoft->sequence)
 		{
-			BUGMSG(D_NORMAL,"wrong seq number, aborting assembly (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
+			BUGMSG(D_NORMAL,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
 				saddr,in->sequence,arcsoft->sequence,
 				arcsoft->split_flag);
 	        	kfree_skb(in->skb,FREE_WRITE);
@@ -2478,49 +2494,510 @@
 }
 
 
-/* Packet receiver for non-standard ethernet-style packets
+
+
+/****************************************************************************
+ *                                                                          *
+ * Miscellaneous routines                                                   *
+ *                                                                          *
+ ****************************************************************************/
+
+
+/* Get the current statistics.	This may be called with the card open or
+ * closed.
  */
-static void
-arcnetE_rx(struct device *dev,u_char *arcsoft,
-	int length,u_char saddr, u_char daddr)
+
+static struct enet_statistics *
+arcnet_get_stats(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	struct sk_buff *skb;
-	
-	BUGMSG(D_DURING,"it's an ethernet-encap packet (length=%d)\n",
+
+	return &lp->stats;
+}
+
+#if 0
+/* Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+ *			best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev)
+{
+#if 0	  /* no promiscuous mode at all on most ARCnet models */
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+
+	short ioaddr = dev->base_addr;
+	if (num_addrs) {
+		outw(69, ioaddr);		/* Enable promiscuous mode */
+	} else
+		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
+#endif
+}
+#endif
+
+/* Create the ARCnet ClientData header for an arbitrary protocol layer
+ *
+ * saddr=NULL	means use device source address (always will anyway)
+ * daddr=NULL	means leave destination address (eg unresolved arp)
+ */
+int arcnetA_header(struct sk_buff *skb,struct device *dev,
+		unsigned short type,void *daddr,void *saddr,unsigned len)
+{
+	struct ClientData *head = (struct ClientData *)
+		skb_push(skb,dev->hard_header_len);
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+
+	BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
+			saddr ? *(u_char*)saddr : -1,
+			daddr ? *(u_char*)daddr : -1,
+			type,type,len);
+
+	/* set the protocol ID according to RFC1201 */
+	switch(type)
+	{
+	case ETH_P_IP:
+		head->protocol_id=ARC_P_IP;
+		break;
+	case ETH_P_ARP:
+		head->protocol_id=ARC_P_ARP;
+		break;
+	case ETH_P_RARP:
+		head->protocol_id=ARC_P_RARP;
+		break;
+	case ETH_P_IPX:
+	case ETH_P_802_3:
+	case ETH_P_802_2:
+		head->protocol_id=ARC_P_IPX;
+		break;
+	case ETH_P_ATALK:
+		head->protocol_id=ARC_P_ATALK;
+		break;
+	default:
+		BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
+			type,type);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+		return 0;
+	}	
+
+	/*
+	 * Set the source hardware address.
+	 *
+	 * This is pretty pointless for most purposes, but it can help
+	 * in debugging.  saddr is stored in the ClientData header and
+	 * removed before sending the packet (since ARCnet does not allow
+	 * us to change the source address in the actual packet sent)
+	 */
+	if(saddr)
+		head->saddr=((u_char*)saddr)[0];
+	else
+		head->saddr=((u_char*)(dev->dev_addr))[0];
+
+	head->split_flag=0;	/* split packets are done elsewhere */
+	head->sequence=0;	/* so are sequence numbers */
+
+	/* supposedly if daddr is NULL, we should ignore it... */
+	if(daddr)
+	{
+		head->daddr=((u_char*)daddr)[0];
+		return dev->hard_header_len;
+	}
+	else
+		head->daddr=0;	/* better fill one in anyway */
+		
+	return -dev->hard_header_len;
+}
+
+
+
+/* Rebuild the ARCnet ClientData header. This is called after an ARP
+ * (or in future other address resolution) has completed on this
+ * sk_buff. We now let ARP fill in the other fields.
+ */
+int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
+		struct sk_buff *skb)
+{
+	struct ClientData *head = (struct ClientData *)buff;
+	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+	int status;
+
+	/*
+	 * Only ARP and IP are currently supported
+	 */
+	 
+	if(head->protocol_id != ARC_P_IP) 
+	{
+		BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
+			head->protocol_id,head->protocol_id);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+		head->daddr=0;
+		/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
+		return 0;
+	}
+
+	/*
+	 * Try and get ARP to resolve the header.
+	 */
+#ifdef CONFIG_INET	 
+	BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
+			head->saddr,head->daddr,head->protocol_id);
+	status=arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
+	BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
+			head->saddr,head->daddr,head->protocol_id);
+	return status;
+#else
+	return 0;	
+#endif	
+}
+
+
+/* Determine a packet's protocol ID.
+ *
+ * With ARCnet we have to convert everything to Ethernet-style stuff.
+ */
+unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
+{
+	struct ClientData *head;
+	struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
+
+	/* Pull off the arcnet header. */
+	skb->mac.raw=skb->data;
+	skb_pull(skb,dev->hard_header_len);
+	head=(struct ClientData *)skb->mac.raw;
+	
+	if (head->daddr==0)
+		skb->pkt_type=PACKET_BROADCAST;
+	else if (dev->flags&IFF_PROMISC)
+	{
+		/* if we're not sending to ourselves :) */
+		if (head->daddr != dev->dev_addr[0])
+			skb->pkt_type=PACKET_OTHERHOST;
+	}
+	
+	/* now return the protocol number */
+	switch (head->protocol_id)
+	{
+	case ARC_P_IP:		return htons(ETH_P_IP);
+	case ARC_P_ARP:		return htons(ETH_P_ARP);
+	case ARC_P_RARP:	return htons(ETH_P_RARP);
+
+	case ARC_P_IPX:
+	case ARC_P_NOVELL_EC:
+		return htons(ETH_P_802_3);
+	default:
+		BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
+				head->protocol_id,head->protocol_id);
+		lp->stats.rx_errors++;
+		lp->stats.rx_crc_errors++;
+		return 0;
+	}
+
+	return htons(ETH_P_IP);
+}
+
+
+#ifdef CONFIG_ARCNET_ETH
+/****************************************************************************
+ *                                                                          *
+ * Ethernet-Encap Support                                                   *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Initialize the arc0e device.
+ */
+static int arcnetE_init(struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+
+	ether_setup(dev); /* we're emulating ether here, not ARCnet */
+	dev->dev_addr[0]=0;
+	dev->dev_addr[5]=lp->stationid;
+	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1;
+	dev->open=NULL;
+	dev->stop=NULL;
+	dev->hard_start_xmit=arcnetE_send_packet;
+
+	BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
+			
+	return 0;
+}
+
+
+/* Called by the kernel in order to transmit an ethernet-type packet.
+ */
+static int
+arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr,bad;
+	union ArcPacket *arcpacket = 
+		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+	u_char *arcsoft,daddr;
+	short offset,length=skb->len+1;
+
+	lp->intx++;
+	
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
+	{
+		lp->intx--;
+		return bad;
+	}
+
+	TBUSY=1;
+		
+	if (length>XMTU)
+	{
+		BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
+			length);
+		BUGMSG(D_NORMAL,"transmit aborted.\n");
+
+		dev_kfree_skb(skb,FREE_WRITE);
+		lp->intx--;
+		return 0;
+	}
+		
+	BUGMSG(D_DURING,"starting tx sequence...\n");
+
+	lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
+
+#ifndef SLOW_XMIT_COPY
+	/* clean out the page to make debugging make more sense :) */
+	BUGLVL(D_DURING)
+		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+#endif
+
+	/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
+	if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
+		daddr=arcpacket->hardheader.destination=0;
+	else
+		daddr=arcpacket->hardheader.destination=
+			((struct ethhdr*)(skb->data))->h_dest[5];
+
+	/* load packet into shared memory */
+	offset=512-length;
+	if (length>MTU)		/* long/exception packet */
+	{
+		if (length<MinTU) offset-=3;
+		arcpacket->hardheader.offset1=0;
+		arcpacket->hardheader.offset2=offset;
+	}
+	else			/* short packet */
+	{
+		arcpacket->hardheader.offset1=(offset-=256);
+	}
+	
+	BUGMSG(D_DURING," length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
+			length,offset,arcpacket->hardheader.offset1,
+			arcpacket->hardheader.offset2);
+	
+	arcsoft=&arcpacket->raw[offset];
+	arcsoft[0]=ARC_P_ETHER;
+	arcsoft++;
+		
+	/* copy the packet into ARCnet shmem
+	 *  - the first bytes of ClientData header are skipped
+	 */
+	BUGMSG(D_DURING,"ready to memcpy\n");
+	
+	memcpy(arcsoft,skb->data,skb->len);
+		
+	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
+			daddr,length);
+				
+	BUGLVL(D_TX)
+	{
+		int countx,county;
+			
+		printk("%6s: packet dump [tx] follows:",dev->name);
+
+ 		for (county=0; county<16+(length>=240)*16; county++)
+		{
+			printk("\n[%04X] ",county*16);
+			for (countx=0; countx<16; countx++)
+				printk("%02X ",
+					arcpacket->raw[county*16+countx]);
+		}
+		
+		printk("\n");
+	}
+
+	lp->lastload_dest=daddr;
+	lp->txready=lp->txbuf;	/* packet is ready for sending */
+
+	dev_kfree_skb(skb,FREE_WRITE);
+
+	if (arcnet_go_tx(dev,1))
+	{
+		/* inform upper layers */
+		TBUSY=0;
+		mark_bh(NET_BH);
+	}
+
+	dev->trans_start=jiffies;
+	lp->intx--;
+	
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
+	return 0;
+}
+
+
+/* Packet receiver for ethernet-encap packets.
+ */
+static void
+arcnetE_rx(struct device *dev,u_char *arcsoft,
+	int length,u_char saddr, u_char daddr)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	struct sk_buff *skb;
+	
+	BUGMSG(D_DURING,"it's an ethernet-encap packet (length=%d)\n",
+			length);
+
+       	skb = alloc_skb(length, GFP_ATOMIC);
+       	if (skb == NULL) {
+       		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
+       		lp->stats.rx_dropped++;
+       		return;
+       	}
+       	
+       	skb->len = length;
+       	skb->dev = dev;
+       	
+       	memcpy(skb->data,(u_char *)arcsoft+1,length-1);
+
+        BUGLVL(D_SKB)
+        {
+		short i;
+		printk("%6s: rx skb dump follows:\n",dev->name);
+                for(i=0; i<skb->len; i++)
+                {
+			if (i%16==0)
+				printk("\n[%04hX] ",i);
+			else
+                        	printk("%02hX ",((u_char *)skb->data)[i]);
+		}
+                printk("\n");
+        }
+        
+	skb->protocol=eth_type_trans(skb,dev);
+        
+        netif_rx(skb);
+}
+
+#endif /* CONFIG_ARCNET_ETH */
+
+#ifdef CONFIG_ARCNET_1051
+/****************************************************************************
+ *                                                                          *
+ * RFC1051 Support                                                          *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Initialize the arc0s device.
+ */
+static int arcnetS_init(struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+
+	arcnet_setup(dev);
+       
+	/* And now fill particular fields with arcnet values */
+	dev->dev_addr[0]=lp->stationid;
+	dev->hard_header_len=sizeof(struct S_ClientData);
+	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len
+		+ S_EXTRA_CLIENTDATA;
+	dev->open=NULL;
+	dev->stop=NULL;
+	dev->hard_start_xmit=arcnetS_send_packet;
+	dev->hard_header=arcnetS_header;
+	dev->rebuild_header=arcnetS_rebuild_header;
+	BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
+
+	return 0;
+}
+
+
+/* Called by the kernel in order to transmit an RFC1051-type packet.
+ */
+static int
+arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
+	int ioaddr=dev->base_addr,bad,length;
+	struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
+
+	lp->intx++;
+	
+	bad=arcnet_send_packet_bad(skb,dev);
+	if (bad)
+	{
+		lp->intx--;
+		return bad;
+	}
+	
+	TBUSY=1;
+
+	length = 1 < skb->len ? skb->len : 1;
+
+	BUGLVL(D_SKB)
+	{
+		short i;
+		for(i=0; i<skb->len; i++)
+		{
+			if (i%16 == 0) printk("\n[%04hX] ",i);
+			printk("%02hX ",((unsigned char*)skb->data)[i]);
+		}
+		printk("\n");
+	}
+
+	/* fits in one packet? */
+	if (length-S_EXTRA_CLIENTDATA<=XMTU)
+	{
+		arcnetAS_prepare_tx(dev,
+			skb->data+S_EXTRA_CLIENTDATA,
+			sizeof(struct S_ClientData)-S_EXTRA_CLIENTDATA,
+			skb->data+sizeof(struct S_ClientData),
+			length-sizeof(struct S_ClientData),
+			hdr->daddr,0);
+
+		/* done right away */
+		dev_kfree_skb(skb,FREE_WRITE);
+				
+		if (arcnet_go_tx(dev,1))
+		{
+			/* inform upper layers */
+			TBUSY=0;
+			mark_bh(NET_BH);
+		}
+	}
+	else			/* too big for one - not accepted */
+	{
+		BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
 			length);
+		dev_kfree_skb(skb,FREE_WRITE);
+		lp->stats.tx_dropped++;
+		TBUSY=0;
+		mark_bh(NET_BH);	
+	}
 
-       	skb = alloc_skb(length, GFP_ATOMIC);
-       	if (skb == NULL) {
-       		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
-       		lp->stats.rx_dropped++;
-       		return;
-       	}
-       	
-       	skb->len = length;
-       	skb->dev = dev;
-       	
-       	memcpy(skb->data,(u_char *)arcsoft+1,length-1);
+	dev->trans_start=jiffies;
+	lp->intx--;
 
-        BUGLVL(D_SKB)
-        {
-		short i;
-		printk("%6s: rx skb dump follows:\n",dev->name);
-                for(i=0; i<skb->len; i++)
-                {
-			if (i%16==0)
-				printk("\n[%04hX] ",i);
-			else
-                        	printk("%02hX ",((u_char *)skb->data)[i]);
-		}
-                printk("\n");
-        }
-        
-	skb->protocol=eth_type_trans(skb,dev);
-        
-        netif_rx(skb);
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
+	return 0;
 }
 
+
 /* Packet receiver for RFC1051 packets; 
  */
 static void
@@ -2578,122 +3055,6 @@
 }
 
 
-
-/****************************************************************************
- *                                                                          *
- * Miscellaneous routines                                                   *
- *                                                                          *
- ****************************************************************************/
-
-
-/* Get the current statistics.	This may be called with the card open or
- * closed.
- */
-
-static struct enet_statistics *
-arcnet_get_stats(struct device *dev)
-{
-	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
-	return &lp->stats;
-}
-
-#if 0
-/* Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets, and do
- *			best-effort filtering.
- */
-static void
-set_multicast_list(struct device *dev)
-{
-#if 0	  /* no promiscuous mode at all on most ARCnet models */
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	short ioaddr = dev->base_addr;
-	if (num_addrs) {
-		outw(69, ioaddr);		/* Enable promiscuous mode */
-	} else
-		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
-#endif
-}
-#endif
-
-/* Create the ARCnet ClientData header for an arbitrary protocol layer
- *
- * saddr=NULL	means use device source address (always will anyway)
- * daddr=NULL	means leave destination address (eg unresolved arp)
- */
-int arcnetA_header(struct sk_buff *skb,struct device *dev,
-		unsigned short type,void *daddr,void *saddr,unsigned len)
-{
-	struct ClientData *head = (struct ClientData *)
-		skb_push(skb,dev->hard_header_len);
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
-			saddr ? *(u_char*)saddr : -1,
-			daddr ? *(u_char*)daddr : -1,
-			type,type,len);
-
-	/* set the protocol ID according to RFC1201 */
-	switch(type)
-	{
-	case ETH_P_IP:
-		head->protocol_id=ARC_P_IP;
-		break;
-	case ETH_P_ARP:
-		head->protocol_id=ARC_P_ARP;
-		break;
-	case ETH_P_RARP:
-		head->protocol_id=ARC_P_RARP;
-		break;
-	case ETH_P_IPX:
-	case ETH_P_802_3:
-	case ETH_P_802_2:
-		head->protocol_id=ARC_P_IPX;
-		break;
-	case ETH_P_ATALK:
-		head->protocol_id=ARC_P_ATALK;
-		break;
-	default:
-		BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
-			type,type);
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
-		return 0;
-	}	
-
-	/*
-	 * Set the source hardware address.
-	 *
-	 * This is pretty pointless for most purposes, but it can help
-	 * in debugging.  saddr is stored in the ClientData header and
-	 * removed before sending the packet (since ARCnet does not allow
-	 * us to change the source address in the actual packet sent)
-	 */
-	if(saddr)
-		head->saddr=((u_char*)saddr)[0];
-	else
-		head->saddr=((u_char*)(dev->dev_addr))[0];
-
-	head->split_flag=0;	/* split packets are done elsewhere */
-	head->sequence=0;	/* so are sequence numbers */
-
-	/* supposedly if daddr is NULL, we should ignore it... */
-	if(daddr)
-	{
-		head->daddr=((u_char*)daddr)[0];
-		return dev->hard_header_len;
-	}
-	else
-		head->daddr=0;	/* better fill one in anyway */
-		
-	return -dev->hard_header_len;
-}
-
-
 /* Create the ARCnet ClientData header for an arbitrary protocol layer
  *
  * saddr=NULL	means use device source address (always will anyway)
@@ -2751,49 +3112,10 @@
 }
 
 
-
 /* Rebuild the ARCnet ClientData header. This is called after an ARP
  * (or in future other address resolution) has completed on this
  * sk_buff. We now let ARP fill in the other fields.
  */
-int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
-		struct sk_buff *skb)
-{
-	struct ClientData *head = (struct ClientData *)buff;
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-	int status;
-
-	/*
-	 * Only ARP and IP are currently supported
-	 */
-	 
-	if(head->protocol_id != ARC_P_IP) 
-	{
-		BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
-			head->protocol_id,head->protocol_id);
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
-		head->daddr=0;
-		/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
-		return 0;
-	}
-
-	/*
-	 * Try and get ARP to resolve the header.
-	 */
-#ifdef CONFIG_INET	 
-	BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
-			head->saddr,head->daddr,head->protocol_id);
-	status=arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
-	BUGMSG(D_DURING," rebuilt: from %d to %d; protocol %Xh\n",
-			head->saddr,head->daddr,head->protocol_id);
-	return status;
-#else
-	return 0;	
-#endif	
-}
-
-
 int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
 		struct sk_buff *skb)
 {
@@ -2830,47 +3152,6 @@
  *
  * With ARCnet we have to convert everything to Ethernet-style stuff.
  */
-unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
-{
-	struct ClientData *head;
-	struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
-
-	/* Pull off the arcnet header. */
-	skb->mac.raw=skb->data;
-	skb_pull(skb,dev->hard_header_len);
-	head=(struct ClientData *)skb->mac.raw;
-	
-	if (head->daddr==0)
-		skb->pkt_type=PACKET_BROADCAST;
-	else if (dev->flags&IFF_PROMISC)
-	{
-		/* if we're not sending to ourselves :) */
-		if (head->daddr != dev->dev_addr[0])
-			skb->pkt_type=PACKET_OTHERHOST;
-	}
-	
-	/* now return the protocol number */
-	switch (head->protocol_id)
-	{
-	case ARC_P_IP:		return htons(ETH_P_IP);
-	case ARC_P_ARP:		return htons(ETH_P_ARP);
-	case ARC_P_RARP:	return htons(ETH_P_RARP);
-
-	case ARC_P_IPX:
-	case ARC_P_NOVELL_EC:
-		return htons(ETH_P_802_3);
-	default:
-		BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
-				head->protocol_id,head->protocol_id);
-		lp->stats.rx_errors++;
-		lp->stats.rx_crc_errors++;
-		return 0;
-	}
-
-	return htons(ETH_P_IP);
-}
-
-
 unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
 {
 	struct S_ClientData *head;
@@ -2907,7 +3188,7 @@
 	return htons(ETH_P_IP);
 }
 
-
+#endif	/* CONFIG_ARCNET_1051 */
 
 /****************************************************************************
  *                                                                          *
diff -u --recursive --new-file v1.3.63/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v1.3.63/linux/drivers/scsi/aic7xxx.c	Thu Dec 21 08:53:33 1995
+++ linux/drivers/scsi/aic7xxx.c	Thu Feb 15 06:57:02 1996
@@ -1,5 +1,5 @@
 /*+M*************************************************************************
- * Adaptec 274x/284x/294x device driver for Linux.
+ * Adaptec AIC7xxx device driver for Linux.
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -41,7 +41,7 @@
  *
  *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
  *
- *  $Id: aic7xxx.c,v 2.15 1995/12/17 19:43:20 deang Exp $
+ *  $Id: aic7xxx.c,v 2.22 1996/02/10 09:22:50 deang Exp deang $
  *-M*************************************************************************/
 
 #ifdef MODULE
@@ -64,6 +64,7 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx.h"
+#include "aic7xxx_reg.h"
 #include <linux/stat.h>
 
 #include <linux/config.h>	/* for CONFIG_PCI */
@@ -73,7 +74,7 @@
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 2.15 $"
+#define AIC7XXX_C_VERSION  "$Revision: 2.22 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        ((a < b) ? a : b)
@@ -92,10 +93,9 @@
  *
  *   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 and do not wish to configure your kernel with PCI
- *     support, then make sure this define is set to the cprrect
- *     define for PCI support (CONFIG_PCI) and configure your kernel
- *     without PCI support (make config).
+ *     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.
  *
@@ -130,7 +130,17 @@
  *     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.
  *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 03/11/95
+ *   o 3985 support - The 3985 adapter is much like the 3940, but
+ *     has three 7870 controllers as opposed to two for the 3940.
+ *     It will get probed and recognized as three different adapters,
+ *     but all three controllers share the same bank of 255 SCBs
+ *     instead of each controller having their own bank (like the
+ *     controllers on the 3940).  For this reason, it is important
+ *     that all devices be resident on just one channel of the 3985.
+ *     In the near future, we'll modify the driver to reserve 1/3
+ *     of the SCBs for each controller.
+ *
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/11/96
  */
 
 /* Uncomment this for testing twin bus support. */
@@ -211,8 +221,7 @@
 
 typedef enum {
   LIST_HEAD,
-  LIST_SECOND,
-  LIST_TAIL
+  LIST_SECOND
 } insert_type;
 
 typedef enum {
@@ -268,523 +277,52 @@
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
  */
-#define HID0(x)         ((x) + 0xC80)   /* 0,1: msb of ID2, 2-7: ID1      */
-#define HID1(x)         ((x) + 0xC81)   /* 0-4: ID3, 5-7: LSB ID2         */
-#define HID2(x)         ((x) + 0xC82)   /* product                        */
-#define HID3(x)         ((x) + 0xC83)   /* 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(x)	((x) + 0xC00ul)
-#define MAXREG(x)	((x) + 0xCBFul)
-
-/* -------------------- AIC-7770 offset definitions ----------------------- */
-
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ(x)		((x) + 0xC00ul)
-#define		TEMODEO		0x80
-#define		ENSELO		0x40
-#define		ENSELI		0x20
-#define		ENRSELI		0x10
-#define		ENAUTOATNO	0x08
-#define		ENAUTOATNI	0x04
-#define		ENAUTOATNP	0x02
-#define		SCSIRSTO	0x01
-
-
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define	SXFRCTL0(x)		((x) + 0xC01ul)
-#define		DFON		0x80
-#define		DFPEXP		0x40
-#define		ULTRAEN		0x20
-#define		CLRSTCNT	0x10
-#define		SPIOEN		0x08
-#define		SCAMEN		0x04
-#define		CLRCHN		0x02
-/*  UNUSED			0x01 */
-
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL1(x)		((x) + 0xC02ul)
-#define		BITBUCKET	0x80
-#define		SWRAPEN		0x40
-#define		ENSPCHK		0x20
-#define		STIMESEL	0x18
-#define		ENSTIMER	0x04
-#define		ACTNEGEN	0x02
-#define		STPWEN		0x01		/* Powered Termination */
-
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI(x)		((x) + 0xC03ul)
-#define		CDI		0x80
-#define		IOI		0x40
-#define		MSGI		0x20
-#define		ATNI		0x10
-#define		SELI		0x08
-#define		BSYI		0x04
-#define		REQI		0x02
-#define		ACKI		0x01
-
-/*
- * SCSI Contol Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus. Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO(x)		((x) + 0xC03ul)
-#define		CDO		0x80
-#define		IOO		0x40
-#define		MSGO		0x20
-#define		ATNO		0x10
-#define		SELO		0x08
-#define		BSYO		0x04
-#define		REQO		0x02
-#define		ACKO		0x01
-
-/*
- * SCSI Rate
- */
-#define SCSIRATE(x)		((x) + 0xC04ul)
-#define WIDEXFER		0x80		/* Wide transfer control */
-#define SXFR			0x70		/* Sync transfer rate */
-#define SOFS			0x0F		/* Sync offset */
-
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel
- */
-#define SCSIID(x)		((x) + 0xC05ul)
-#define		TID		0xF0		/* Target ID mask */
-#define		OID		0x0F		/* Our ID mask */
-
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus.  The counter is decremented only once
- * the data has been safely transfered.  SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */
-#define STCNT(x)		((x) + 0xC08ul)
-
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0(x)		((x) + 0xC0Bul)
-#define		TARGET		0x80		/* Board is a target */
-#define		SELDO		0x40		/* Selection Done */
-#define		SELDI		0x20		/* Board has been selected */
-#define		SELINGO		0x10		/* Selection In Progress */
-#define		SWRAP		0x08		/* 24bit counter wrap */
-#define		SDONE		0x04		/* STCNT = 0x000000 */
-#define		SPIORDY		0x02		/* SCSI PIO Ready */
-#define		DMADONE		0x01		/* DMA transfer completed */
-
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1(x)		((x) + 0xC0Cul)
-#define		CLRSELTIMEO	0x80
-#define		CLRATNO		0x40
-#define		CLRSCSIRSTI	0x20
-/*  UNUSED			0x10 */
-#define		CLRBUSFREE	0x08
-#define		CLRSCSIPERR	0x04
-#define		CLRPHASECHG	0x02
-#define		CLRREQINIT	0x01
-
-/*
- * SCSI Status 1 (p. 3-24)
- * These interrupt bits are of interest to the kernel driver
- */
-#define SSTAT1(x)		((x) + 0xC0Cul)
-#define		SELTO		0x80
-#define		ATNTARG 	0x40
-#define		SCSIRSTI	0x20
-#define		PHASEMIS	0x10
-#define		BUSFREE		0x08
-#define		SCSIPERR	0x04
-#define		PHASECHG	0x02
-#define		REQINIT		0x01
-
-/*
- * SCSI Interrrupt Mode 1 (pp. 3-28,29).
- * Set bits in this register enable the corresponding
- * interrupt source.
- */
-#define	SIMODE1(x)		((x) + 0xC11ul)
-#define		ENSELTIMO	0x80
-#define		ENATNTARG	0x40
-#define		ENSCSIRST	0x20
-#define		ENPHASEMIS	0x10
-#define		ENBUSFREE	0x08
-#define		ENSCSIPERR	0x04
-#define		ENPHASECHG	0x02
-#define		ENREQINIT	0x01
-
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus.  They are counted up in the same
- * manner as STCNT is counted down.  SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be squewed by write ahead.
- */
-#define	SHADDR(x)		((x) + 0xC14ul)
-
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id. The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID(x)		((x) + 0xC19ul)
-#define		SELID_MASK	0xF0
-#define		ONEBIT		0x08
-/*  UNUSED			0x07 */
-
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection. In a twin channel configuration
- * addresses 0x00-0x1E are gated to the appropriate channel based on this
- * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL(x)		((x) + 0xC1Ful)
-/*  UNUSED			0xC0 */
-#define		DIAGLEDEN	0x80
-#define		DIAGLEDON	0x40
-#define		AUTOFLUSHDIS	0x20		/* used for Rev C check */
-/*  UNUSED			0x10 */
-#define		SELBUS_MASK	0x0F
-#define		SELBUSB		0x08
-/*  UNUSED			0x04 */
-#define		SELWIDE		0x02
-/*  UNUSED			0x01 */
-#define		SELSINGLE	0x00
-
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL(x)		((x) + 0xC60ul)
-#define		PERRORDIS	0x80
-#define		PAUSEDIS	0x40
-#define		FAILDIS		0x20
-#define 	FASTMODE	0x10
-#define		BRKADRINTEN	0x08
-#define		STEP		0x04
-#define		SEQRESET	0x02
-#define		LOADRAM		0x01
-
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
- * four bytes in sucessesion. The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM(x)		((x) + 0xC61ul)
-
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0(x)		((x) + 0xC62ul)
-#define SEQADDR1(x)		((x) + 0xC63ul)
-
-#define ACCUM(x)		((x) + 0xC64ul)		/* accumulator */
-#define SINDEX(x)		((x) + 0xC65ul)
-
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL(x)			((x) + 0xC84ul)
-/*   RSVD			0xF0 */
-#define		ACE		0x08	/* Support for external processors */
-/*   RSVD			0x06 */
-#define		ENABLE		0x01
-
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME(x)		((x) + 0xC85ul)
-#define		BOFF		0xF0
-#define		BON		0x0F
-
-/*
- * Bus Speed (p. 3-45)
- */
-#define	BUSSPD(x)		((x) + 0xC86ul)
-#define		DFTHRSH		0xC0
-#define		STBOFF		0x38
-#define		STBON		0x07
+#define MINREG		0xC00
+#define MAXREG		0xCBF
 
-/*
- * Host Control (p. 3-47) R/W
- * Overal host control of the device.
- */
-#define HCNTRL(x)		((x) + 0xC87ul)
-/*    UNUSED			0x80 */
-#define		POWRDN		0x40
-/*    UNUSED			0x20 */
-#define		SWINT		0x10
-#define		IRQMS		0x08
-#define		PAUSE		0x04
-#define		INTEN		0x02
-#define		CHIPRST		0x01
-#define		REQ_PAUSE	IRQMS | INTEN | PAUSE
-#define		UNPAUSE_274X	IRQMS | INTEN
-#define		UNPAUSE_284X	INTEN
-#define		UNPAUSE_294X	IRQMS | INTEN
+#define INTDEF		0x5C		/* Interrupt Definition Register */
 
 /*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
+ * Some defines for the HCNTRL register.
  */
-#define HADDR(x)		((x) + 0xC88ul)
-
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR(x)		((x) + 0xC90ul)
-
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT(x)		((x) + 0xC91ul)
-#define		SEQINT_MASK	0xF0		/* SEQINT Status Codes */
-#define			BAD_PHASE	0x00
-#define			SEND_REJECT	0x10
-#define			NO_IDENT	0x20
-#define			NO_MATCH	0x30
-#define			MSG_SDTR	0x40
-#define			MSG_WDTR	0x50
-#define			MSG_REJECT	0x60
-#define			BAD_STATUS	0x70
-#define			RESIDUAL	0x80
-#define			ABORT_TAG	0x90
-#define			AWAITING_MSG	0xA0
-#define			IMMEDDONE	0xB0
-#define 	BRKADRINT 0x08
-#define		SCSIINT	  0x04
-#define		CMDCMPLT  0x02
-#define		SEQINT    0x01
-#define		INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
-
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors. You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR(x)		((x) + 0xC92ul)
-/*    UNUSED			0xF0 */
-#define		PARERR		0x08
-#define		ILLOPCODE	0x04
-#define		ILLSADDR	0x02
-#define		ILLHADDR	0x01
-
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT(x)		((x) + 0xC92ul)
-#define		CLRBRKADRINT	0x08
-#define		CLRSCSIINT	0x04
-#define		CLRCMDINT 	0x02
-#define		CLRSEQINT 	0x01
-
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT(x)		((x) + 0xC9Aul)
-#define		SCBAUTO		0x80
-#define		SCBCNT_MASK	0x1F
-
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the seqencer has yet to start)
- */
-#define QINFIFO(x)		((x) + 0xC9Bul)
-
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT(x)		((x) + 0xC9Cul)
-
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO(x)		((x) + 0xC9Dul)
-
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT(x)		((x) + 0xC9Eul)
-
-#define SCBARRAY(x)		((x) + 0xCA0ul)
-
-/* ---------------- END AIC-7770 Register Definitions ----------------- */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define SEECTL_2840(x)		((x) + 0xCC0ul)
-/*    UNUSED			0xF8 */
-#define		CS_2840		0x04
-#define		CK_2840		0x02
-#define		DO_2840		0x01
-
-#define STATUS_2840(x)		((x) + 0xCC1ul)
-#define		EEPROM_TF	0x80
-#define		BIOS_SEL	0x60
-#define		ADSEL		0x1E
-#define		DI_2840		0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS(x)	 	((x) + 0xC86ul)
-#define 	DFTHRESH        0xC0
-
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  See aic7xxx_read_eprom for detailed information on
- * the protocol necessary to read the serial EEPROM.
- */
-#define SEECTL(x)		((x) + 0xC1Eul)
-#define		EXTARBACK	0x80
-#define		EXTARBREQ	0x40
-#define		SEEMS		0x20
-#define		SEERDY		0x10
-#define		SEECS		0x08
-#define		SEECK		0x04
-#define		SEEDO		0x02
-#define		SEEDI		0x01
-
-#define DEVREVID  		0x08ul
-
-#define	DEVSTATUS		0x40ul
-#define		MPORTMODE	0x04	/* aic7870 only */
-#define		RAMPSM		0x02	/* aic7870 only */
-#define		VOLSENSE	0x01
-
-#define	DEVCONFIG		0x41ul
-#define		SCBRAMSEL	0x80
-#define		MRDCEN		0x40
-#define		EXTSCBTIME	0x20	/* aic7870 only */
-#define		EXTSCBPEN	0x10	/* aic7870 only */
-#define		BERREN		0x08
-#define		DACEN		0x04
-#define		STPWLEVEL	0x02
-#define		DIFACTNEGEN	0x01	/* aic7870 only */
-
-/* Scratch RAM offset definitions */
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the Linux sequencer code. If I can figure out
- * how to read the EISA configuration info at probe time, the cards could
- * be run without BIOS support installed
- */
-
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define HA_TARG_SCRATCH(x)	((x) + 0xC20ul)
-
-/*
- * The sequencer will stick the first byte of any rejected message here so
- * we can see what is getting thrown away.
- */
-#define HA_REJBYTE(x)		((x) + 0xC31ul)
-
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define	HA_DISC_DSB(x)		((x) + 0xC32ul)
-
-/*
- * Length of pending message
- */
-#define HA_MSG_LEN(x)		((x) + 0xC34ul)
-
-/*
- * Outgoing Message Body
- */
-#define HA_MSG_START(x)		((x) + 0xC35ul)
-
-/*
- * These are offsets into the card's scratch ram. Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define HA_ARG_1(x)		((x) + 0xC4Aul)	/* sdtr <-> rate parameters */
-#define HA_RETURN_1(x)		((x) + 0xC4Aul)
-#define		SEND_SENSE	0x80
-#define		SEND_SDTR 	0x80
-#define		SEND_WDTR 	0x80
-#define		SEND_REJ	0x40
-
-#define	SG_COUNT(x)		((x) + 0xC4Dul)
-#define	SG_NEXT(x)		((x) + 0xC4Eul)
-#define HA_SIGSTATE(x)		((x) + 0xC4Bul)	/* value in SCSISIGO */
-#define HA_SCBCOUNT(x)		((x) + 0xC52ul)	/* number of hardware SCBs */
-
-#define HA_FLAGS(x)		((x) + 0xC53ul)	/* TWIN and WIDE bus flags */
-#define		SINGLE_BUS	0x00
-#define		TWIN_BUS	0x01
-#define		WIDE_BUS	0x02
-#define		ACTIVE_MSG	0x20
-#define		IDENTIFY_SEEN	0x40
-#define		RESELECTING	0x80
-
-#define HA_ACTIVE0(x)		((x) + 0xC54ul)	/* Active bits; targets 0-7 */
-#define HA_ACTIVE1(x)		((x) + 0xC55ul)	/* Active bits; targets 8-15 */
-#define	SAVED_TCL(x)		((x) + 0xC56ul)	/* Saved target, channel, LUN */
-#define WAITING_SCBH(x)		((x) + 0xC57ul) /* Head of disconnected targets list. */
-#define WAITING_SCBT(x)		((x) + 0xC58ul) /* Tail of disconnected targets list. */
-
-#define HA_SCSICONF(x)		((x) + 0xC5Aul)	/* SCSI config register */
-#define HA_INTDEF(x)		((x) + 0xC5Cul)	/* interrupt def'n register */
-#define HA_HOSTCONF(x)		((x) + 0xC5Dul)	/* host config def'n register */
-
-#define HA_274_BIOSCTRL(x)	((x) + 0xC5Ful) /* BIOS enabled for 274x */
-#define BIOSMODE		0x30
-#define BIOSDISABLED		0x30
-
-#define MSG_ABORT		0x06
-#define	MSG_BUS_DEVICE_RESET	0x0C
-#define BUS_8_BIT		0x00
-#define BUS_16_BIT		0x01
-#define BUS_32_BIT		0x02
-
+#define	REQ_PAUSE	IRQMS | INTEN | PAUSE
+#define	UNPAUSE_274X	IRQMS | INTEN
+#define	UNPAUSE_284X	INTEN
+#define	UNPAUSE_294X	IRQMS | INTEN
+
+/*
+ * AIC-78X0 PCI registers
+ */
+#define	CLASS_PROGIF_REVID	0x08
+#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 */
 
 /*
  *
@@ -853,7 +391,6 @@
 
   unsigned short res_1[11];		/* words 20-30 */
   unsigned short checksum;		/* word 31 */
-
 };
 
 /*
@@ -862,8 +399,8 @@
  * sections.
  */
 #define PAUSE_SEQUENCER(p) \
-  outb(p->pause, HCNTRL(p->base));			\
-  while ((inb(HCNTRL(p->base)) & PAUSE) == 0)		\
+  outb(p->pause, HCNTRL + p->base);			\
+  while ((inb(HCNTRL + p->base) & PAUSE) == 0)		\
     ;							\
 
 /*
@@ -871,16 +408,16 @@
  * warrant an easy way to do it.
  */
 #define UNPAUSE_SEQUENCER(p) \
-  outb(p->unpause, HCNTRL(p->base))
+  outb(p->unpause, HCNTRL + p->base)
 
 /*
  * Restart the sequencer program from address zero
  */
 #define RESTART_SEQUENCER(p) \
   do {							\
-    outb(SEQRESET | FASTMODE, SEQCTL(p->base));		\
-  } while (inb(SEQADDR0(p->base)) != 0 &&		\
-	   inb(SEQADDR1(p->base)) != 0);		\
+    outb(SEQRESET | FASTMODE, SEQCTL + p->base);	\
+  } while (inb(SEQADDR0 + p->base) != 0 &&		\
+	   inb(SEQADDR1 + p->base) != 0);		\
   UNPAUSE_SEQUENCER(p);
 
 /*
@@ -958,48 +495,31 @@
 
 /*
  * The driver keeps up to four scb structures per card in memory. Only the
- * first 26 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookeeping.
+ * first 25 bytes of the structure are valid for the hardware, the rest used
+ * for driver level bookkeeping.
  */
-#define SCB_DOWNLOAD_SIZE	26	/* amount to actually download */
-#define SCB_UPLOAD_SIZE		26	/* amount to actually upload */
 
 struct aic7xxx_scb {
 /* ------------    Begin hardware supported fields    ---------------- */
-/*1 */  unsigned char control;
-#define	SCB_NEEDWDTR 0x80			/* Initiate Wide Negotiation */
-#define SCB_DISCENB  0x40			/* Disconnection Enable */
-#define	SCB_TE	     0x20			/* Tag enable */
-#define SCB_NEEDSDTR 0x10			/* Initiate Sync Negotiation */
-#define	SCB_NEEDDMA  0x08			/* Refresh SCB from host ram */
-#define	SCB_DIS	     0x04
-#define	SCB_TAG_TYPE 0x03
-#define		SIMPLE_QUEUE	0x00
-#define		HEAD_QUEUE	0x01
-#define		OR_QUEUE	0x02
-/*              ILLEGAL      0x03 */
-/*2 */  unsigned char target_channel_lun;       /* 4/1/3 bits */
-/*3 */  unsigned char SG_segment_count;
-/*7 */  unsigned char SG_list_pointer[4] __attribute__ ((packed));
-/*11*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
-/*12*/  unsigned char SCSI_cmd_length;
-/*14*/  unsigned char RESERVED[2];              /* must be zero */
-/*15*/  unsigned char target_status;
-/*18*/  unsigned char residual_data_count[3];
-/*19*/  unsigned char residual_SG_segment_count;
-/*23*/  unsigned char data_pointer[4] __attribute__ ((packed));
-/*26*/  unsigned char data_count[3];
-/*30*/  unsigned char host_scb[4] __attribute__ ((packed));
-/*31*/  u_char next_waiting;            /* Used to thread SCBs awaiting selection. */
-#define SCB_LIST_NULL 0xFF              /* SCB list equivelent to NULL */
-#if 0
-	/*
-	 *  No real point in transferring this to the
-	 *  SCB registers.
-	 */
-	unsigned char RESERVED[1];
-#endif
-
+/* 0*/  unsigned char control;
+/* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
+/* 2*/  unsigned char target_status;
+/* 3*/  unsigned char SG_segment_count;
+/* 4*/  unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/* 8*/  unsigned char residual_SG_segment_count;
+/* 9*/  unsigned char residual_data_count[3];
+/*12*/  unsigned char data_pointer[4] __attribute__ ((packed));
+/*16*/  unsigned long data_count;
+/*20*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/*24*/  unsigned char SCSI_cmd_length;
+#define SCB_PIO_TRANSFER_SIZE   25      /*
+                                         * amount we need to upload/download
+                                         * via rep in/outsb to perform
+                                         * a request sense.  The second
+                                         * RESERVED byte is initialized to
+                                         * 0 in getscb().
+                                         */
+/*25*/  u_char next_waiting;            /* Used to thread SCBs awaiting selection. */
 	/*-----------------end of hardware supported fields----------------*/
 	struct aic7xxx_scb *next;	/* next ptr when in free list */
 	Scsi_Cmnd          *cmd;	/* Scsi_Cmnd for this scb */
@@ -1016,8 +536,6 @@
 	unsigned char       sense_cmd[6];   /* Allocate 6 characters for sense command */
 };
 
-typedef void (*timeout_fn)(unsigned long);
-
 static struct {
   unsigned char errno;
   const char *errmesg;
@@ -1142,10 +660,11 @@
 static int num_aic7xxx_syncrates =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
+#ifdef CONFIG_PCI
 static int number_of_39xxs = 0;
+#endif CONFIG_PCI
 
 #ifdef AIC7XXX_DEBUG
-
 static void
 debug(const char *fmt, ...)
 {
@@ -1169,8 +688,8 @@
   static int SST[] = { 256, 128, 64, 32 };
   static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
 
-  host_conf = inb(HA_HOSTCONF(p->base));
-  scsi_conf = inb(HA_SCSICONF(p->base));
+  host_conf = inb(HOSTCONF + p->base);
+  scsi_conf = inb(SCSICONF + p->base);
 
   /*
    * The 7870 gets the bus release time and data FIFO threshold
@@ -1282,13 +801,11 @@
          scb->SCSI_cmd_length);
   printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
          (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
-         scb->residual_SG_segment_count, (scb->residual_data_count[2] << 16) |
-         (scb->residual_data_count[1] << 8) | scb->residual_data_count[0]);
-  printk("data ptr 0x%x, data count %d, host scb 0x%x, next waiting %d\n",
+         scb->residual_SG_segment_count, scb->residual_data_count);
+  printk("data ptr 0x%x, data count %d, next waiting %d\n",
          (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
          (scb->data_pointer[1] << 8) | scb->data_pointer[0],
-         (scb->data_count[2] << 16) | (scb->data_count[1] << 8) | scb->data_count[0],
-         (unsigned int) scb->host_scb, scb->next_waiting);
+         scb->data_count, scb->next_waiting);
   printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
          (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
          scb->position);
@@ -1385,14 +902,9 @@
    * sequencer RAM parity error detection while loading, and
    * make sure the LOADRAM bit is enabled for loading.
    */
-  outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL(base));
+  outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
 
-  asm volatile("cld\n\t"
-	       "rep\n\t"
-	       "outsb"
-	       : /* no output */
-	       :"S" (seqprog), "c" (sizeof(seqprog)), "d" (SEQRAM(base))
-	       :"si", "cx", "dx");
+  outsb(SEQRAM + base, seqprog, sizeof(seqprog));
 
   /*
    * WARNING!  This is a magic sequence!  After extensive
@@ -1410,8 +922,8 @@
      * the address shows up as
      * zero just to be safe..
      */
-    outb(SEQRESET | FASTMODE, SEQCTL(base));
-  } while ((inb(SEQADDR0(base)) != 0) && (inb(SEQADDR1(base)) != 0));
+    outb(SEQRESET | FASTMODE, SEQCTL + base);
+  } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
 }
 
 /*+F*************************************************************************
@@ -1551,7 +1063,7 @@
  *-F*************************************************************************/
 static void
 aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-                 unsigned char period, unsigned char offset,
+                 short period, unsigned char offset,
                  int target, char channel)
 {
   int i;
@@ -1568,8 +1080,8 @@
       {
         if (!(aic7xxx_syncrates[i].rate & ULTRA_SXFR))
         {
-          printk ("aic7xxx: Target %d, channel %c, requests %sMB/s transfers, "
-                  "but adapter in Ultra mode can only sync at 10MB/s or "
+          printk ("aic7xxx: Target %d, channel %c, requests %sMHz transfers, "
+                  "but adapter in Ultra mode can only sync at 10MHz or "
                   "above.\n", target, channel, aic7xxx_syncrates[i].english);
           break;  /* Use asynchronous transfers. */
         }
@@ -1591,7 +1103,7 @@
         }
       }
       *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
-      printk("aic7xxx: Target %d, channel %c, now synchronous at %sMB/s, "
+      printk("aic7xxx: Target %d, channel %c, now synchronous at %sMHz, "
              "offset(0x%x).\n",
 	     target, channel, aic7xxx_syncrates[i].english, offset);
       return;
@@ -1613,43 +1125,35 @@
  * Description:
  *   Transfer a SCB to the controller.
  *-F*************************************************************************/
-static void
-aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
+static inline void
+aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  /*
-   * All we need to do, is to output the position
-   * of the SCB in the SCBARRAY to the QINFIFO
-   * of the host adapter.
-   */
-  outb(scb->position, QINFIFO(base));
-}
+  unsigned char curscb;
+  int base = p->base;
+
+  curscb = inb(SCBPTR + base);
+  outb(scb->position, SCBPTR + base);
+  outb(SCBAUTO, SCBCNT + base);
 
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_putscb_dma
- *
- * Description:
- *   DMA a SCB to the controller.
- *-F*************************************************************************/
-static void
-aic7xxx_putscb_dma(int base, struct aic7xxx_scb *scb)
-{
   /*
    * By turning on the SCB auto increment, any reference
    * to the SCB I/O space postincrements the SCB address
    * we're looking at. So turn this on and dump the relevant
    * portion of the SCB to the card.
+   *
+   * We can do 16bit transfers on all but 284x.
    */
-  outb(SCBAUTO, SCBCNT(base));
-
-  asm volatile("cld\n\t"
-	       "rep\n\t"
-	       "outsb"
-	       : /* no output */
-	       :"S" (scb), "c" (31), "d" (SCBARRAY(base))
-	       :"si", "cx", "dx");
+  if (p->type == AIC_284x)
+  {
+    outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+  }
+  else
+  {
+    outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
+  }
 
-  outb(0, SCBCNT(base));
+  outb(0, SCBCNT + base);
+  outb(curscb, SCBPTR + base);
 }
 
 /*+F*************************************************************************
@@ -1659,22 +1163,17 @@
  * Description:
  *   Get a SCB from the controller.
  *-F*************************************************************************/
-static void
-aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
+static inline void
+aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
+  int base = p->base;
+
   /*
    * This is almost identical to aic7xxx_putscb().
    */
-  outb(SCBAUTO, SCBCNT(base));
-
-  asm volatile("cld\n\t"
-	       "rep\n\t"
-	       "insb"
-	       : /* no output */
-	       :"D" (scb), "c" (SCB_UPLOAD_SIZE), "d" (SCBARRAY(base))
-	       :"di", "cx", "dx");
-
-  outb(0, SCBCNT(base));
+  outb(SCBAUTO, SCBCNT + base);
+  insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+  outb(0, SCBCNT + base);
 }
 
 /*+F*************************************************************************
@@ -1709,6 +1208,32 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_busy_target
+ *
+ * Description:
+ *   Set the specified target active.
+ *-F*************************************************************************/
+static void
+aic7xxx_busy_target(unsigned char target, char channel, int base)
+{
+  unsigned char active;
+  unsigned long active_port = ACTIVE_A + base;
+
+  if ((target > 0x07) || (channel == 'B'))
+  {
+    /*
+     * targets on the Second channel or above id 7 store info in byte two
+     * of ACTIVE
+     */
+    active_port++;
+  }
+  active = inb(active_port);
+  active |= (0x01 << (target & 0x07));
+  outb(active, active_port);
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_unbusy_target
  *
  * Description:
@@ -1718,9 +1243,9 @@
 aic7xxx_unbusy_target(unsigned char target, char channel, int base)
 {
   unsigned char active;
-  unsigned long active_port = HA_ACTIVE0(base);
+  unsigned long active_port = ACTIVE_A + base;
 
-#ifdef AIC7XXX_DEBUG_ABORT
+#ifdef 0
   printk ("aic7xxx: (unbusy_target) target/channel %d/%c\n",
           target, channel);
 #endif
@@ -1728,13 +1253,13 @@
   {
     /*
      * targets on the Second channel or above id 7 store info in byte two
-     * of HA_ACTIVE
+     * of ACTIVE
      */
     active_port++;
   }
   active = inb(active_port);
   active &= ~(0x01 << (target & 0x07));
-  outb(active_port, active);
+  outb(active, active_port);
 }
 
 /*+F*************************************************************************
@@ -1767,7 +1292,7 @@
    */
   scb->state = SCB_FREE;
   scb->next = p->free_scb;
-  p->free_scb = &(p->scb_array[scb->position]);
+  p->free_scb = scb;
   scb->cmd = NULL;
 
   restore_flags(flags);
@@ -1787,63 +1312,40 @@
                         struct aic7xxx_scb *scb,
                         insert_type         where)
 {
-  unsigned char head, tail;
+  unsigned char head;
   unsigned char curscb;
 
-  curscb = inb(SCBPTR(base));
-  head = inb(WAITING_SCBH(base));
-  tail = inb(WAITING_SCBT(base));
+  curscb = inb(SCBPTR + base);
+  head = inb(WAITING_SCBH + base);
   if (head == SCB_LIST_NULL)
   {
     /*
      * List was empty
      */
     head = scb->position;
-    tail = SCB_LIST_NULL;
   }
   else
   {
     if (where == LIST_HEAD)
     {
-      outb(scb->position, SCBPTR(base));
-      outb(head, SCBARRAY(base) + 30);
+      outb(scb->position, SCBPTR + base);
+      outb(head, SCB_NEXT_WAITING + base);
       head = scb->position;
     }
     else
     {
-      if (tail == SCB_LIST_NULL)
-      {
-        /*
-         * List had one element
-         */
-        tail = scb->position;
-        outb(head, SCBPTR(base));
-        outb(tail, SCBARRAY(base) + 30);
-      }
-      else
-      {
-        if (where == LIST_SECOND)
-        {
-          unsigned char third_scb;
+      /* where == LIST_SECOND */
+      unsigned char third_scb;
 
-          outb(head, SCBPTR(base));
-          third_scb = inb(SCBARRAY(base) + 30);
-          outb(scb->position, SCBARRAY(base) + 30);
-          outb(scb->position, SCBPTR(base));
-          outb(third_scb, SCBARRAY(base) + 30);
-        }
-        else
-        {
-          outb(tail, SCBPTR(base));
-          tail = scb->position;
-          outb(tail, SCBARRAY(base) + 30);
-        }
-      }
+      outb(head, SCBPTR + base);
+      third_scb = inb(SCB_NEXT_WAITING + base);
+      outb(scb->position, SCB_NEXT_WAITING + base);
+      outb(scb->position, SCBPTR + base);
+      outb(third_scb, SCB_NEXT_WAITING + base);
     }
   }
-  outb(head, WAITING_SCBH(base));
-  outb(tail, WAITING_SCBT(base));
-  outb(curscb, SCBPTR(base));
+  outb(head, WAITING_SCBH + base);
+  outb(curscb, SCBPTR + base);
 }
 
 /*+F*************************************************************************
@@ -1867,15 +1369,15 @@
    * Select the SCB we want to abort and
    * pull the next pointer out of it.
    */
-  curscb = inb(SCBPTR(base));
-  outb(scb->position, SCBPTR(base));
-  next = inb(SCBARRAY(base) + 30);
+  curscb = inb(SCBPTR + base);
+  outb(scb->position, SCBPTR + base);
+  next = inb(SCB_NEXT_WAITING + base);
 
   /*
    * Clear the necessary fields
    */
-  outb(SCB_NEEDDMA, SCBARRAY(base));
-  outb(SCB_LIST_NULL, SCBARRAY(base) + 30);
+  outb(0, SCBARRAY + base);
+  outb(SCB_LIST_NULL, SCB_NEXT_WAITING + base);
   aic7xxx_unbusy_target(target, channel, base);
 
   /*
@@ -1886,22 +1388,22 @@
     /*
      * First in the list
      */
-    outb(next, WAITING_SCBH(base));
+    outb(next, WAITING_SCBH + base);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, SCBPTR(base));
-    outb(next, SCBARRAY(base) + 30);
+    outb(prev, SCBPTR + base);
+    outb(next, SCB_NEXT_WAITING + base);
   }
   /*
-   * Update the tale pointer
+   * Update the tail pointer
    */
-  if (inb(WAITING_SCBT(base)) == scb->position)
+  if (inb(WAITING_SCBT + base) == scb->position)
   {
-    outb(prev, WAITING_SCBT(base));
+    outb(prev, WAITING_SCBT + base);
   }
 
   /*
@@ -1909,7 +1411,7 @@
    * and inform the SCSI system that the command
    * has been aborted.
    */
-  outb(curscb, SCBPTR(base));
+  outb(curscb, SCBPTR + base);
   scb->state |= SCB_ABORTED;
   scb->cmd->result = (DID_RESET << 16);
   aic7xxx_done(p, scb);
@@ -1942,7 +1444,7 @@
   /*
    * Restore this when we're done
    */
-  active_scb = inb(SCBPTR(base));
+  active_scb = inb(SCBPTR + base);
 
 #ifdef AIC7XXX_DEBUG_ABORT
   printk ("aic7xxx: (reset_device) target/channel %d/%c, to_scb %d, "
@@ -1953,11 +1455,11 @@
    */
   {
     int saved_queue[AIC7XXX_MAXSCB];
-    int queued = inb(QINCNT(base));
+    int queued = inb(QINCNT + base);
 
     for (i = 0; i < (queued - found); i++)
     {
-      saved_queue[i] = inb(QINFIFO(base));
+      saved_queue[i] = inb(QINFIFO + base);
       scb = &(p->scb_array[saved_queue[i]]);
       if (aic7xxx_match_scb(scb, target, channel))
       {
@@ -1967,8 +1469,8 @@
         scb->state |= SCB_ABORTED;
         scb->cmd->result = (DID_RESET << 16);
         aic7xxx_done(p, scb);
-        outb(scb->position, SCBPTR(base));
-        outb(SCB_NEEDDMA, SCBARRAY(base));
+        outb(scb->position, SCBPTR + base);
+        outb(0, SCBARRAY + base);
         i--;
         found++;
       }
@@ -1978,7 +1480,7 @@
      */
     for (queued = 0; queued < i; queued++)
     {
-      outb(saved_queue[queued], QINFIFO(base));
+      outb(saved_queue[queued], QINFIFO + base);
     }
   }
 
@@ -1988,7 +1490,7 @@
   {
     unsigned char next, prev;
 
-    next = inb(WAITING_SCBH(base));  /* Start at head of list. */
+    next = inb(WAITING_SCBH + base);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
 
     while (next != SCB_LIST_NULL)
@@ -2004,9 +1506,9 @@
       }
       else
       {
-        outb(scb->position, SCBPTR(base));
+        outb(scb->position, SCBPTR + base);
         prev = next;
-        next = inb(SCBARRAY(base) + 30);
+        next = inb(SCB_NEXT_WAITING + base);
       }
     }
   }
@@ -2026,8 +1528,8 @@
        * Ensure the target is "free"
        */
       aic7xxx_unbusy_target(target, channel, base);
-      outb(scb->position, SCBPTR(base));
-      outb(SCB_NEEDDMA, SCBARRAY(base));
+      outb(scb->position, SCBPTR + base);
+      outb(0, SCBARRAY + base);
       scb->state |= SCB_ABORTED;
       scb->cmd->result = (DID_RESET << 16);
       aic7xxx_done(p, scb);
@@ -2035,7 +1537,7 @@
     }
   }
 
-  outb(active_scb, SCBPTR(base));
+  outb(active_scb, SCBPTR + base);
   return (found);
 }
 
@@ -2052,9 +1554,9 @@
 #ifdef AIC7XXX_DEBUG_ABORT
     printk ("aic7xxx: (reset_current_bus)\n");
 #endif
-  outb(SCSIRSTO, SCSISEQ(base));
+  outb(SCSIRSTO, SCSISEQ + base);
   udelay(1000);
-  outb(0, SCSISEQ(base));
+  outb(0, SCSISEQ + base);
 }
 
 /*+F*************************************************************************
@@ -2088,9 +1590,9 @@
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
-    outb(0, HA_ACTIVE1(base));
-    offset = HA_TARG_SCRATCH(base) + 8;
-    offset_max = HA_TARG_SCRATCH(base) + 16;
+    outb(0, ACTIVE_B + base);
+    offset = TARG_SCRATCH + base + 8;
+    offset_max = TARG_SCRATCH + base + 16;
   }
   else
   {
@@ -2098,20 +1600,20 @@
     {
       p->needsdtr = p->needsdtr_copy;
       p->needwdtr = p->needwdtr_copy;
-      p->sdtr_pending = 0;
-      p->wdtr_pending = 0;
-      outb(0, HA_ACTIVE0(base));
-      outb(0, HA_ACTIVE1(base));
-      offset = HA_TARG_SCRATCH(base);
-      offset_max = HA_TARG_SCRATCH(base) + 16;
+      p->sdtr_pending = 0x0;
+      p->wdtr_pending = 0x0;
+      outb(0, ACTIVE_A + base);
+      outb(0, ACTIVE_B + base);
+      offset = TARG_SCRATCH + base;
+      offset_max = TARG_SCRATCH + base + 16;
     }
     else
     {
       p->needsdtr |= (p->needsdtr_copy & 0x00FF);
       p->sdtr_pending &= 0xFF00;
-      outb(0, HA_ACTIVE0(base));
-      offset = HA_TARG_SCRATCH(base);
-      offset_max = HA_TARG_SCRATCH(base) + 8;
+      outb(0, ACTIVE_A + base);
+      offset = TARG_SCRATCH + base;
+      offset_max = TARG_SCRATCH + base + 8;
     }
   }
   while (offset < offset_max)
@@ -2134,7 +1636,7 @@
   /*
    * Case 1: Command for another bus is active
    */
-  sblkctl = inb(SBLKCTL(base));
+  sblkctl = inb(SBLKCTL + base);
   cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
   if (cur_channel != channel)
   {
@@ -2145,9 +1647,9 @@
     /*
      * Stealthily reset the other bus without upsetting the current bus
      */
-    outb(sblkctl ^ SELBUSB, SBLKCTL(base));
+    outb(sblkctl ^ SELBUSB, SBLKCTL + base);
     aic7xxx_reset_current_bus(base);
-    outb(sblkctl, SBLKCTL(base));
+    outb(sblkctl, SBLKCTL + base);
 
     UNPAUSE_SEQUENCER(p);
   }
@@ -2183,11 +1685,12 @@
   int base, intstat;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
-  unsigned char ha_flags, transfer;
+  unsigned char ha_flags;
+  short         transfer;
   unsigned char scsi_id, bus_width;
   unsigned char offset, rate, scratch, scratch_offset;
   unsigned char max_offset, rej_byte;
-  unsigned short target_mask, active;
+  unsigned short target_mask;
   char channel;
   void *addr;
   int actual;
@@ -2200,7 +1703,7 @@
    * Search for the host with a pending interrupt.  If we can't find
    * one, then we've encountered a spurious interrupt.
    */
-  while ((p != NULL) && !(inb(INTSTAT(p->base)) & INT_PEND))
+  while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
   {
     if (p->next == NULL)
     {
@@ -2235,7 +1738,7 @@
    */
   p->isr_count++;
 
-  if ((p->a_scanned == 0) && (p->isr_count == 1))
+  if (!p->a_scanned && (p->isr_count == 1))
   {
     /*
      * We must only have one card at this IRQ and it must have been
@@ -2252,12 +1755,12 @@
    * Handle all the interrupt sources - especially for SCSI
    * interrupts, we won't get a second chance at them.
    */
-  intstat = inb(INTSTAT(base));
+  intstat = inb(INTSTAT + base);
 
   if (intstat & BRKADRINT)
   {
     int i;
-    unsigned char errno = inb(ERROR(base));
+    unsigned char errno = inb(ERROR + base);
 
     printk("aic7xxx: (aic7xxx_isr) BRKADRINT error(0x%x):\n", errno);
     for (i = 0; i < NUMBER(hard_error); i++)
@@ -2269,7 +1772,7 @@
     }
 
     panic("aic7xxx: (aic7xxx_isr) BRKADRINT, error(0x%x) seqaddr(0x%x).\n",
-	  inb(ERROR(base)), (inb(SEQADDR1(base)) << 8) | inb(SEQADDR0(base)));
+	  inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
   }
 
   if (intstat & SEQINT)
@@ -2281,10 +1784,10 @@
      */
     PAUSE_SEQUENCER(p);
 
-    scsi_id = (inb(SCSIID(base)) >> 4) & 0x0F;
+    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
     scratch_offset = scsi_id;
     channel = 'A';
-    if (inb(SBLKCTL(base)) & SELBUSB)
+    if (inb(SBLKCTL + base) & SELBUSB)
     {
       channel = 'B';
       scratch_offset += 8;
@@ -2298,50 +1801,50 @@
 	break;
 
       case SEND_REJECT:
-        rej_byte = inb(HA_REJBYTE(base));
-        if (rej_byte != 0x20)
-        {
-          debug("aic7xxx: Warning - Issuing message reject, 1st byte(0x%x)\n",
-                rej_byte);
-        }
-        else
+        rej_byte = inb(REJBYTE + base);
+        if ((rej_byte & 0xF0) == 0x20)
         {
-          scb_index = inb(SCBPTR(base));
+          scb_index = inb(SCBPTR + base);
           scb = &(p->scb_array[scb_index]);
-          printk("aic7xxx: Warning - Tagged message rejected for target %d,"
-                 " channel %c.\n", scsi_id, channel);
+          printk("aic7xxx: Warning - Tagged message received without identify."
+                 "Disabling tagged commands for target %d channel %c.\n",
+                  scsi_id, channel);
           scb->cmd->device->tagged_supported = 0;
           scb->cmd->device->tagged_queue = 0;
         }
+        else
+        {
+          debug("aic7xxx: Warning - Rejecting unknown message (0x%x) received "
+                "from target %d channel %c.\n", rej_byte, scsi_id, channel);
+        }
 	break;
 
       case NO_IDENT:
 	panic("aic7xxx: Target %d, channel %c, did not send an IDENTIFY "
 	      "message. SAVED_TCL(0x%x).\n",
-              scsi_id, channel, inb(SAVED_TCL(base)));
+              scsi_id, channel, inb(SAVED_TCL + base));
 	break;
 
       case NO_MATCH:
 	printk("aic7xxx: No active SCB for reconnecting target %d, "
 	      "channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-              scsi_id, channel, inb(SAVED_TCL(base)));
+              scsi_id, channel, inb(SAVED_TCL + base));
         aic7xxx_unbusy_target(scsi_id, channel, base);
-        outb(SCB_NEEDDMA, SCBARRAY(base));
-
-	outb(CLRSELTIMEO, CLRSINT1(base));
+        outb(0, SCBARRAY + base);
+	outb(CLRSELTIMEO, CLRSINT1 + base);
 	RESTART_SEQUENCER(p);
 	break;
 
-      case MSG_SDTR:
+      case SDTR_MSG:
 	/*
 	 * Help the sequencer to translate the negotiated
 	 * transfer rate. Transfer is 1/4 the period
 	 * in ns as is returned by the sync negotiation
 	 * message. So, we must multiply by four.
 	 */
-	transfer = (inb(HA_ARG_1(base)) << 2);
-	offset = inb(ACCUM(base));
-	scratch = inb(HA_TARG_SCRATCH(base) + scratch_offset);
+	transfer = (inb(ARG_1 + base) << 2);
+	offset = inb(ACCUM + base);
+	scratch = inb(TARG_SCRATCH + base + scratch_offset);
 	/*
 	 * The maximum offset for a wide device is 0x08; for a
 	 * 8-bit bus device the maximum offset is 0x0F.
@@ -2354,13 +1857,14 @@
 	{
 	  max_offset = 0x0F;
 	}
-	aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset), scsi_id, channel);
+	aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
+                         scsi_id, channel);
 	/*
 	 * Preserve the wide transfer flag.
 	 */
 	scratch = rate | (scratch & WIDEXFER);
-	outb(scratch, HA_TARG_SCRATCH(base) + scratch_offset);
-	outb(scratch, SCSIRATE(base));
+	outb(scratch, TARG_SCRATCH + base + scratch_offset);
+	outb(scratch, SCSIRATE + base);
 	if ((scratch & 0x0F) == 0)
 	{ /*
 	   * The requested rate was so low that asynchronous transfers
@@ -2368,7 +1872,7 @@
 	   * them), so we issue a reject to ensure we go to asynchronous
 	   * transfers.
 	   */
-	   outb(SEND_REJ, HA_RETURN_1(base));
+	   outb(SEND_REJ, RETURN_1 + base);
 	}
 	else
 	{
@@ -2380,7 +1884,7 @@
 	    /*
 	     * Don't send an SDTR back to the target.
 	     */
-	    outb(0, HA_RETURN_1(base));
+	    outb(0, RETURN_1 + base);
 	  }
 	  else
 	  {
@@ -2388,7 +1892,7 @@
 	     * Send our own SDTR in reply.
 	     */
 	    printk("aic7xxx: Sending SDTR!!\n");
-	    outb(SEND_SDTR, HA_RETURN_1(base));
+	    outb(SEND_SDTR, RETURN_1 + base);
 	  }
 	}
 	/*
@@ -2396,27 +1900,21 @@
 	 */
 	p->needsdtr &= ~target_mask;
 	p->sdtr_pending &= ~target_mask;
-#if 0
-  scb_index = inb(SCBPTR(base));
-  scb = &(p->scb_array[scb_index]);
-  debug_scb(scb);
-#endif
-
 	break;
 
-      case MSG_WDTR:
+      case WDTR_MSG:
       {
-	bus_width = inb(ACCUM(base));
+	bus_width = inb(ARG_1 + base);
 	printk("aic7xxx: Received MSG_WDTR, Target %d, channel %c "
 	       "needwdtr(0x%x).\n", scsi_id, channel, p->needwdtr);
-	scratch = inb(HA_TARG_SCRATCH(base) + scratch_offset);
+	scratch = inb(TARG_SCRATCH + base + scratch_offset);
 
 	if (p->wdtr_pending & target_mask)
 	{
 	  /*
 	   * Don't send an WDTR back to the target, since we asked first.
 	   */
-	  outb(0, HA_RETURN_1(base));
+	  outb(0, RETURN_1 + base);
 	  switch (bus_width)
 	  {
 	    case BUS_8_BIT:
@@ -2428,6 +1926,12 @@
                      "transfers.\n", scsi_id, channel);
 	      scratch |= 0x80;
 	      break;
+
+	    case BUS_32_BIT:
+	      outb(SEND_REJ, RETURN_1 + base);
+	      printk("aic7xxx: Target %d, channel %c, requesting 32 bit "
+                     "transfers, rejecting...\n", scsi_id, channel);
+	      break;
 	  }
 	}
 	else
@@ -2455,16 +1959,16 @@
 	      scratch |= 0x80;
 	      break;
 	  }
-	  outb(bus_width | SEND_WDTR, HA_RETURN_1(base));
+	  outb(bus_width | SEND_WDTR, RETURN_1 + base);
 	}
 	p->needwdtr &= ~target_mask;
 	p->wdtr_pending &= ~target_mask;
-	outb(scratch, HA_TARG_SCRATCH(base) + scratch_offset);
-	outb(scratch, SCSIRATE(base));
+	outb(scratch, TARG_SCRATCH + base + scratch_offset);
+	outb(scratch, SCSIRATE + base);
 	break;
       }
 
-      case MSG_REJECT:
+      case REJECT_MSG:
       {
 	/*
 	 * What we care about here is if we had an
@@ -2473,7 +1977,7 @@
 	 * the target is refusing negotiation.
 	 */
 
-	scratch = inb(HA_TARG_SCRATCH(base) + scratch_offset);
+	scratch = inb(TARG_SCRATCH + base + scratch_offset);
 
 	if (p->wdtr_pending & target_mask)
 	{
@@ -2483,7 +1987,6 @@
 	  scratch &= 0x7F;
 	  p->needwdtr &= ~target_mask;
 	  p->wdtr_pending &= ~target_mask;
-	  outb(scratch, HA_TARG_SCRATCH(base) + scratch_offset);
 	  printk("aic7xxx: Target %d, channel %c, refusing WIDE negotiation. "
                  "Using 8 bit transfers.\n", scsi_id, channel);
 	}
@@ -2497,7 +2000,6 @@
 	    scratch &= 0xF0;
 	    p->needsdtr &= ~target_mask;
 	    p->sdtr_pending &= ~target_mask;
-	    outb(scratch, HA_TARG_SCRATCH(base) + scratch_offset);
 	    printk("aic7xxx: Target %d, channel %c, refusing synchronous "
                    "negotiation. Using asynchronous transfers.\n",
                    scsi_id, channel);
@@ -2506,16 +2008,16 @@
 	   * Otherwise, we ignore it.
 	   */
 	}
-	outb(scratch, HA_TARG_SCRATCH(base) + scratch_offset);
-	outb(scratch, SCSIRATE(base));
+	outb(scratch, TARG_SCRATCH + base + scratch_offset);
+	outb(scratch, SCSIRATE + base);
 	break;
       }
 
       case BAD_STATUS:
-	scb_index = inb(SCBPTR(base));
+	scb_index = inb(SCBPTR + base);
 	scb = &(p->scb_array[scb_index]);
-	outb(0, HA_RETURN_1(base));   /* CHECK_CONDITION may change this */
-	if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+	outb(0, RETURN_1 + base);   /* CHECK_CONDITION may change this */
+	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
 	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
 		 "scb(%d) state(0x%x) cmd(0x%x).\n",
@@ -2524,7 +2026,7 @@
 	else
 	{
 	  cmd = scb->cmd;
-	  aic7xxx_getscb(base, scb);
+	  aic7xxx_getscb(p, scb);
 	  aic7xxx_status(cmd) = scb->target_status;
 
 	  cmd->result |= scb->target_status;
@@ -2543,6 +2045,7 @@
 		void         *req_buf;
 
                 tcl = scb->target_channel_lun;
+
 		/*
                  * Send a sense command to the requesting target.
                  */
@@ -2558,8 +2061,9 @@
 		req_buf = &scb->sense_sg;
 		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
                 control = scb->control;
-		memset(scb, 0, SCB_DOWNLOAD_SIZE);
-                scb->control = control & SCB_DISCENB;
+
+		memset(scb, 0, SCB_PIO_TRANSFER_SIZE);
+                scb->control = control & DISCENB;
 		scb->target_channel_lun = tcl;
 		addr = scb->sense_cmd;
 		scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
@@ -2568,41 +2072,26 @@
 		scb->SG_segment_count = 1;
 		memcpy(scb->SG_list_pointer, &req_buf,
 			sizeof(scb->SG_list_pointer));
-                scb->data_count[0] = scb->sense_sg.length & 0xFF;
-                scb->data_count[1] = (scb->sense_sg.length >> 8) & 0xFF;
-                scb->data_count[2] = (scb->sense_sg.length >> 16) & 0xFF;
+                scb->data_count = scb->sense_sg.length;
 		memcpy(scb->data_pointer, &(scb->sense_sg.address), 4);
 
-		outb(SCBAUTO, SCBCNT(base));
-		asm volatile("cld\n\t"
-			     "rep\n\t"
-			     "outsb"
-			     : /* no output */
-			     :"S" (scb), "c" (SCB_DOWNLOAD_SIZE), "d" (SCBARRAY(base))
-			     :"si", "cx", "dx");
-		outb(0, SCBCNT(base));
-		outb(SCB_LIST_NULL, (SCBARRAY(base) + 30));
+                aic7xxx_putscb(p, scb);
+		outb(SCB_LIST_NULL, SCB_NEXT_WAITING + base);
                 /*
                  * Ensure that the target is "BUSY" so we don't get overlapping
                  * commands if we happen to be doing tagged I/O.
                  */
-                active = inb(HA_ACTIVE0(base)) | (inb(HA_ACTIVE1(base)) << 8);
-                active |= target_mask;
-                outb(active & 0xFF, HA_ACTIVE0(base));
-                outb((active >> 8) & 0xFF, HA_ACTIVE1(base));
+		aic7xxx_busy_target(scsi_id, channel, base);
 
                 aic7xxx_add_waiting_scb(base, scb, LIST_HEAD);
-		outb(SEND_SENSE, HA_RETURN_1(base));
+		outb(SEND_SENSE, RETURN_1 + base);
 	      }  /* first time sense, no errors */
-	      else
-	      {
-		/*
-		 * Indicate that we asked for sense, have the sequencer do
-		 * a normal command complete, and have the scsi driver handle
-		 * this condition.
-		 */
-		cmd->flags |= ASKED_FOR_SENSE;
-	      }
+
+              cmd->flags &= ~ASKED_FOR_SENSE;
+	      if (aic7xxx_error(cmd) == 0)
+              {
+		aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+              }
 	      break;
 
 	    case BUSY:
@@ -2634,9 +2123,9 @@
 	break;
 
       case RESIDUAL:
-	scb_index = inb(SCBPTR(base));
+	scb_index = inb(SCBPTR + base);
 	scb = &(p->scb_array[scb_index]);
-	if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
 	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
 		 "scb(%d) state(0x%x) cmd(0x%x).\n",
@@ -2659,16 +2148,16 @@
 	     */
 	    actual = aic7xxx_length(cmd, scb->residual_SG_segment_count);
 
-	    actual -= ((inb(SCBARRAY(base + 17)) << 16) |
-		       (inb(SCBARRAY(base + 16)) <<  8) |
-		       inb(SCBARRAY(base + 15)));
+	    actual -= (inb(SCB_RESID_DCNT2 + base) << 16) |
+		      (inb(SCB_RESID_DCNT1 + base) <<  8) |
+		      inb(SCB_RESID_DCNT0 + base);
 
 	    if (actual < cmd->underflow)
 	    {
 	      printk("aic7xxx: Target %d underflow - "
 		     "Wanted (at least) (%u) got(%u) count(%d).\n",
 		     cmd->target, cmd->underflow, actual,
-                     inb(SCBARRAY(base + 18)));
+                     inb(SCB_RESID_SGCNT + base));
 	      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
 	      aic7xxx_status(cmd) = scb->target_status;
 	    }
@@ -2677,9 +2166,9 @@
 	break;
 
       case ABORT_TAG:
-	scb_index = inb(SCBPTR(base));
+	scb_index = inb(SCBPTR + base);
 	scb = &(p->scb_array[scb_index]);
-	if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
 	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
 		 "scb(%d) state(0x%x) cmd(0x%x)\n",
@@ -2702,9 +2191,9 @@
 	break;
 
       case AWAITING_MSG:
-	scb_index = inb(SCBPTR(base));
+	scb_index = inb(SCBPTR + base);
 	scb = &(p->scb_array[scb_index]);
-	if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
 	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
 		 "scb(%d) state(0x%x) cmd(0x%x).\n",
@@ -2723,8 +2212,8 @@
   printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
           scsi_id);
 #endif
-	     outb(MSG_BUS_DEVICE_RESET, HA_MSG_START(base));
-	     outb(1, HA_MSG_LEN(base));
+	     outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
+	     outb(1, MSG_LEN + base);
 	   }
 	   else
 	   {
@@ -2735,7 +2224,7 @@
 	break;
 
       case IMMEDDONE:
-        scb_index = inb(SCBPTR(base));
+        scb_index = inb(SCBPTR + base);
 	scb = &(p->scb_array[scb_index]);
 #ifdef AIC7XXX_DEBUG_ABORT
   printk ("aic7xxx: (isr) received IMMEDDONE for target %d, scb %d, state %d\n",
@@ -2753,9 +2242,9 @@
           p->needwdtr |= (p->needwdtr_copy & target_mask);
           p->sdtr_pending &= ~target_mask;
           p->wdtr_pending &= ~target_mask;
-          scratch = inb(HA_TARG_SCRATCH(base) + scratch_offset);
+          scratch = inb(TARG_SCRATCH + base + scratch_offset);
           scratch &= SXFR;
-          outb(scratch, HA_TARG_SCRATCH(base));
+          outb(scratch, TARG_SCRATCH + base + scratch_offset);
           found = aic7xxx_reset_device(p, (int) scsi_id, channel, SCB_LIST_NULL);
         }
         else
@@ -2764,22 +2253,112 @@
         }
         break;
 
+#if AIC7XXX_NOT_YET
+     /* XXX Fill these in later */
+     case MESG_BUFFER_BUSY:
+       break;
+     case MSGIN_PHASEMIS:
+       break;
+#endif
+
+      case PARITY_ERROR:
+      {
+	scb_index = inb(SCBPTR + base);
+	scb = &(p->scb_array[scb_index]);
+	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+	{
+	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
+		 "scb(%d) state(0x%x) cmd(0x%x).\n",
+		 intstat, scb_index, scb->state, (unsigned int) scb->cmd);
+	}
+	else
+	{
+          char  *phase;
+          unsigned char mesg_out = MSG_NOP;
+          unsigned char lastphase = inb(LASTPHASE + base);
+
+	  cmd = scb->cmd;
+          switch (lastphase)
+          {
+            case P_DATAOUT:
+              phase = "Data-Out";
+              break;
+            case P_DATAIN:
+              phase = "Data-In";
+              mesg_out = MSG_INITIATOR_DET_ERROR;
+              break;
+            case P_COMMAND:
+              phase = "Command";
+              break;
+            case P_MESGOUT:
+              phase = "Message-Out";
+              break;
+            case P_STATUS:
+              phase = "Status";
+              mesg_out = MSG_INITIATOR_DET_ERROR;
+              break;
+            case P_MESGIN:
+              phase = "Message-In";
+              mesg_out = MSG_MSG_PARITY_ERROR;
+              break;
+            default:
+              phase = "unknown";
+              break;
+          }
+
+          /*
+           * A parity error has occurred during a data
+           * transfer phase. Flag it and continue.
+           */
+          printk("aic7xxx: Parity error during phase %s on target %d, "
+                 "channel %d, lun %d.\n", phase,
+                 cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
+
+          /*
+           * We've set the hardware to assert ATN if we get a parity
+           * error on "in" phases, so all we need to do is stuff the
+           * message buffer with the appropriate message. In phases
+           * have set mesg_out to something other than MSG_NOP.
+           */
+          if (mesg_out != MSG_NOP)
+          {
+             outb(mesg_out, MSG0 + base);
+             outb(1, MSG_LEN + base);
+             aic7xxx_error(cmd) = DID_PARITY;
+          }
+          else
+          {
+             /*
+              * Should we allow the target to make this decision for us?
+              */
+             aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+          }
+        }
+        break;
+      }
       default:               /* unknown */
 	debug("aic7xxx: SEQINT, INTSTAT(0x%x) SCSISIGI(0x%x).\n",
-	      intstat, inb(SCSISIGI(base)));
+	      intstat, inb(SCSISIGI + base));
 	break;
     }
-    outb(CLRSEQINT, CLRINT(base));
+
+    outb(CLRSEQINT, CLRINT + base);
     UNPAUSE_SEQUENCER(p);
   }
 
   if (intstat & SCSIINT)
   {
-    int status = inb(SSTAT1(base));
+    int status = inb(SSTAT1 + base);
+    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
+    channel = 'A';
+    if (inb(SBLKCTL + base) & SELBUSB)
+    {
+      channel = 'B';
+    }
 
-    scb_index = inb(SCBPTR(base));
+    scb_index = inb(SCBPTR + base);
     scb = &(p->scb_array[scb_index]);
-    if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+    if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
     {
       printk("aic7xxx: No command for SCB (SCSIINT).\n");
       /*
@@ -2787,10 +2366,9 @@
        * to zero, so that it falls through the
        * reset of the SCSIINT code.
        */
-      outb(status, CLRSINT1(base));
+      outb(status, CLRSINT1 + base);
       UNPAUSE_SEQUENCER(p);
-      outb(CLRSCSIINT, CLRINT(base));
-      status = 0;
+      outb(CLRSCSIINT, CLRINT + base);
       scb = NULL;
     }
     else
@@ -2806,36 +2384,23 @@
        */
       if (status & SELTO)
       {
-	unsigned char target_mask = (1 << (cmd->target & 0x07));
 	unsigned char waiting;
 
 	/*
 	 * Hardware selection timer has expired. Turn
 	 * off SCSI selection sequence.
 	 */
-	outb(ENRSELI, SCSISEQ(base));
+	outb(ENRSELI, SCSISEQ + base);
 	cmd->result = (DID_TIME_OUT << 16);
 	/*
 	 * Clear an pending messages for the timed out
 	 * target and mark the target as free.
 	 */
-	ha_flags = inb(HA_FLAGS(base));
-	outb(ha_flags & ~ACTIVE_MSG, HA_FLAGS(base));
-
-	if (scb->target_channel_lun & 0x88)
-	{
-	  active = inb(HA_ACTIVE1(base));
-	  active = active & ~(target_mask);
-	  outb(active, HA_ACTIVE1(base));
-	}
-	else
-	{
-	  active = inb(HA_ACTIVE0(base));
-	  active &= ~(target_mask);
-	  outb(active, HA_ACTIVE0(base));
-	}
+	ha_flags = inb(FLAGS + base);
+	outb(0, MSG_LEN + base);
+        aic7xxx_unbusy_target(scsi_id, channel, base);
 
-	outb(SCB_NEEDDMA, SCBARRAY(base));
+	outb(0, SCBARRAY + base);
 
 	/*
 	 * Shut off the offending interrupt sources, reset
@@ -2852,17 +2417,17 @@
 	 * with an Illegal Host Address status, so the
 	 * sequencer has to be restarted first.
 	 */
-	outb(CLRSELTIMEO, CLRSINT1(base));
+	outb(CLRSELTIMEO, CLRSINT1 + base);
 
-	outb(CLRSCSIINT, CLRINT(base));
+	outb(CLRSCSIINT, CLRINT + base);
 
 	/*
          * Shift the waiting for selection queue forward
          */
-	waiting = inb(WAITING_SCBH(base));
-	outb(waiting, SCBPTR(base));
-	waiting = inb(SCBARRAY(base) + 30);
-	outb(waiting, WAITING_SCBH(base));
+	waiting = inb(WAITING_SCBH + base);
+	outb(waiting, SCBPTR + base);
+	waiting = inb(SCB_NEXT_WAITING + base);
+	outb(waiting, WAITING_SCBH + base);
 
 	RESTART_SEQUENCER(p);
         aic7xxx_done(p, scb);
@@ -2873,40 +2438,17 @@
       }
       else
       {
-	if (status & SCSIPERR)
-	{
-	  /*
-	   * A parity error has occurred during a data
-	   * transfer phase. Flag it and continue.
-	   */
-	  printk("aic7xxx: Parity error on target %d, channel %d, lun %d.\n",
-		 cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
-	  aic7xxx_error(cmd) = DID_PARITY;
-
-	  /*
-	   * Clear interrupt and resume as above.
-	   */
-	  outb(CLRSCSIPERR, CLRSINT1(base));
-	  UNPAUSE_SEQUENCER(p);
-
-	  outb(CLRSCSIINT, CLRINT(base));
-	  scb = NULL;
-	}
-	else
-	{
-	  if (!(status & BUSFREE))
-	  {
-	     /*
-	      * We don't know what's going on. Turn off the
-	      * interrupt source and try to continue.
-	      */
-	     printk("aic7xxx: SSTAT1(0x%x).\n", status);
-	     outb(status, CLRSINT1(base));
-	     UNPAUSE_SEQUENCER(p);
-	     outb(CLRSCSIINT, CLRINT(base));
-	     scb = NULL;
-	  }
-	}
+        if (!(status & BUSFREE))
+        {
+           /*
+            * We don't know what's going on. Turn off the
+            * interrupt source and try to continue.
+            */
+           printk("aic7xxx: SSTAT1(0x%x).\n", status);
+           outb(status, CLRSINT1 + base);
+           UNPAUSE_SEQUENCER(p);
+           outb(CLRSCSIINT, CLRINT + base);
+        }
       }
     }  /* else */
   }
@@ -2921,21 +2463,20 @@
      * finished, so loop until we've processed them all.
      */
     do {
-      complete = inb(QOUTFIFO(base));
+      complete = inb(QOUTFIFO + base);
 
       scb = &(p->scb_array[complete]);
-      if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+      if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
       {
 	printk("aic7xxx: Warning - No command for SCB %d (CMDCMPLT).\n"
 	       "         QOUTCNT(%d) SCB state(0x%x) cmd(0x%x) pos(%d).\n",
-	       complete, inb(QOUTFIFO(base)),
+	       complete, inb(QOUTFIFO + base),
 	       scb->state, (unsigned int) scb->cmd, scb->position);
-	outb(CLRCMDINT, CLRINT(base));
+	outb(CLRCMDINT, CLRINT + base);
 	continue;
       }
       cmd = scb->cmd;
 
-      cmd->result = (aic7xxx_error(cmd) << 16) | aic7xxx_status(cmd);
       if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
       {
         /*
@@ -2957,7 +2498,7 @@
        * command being complete never made it back
        * up to the kernel.
        */
-      outb(CLRCMDINT, CLRINT(base));
+      outb(CLRCMDINT, CLRINT + base);
       aic7xxx_done(p, scb);
 #if 0
   if (scb != &p->scb_array[scb->position])
@@ -2974,7 +2515,7 @@
        * XXX: for each command, but apparently that's too difficult.
        */
       actual = aic7xxx_length(cmd, 0);
-      if (((cmd->flags & WAS_SENSE) == 0) && (actual > 0))
+      if (!(cmd->flags & WAS_SENSE) && (actual > 0))
       {
         struct aic7xxx_xferstats *sp;
         long *ptr;
@@ -3010,7 +2551,7 @@
       }
 #endif /* AIC7XXX_PROC_STATS */
 
-    } while (inb(QOUTCNT(base)));
+    } while (inb(QOUTCNT + base));
   }
 }
 
@@ -3118,11 +2659,11 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(STATUS_2840(base)) & EEPROM_TF) == 0)	\
+  while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0)	\
   {						\
     ;  /* Do nothing */				\
   }						\
-  (void) inb(SEECTL_2840(base));
+  (void) inb(SEECTL_2840 + base);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -3135,7 +2676,7 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, SEECTL_2840(base));
+    outb(CK_2840 | CS_2840, SEECTL_2840 + base);
     CLOCK_PULSE(base);
 
     /*
@@ -3145,10 +2686,10 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, SEECTL_2840(base));
+      outb(temp, SEECTL_2840 + base);
       CLOCK_PULSE(base);
       temp = temp ^ CK_2840;
-      outb(temp, SEECTL_2840(base));
+      outb(temp, SEECTL_2840 + base);
       CLOCK_PULSE(base);
     }
     /*
@@ -3159,10 +2700,10 @@
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, SEECTL_2840(base));
+      outb(temp, SEECTL_2840 + base);
       CLOCK_PULSE(base);
       temp = temp ^ CK_2840;
-      outb(temp, SEECTL_2840(base));
+      outb(temp, SEECTL_2840 + base);
       CLOCK_PULSE(base);
     }
 
@@ -3175,11 +2716,11 @@
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, SEECTL_2840(base));
+      outb(temp, SEECTL_2840 + base);
       CLOCK_PULSE(base);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840(base)) & DI_2840);
-      outb(temp, SEECTL_2840(base));
+      seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
+      outb(temp, SEECTL_2840 + base);
       CLOCK_PULSE(base);
     }
     /*
@@ -3196,11 +2737,11 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, SEECTL_2840(base));
+    outb(0, SEECTL_2840 + base);
     CLOCK_PULSE(base);
-    outb(CK_2840, SEECTL_2840(base));
+    outb(CK_2840, SEECTL_2840 + base);
     CLOCK_PULSE(base);
-    outb(0, SEECTL_2840(base));
+    outb(0, SEECTL_2840 + base);
     CLOCK_PULSE(base);
   }
 
@@ -3292,7 +2833,7 @@
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(SEECTL(base)) & SEERDY) == 0)	\
+  while ((inb(SEECTL + base) & SEERDY) == 0)	\
   {						\
     ;  /* Do nothing */				\
   }
@@ -3304,15 +2845,15 @@
    * is needed.  Reason: after the 7870 chip reset, there
    * should be no contention.
    */
-  outb(SEEMS, SEECTL(base));
+  outb(SEEMS, SEECTL + base);
   timeout = jiffies + 100;  /* 1 second timeout */
-  while ((jiffies < timeout) && ((inb(SEECTL(base)) & SEERDY) == 0))
+  while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
   {
     ; /* Do nothing!  Wait for access to be granted.  */
   }
-  if ((inb(SEECTL(base)) & SEERDY) == 0)
+  if ((inb(SEECTL + base) & SEERDY) == 0)
   {
-    outb(0, SEECTL(base));
+    outb(0, SEECTL + base);
     return (0);
   }
 
@@ -3327,7 +2868,7 @@
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, SEECTL(base));
+    outb(SEEMS | SEECK | SEECS, SEECTL + base);
     CLOCK_PULSE(base);
 
     /*
@@ -3337,10 +2878,10 @@
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, SEECTL(base));
+      outb(temp, SEECTL + base);
       CLOCK_PULSE(base);
       temp = temp ^ SEECK;
-      outb(temp, SEECTL(base));
+      outb(temp, SEECTL + base);
       CLOCK_PULSE(base);
     }
     /*
@@ -3351,10 +2892,10 @@
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, SEECTL(base));
+      outb(temp, SEECTL + base);
       CLOCK_PULSE(base);
       temp = temp ^ SEECK;
-      outb(temp, SEECTL(base));
+      outb(temp, SEECTL + base);
       CLOCK_PULSE(base);
     }
 
@@ -3367,11 +2908,11 @@
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, SEECTL(base));
+      outb(temp, SEECTL + base);
       CLOCK_PULSE(base);
       temp = temp ^ SEECK;
-      seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL(base)) & SEEDI);
-      outb(temp, SEECTL(base));
+      seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
+      outb(temp, SEECTL + base);
       CLOCK_PULSE(base);
     }
 
@@ -3389,18 +2930,18 @@
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, SEECTL(base));
+    outb(SEEMS, SEECTL + base);
     CLOCK_PULSE(base);
-    outb(SEEMS | SEECK, SEECTL(base));
+    outb(SEEMS | SEECK, SEECTL + base);
     CLOCK_PULSE(base);
-    outb(SEEMS, SEECTL(base));
+    outb(SEEMS, SEECTL + base);
     CLOCK_PULSE(base);
   }
 
   /*
    * Release access to the memory port and the serial EEPROM.
    */
-  outb(0, SEECTL(base));
+  outb(0, SEECTL + base);
 
 #if 0
   printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
@@ -3451,22 +2992,22 @@
        * we limit them, along with the Rev C chips, to 4 SCBs.
        *
        * The Rev E boards have a read/write autoflush bit in the
-       * SBLKCTL registor, while in the Rev C boards it is read only.
+       * SBLKCTL register, while in the Rev C boards it is read only.
        */
-      sblkctl_reg = inb(SBLKCTL(base)) ^ AUTOFLUSHDIS;
-      outb(sblkctl_reg, SBLKCTL(base));
-      if (inb(SBLKCTL(base)) == sblkctl_reg)
+      sblkctl_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
+      outb(sblkctl_reg, SBLKCTL + base);
+      if (inb(SBLKCTL + base) == sblkctl_reg)
       {
         /*
          * We detected a Rev E board.
          */
-	printk("aic7770: Rev E and subsequent; using 4 SCB's.\n");
-	outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL(base));
+        printk("aic7xxx: %s Rev E and subsequent.\n", board_names[type]);
+	outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
 	maxscb = 4;
       }
       else
       {
-	printk("aic7770: Rev C and previous; using 4 SCB's.\n");
+        printk("aic7xxx: %s Rev C and previous.\n", board_names[type]);
 	maxscb = 4;
       }
       break;
@@ -3501,6 +3042,7 @@
        */
       break;
   }
+
   if (walk_scbs)
   {
     /*
@@ -3510,16 +3052,22 @@
     i = 0;
     while (i < AIC7XXX_MAXSCB)
     {
-      outb(i, SCBPTR(base));
-      scb_byte = ~(inb(SCBARRAY(base)));  /* complement the byte */
-      outb(scb_byte, SCBARRAY(base));     /* write it back out */
-      if (inb(SCBARRAY(base)) != scb_byte)
+      outb(i, SCBPTR + base);
+      scb_byte = ~(inb(SCBARRAY + base));  /* complement the byte */
+      outb(scb_byte, SCBARRAY + base);     /* write it back out */
+      if (inb(SCBARRAY + base) != scb_byte)
       {
         break;
       }
       i++;
     }
     maxscb = i;
+
+    printk("aic7xxx: Using %d SCB's after checking for SCB memory.\n", maxscb);
+  }
+  else
+  {
+    printk("aic7xxx: Using %d SCB's; No SCB memory check.\n", maxscb);
   }
 
   return (maxscb);
@@ -3540,10 +3088,10 @@
   unsigned char sblkctl;
   int max_targets;
   int found = 1, base;
-  int bios_disabled = 0;
+  int bios_disabled = FALSE;
   unsigned char target_settings;
   unsigned char scsi_conf, host_conf;
-  int have_seeprom = 0;
+  int have_seeprom = FALSE;
   struct Scsi_Host *host;
   struct aic7xxx_host *p;
   struct seeprom_config sc;
@@ -3553,7 +3101,7 @@
   /*
    * Lock out other contenders for our i/o space.
    */
-  request_region(MINREG(base), MAXREG(base) - MINREG(base), "aic7xxx");
+  request_region(MINREG + base, MAXREG - MINREG, "aic7xxx");
 
   switch (config->type)
   {
@@ -3569,33 +3117,33 @@
        * trigger type (level or edge) and use this value
        * for pausing and unpausing the sequencer.
        */
-      config->unpause = (inb(HCNTRL(base)) & IRQMS) | INTEN;
+      config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN;
       config->pause = config->unpause | PAUSE;
       config->extended = aic7xxx_extended;
 
-      outb(config->pause | CHIPRST, HCNTRL(base));
+      outb(config->pause | CHIPRST, HCNTRL + base);
       aic7xxx_delay(1);
-      if (inb(HCNTRL(base)) & CHIPRST)
+      if (inb(HCNTRL + base) & CHIPRST)
       {
 	printk("aic7xxx: Chip reset not cleared; clearing manually.\n");
       }
-      outb(config->pause, HCNTRL(base));
+      outb(config->pause, HCNTRL + base);
 
       /*
        * Just to be on the safe side with the 274x, we will re-read the irq
-       * since there was some issue about reseting the board.
+       * since there was some issue about resetting the board.
        */
-      config->irq = inb(HA_INTDEF(base)) & 0x0F;
-      if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
+      config->irq = inb(INTDEF + base) & 0x0F;
+      if ((inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
       {
-        bios_disabled = 1;
+        bios_disabled = TRUE;
       }
-      host_conf = inb(HA_HOSTCONF(base));
+      host_conf = inb(HOSTCONF + base);
       config->busrtime = host_conf & 0x3C;
       /* XXX Is this valid for motherboard based controllers? */
       /* Setup the FIFO threshold and the bus off time */
-      outb(host_conf & DFTHRSH, BUSSPD(base));
-      outb((host_conf << 2) & BOFF, BUSTIME(base));
+      outb(host_conf & DFTHRSH, BUSSPD + base);
+      outb((host_conf << 2) & BOFF, BUSTIME + base);
 
       /*
        * A reminder until this can be detected automatically.
@@ -3605,19 +3153,19 @@
       break;
 
     case AIC_284x:
-      outb(CHIPRST, HCNTRL(base));
+      outb(CHIPRST, HCNTRL + base);
       config->unpause = UNPAUSE_284X;
       config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
       aic7xxx_delay(1);
-      outb(config->pause, HCNTRL(base));
+      outb(config->pause, HCNTRL + base);
 
       config->extended = aic7xxx_extended;
-      config->irq = inb(HA_INTDEF(base)) & 0x0F;
-      if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
+      config->irq = inb(INTDEF + base) & 0x0F;
+      if ((inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
       {
-        bios_disabled = 1;
+        bios_disabled = TRUE;
       }
-      host_conf = inb(HA_HOSTCONF(base));
+      host_conf = inb(HOSTCONF + base);
 
       printk("aic7xxx: Reading SEEPROM...");
       have_seeprom = read_2840_seeprom(base, &sc);
@@ -3647,8 +3195,8 @@
       }
       /* XXX Is this valid for motherboard based controllers? */
       /* Setup the FIFO threshold and the bus off time */
-      outb(host_conf & DFTHRSH, BUSSPD(base));
-      outb((host_conf << 2) & BOFF, BUSTIME(base));
+      outb(host_conf & DFTHRSH, BUSSPD + base);
+      outb((host_conf << 2) & BOFF, BUSTIME + base);
 
       printk("aic7xxx: Extended translation %sabled.\n",
 	     config->extended ? "en" : "dis");
@@ -3665,11 +3213,11 @@
     case AIC_7882:
     case AIC_7883:
     case AIC_7884:
-      outb(CHIPRST, HCNTRL(base));
+      outb(CHIPRST, HCNTRL + base);
       config->unpause = UNPAUSE_294X;
       config->pause = config->unpause | PAUSE;
       aic7xxx_delay(1);
-      outb(config->pause, HCNTRL(base));
+      outb(config->pause, HCNTRL + base);
 
       config->extended = aic7xxx_extended;
       config->scsi_id = 7;
@@ -3704,14 +3252,17 @@
       /*
        * XXX - force data fifo threshold to 100%. Why does this
        *       need to be done?
+       *
+       * We don't know where this is set in the SEEPROM or by the BIOS,
+       * so we default it to 100%.
        */
-      outb(inb(DSPCISTATUS(base)) | DFTHRESH, DSPCISTATUS(base));
-      outb(config->scsi_id | DFTHRESH, HA_SCSICONF(base));
+      outb(config->scsi_id | DFTHRSH_100, SCSICONF + base);
+      outb(DFTHRSH_100, DSPCISTATUS + base);
 
       /*
        * In case we are a wide card, place scsi ID in second conf byte.
        */
-      outb(config->scsi_id, (HA_SCSICONF(base) + 1));
+      outb(config->scsi_id, (SCSICONF + base + 1));
 
       printk("aic7xxx: Extended translation %sabled.\n",
 	     config->extended ? "en" : "dis");
@@ -3739,43 +3290,43 @@
    * Read the bus type from the SBLKCTL register. Set the FLAGS
    * register in the sequencer for twin and wide bus cards.
    */
-  sblkctl = inb(SBLKCTL(base));
+  sblkctl = inb(SBLKCTL + base);
   switch (sblkctl & SELBUS_MASK)
   {
-    case SELSINGLE:     /* narrow/normal bus */
-      config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+    case SELNARROW:     /* narrow/normal bus */
+      config->scsi_id = inb(SCSICONF + base) & 0x07;
       config->bus_type = AIC_SINGLE;
-      outb(SINGLE_BUS, HA_FLAGS(base));
+      outb(SINGLE_BUS, FLAGS + base);
       break;
 
     case SELWIDE:     /* Wide bus */
-      config->scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
+      config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
       config->bus_type = AIC_WIDE;
       printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
 	     board_names[config->type]);
-      outb(WIDE_BUS, HA_FLAGS(base));
+      outb(WIDE_BUS, FLAGS + base);
       break;
 
     case SELBUSB:     /* Twin bus */
-      config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+      config->scsi_id = inb(SCSICONF + base) & 0x07;
 #ifdef AIC7XXX_TWIN_SUPPORT
-      config->scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
+      config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
       config->bus_type = AIC_TWIN;
       printk("aic7xxx: Enabled channel B of %s-Twin.\n",
 	     board_names[config->type]);
-      outb(TWIN_BUS, HA_FLAGS(base));
+      outb(TWIN_BUS, FLAGS + base);
 #else
       config->bus_type = AIC_SINGLE;
       printk("aic7xxx: Channel B of %s-Twin will be ignored.\n",
 	     board_names[config->type]);
-      outb(0, HA_FLAGS(base));
+      outb(0, FLAGS + base);
 #endif
       break;
 
     default:
       printk("aic7xxx: Unsupported type 0x%x, please "
-	     "mail deang@ims.com\n", inb(SBLKCTL(base)));
-      outb(0, HA_FLAGS(base));
+	     "mail deang@ims.com\n", inb(SBLKCTL + base));
+      outb(0, FLAGS + base);
       return (0);
   }
 
@@ -3784,7 +3335,7 @@
    * take the card out of diagnostic mode and make the host adatper
    * LED follow bus activity (will not always be on).
    */
-  outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL(base));
+  outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + base);
 
   /*
    * The IRQ level in i/o port 4 maps directly onto the real
@@ -3878,8 +3429,8 @@
   }
 
   p->isr_count = 0;
-  p->a_scanned = 0;
-  p->b_scanned = 0;
+  p->a_scanned = FALSE;
+  p->b_scanned = FALSE;
   p->base = base;
   p->maxscb = config->maxscb;
   p->numscb = 0;
@@ -3942,11 +3493,11 @@
   /*
    * Set Fast Mode and Enable the board
    */
-  outb(FASTMODE, SEQCTL(base));
+  outb(FASTMODE, SEQCTL + base);
 
   if (p->chip_type == AIC_777x)
   {
-    outb(ENABLE, BCTL(base));
+    outb(ENABLE, BCTL + base);
   }
 
   printk("done.\n");
@@ -3959,29 +3510,37 @@
     /*
      * Select Channel B.
      */
-    outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
+    outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
 
-    outb(config->scsi_id_b, SCSIID(base));
-    scsi_conf = inb(HA_SCSICONF(base) + 1) & (ENSPCHK | STIMESEL);
-    outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
-    outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+    outb(config->scsi_id_b, SCSIID + base);
+    scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
+    outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
+    outb(ENSELTIMO , SIMODE1 + base);
     if (p->ultra_enabled)
     {
-      outb(ULTRAEN, SXFRCTL0(base));
+      outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+    }
+    else
+    {
+      outb(DFON | SPIOEN, SXFRCTL0 + base);
     }
 
     /*
      * Select Channel A
      */
-    outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
+    outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
   }
-  outb(config->scsi_id, SCSIID(base));
-  scsi_conf = inb(HA_SCSICONF(base)) & (ENSPCHK | STIMESEL);
-  outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
-  outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+  outb(config->scsi_id, SCSIID + base);
+  scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
+  outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
+  outb(ENSELTIMO , SIMODE1 + base);
   if (p->ultra_enabled)
   {
-    outb(ULTRAEN, SXFRCTL0(base));
+    outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+  }
+  else
+  {
+    outb(DFON | SPIOEN, SXFRCTL0 + base);
   }
 
   /*
@@ -3992,10 +3551,10 @@
    * BIOS has decided to disable synchronous negotiation to that
    * target so we don't activate the needsdtr flag.
    */
-  p->needsdtr_copy = 0;
-  p->sdtr_pending = 0;
-  p->needwdtr_copy = 0;
-  p->wdtr_pending = 0;
+  p->needsdtr_copy = 0x0;
+  p->sdtr_pending = 0x0;
+  p->needwdtr_copy = 0x0;
+  p->wdtr_pending = 0x0;
   if (p->bus_type == AIC_SINGLE)
   {
     max_targets = 8;
@@ -4010,7 +3569,7 @@
    */
   if (have_seeprom)
   {
-    p->discenable = 0;
+    p->discenable = 0x0;
   }
   else
   {
@@ -4022,8 +3581,8 @@
     }
     else
     {
-      p->discenable = ~((inb(HA_DISC_DSB(base) + 1) << 8) |
-          inb(HA_DISC_DSB(base)));
+      p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
+          inb(DISC_DSB + base));
     }
   }
 
@@ -4036,7 +3595,7 @@
       {
 	p->needsdtr_copy |= (0x01 << i);
       }
-      if ((sc.device_flags[i] & CFWIDEB) && (p->bus_type == AIC_WIDE))
+      if (sc.device_flags[i] & CFWIDEB)
       {
 	p->needwdtr_copy |= (0x01 << i);
       }
@@ -4047,29 +3606,42 @@
     }
     else
     {
-      target_settings = inb(HA_TARG_SCRATCH(base) + i);
-      if (target_settings & 0x0F)
+      if (bios_disabled)
       {
-	p->needsdtr_copy |= (0x01 << i);
-	/*
-	 * Default to asynchronous transfers (0 offset)
-	 */
-	target_settings &= 0xF0;
+        target_settings = 0;  /* 10 MHz */
+        p->needsdtr_copy |= (0x01 << i);
+        p->needwdtr_copy |= (0x01 << i);
       }
-      /*
-       * If we are not wide, forget WDTR. This makes the driver
-       * work on some cards that don't leave these fields cleared
-       * when BIOS is not installed.
-       */
-      if ((target_settings & 0x80) && (p->bus_type == AIC_WIDE))
+      else
       {
-	p->needwdtr_copy |= (0x01 << i);
-	target_settings &= 0x7F;
+        target_settings = inb(TARG_SCRATCH + base + i);
+        if (target_settings & 0x0F)
+        {
+          p->needsdtr_copy |= (0x01 << i);
+          /*
+           * Default to asynchronous transfers (0 offset)
+           */
+          target_settings &= 0xF0;
+        }
+        if (target_settings & 0x80)
+        {
+          p->needwdtr_copy |= (0x01 << i);
+          target_settings &= 0x7F;
+        }
       }
     }
-    outb(target_settings, (HA_TARG_SCRATCH(base) + i));
+    outb(target_settings, (TARG_SCRATCH + base + i));
   }
 
+  /*
+   * If we are not wide, forget WDTR. This makes the driver
+   * work on some cards that don't leave these fields cleared
+   * when BIOS is not installed.
+   */
+  if (p->bus_type != AIC_WIDE)
+  {
+    p->needwdtr = 0;
+  }
   p->needsdtr = p->needsdtr_copy;
   p->needwdtr = p->needwdtr_copy;
 #if 0
@@ -4083,27 +3655,33 @@
    */
   for (i = 0; i < config->maxscb; i++)
   {
-    outb(i, SCBPTR(base));
-    outb(0, SCBARRAY(base));
+    outb(i, SCBPTR + base);
+    outb(0, SCBARRAY + base);
   }
 
   /*
    * For reconnecting targets, the sequencer code needs to
    * know how many SCBs it has to search through.
    */
-  outb(config->maxscb, HA_SCBCOUNT(base));
+  outb(config->maxscb, SCBCOUNT + base);
+
+  /*
+   * 2s compliment of SCBCOUNT
+   */
+  i = p->maxscb;
+  outb(-i & 0xff, COMP_SCBCOUNT + base);
 
   /*
    * Clear the active flags - no targets are busy.
    */
-  outb(0, HA_ACTIVE0(base));
-  outb(0, HA_ACTIVE1(base));
+  outb(0, ACTIVE_A + base);
+  outb(0, ACTIVE_B + base);
 
   /*
    * We don't have any waiting selections
    */
-  outb(SCB_LIST_NULL, WAITING_SCBH(base));
-  outb(SCB_LIST_NULL, WAITING_SCBT(base));
+  outb(SCB_LIST_NULL, WAITING_SCBH + base);
+  outb(SCB_LIST_NULL, WAITING_SCBT + base);
 
   /*
    * Reset the SCSI bus. Is this necessary?
@@ -4126,21 +3704,21 @@
       /*
        * Select Channel B.
        */
-      outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
+      outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
 
-      outb(SCSIRSTO, SCSISEQ(base));
+      outb(SCSIRSTO, SCSISEQ + base);
       udelay(1000);
-      outb(0, SCSISEQ(base));
+      outb(0, SCSISEQ + base);
 
       /*
        * Select Channel A.
        */
-      outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
+      outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
     }
 
-    outb(SCSIRSTO, SCSISEQ(base));
+    outb(SCSIRSTO, SCSISEQ + base);
     udelay(1000);
-    outb(0, SCSISEQ(base));
+    outb(0, SCSISEQ + base);
 
     aic7xxx_delay(AIC7XXX_RESET_DELAY);
 
@@ -4196,9 +3774,9 @@
    */
   for (slot = MINSLOT; slot <= MAXSLOT; slot++)
   {
-    base = SLOTBASE(slot);
+    base = SLOTBASE(slot) + MINREG;
 
-    if (check_region(MINREG(base), MAXREG(base) - MINREG(base)))
+    if (check_region(MINREG + base, MAXREG - MINREG))
     {
       /*
        * Some other driver has staked a
@@ -4207,7 +3785,7 @@
       continue;
     }
 
-    config.type = aic7xxx_probe(slot, HID0(base));
+    config.type = aic7xxx_probe(slot, HID0 + base);
     if (config.type != AIC_NONE)
     {
       /*
@@ -4269,7 +3847,9 @@
     unsigned int io_port;
     unsigned short index = 0;
     unsigned char pci_bus, pci_device_fn;
-    unsigned char devrevid, devconfig, devstatus;
+    unsigned int  csize_lattime;
+    unsigned int  class_revid;
+    unsigned int  devconfig;
     char rev_id[] = {'B', 'C', 'D'};
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -4287,10 +3867,13 @@
         {
           config.type = aic7xxx_pci_devices[i].card_type;
           config.chip_type = aic7xxx_pci_devices[i].chip_type;
+          config.chan_num = 0;
+          config.walk_scbs = FALSE;
           switch (config.type)
           {
             case AIC_7872:  /* 3940 */
             case AIC_7882:  /* 3940-Ultra */
+              config.walk_scbs = TRUE;
               config.chan_num = number_of_39xxs & 0x1;  /* Has 2 controllers */
               number_of_39xxs++;
               if (number_of_39xxs == 2)
@@ -4313,69 +3896,67 @@
               break;
           }
 
-	  /*
-	   * Read esundry information from PCI BIOS.
-	   */
-	  error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-					    PCI_BASE_ADDRESS_0, &io_port);
-	  if (error)
-	  {
-	    panic("aic7xxx: (aic7xxx_detect) Error %d reading I/O port.\n",
-                  error);
-	  }
-
-	  error = pcibios_read_config_byte(pci_bus, pci_device_fn,
-					   PCI_INTERRUPT_LINE, &irq);
-	  if (error)
-	  {
-	    panic("aic7xxx: (aic7xxx_detect) Error %d reading IRQ.\n",
-                   error);
-	  }
-
-	  error = pcibios_read_config_byte(pci_bus, pci_device_fn,
-					   DEVREVID, &devrevid);
-	  if (error)
-	  {
-	    panic("aic7xxx: (aic7xxx_detect) Error %d reading device "
-                  "revision ID.\n", error);
-	  }
-
-	  if (devrevid < 3)
-	  {
-	    printk("aic7xxx: %s Rev %c.\n", board_names[config.type],
-                   rev_id[devrevid]);
-	  }
+          /*
+           * Read esundry information from PCI BIOS.
+           */
+          error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                            PCI_BASE_ADDRESS_0, &io_port);
+          error += pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                            PCI_INTERRUPT_LINE, &irq);
 
-	  error = pcibios_read_config_byte(pci_bus, pci_device_fn,
-					   DEVCONFIG, &devconfig);
-	  if (error)
-	  {
-	    panic("aic7xxx: (aic7xxx_detect) Error %d reading device "
-                  "configuration.\n", error);
-	  }
+          /*
+           * Ensure that we are using good values for the PCI burst size
+           * and latency timer.
+           */
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             CSIZE_LATTIME, &csize_lattime);
+          if ((csize_lattime & CACHESIZE) == 0)
+          {
+            /* Default to 8DWDs - what's the PCI define for this? */
+            csize_lattime |= 8;
+          }
+          if((csize_lattime & LATTIME) == 0)
+          {
+            /* Default to 64 PCLKS (is this a good value?) */
+            /* This may also be availble in the SEEPROM?? */
+            csize_lattime |= (64 << 8);
+          }
+          pcibios_write_config_dword(pci_bus, pci_device_fn,
+                                     CSIZE_LATTIME, csize_lattime);
+          printk("aic7xxx: BurstLen = %d DWDs, Latency Timer = %d PCLKS\n",
+                  (int) (csize_lattime & CACHESIZE),
+                  (csize_lattime >> 8) & 0x000000ff);
+
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             CLASS_PROGIF_REVID, &class_revid);
+          if ((class_revid & DEVREVID) < 3)
+          {
+            printk("aic7xxx: %s Rev %c.\n", board_names[config.type],
+                   rev_id[class_revid & DEVREVID]);
+          }
 
-	  error = pcibios_read_config_byte(pci_bus, pci_device_fn,
-					   DEVSTATUS, &devstatus);
-	  if (error)
-	  {
-	    panic("aic7xxx: (aic7xxx_detect) Error %d reading device status.\n",
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             DEVCONFIG, &devconfig);
+          if (error)
+          {
+            panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
                   error);
-	  }
+          }
 
-	  printk("aic7xxx: devconfig(0x%x) devstatus(0x%x).\n",
-	         devconfig, devstatus);
+          printk("aic7xxx: devconfig = 0x%x.\n", devconfig);
 
-	  /*
-	   * Make the base I/O register look like EISA and VL-bus.
-	   */
-	  base = io_port - 0xC01;
+          /*
+           * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+           * we mask it off.
+           */
+          base = io_port & 0xfffffffe;
 
-	  /*
-	   * I don't think we need to bother with allowing
-	   * spurious interrupts for the 787x/7850, but what
-	   * the hey.
-	   */
-	  aic7xxx_spurious_count = 1;
+          /*
+           * I don't think we need to bother with allowing
+           * spurious interrupts for the 787x/7850, but what
+           * the hey.
+           */
+          aic7xxx_spurious_count = 1;
 
           config.base = base;
           config.irq = irq;
@@ -4383,20 +3964,39 @@
           config.low_term = AIC_UNKNOWN;
           config.high_term = AIC_UNKNOWN;
           config.busrtime = 0;
-          config.walk_scbs = FALSE;
           config.ultra_enabled = FALSE;
-	  if ((devstatus & RAMPSM) || (devconfig & SCBRAMSEL))
-	  {
+          if (devconfig & RAMPSM)
+          {
+            /*
+             * External SRAM present.  Have the probe walk the SCBs to see
+             * how much SRAM we have and set the number of SCBs accordingly.
+             * We have to turn off SCBRAMSEL to access the external SCB
+             * SRAM.
+             *
+             * It seems that early versions of the aic7870 didn't use these
+             * bits, hence the hack for the 3940 above.  I would guess that
+             * recent 3940s using later aic7870 or aic7880 chips do actually
+             * set RAMPSM.
+             *
+             * The documentation isn't clear, but it sounds like the value
+             * written to devconfig must not have RAMPSM set.  The second
+             * sixteen bits of the register are R/O anyway, so it shouldn't
+             * affect RAMPSM either way.
+             */
+            printk ("aic7xxx: External RAM detected. Enabling RAM access.\n");
+            devconfig &= ~(RAMPSM | SCBRAMSEL);
+            pcibios_write_config_dword(pci_bus, pci_device_fn,
+                                       DEVCONFIG, devconfig);
             config.walk_scbs = TRUE;
-	  }
-	  found += aic7xxx_register(template, &config);
+          }
+          found += aic7xxx_register(template, &config);
 
-	  /*
-	   * Disable spurious interrupts.
-	   */
-	  aic7xxx_spurious_count = 0;
+          /*
+           * Disable spurious interrupts.
+           */
+          aic7xxx_spurious_count = 0;
 
-	  index++;
+          index++;
         }  /* Found an Adaptec PCI device. */
       }
     }
@@ -4440,18 +4040,18 @@
     }
     cmd->tag = cmd->device->current_tag;
     cmd->device->current_tag++;
-    scb->control |= SCB_TE;
+    scb->control |= TAG_ENB;
   }
 #endif
   mask = (0x01 << (cmd->target | (cmd->channel << 3)));
   if (p->discenable & mask)
   {
-    scb->control |= SCB_DISCENB;
+    scb->control |= DISCENB;
   }
   if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
   {
     p->wdtr_pending |= mask;
-    scb->control |= SCB_NEEDWDTR;
+    scb->control |= NEEDWDTR;
 #if 0
     printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
 #endif
@@ -4461,7 +4061,7 @@
     if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
     {
       p->sdtr_pending |= mask;
-      scb->control |= SCB_NEEDSDTR;
+      scb->control |= NEEDSDTR;
 #if 0
       printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
 #endif
@@ -4493,18 +4093,16 @@
 
   if (cmd->use_sg)
   {
-#if 0
-    debug("aic7xxx: (build_scb) SG used, %d segments, length(%u).\n",
-           cmd->use_sg, length);
-#endif
     scb->SG_segment_count = cmd->use_sg;
     memcpy(scb->SG_list_pointer, &cmd->request_buffer,
 	   sizeof(scb->SG_list_pointer));
     memcpy(&sg, &cmd->request_buffer, sizeof(sg));
     memcpy(scb->data_pointer, &(sg[0].address), sizeof(scb->data_pointer));
-    scb->data_count[0] = sg[0].length & 0xFF;
-    scb->data_count[1] = (sg[0].length >> 8) & 0xFF;
-    scb->data_count[2] = (sg[0].length >> 16) & 0xFF;
+    scb->data_count = sg[0].length;
+#if 0
+    debug("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
+           cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
+#endif
   }
   else
   {
@@ -4522,7 +4120,7 @@
       scb->SG_segment_count = 0;
       memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
       memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
-      memset(scb->data_count, 0, sizeof(scb->data_count));
+      scb->data_count = 0;
     }
     else
     {
@@ -4531,9 +4129,7 @@
       scb->sg.length = cmd->request_bufflen;
       addr = &scb->sg;
       memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
-      scb->data_count[0] = scb->sg.length & 0xFF;
-      scb->data_count[1] = (scb->sg.length >> 8) & 0xFF;
-      scb->data_count[2] = (scb->sg.length >> 16) & 0xFF;
+      scb->data_count = scb->sg.length;
       memcpy(scb->data_pointer, &cmd->request_buffer, sizeof(scb->data_pointer));
     }
   }
@@ -4552,7 +4148,6 @@
   long flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
-  unsigned char curscb;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
 
@@ -4562,19 +4157,19 @@
   if (!p->a_scanned && (cmd->channel == 0))
   {
     printk("aic7xxx: Scanning channel A for devices.\n");
-    p->a_scanned = 1;
+    p->a_scanned = TRUE;
   }
   else
   {
     if (!p->b_scanned && (cmd->channel == 1))
     {
       printk("aic7xxx: Scanning channel B for devices.\n");
-      p->b_scanned = 1;
+      p->b_scanned = TRUE;
     }
   }
 
 #if 0
-  debug("aic7xxx_queue: cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
+  debug("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
@@ -4632,16 +4227,6 @@
       scb->position = p->numscb;
       p->numscb++;
       scb->state = SCB_ACTIVE;
-      scb->next_waiting = SCB_LIST_NULL;
-      memcpy(scb->host_scb, &scb, sizeof(scb));
-      scb->control = SCB_NEEDDMA;
-      PAUSE_SEQUENCER(p);
-      curscb = inb(SCBPTR(p->base));
-      outb(scb->position, SCBPTR(p->base));
-      aic7xxx_putscb_dma(p->base, scb);
-      outb(curscb, SCBPTR(p->base));
-      UNPAUSE_SEQUENCER(p);
-      scb->control = 0;
     }
   }
 
@@ -4681,7 +4266,8 @@
    * the SCB, then write its pointer into the queue in FIFO
    * and restore the saved SCB pointer.
    */
-  aic7xxx_putscb(p->base, scb);
+  aic7xxx_putscb(p, scb);
+  outb(scb->position, QINFIFO + p->base);
 
   /*
    * Make sure the Scsi_Cmnd pointer is saved, the struct it
@@ -4720,7 +4306,7 @@
                   unsigned char errcode)
 {
   int base = p->base;
-  int found = 0;
+  int found = FALSE;
   aha_abort_reset_type scb_status = ABORT_RESET_SUCCESS;
   char channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
 
@@ -4730,7 +4316,7 @@
    */
   PAUSE_SEQUENCER(p);
 
-#ifdef AIC7XXX_DEBUG_ABORT 
+#ifdef AIC7XXX_DEBUG_ABORT
   printk ("aic7xxx: (abort_scb) scb %d, scb_aborted 0x%x\n",
           scb->position, (scb->state & SCB_ABORTED));
 #endif
@@ -4765,15 +4351,15 @@
      * may also be that we're timing out on a command that just takes
      * too much time, so we try the bus device reset there first.
      */
-    active_scb = inb(SCBPTR(base));
+    active_scb = inb(SCBPTR + base);
     active_scbp = &(p->scb_array[active_scb]);
-    control = inb(SCBARRAY(base));
+    control = inb(SCBARRAY + base);
 
     /*
      * Test to see if scbp is disconnected
      */
-    outb(scb->position, SCBPTR(base));
-    if (inb(SCBARRAY(base)) & SCB_DIS)
+    outb(scb->position, SCBPTR + base);
+    if (inb(SCBARRAY + base) & DISCONNECTED)
     {
 #ifdef AIC7XXX_DEBUG_ABORT
   printk ("aic7xxx: (abort_scb) scb %d is disconnected.\n", scb->position);
@@ -4782,15 +4368,8 @@
       scb->SG_segment_count = 0;
       memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
       memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
-      memset(scb->data_count, 0, sizeof(scb->data_count));
-      outb(SCBAUTO, SCBCNT(base));
-      asm volatile("cld\n\t"
-                   "rep\n\t"
-                   "outsb"
-                   : /* no output */
-                   :"S" (scb), "c" (SCB_DOWNLOAD_SIZE), "d" (SCBARRAY(base))
-                   :"si", "cx", "dx");
-      outb(0, SCBCNT(base));
+      scb->data_count = 0;
+      aic7xxx_putscb(p, scb);
       aic7xxx_error(scb->cmd) = errcode;
       scb_status = ABORT_RESET_PENDING;
       aic7xxx_add_waiting_scb(base, scb, LIST_SECOND);
@@ -4801,14 +4380,14 @@
       /*
        * Is the active SCB really active?
        */
-      if ((active_scbp->state & SCB_ACTIVE) && (control & SCB_NEEDDMA))
+      if (active_scbp->state & SCB_ACTIVE)
       {
-        unsigned char flags = inb(HA_FLAGS(base));
-        if (flags & ACTIVE_MSG)
+        unsigned char msg_len = inb(MSG_LEN + base);
+        if (msg_len != 0)
         {
 #ifdef AIC7XXX_DEBUG_ABORT
           printk ("aic7xxx: (abort_scb) scb is active, needs DMA, "
-                  "ha_flags active.\n");
+                  "msg_len is non-zero.\n");
 #endif
           /*
            * If we're in a message phase, tacking on another message
@@ -4822,15 +4401,14 @@
         {
 #ifdef AIC7XXX_DEBUG_ABORT
           printk ("aic7xxx: (abort_scb) scb is active, needs DMA, "
-                  "ha_flags inactive.\n");
+                  "msg_len is zero.\n");
 #endif
           /*
            * Load the message buffer and assert attention.
            */
           active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
-          outb(flags | ACTIVE_MSG, HA_FLAGS(base));
-          outb(1, HA_MSG_LEN(base));
-          outb(MSG_BUS_DEVICE_RESET, HA_MSG_START(base));
+          outb(1, MSG_LEN + base);
+          outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
           if (active_scbp->target_channel_lun != scb->target_channel_lun)
           {
             /*
@@ -4897,7 +4475,7 @@
        */
       /* cmd->retries = 0; */
       aic7xxx_error(cmd) = errcode;
-      aic7xxx_done (p, scb);
+      aic7xxx_done(p, scb);
     }
     else
     {
@@ -5060,3 +4638,4 @@
  * tab-width: 8
  * End:
  */
+
diff -u --recursive --new-file v1.3.63/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
--- v1.3.63/linux/drivers/scsi/aic7xxx.seq	Tue Jan 23 21:15:43 1996
+++ linux/drivers/scsi/aic7xxx.seq	Thu Feb 15 06:57:02 1996
@@ -1,907 +1,797 @@
-##+M#########################################################################
-# Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
-#
-# Copyright (c) 1994 John Aycock
-#   The University of Calgary Department of Computer Science.
-#
-# Modifications/enhancements:
-#   Copyright (c) 1994, 1995 Justin Gibbs. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; see the file COPYING.  If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-# 
-# FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
-# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
-##-M#########################################################################
-
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.3 1995/11/10 10:51:22 deang Exp $"
-
-SCBMASK		= 0xff
-
-SCSISEQ		= 0x00
-ENRSELI		= 0x10
-SXFRCTL0	= 0x01
-ULTRAEN		= 0x20
-SXFRCTL1	= 0x02
-SCSISIGI	= 0x03
-SCSISIGO	= 0x03
-SCSIRATE	= 0x04
-SCSIID		= 0x05
-SCSIDATL	= 0x06
-STCNT		= 0x08
-STCNT+0		= 0x08
-STCNT+1		= 0x09
-STCNT+2		= 0x0a
-CLRSINT0	= 0x0b
-SSTAT0		= 0x0b
-SELDO		= 0x40
-SELDI		= 0x20
-CLRSINT1	= 0x0c
-SSTAT1		= 0x0c
-PHASEMIS	= 0x10
-SIMODE1		= 0x11
-SCSIBUSL	= 0x12
-SHADDR		= 0x14
-SELID		= 0x19
-SBLKCTL		= 0x1f
-SEQCTL		= 0x60
-A		= 0x64				# == ACCUM
-SINDEX		= 0x65
-DINDEX		= 0x66
-ALLZEROS	= 0x6a
-NONE		= 0x6a
-SINDIR		= 0x6c
-DINDIR		= 0x6d
-FUNCTION1	= 0x6e
-HADDR		= 0x88
-HADDR+1		= 0x89
-HADDR+2		= 0x8a
-HADDR+3		= 0x8b
-HCNT		= 0x8c
-HCNT+0		= 0x8c
-HCNT+1		= 0x8d
-HCNT+2		= 0x8e
-SCBPTR		= 0x90
-INTSTAT		= 0x91
-DFCNTRL		= 0x93
-DFSTATUS	= 0x94
-DFDAT		= 0x99
-QINFIFO		= 0x9b
-QINCNT		= 0x9c
-QOUTFIFO	= 0x9d
-
-SCSICONF_A	= 0x5a
-SCSICONF_B	= 0x5b
-
-#  The two reserved bytes at SCBARRAY+1[23] are expected to be set to
-#  zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate 
-#  whether or not to DMA an SCB from host ram. This flag prevents the
-#  "re-fetching" of transactions that are requed because the target is
-#  busy with another command. We also use bits 6 & 7 to indicate whether 
-#  or not to initiate SDTR or WDTR repectively when starting this command.
-#
-SCBARRAY+0	= 0xa0
-
-DISCONNECTED	= 0x04
-NEEDDMA		= 0x08
-NEEDSDTR	= 0x10
-TAG_ENB		= 0x20
-DISCENB		= 0x40
-NEEDWDTR	= 0x80
-
-SCBARRAY+1	= 0xa1
-SCBARRAY+2	= 0xa2
-SCBARRAY+3	= 0xa3
-SCBARRAY+4	= 0xa4
-SCBARRAY+5	= 0xa5
-SCBARRAY+6	= 0xa6
-SCBARRAY+7	= 0xa7
-SCBARRAY+8	= 0xa8
-SCBARRAY+9	= 0xa9
-SCBARRAY+10	= 0xaa
-SCBARRAY+11	= 0xab
-SCBARRAY+12	= 0xac
-SCBARRAY+13	= 0xad
-SCBARRAY+14	= 0xae
-SCBARRAY+15	= 0xaf
-SCBARRAY+16	= 0xb0
-SCBARRAY+17	= 0xb1
-SCBARRAY+18	= 0xb2
-SCBARRAY+19	= 0xb3
-SCBARRAY+20	= 0xb4
-SCBARRAY+21	= 0xb5
-SCBARRAY+22	= 0xb6
-SCBARRAY+23	= 0xb7
-SCBARRAY+24	= 0xb8
-SCBARRAY+25	= 0xb9
-SCBARRAY+26	= 0xba
-SCBARRAY+27	= 0xbb
-SCBARRAY+28	= 0xbc
-SCBARRAY+29	= 0xbd
-SCBARRAY+30	= 0xbe
-
-BAD_PHASE	= 0x01				# unknown scsi bus phase
-CMDCMPLT	= 0x02				# Command Complete
-SEND_REJECT	= 0x11				# sending a message reject
-NO_IDENT	= 0x21				# no IDENTIFY after reconnect
-NO_MATCH	= 0x31				# no cmd match for reconnect
-MSG_SDTR	= 0x41				# SDTR message received
-MSG_WDTR	= 0x51				# WDTR message received
-MSG_REJECT	= 0x61				# Reject message received
-BAD_STATUS	= 0x71				# Bad status from target
-RESIDUAL	= 0x81				# Residual byte count != 0
-ABORT_TAG	= 0x91				# Sent an ABORT_TAG message
-AWAITING_MSG	= 0xa1				# Kernel requested to specify
-						# a message to this target
-						# (command was null), so tell
-						# it that it can fill the
-						# message buffer.
-IMMEDDONE	= 0xb1
-
-
-#  The host adapter card (at least the BIOS) uses 20-2f for SCSI
-#  device information, 32-33 and 5a-5f as well. As it turns out, the
-#  BIOS trashes 20-2f, writing the synchronous negotiation results
-#  on top of the BIOS values, so we re-use those for our per-target
-#  scratchspace (actually a value that can be copied directly into
-#  SCSIRATE).  The kernel driver will enable synchronous negotiation
-#  for all targets that have a value other than 0 in the lower four
-#  bits of the target scratch space.  This should work regardless of
-#  whether the bios has been installed. NEEDSDTR and NEEDWDTR are the
-#  fouth and sevent bits of the SCB control byte.  The kernel driver 
-#  will set these when a WDTR or SDTR message should be sent to the 
-#  target the SCB's command references.
-#
-#  REJBYTE contains the first byte of a MESSAGE IN message, so the driver 
-#  can report an intelligible error if a message is rejected.
-#
-#  FLAGS's high bit is true if we are currently handling a reselect;
-#  its next-highest bit is true ONLY IF we've seen an IDENTIFY message
-#  from the reselecting target.  If we haven't had IDENTIFY, then we have
-#  no idea what the lun is, and we can't select the right SCB register
-#  bank, so force a kernel panic if the target attempts a data in/out or
-#  command phase instead of corrupting something.  FLAGS also contains
-#  configuration bits so that we can optimize for TWIN and WIDE controllers,
-#  the MAX_OFFSET bit which we set when we want to negotiate for maximum sync 
-#  offset irregardless of what the per target scratch space says.
-#
-#  Note that SG_NEXT occupies four bytes.
-#
-SYNCNEG		= 0x20
-
-REJBYTE		= 0x31
-DISC_DSB_A	= 0x32
-DISC_DSB_B	= 0x33
-
-MSG_LEN		= 0x34
-MSG_START+0	= 0x35
-MSG_START+1	= 0x36
-MSG_START+2	= 0x37
-MSG_START+3	= 0x38
-MSG_START+4	= 0x39
-MSG_START+5	= 0x3a
--MSG_START+0	= 0xcb				# 2's complement of MSG_START+0
-
-ARG_1		= 0x4a				# sdtr conversion args & return
-BUS_16_BIT	= 0x01
-RETURN_1	= 0x4a
-
-SIGSTATE	= 0x4b				# value written to SCSISIGO
-
-# Linux users should use 0xc (12) for SG_SIZEOF
-#SG_SIZEOF	= 0x8 				# sizeof(struct ahc_dma)
-SG_SIZEOF	= 0xc 				# sizeof(struct scatterlist)
-SCB_SIZEOF	= 0x1a				# sizeof SCB to DMA (26 bytes)
-
-DMAPARAMS	= 0x4c				# Parameters for DMA
-SG_COUNT	= 0x4d				# working value of SG count
-SG_NEXT		= 0x4e				# working value of SG pointer
-SG_NEXT+0	= 0x4e
-SG_NEXT+1	= 0x4f
-SG_NEXT+2	= 0x50
-SG_NEXT+3	= 0x51
-
-SCBCOUNT	= 0x52				# the actual number of SCBs
-FLAGS		= 0x53				# Device configuration flags
-TWIN_BUS	= 0x01
-WIDE_BUS	= 0x02
-DPHASE		= 0x04
-MAX_OFFSET	= 0x08
-ACTIVE_MSG	= 0x20
-IDENTIFY_SEEN	= 0x40
-RESELECTED	= 0x80
-
-MAX_OFFSET_8BIT	= 0x0f
-MAX_OFFSET_WIDE	= 0x08
-
-ACTIVE_A	= 0x54
-ACTIVE_B	= 0x55
-SAVED_TCL	= 0x56				# Temporary storage for the 
-						# target/channel/lun of a
-						# reconnecting target
-# After starting the selection hardware, we return to the "poll_for_work"
-# loop so that we can check for reconnecting targets as well as for our
-# selection to complete just in case the reselection wins bus arbitration.
-# The problem with this is that we must keep track of the SCB that we've
-# already pulled from the QINFIFO and started the selection on just in case
-# the reselection wins so that we can retry the selection at a later time.
-# This problem cannot be resolved by holding a single entry in scratch
-# ram since a reconnecting target can request sense and this will create
-# yet another SCB waiting for selection.  The solution used here is to 
-# use byte 31 of the SCB as a psuedo-next pointer and to thread a list
-# of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB offsets, 
-# SCB_LIST_NULL is 0xff which is out of range.  The kernel driver must
-# add an entry to this list everytime a request sense occurs.  The sequencer
-# will automatically consume the entries.
-
-WAITING_SCBH	= 0x57				# head of list of SCBs awaiting
-						# selection
-WAITING_SCBT	= 0x58				# tail of list of SCBs awaiting
-						# selection
-SCB_LIST_NULL	= 0xff
-
-
-#  Poll QINCNT for work - the lower bits contain
-#  the number of entries in the Queue In FIFO.
-#
+/*+M*************************************************************************
+ * Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ *Modifications/enhancements:
+ *  Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
+ * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
+ *-M*************************************************************************/
+
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.8 1996/02/10 06:23:39 deang Exp $"
+
+#ifdef linux
+#include "aic7xxx_reg.h"
+#else
+#include "../../dev/aic7xxx/aic7xxx_reg.h"
+#endif
+
+/*
+ * We can't just use ACCUM in the sequencer code because it
+ * must be treated specially by the assembler, and it currently
+ * looks for the symbol 'A'.  This is the only register defined in
+ * the assembler's symbol space.
+ */
+A = ACCUM
+
+/* After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB offsets, 
+ * SCB_LIST_NULL is 0xff which is out of range.  The kernel driver must
+ * add an entry to this list everytime a request sense occurs.  The sequencer
+ * will automatically consume the entries.
+ */
+
+/*
+ * Initialize any state valid during the idle loop here.  This code is
+ * executed on startup and after every bus free.
+ */
+start:
+	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
 poll_for_work:
-	test	FLAGS,TWIN_BUS	jz start2	# Are we a twin channel device?
-# For fairness, we check the other bus first, since we just finished a 
-# transaction on the current channel.
-	xor	SBLKCTL,0x08			# Toggle to the other bus
+	/*
+	 * Are we a twin channel device?
+	 * For fairness, we check the other bus first,
+	 * since we just finished a transaction on the
+	 * current channel.
+	 */
+	test	FLAGS,TWIN_BUS	jz start2
+	xor	SBLKCTL,SELBUSB			/* Toggle to the other bus */
 	test	SSTAT0,SELDI	jnz reselect
-	xor	SBLKCTL,0x08			# Toggle to the original bus
+	xor	SBLKCTL,SELBUSB			/* Toggle to the original bus */
 start2:
 	test	SSTAT0,SELDI	jnz reselect
 	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting
-	test	QINCNT,SCBMASK	jz poll_for_work
+	test	QINCNT,0xff	jz poll_for_work
 
-# We have at least one queued SCB now and we don't have any 
-# SCBs in the list of SCBs awaiting selection.  Set the SCB
-# pointer from the FIFO so we see the right bank of SCB 
-# registers, then set SCSI options and set the initiator and
-# target SCSI IDs.
-#
+/*
+ * We have at least one queued SCB now and we don't have any 
+ * SCBs in the list of SCBs awaiting selection.  Set the SCB
+ * pointer from the FIFO so we see the right bank of SCB 
+ * registers.
+ */
 	mov	SCBPTR,QINFIFO
 
-# If the control byte of this SCB has the NEEDDMA flag set, we have
-# yet to DMA it from host memory
-
-test    SCBARRAY+0,NEEDDMA      jz test_busy    
-	clr	HCNT+2
-	clr	HCNT+1
-	mvi	HCNT+0,SCB_SIZEOF
-
-	mvi	DINDEX,HADDR      
-	mvi	SCBARRAY+26     call bcopy_4
-        
-	mvi	DFCNTRL,0xd                     # HDMAEN|DIRECTION|FIFORESET
-
-#  Wait for DMA from host memory to data FIFO to complete, then disable
-#  DMA and wait for it to acknowledge that it's off.
-#
-	call	dma_finish
-
-# Copy the SCB from the FIFO to  the SCBARRAY
-
-	mvi	DINDEX, SCBARRAY+0
-	call	bcopy_5_dfdat 
-	call	bcopy_7_dfdat
-	call	bcopy_7_dfdat
-	call	bcopy_7_dfdat   
-
-# See if there is not already an active SCB for this target.  This code
-# locks out on a per target basis instead of target/lun.  Although this
-# is not ideal for devices that have multiple luns active at the same
-# time, it is faster than looping through all SCB's looking for active
-# commands.  It may be benificial to make findscb a more general procedure
-# to see if the added cost of the search is negligible.  This code also 
-# assumes that the kernel driver will clear the active flags on board 
-# initialization, board reset, and a target's SELTO.
+/*
+ * See if there is not already an active SCB for this target.  This code
+ * locks out on a per target basis instead of target/lun.  Although this
+ * is not ideal for devices that have multiple luns active at the same
+ * time, it is faster than looping through all SCB's looking for active
+ * commands.  It may be benificial to make findscb a more general procedure
+ * to see if the added cost of the search is negligible.  This code also 
+ * assumes that the kernel driver will clear the active flags on board 
+ * initialization, board reset, and a target SELTO.  Tagged commands
+ * don't set the active bits since you can queue more than one command
+ * at a time.  We do, however, look to see if there are any non-tagged
+ * I/Os in progress, and requeue the command if there are.  Tagged and
+ * non-tagged commands cannot be mixed to a single target.
+ */
 
 test_busy:
-	and	FUNCTION1,0x70,SCBARRAY+1
+	mov	FUNCTION1,SCB_TCL
 	mov	A,FUNCTION1
-	test	SCBARRAY+1,0x88	jz test_a	# Id < 8 && A channel
+	test	SCB_TCL,0x88	jz test_a	/* Id < 8 && A channel */
 
 	test	ACTIVE_B,A	jnz requeue
-	test	SCBARRAY+0,TAG_ENB	jnz start_scb
-	or	ACTIVE_B,A	# Mark the current target as busy
+	test	SCB_CONTROL,TAG_ENB	jnz start_scb
+	/* Mark the current target as busy */
+	or	ACTIVE_B,A
 	jmp	start_scb
 
-# Place the currently active back on the queue for later processing
+/* Place the currently active SCB back on the queue for later processing */
 requeue:
 	mov	QINFIFO, SCBPTR
 	jmp	poll_for_work
 
-# Pull the first entry off of the waiting for selection list
+/*
+ * Pull the first entry off of the waiting for selection list
+ * We don't have to "test_busy" because only transactions that
+ * have passed that test can be in the waiting_scb list.
+ */
 start_waiting:
 	mov	SCBPTR,WAITING_SCBH
-	jmp	start_scb
+	jmp	start_scb2
 
 test_a:
-	test	ACTIVE_A,A	jnz requeue
-	test	SCBARRAY+0,TAG_ENB	jnz start_scb
-	or	ACTIVE_A,A	# Mark the current target as busy
+	test	ACTIVE_A,A jnz requeue
+	test	SCB_CONTROL,TAG_ENB jnz start_scb
+	/* Mark the current target as busy */
+	or	ACTIVE_A,A
 
 start_scb:
-	and	SINDEX,0xf7,SBLKCTL  #Clear the channel select bit
-	and	A,0x08,SCBARRAY+1    #Get new channel bit
-	or	SINDEX,A	     
-	mov	SBLKCTL,SINDEX	# select channel
-	mov	SCBARRAY+1	call initialize_scsiid
-
-# Enable selection phase as an initiator, and do automatic ATN
-# after the selection.  We do this now so that we can overlap the
-# rest of our work to set up this target with the arbitration and
-# selection bus phases.
-#
-start_selection:
-	or	SCSISEQ,0x48			# ENSELO|ENAUTOATNO
+	mov	SCB_NEXT_WAITING,WAITING_SCBH
 	mov	WAITING_SCBH, SCBPTR
-	and	FLAGS,0x3f	# !RESELECTING 
+start_scb2:
+	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
+	and	A,0x08,SCB_TCL		/* Get new channel bit */
+	or	SINDEX,A
+	mov	SBLKCTL,SINDEX		/* select channel */
+	mov	SCB_TCL	call initialize_scsiid
 
-#  As soon as we get a successful selection, the target should go
-#  into the message out phase since we have ATN asserted.  Prepare
-#  the message to send, locking out the device driver.  If the device
-#  driver hasn't beaten us with an ABORT or RESET message, then tack
-#  on an SDTR negotiation if required.
-#
-#  Messages are stored in scratch RAM starting with a flag byte (high bit
-#  set means active message), one length byte, and then the message itself.
-#
-
-	test	SCBARRAY+11,0xff jnz identify	# 0 Length Command?
-
-#  The kernel has sent us an SCB with no command attached.  This implies
-#  that the kernel wants to send a message of some sort to this target,
-#  so we interrupt the driver, allow it to fill the message buffer, and
-#  then go back into the arbitration loop
+/*
+ * Enable selection phase as an initiator, and do automatic ATN
+ * after the selection.  We do this now so that we can overlap the
+ * rest of our work to set up this target with the arbitration and
+ * selection bus phases.
+ */
+start_selection:
+	mvi	SCSISEQ,0x58		/* ENSELO|ENAUTOATNO|ENRSELI */
+
+/*
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.  Prepare
+ * the message to send.
+ *
+ * Messages are stored in scratch RAM starting with a length byte
+ * followed by the message itself.
+ */
+	test	SCB_CMDLEN,0xff jnz mk_identify	/* 0 Length Command? */
+
+/*
+ * The kernel has sent us an SCB with no command attached.  This implies
+ * that the kernel wants to send a message of some sort to this target,
+ * so we interrupt the driver, allow it to fill the message buffer, and
+ * then go back into the arbitration loop
+ */
 	mvi     INTSTAT,AWAITING_MSG
 	jmp     wait_for_selection
 
-identify:
-	and	A,DISCENB,SCBARRAY+0		# mask off disconnect privledge
-
-	and	SINDEX,0x7,SCBARRAY+1		# lun
-	or	SINDEX,A			# or in disconnect privledge
-	or	SINDEX,0x80	call mk_mesg	# IDENTIFY message
-
-	mov	A,SINDEX
-	test	SCBARRAY+0,0xb0	jz  !message	# WDTR, SDTR or TAG??
-	cmp	MSG_START+0,A	jne !message	# did driver beat us?
+mk_identify:
+	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
 
-# Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
-# value
+	and	MSG0,0x7,SCB_TCL	/* lun */
+	or	MSG0,A			/* or in disconnect privledge */
+	or	MSG0,MSG_IDENTIFY
+	mvi	MSG_LEN, 1
+
+	test	SCB_CONTROL,0xb0 jz  !message	/* WDTR, SDTR or TAG?? */
+/*
+ * Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
+ * value
+ */
 
 mk_tag:
-	mvi	DINDEX, MSG_START+1
-	test	SCBARRAY+0,TAG_ENB jz mk_tag_done
-	and	A,0x23,SCBARRAY+0
+	mvi	DINDEX, MSG1
+	test	SCB_CONTROL,TAG_ENB jz mk_tag_done
+	and	A,0x23,SCB_CONTROL
 	mov	DINDIR,A
 	mov	DINDIR,SCBPTR
 
-	add	MSG_LEN,-MSG_START+0,DINDEX	# update message length
+	add	MSG_LEN,COMP_MSG0,DINDEX	/* update message length */
 
 mk_tag_done:
 
-	mov	DINDEX	call mk_dtr	# build DTR message if needed
+	test	SCB_CONTROL,0x90 jz !message	/* NEEDWDTR|NEEDSDTR */
+	mov	DINDEX	call mk_dtr	/* build DTR message if needed */
 
 !message:
 wait_for_selection:
-	test	SSTAT0,SELDI	jnz reselect
-	test	SSTAT0,SELDO	jnz select
-	jmp	wait_for_selection
+	test	SSTAT0,SELDO	jnz select 
+	test	SSTAT0,SELDI	jz wait_for_selection
 
-#  Reselection has been initiated by a target. Make a note that we've been
-#  reselected, but haven't seen an IDENTIFY message from the target
-#  yet.
-#
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target
+ * yet.
+ */
 reselect:
+	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
 	mov	SELID		call initialize_scsiid
-	and	FLAGS,0x3f			# reselected, no IDENTIFY	
-	or	FLAGS,RESELECTED jmp select2
-
-# After the selection, remove this SCB from the "waiting for selection"
-# list.  This is achieved by simply moving our "next" pointer into
-# WAITING_SCBH and setting our next pointer to null so that the next
-# time this SCB is used, we don't get confused.
-#
+	and	FLAGS,0x03	/* clear target specific flags */
+	or	FLAGS,RESELECTED
+	jmp	select2
+
+/*
+ * After the selection, remove this SCB from the "waiting for selection"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH.  Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
 select:
-	or	SCBARRAY+0,NEEDDMA
-	mov	WAITING_SCBH,SCBARRAY+30
-	mvi	SCBARRAY+30,SCB_LIST_NULL
+	and	FLAGS,0x03		/* Clear target flags */
+	mov	WAITING_SCBH,SCB_NEXT_WAITING
 select2:
-	call	initialize_for_target
-	mvi	SCSISEQ,ENRSELI
-	mvi	CLRSINT0,0x60			# CLRSELDI|CLRSELDO
-	mvi	CLRSINT1,0x8			# CLRBUSFREE
-
-#  Main loop for information transfer phases.  If BSY is false, then
-#  we have a bus free condition, expected or not.  Otherwise, wait
-#  for the target to assert REQ before checking MSG, C/D and I/O
-#  for the bus phase.
-#
-#  We can't simply look at the values of SCSISIGI here (if we want
-#  to do synchronous data transfer), because the target won't assert
-#  REQ if it's already sent us some data that we haven't acknowledged
-#  yet.
-#
+/*
+ * Set CLRCHN here before the target has entered a data transfer mode -
+ * with synchronous SCSI, if you do it later, you blow away some
+ * data in the SCSI FIFO that the target has already sent to you.
+ */
+	or	SXFRCTL0,CLRCHN
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ */
+	call	ndx_dtr
+	mov	SCSIRATE,SINDIR
+
+	mvi	SCSISEQ,ENAUTOATNP		/*
+						 * ATN on parity errors
+						 * for "in" phases
+						 */
+	mvi	CLRSINT1,CLRBUSFREE
+	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
+
+/*
+ * Main loop for information transfer phases.  If BSY is false, then
+ * we have a bus free condition, expected or not.  Otherwise, wait
+ * for the target to assert REQ before checking MSG, C/D and I/O
+ * for the bus phase.
+ *
+ */
 ITloop:
-	test	SSTAT1,0x8	jnz p_busfree	# BUSFREE
-	test	SSTAT1,0x1	jz ITloop	# REQINIT
+	test	SSTAT1,BUSFREE	jnz p_busfree
+	test	SSTAT1,REQINIT	jz ITloop
 
-	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
+/*
+ * If we've had a parity error, let the driver know before
+ * we overwrite LASTPHASE.
+ */
+	test	SSTAT1, SCSIPERR jz parity_okay
+	or	CLRSINT1, CLRSCSIPERR
+	mvi	INTSTAT, PARITY_ERROR
+
+parity_okay:
+	and	A,PHASE_MASK,SCSISIGI
+	mov	LASTPHASE,A
+	mov	SCSISIGO,A
 
-	mov	A		call scsisig
 	cmp	ALLZEROS,A	je p_dataout
-	cmp	A,0x40		je p_datain
-	cmp	A,0x80		je p_command
-	cmp	A,0xc0		je p_status
-	cmp	A,0xa0		je p_mesgout
-	cmp	A,0xe0		je p_mesgin
+	cmp	A,P_DATAIN	je p_datain
+	cmp	A,P_COMMAND	je p_command
+	cmp	A,P_MESGOUT	je p_mesgout
+	cmp	A,P_STATUS	je p_status
+	cmp	A,P_MESGIN	je p_mesgin
 
-	mvi	INTSTAT,BAD_PHASE		# unknown - signal driver
+	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
 
 p_dataout:
-	mvi	DMAPARAMS,0x7d			# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
-						#   DIRECTION|FIFORESET
+	mvi	DMAPARAMS,0x7d			/*
+						 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+						 * DIRECTION|FIFORESET
+						 */
 	jmp	data_phase_init
 
-# If we re-enter the data phase after going through another phase, the
-# STCNT may have been cleared, so restore it from the residual field.
+/*
+ * If we re-enter the data phase after going through another phase, the
+ * STCNT may have been cleared, so restore it from the residual field.
+ */
 data_phase_reinit:
-	mvi	DINDEX, STCNT
-	mvi	SCBARRAY+15	call bcopy_3
+	mov	STCNT0,SCB_RESID_DCNT0
+	mov	STCNT1,SCB_RESID_DCNT1
+	mov	STCNT2,SCB_RESID_DCNT2
 	jmp	data_phase_loop
 
-# Reads should not use WIDEODD since it may make the last byte for a SG segment
-# go to the next segment.
 p_datain:
-	mvi	DMAPARAMS,0x79			# WIDEODD|SCSIEN|SDMAEN|HDMAEN|
-						#   !DIRECTION|FIFORESET
+	mvi	DMAPARAMS,0x79		/*
+					 * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+					 * !DIRECTION|FIFORESET
+					 */
 data_phase_init:
 	call	assert
 
 	test	FLAGS, DPHASE	jnz data_phase_reinit
 	call	sg_scb2ram
-	or	FLAGS, DPHASE			# We have seen a data phase
+	or	FLAGS, DPHASE		/* We have seen a data phase */
 
 data_phase_loop:
-# If we are the last SG block, don't set wideodd.
+/* If we are the last SG block, don't set wideodd. */
 	cmp	SG_COUNT,0x01 jne data_phase_wideodd
-	and	DMAPARAMS, 0xbf		        # Turn off WIDEODD 
+	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
 data_phase_wideodd:
 	mov	DMAPARAMS  call dma
 
-# Exit if we had an underrun
-	test	SSTAT0,0x04	jz data_phase_finish	# underrun STCNT != 0
+/* Exit if we had an underrun */
+	test	SSTAT0,SDONE	jz data_phase_finish /* underrun STCNT != 0 */
 
-#  Advance the scatter-gather pointers if needed 
-#
+/*
+ * Advance the scatter-gather pointers if needed 
+ */
 sg_advance:
-	dec	SG_COUNT			# one less segment to go
+	dec	SG_COUNT	/* one less segment to go */
 
-	test	SG_COUNT, 0xff	jz data_phase_finish #Are we done?
+	test	SG_COUNT, 0xff	jz data_phase_finish /* Are we done? */
 
-	clr	A				# add sizeof(struct scatter)
-	add	SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
-	adc	SG_NEXT+1,A,SG_NEXT+1
-	adc	SG_NEXT+2,A,SG_NEXT+2
-	adc	SG_NEXT+3,A,SG_NEXT+3
-
-#  Load a struct scatter and set up the data address and length.
-#  If the working value of the SG count is nonzero, then
-#  we need to load a new set of values.
-#
-#  This, like all DMA's, assumes a little-endian host data storage.
-#
+	clr	A			/* add sizeof(struct scatter) */
+	add	SG_NEXT0,SG_SIZEOF,SG_NEXT0
+	adc	SG_NEXT1,A,SG_NEXT1
+
+/*
+ * Load a struct scatter and set up the data address and length.
+ * If the working value of the SG count is nonzero, then
+ * we need to load a new set of values.
+ *
+ * This, like all DMA's, assumes a little-endian host data storage.
+ */
 sg_load:
-	clr	HCNT+2
-	clr	HCNT+1
-	mvi	HCNT+0,SG_SIZEOF
-
-	mvi	DINDEX,HADDR
-	mvi	SG_NEXT		call bcopy_4
-
-	mvi	DFCNTRL,0xd			# HDMAEN|DIRECTION|FIFORESET
-
-#  Wait for DMA from host memory to data FIFO to complete, then disable
-#  DMA and wait for it to acknowledge that it's off.
-#
-	call	dma_finish
-
-#  Copy data from FIFO into SCB data pointer and data count.  This assumes
-#  that the struct scatterlist has this structure (this and sizeof(struct
-#  scatterlist) == 12 are asserted in aic7xxx.c):
-#
-#	struct scatterlist {
-#		char *address;		/* four bytes, little-endian order */
-#		...			/* four bytes, ignored */
-#		unsigned short length;	/* two bytes, little-endian order */
-#	}
-#
-
-# Not in FreeBSD.  the scatter list entry is only 8 bytes.
-# 
-# struct ahc_dma_seg {
-#       physaddr addr;                  /* four bytes, little-endian order */
-#       long    len;                    /* four bytes, little endian order */   
-# };
-#
-
-	mvi	DINDEX,HADDR
-#	call	bcopy_7_dfdat
-
-# For Linux, we must throw away four bytes since there is a 32bit gap
-# in the middle of a struct scatterlist
-	call	bcopy_4_dfdat
+	clr	HCNT2
+	clr	HCNT1
+	mvi	HCNT0,SG_SIZEOF
+
+	mov	HADDR0,SG_NEXT0
+	mov	HADDR1,SG_NEXT1
+	mov	HADDR2,SG_NEXT2
+	mov	HADDR3,SG_NEXT3
+
+	or	DFCNTRL,0xd			/* HDMAEN|DIRECTION|FIFORESET */
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+dma_finish:
+	test	DFSTATUS,HDONE	jz dma_finish
+	/* Turn off DMA preserving WIDEODD */
+	and	DFCNTRL,WIDEODD
+dma_finish2:
+	test	DFCNTRL,HDMAENACK jnz dma_finish2
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count.  This assumes
+ * that the struct scatterlist has this structure (this and sizeof(struct
+ * scatterlist) == 12 are asserted in aic7xxx.c):
+ *
+ *	struct scatterlist {
+ *		char *address;		four bytes, little-endian order
+ *		...			four bytes, ignored
+ *		unsigned short length;	two bytes, little-endian order
+ *	}
+ *
+ *
+ * Not in FreeBSD.  the scatter list entry is only 8 bytes.
+ * 
+ * struct ahc_dma_seg {
+ *       physaddr addr;                  four bytes, little-endian order
+ *       long    len;                    four bytes, little endian order
+ * };
+ */
+
+/*
+ * For Linux, we must throw away four bytes since there is a 32bit gap
+ * in the middle of a struct scatterlist
+ */
+#ifdef linux
+	mov	HADDR0,DFDAT
+	mov	HADDR1,DFDAT
+	mov	HADDR2,DFDAT
+	mov	HADDR3,DFDAT
 	mov	NONE,DFDAT
 	mov	NONE,DFDAT
 	mov	NONE,DFDAT
 	mov	NONE,DFDAT
-	call	bcopy_3_dfdat		#Only support 24 bit length.
-
-# Load STCNT as well.  It is a mirror of HCNT
-	mvi	DINDEX,STCNT
-	mvi	HCNT	call bcopy_3
+	mov	HCNT0,DFDAT
+	mov	HCNT1,DFDAT
+	mov	HCNT2,DFDAT
+#else
+/*
+ * For FreeBSD, just copy it wholesale
+ */
+	mov	HADDR0,DFDAT
+	mov	HADDR1,DFDAT
+	mov	HADDR2,DFDAT
+	mov	HADDR3,DFDAT
+	mov	HCNT0,DFDAT
+	mov	HCNT1,DFDAT
+	mov	HCNT2,DFDAT
+#endif
+
+/* Load STCNT as well.  It is a mirror of HCNT */
+	mov	STCNT0,HCNT0
+	mov	STCNT1,HCNT1
+	mov	STCNT2,HCNT2
         test    SSTAT1,PHASEMIS  jz data_phase_loop
 
 data_phase_finish:
-#  After a DMA finishes, save the SG and STCNT residuals back into the SCB
-#  We use STCNT instead of HCNT, since it's a reflection of how many bytes 
-#  were transferred on the SCSI (as opposed to the host) bus.
-#
-	mvi	DINDEX,SCBARRAY+15
-	mvi	STCNT		call bcopy_3
-	mov	SCBARRAY+18, SG_COUNT
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+	mov	SCB_RESID_DCNT0,STCNT0
+	mov	SCB_RESID_DCNT1,STCNT1
+	mov	SCB_RESID_DCNT2,STCNT2
+	mov	SCB_RESID_SGCNT, SG_COUNT
 	jmp	ITloop
 
-#  Command phase.  Set up the DMA registers and let 'er rip - the
-#  two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
-#  so we can copy those three bytes directly into HCNT.
-#
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip - the
+ * two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
+ * so we can copy those three bytes directly into HCNT.
+ */
 p_command:
 	call	assert
 
-# Load HADDR and HCNT.  We can do this in one bcopy since they are neighbors
-	mvi	DINDEX,HADDR
-	mvi	SCBARRAY+7	call bcopy_7
-
-	mvi	DINDEX,STCNT
-	mvi	SCBARRAY+11	call bcopy_3
+/*
+ * Load HADDR and HCNT.  We can do this in one bcopy since they are neighbors
+ */
+	mov	HADDR0, SCB_CMDPTR0
+	mov	HADDR1, SCB_CMDPTR1
+	mov	HADDR2, SCB_CMDPTR2
+	mov	HADDR3, SCB_CMDPTR3
+	mov	HCNT0, SCB_CMDLEN
+	clr	HCNT1
+	clr	HCNT2
+
+	mov	STCNT0, HCNT0
+	mov	STCNT1, HCNT1
+	mov	STCNT2, HCNT2
 
 	mvi	0x3d		call dma	# SCSIEN|SDMAEN|HDMAEN|
 						#   DIRECTION|FIFORESET
 	jmp	ITloop
 
-#  Status phase.  Wait for the data byte to appear, then read it
-#  and store it into the SCB.
-#
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
 p_status:
-
-	mvi	SCBARRAY+14	call inb_first
+	mvi	SCB_TARGET_STATUS	call inb_first
 	jmp	mesgin_done
 
-#  Message out phase.  If there is no active message, but the target
-#  took us into this phase anyway, build a no-op message and send it.
-#
+/*
+ * Message out phase.  If there is no active message, but the target
+ * took us into this phase anyway, build a no-op message and send it.
+ */
 p_mesgout:
-	mvi	0x8		call mk_mesg	# build NOP message
+	test	MSG_LEN, 0xff	jnz  p_mesgout_start
+	mvi	MSG_NOP		call mk_mesg	/* build NOP message */
 
-	clr     STCNT+2
-	clr     STCNT+1
-
-#  Set up automatic PIO transfer from MSG_START.  Bit 3 in
-#  SXFRCTL0 (SPIOEN) is already on.
-#
-	mvi	SINDEX,MSG_START+0
+p_mesgout_start:
+/*
+ * Set up automatic PIO transfer from MSG0.  Bit 3 in
+ * SXFRCTL0 (SPIOEN) is already on.
+ */
+	mvi	SINDEX,MSG0
 	mov	DINDEX,MSG_LEN
 
-#  When target asks for a byte, drop ATN if it's the last one in
-#  the message.  Otherwise, keep going until the message is exhausted.
-#  (We can't use outb for this since it wants the input in SINDEX.)
-#
-#  Keep an eye out for a phase change, in case the target issues
-#  a MESSAGE REJECT.
-#
-p_mesgout2:
-	test	SSTAT0,0x2	jz p_mesgout2	# SPIORDY
-	test	SSTAT1,0x10	jnz p_mesgout6	# PHASEMIS
-
-	cmp	DINDEX,1	jne p_mesgout3	# last byte?
-	mvi	CLRSINT1,0x40			# CLRATNO - drop ATN
-
-#  Write a byte to the SCSI bus.  The AIC-7770 refuses to automatically
-#  send ACKs in automatic PIO or DMA mode unless you make sure that the
-#  "expected" bus phase in SCSISIGO matches the actual bus phase.  This
-#  behaviour is completely undocumented and caused me several days of
-#  grief.
-#
-#  After plugging in different drives to test with and using a longer
-#  SCSI cable, I found that I/O in Automatic PIO mode ceased to function,
-#  especially when transferring >1 byte.  It seems to be much more stable
-#  if STCNT is set to one before the transfer, and SDONE (in SSTAT0) is
-#  polled for transfer completion - for both output _and_ input.  The
-#  only theory I have is that SPIORDY doesn't drop right away when SCSIDATL
-#  is accessed (like the documentation says it does), and that on a longer
-#  cable run, the sequencer code was fast enough to loop back and see
-#  an SPIORDY that hadn't dropped yet.
-#
-p_mesgout3:
-	mvi	STCNT+0, 0x01	
+/*
+ * When target asks for a byte, drop ATN if it's the last one in
+ * the message.  Otherwise, keep going until the message is exhausted.
+ *
+ * Keep an eye out for a phase change, in case the target issues
+ * a MESSAGE REJECT.
+ */
+p_mesgout_loop:
+	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
+	test	SSTAT0,SPIORDY	jz p_mesgout_loop
+	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
+	mvi	CLRSINT1,CLRATNO			/* drop ATN */
+p_mesgout_outb:
+	dec	DINDEX
+	or	CLRSINT0, CLRSPIORDY
 	mov	SCSIDATL,SINDIR
-
+	
 p_mesgout4:
-	test	SSTAT0,0x4	jz p_mesgout4	# SDONE
-	dec	DINDEX
-	test	DINDEX,0xff	jnz p_mesgout2
+	test	DINDEX,0xff	jnz p_mesgout_loop
 
-#  If the next bus phase after ATN drops is a message out, it means
-#  that the target is requesting that the last message(s) be resent.
-#
-p_mesgout5:
-	test	SSTAT1,0x8	jnz p_mesgout6	# BUSFREE
-	test	SSTAT1,0x1	jz p_mesgout5	# REQINIT
-
-	and	A,0xe0,SCSISIGI			# CDI|IOI|MSGI
-	cmp	A,0xa0		jne p_mesgout6
-	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
-	call	scsisig				# ATNO - re-assert ATN
+/*
+ * If the next bus phase after ATN drops is a message out, it means
+ * that the target is requesting that the last message(s) be resent.
+ */
+p_mesgout_snoop:
+	test	SSTAT1,BUSFREE	jnz p_mesgout_done
+	test	SSTAT1,REQINIT	jz p_mesgout_snoop
+
+	test	SSTAT1,PHASEMIS	jnz p_mesgout_done
+
+	or	SCSISIGO,ATNO			/* turn on ATNO */
 
 	jmp	ITloop
 
-p_mesgout6:
-	mvi	CLRSINT1,0x40			# CLRATNO - in case of PHASEMIS
-	and	FLAGS,0xdf			# no active msg
+p_mesgout_phasemis:
+	mvi	CLRSINT1,CLRATNO	/* Be sure turn ATNO off */
+p_mesgout_done:
+	clr	MSG_LEN			/* no active msg */
 	jmp	ITloop
 
-#  Message in phase.  Bytes are read using Automatic PIO mode, but not
-#  using inb.  This alleviates a race condition, namely that if ATN had
-#  to be asserted under Automatic PIO mode, it had to beat the SCSI
-#  circuitry sending an ACK to the target.  This showed up under heavy
-#  loads and really confused things, since ABORT commands wouldn't be
-#  seen by the drive after an IDENTIFY message in until it had changed
-#  to a data I/O phase.
-#
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
 p_mesgin:
-	mvi	A		call inb_first	# read the 1st message byte
-	mvi	REJBYTE,A			# save it for the driver
+	mvi	A		call inb_first	/* read the 1st message byte */
+	mov	REJBYTE,A			/* save it for the driver */
 
-	test	A,0x80		jnz mesgin_identify	# identify message?
-	cmp	A,4		je mesgin_disconnect	# disconnect?
-	cmp	A,2		je mesgin_sdptrs	# save data pointers?
-	cmp	ALLZEROS,A	je mesgin_complete	# command complete?
-	cmp	A,3		je mesgin_rdptrs	# restore pointers code?
-	cmp	A,1		je mesgin_extended	# extended message?
-	cmp	A,7		je mesgin_reject	# message reject code?
+	test	A,MSG_IDENTIFY		jnz mesgin_identify
+	cmp	A,MSG_DISCONNECT	je mesgin_disconnect
+	cmp	A,MSG_SDPTRS		je mesgin_sdptrs
+	cmp	ALLZEROS,A		je mesgin_complete
+	cmp	A,MSG_RDPTRS		je mesgin_rdptrs
+	cmp	A,MSG_EXTENDED		je mesgin_extended
+	cmp	A,MSG_REJECT		je mesgin_reject
 
 rej_mesgin:
-#  We have no idea what this message in is, and there's no way
-#  to pass it up to the kernel, so we issue a message reject and
-#  hope for the best.  Since we're now using manual PIO mode to
-#  read in the message, there should no longer be a race condition
-#  present when we assert ATN.  In any case, rejection should be a
-#  rare occurrence - signal the driver when it happens.
-#
-	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
-	call	scsisig
-	mvi	INTSTAT,SEND_REJECT		# let driver know
+/*
+ * We have no idea what this message in is, and there's no way
+ * to pass it up to the kernel, so we issue a message reject and
+ * hope for the best.  Since we're now using manual PIO mode to
+ * read in the message, there should no longer be a race condition
+ * present when we assert ATN.  In any case, rejection should be a
+ * rare occurrence - signal the driver when it happens.
+ */
+	or	SCSISIGO,ATNO			/* turn on ATNO */
+	mvi	INTSTAT,SEND_REJECT		/* let driver know */
 
-	mvi	0x7		call mk_mesg	# MESSAGE REJECT message
+	mvi	MSG_REJECT	call mk_mesg
 
 mesgin_done:
-	call	inb_last			# ack & turn auto PIO back on
+	call	inb_last			/*ack & turn auto PIO back on*/
 	jmp	ITloop
 
 
 mesgin_complete:
-#  We got a "command complete" message, so put the SCB pointer
-#  into the Queue Out, and trigger a completion interrupt.
-#  Check status for non zero return and interrupt driver if needed
-#  This allows the driver to interpret errors only when they occur
-#  instead of always uploading the scb.  If the status is SCSI_CHECK,
-#  the driver will download a new scb requesting sense to replace
-#  the old one, modify the "waiting for selection" SCB list and set 
-#  RETURN_1 to 0x80.  If RETURN_1 is set to 0x80 the sequencer imediately
-#  jumps to main loop where it will run down the waiting SCB list.
-#  If the kernel driver does not wish to request sense, it need
-#  only clear RETURN_1, and the command is allowed to complete.  We don't 
-#  bother to post to the QOUTFIFO in the error case since it would require 
-#  extra work in the kernel driver to ensure that the entry was removed 
-#  before the command complete code tried processing it.
-
-# First check for residuals
-	test	SCBARRAY+18,0xff	jnz resid
+/*
+ * We got a "command complete" message, so put the SCB pointer
+ * into QUEUEOUT, and trigger a completion interrupt.
+ * Check status for non zero return and interrupt driver if needed
+ * This allows the driver to interpret errors only when they occur
+ * instead of always uploading the scb.  If the status is SCSI_CHECK,
+ * the driver will download a new scb requesting sense to replace
+ * the old one, modify the "waiting for selection" SCB list and set 
+ * RETURN_1 to 0x80.  If RETURN_1 is set to 0x80 the sequencer imediately
+ * jumps to main loop where it will run down the waiting SCB list.
+ * If the kernel driver does not wish to request sense, it need
+ * only clear RETURN_1, and the command is allowed to complete.  We don't 
+ * bother to post to the QOUTFIFO in the error case since it would require 
+ * extra work in the kernel driver to ensure that the entry was removed 
+ * before the command complete code tried processing it.
+ *
+ * First check for residuals
+ */
+	test	SCB_RESID_SGCNT,0xff	jz check_status
+/*
+ * If we have a residual count, interrupt and tell the host.  Other
+ * alternatives are to pause the sequencer on all command completes (yuck),
+ * dma the resid directly to the host (slick, we may have space to do it now)
+ * or have the sequencer pause itself when it encounters a non-zero resid 
+ * (unecessary pause just to flag the command -yuck-, but takes one instruction
+ * and since it shouldn't happen that often is good enough for our purposes).  
+ */
+resid:
+	mvi	INTSTAT,RESIDUAL
 
 check_status:
-	test	SCBARRAY+14,0xff	jz status_ok	# 0 Status?
-	mvi	INTSTAT,BAD_STATUS			# let driver know
-	test	RETURN_1, 0x80	jz status_ok
+	test	SCB_TARGET_STATUS,0xff	jz status_ok	/* Good Status? */
+	mvi	INTSTAT,BAD_STATUS			/* let driver know */
+	cmp	RETURN_1, SEND_SENSE	jne status_ok
 	jmp	mesgin_done
 
 status_ok:
-#  First, mark this target as free.
-	test	SCBARRAY+0,TAG_ENB	jnz complete		# Tagged command
-	and	FUNCTION1,0x70,SCBARRAY+1
+/* First, mark this target as free. */
+	test	SCB_CONTROL,TAG_ENB jnz test_immediate	/*
+							 * Tagged commands
+							 * don't busy the
+							 * target.
+							 */
+	mov	FUNCTION1,SCB_TCL
 	mov	A,FUNCTION1
-	test	SCBARRAY+1,0x88 jz clear_a
+	test	SCB_TCL,0x88 jz clear_a
 	xor	ACTIVE_B,A
-	jmp	immediate
+	jmp	test_immediate
 
 clear_a:
 	xor	ACTIVE_A,A
 
-immediate:
-	test    SCBARRAY+11,0xff jnz complete  # Immediate message complete
-# Pause the sequencer until the driver gets around to handling the command
-# complete.  This is so that any action that might require carefull timing
-# with the completion of this command can occur.
+test_immediate:
+	test    SCB_CMDLEN,0xff jnz complete  /* Immediate message complete */
+/*
+ * Pause the sequencer until the driver gets around to handling the command
+ * complete.  This is so that any action that might require carefull timing
+ * with the completion of this command can occur.
+ */
 	mvi	INTSTAT,IMMEDDONE
-	jmp	poll_for_work
+	jmp	start
 complete:
 	mov	QOUTFIFO,SCBPTR
 	mvi	INTSTAT,CMDCMPLT
 	jmp	mesgin_done
 
-# If we have a residual count, interrupt and tell the host.  Other
-# alternatives are to pause the sequencer on all command completes (yuck),
-# dma the resid directly to the host (slick, but a ton of instructions), or
-# have the sequencer pause itself when it encounters a non-zero resid 
-# (unecessary pause just to flag the command -- yuck, but takes few instructions
-# and since it shouldn't happen that often is good enough for our purposes).  
-
-resid:
-	mvi	INTSTAT,RESIDUAL
-	jmp	check_status
 
-#  Is it an extended message?  We only support the synchronous and wide data
-#  transfer request messages, which will probably be in response to
-#  WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
-#  apparently this can be done after any message in byte, according
-#  to the SCSI-2 spec.
-#
+/*
+ * Is it an extended message?  We only support the synchronous and wide data
+ * transfer request messages, which will probably be in response to
+ * WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
+ * apparently this can be done after any message in byte, according
+ * to the SCSI-2 spec.
+ */
 mesgin_extended:
-	mvi	ARG_1		call inb_next	# extended message length
-	mvi	A		call inb_next	# extended message code
+	mvi	ARG_1		call inb_next	/* extended message length */
+	mvi	A		call inb_next	/* extended message code */
 
-	cmp	A,1		je p_mesginSDTR	# Syncronous negotiation message
-	cmp	A,3		je p_mesginWDTR # Wide negotiation message
+	cmp	A,MSG_SDTR	je p_mesginSDTR
+	cmp	A,MSG_WDTR	je p_mesginWDTR
 	jmp	rej_mesgin
 
 p_mesginWDTR:
-	cmp	ARG_1,2		jne rej_mesgin	# extended mesg length=2
-	mvi	A		call inb_next	# Width of bus
-	mvi	INTSTAT,MSG_WDTR		# let driver know
-	test	RETURN_1,0x80	jz mesgin_done# Do we need to send WDTR?
-
-# We didn't initiate the wide negotiation, so we must respond to the request
-	and	RETURN_1,0x7f			# Clear the SEND_WDTR Flag
-	or	FLAGS,ACTIVE_MSG
-	mvi	DINDEX,MSG_START+0
-	mvi	MSG_START+0	call mk_wdtr	# build WDTR message	
-	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
-	call	scsisig
+	cmp	ARG_1,2		jne rej_mesgin	/* extended mesg length=2 */
+	mvi	ARG_1		call inb_next	/* Width of bus */
+	mvi	INTSTAT,WDTR_MSG		/* let driver know */
+	test	RETURN_1,0xff jz mesgin_done	/* Do we need to send WDTR? */
+	cmp	RETURN_1,SEND_REJ je rej_mesgin /*
+						 * Bus width was too large 
+						 * Reject it.
+						 */
+
+/* We didn't initiate the wide negotiation, so we must respond to the request */
+	and	RETURN_1,0x7f			/* Clear the SEND_WDTR Flag */
+	mvi	DINDEX,MSG0
+	mvi	MSG0	call mk_wdtr		/* build WDTR message */
+	or	SCSISIGO,ATNO			/* turn on ATNO */
 	jmp	mesgin_done
 
 p_mesginSDTR:
-	cmp	ARG_1,3		jne rej_mesgin	# extended mesg length=3
-	mvi	ARG_1		call inb_next	# xfer period
-	mvi	A		call inb_next	# REQ/ACK offset
-	mvi	INTSTAT,MSG_SDTR		# call driver to convert
-
-	test	RETURN_1,0xc0	jz mesgin_done# Do we need to mk_sdtr or rej?
-	test	RETURN_1,0x40	jnz rej_mesgin	# Requested SDTR too small - rej
-	or	FLAGS,ACTIVE_MSG
-	mvi	DINDEX, MSG_START+0
-	mvi     MSG_START+0     call mk_sdtr
-	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
-	call	scsisig
+	cmp	ARG_1,3		jne rej_mesgin	/* extended mesg length=3 */
+	mvi	ARG_1		call inb_next	/* xfer period */
+	mvi	A		call inb_next	/* REQ/ACK offset */
+	mvi	INTSTAT,SDTR_MSG		/* call driver to convert */
+
+	test	RETURN_1,0xff	jz mesgin_done  /* Do we need to mk_sdtr/rej */
+	cmp	RETURN_1,SEND_REJ je rej_mesgin /*
+						 * Requested SDTR too small
+						 * Reject it.
+						 */
+	mvi	DINDEX, MSG0
+	mvi     MSG0     call mk_sdtr
+	or	SCSISIGO,ATNO			/* turn on ATNO */
 	jmp	mesgin_done
 
-#  Is it a disconnect message?  Set a flag in the SCB to remind us
-#  and await the bus going free.
-#
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
 mesgin_disconnect:
-	or	SCBARRAY+0,DISCONNECTED
+	or	SCB_CONTROL,DISCONNECTED
 	jmp	mesgin_done
 
-#  Save data pointers message?  Copy working values into the SCB,
-#  usually in preparation for a disconnect.
-#
+/*
+ * Save data pointers message?  Copy working values into the SCB,
+ * usually in preparation for a disconnect.
+ */
 mesgin_sdptrs:
 	call	sg_ram2scb
 	jmp	mesgin_done
 
-#  Restore pointers message?  Data pointers are recopied from the
-#  SCB anytime we enter a data phase for the first time, so all
-#  we need to do is clear the DPHASE flag and let the data phase
-#  code do the rest.
-#
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
 mesgin_rdptrs:
-	and	FLAGS,0xfb			# !DPHASE we'll reload them
-						#   the next time through
+	and	FLAGS,0xfb			/*
+						 * !DPHASE we'll reload them
+						 * the next time through
+						 */
 	jmp	mesgin_done
 
-#  Identify message?  For a reconnecting target, this tells us the lun
-#  that the reconnection is for - find the correct SCB and switch to it,
-#  clearing the "disconnected" bit so we don't "find" it by accident later.
-#
+/*
+ * Identify message?  For a reconnecting target, this tells us the lun
+ * that the reconnection is for - find the correct SCB and switch to it,
+ * clearing the "disconnected" bit so we don't "find" it by accident later.
+ */
 mesgin_identify:
-	test	A,0x78		jnz rej_mesgin	# !DiscPriv|!LUNTAR|!Reserved
+	test	A,0x78	jnz rej_mesgin	/*!DiscPriv|!LUNTAR|!Reserved*/
 
-	and	A,0x07				# lun in lower three bits
+	and	A,0x07			/* lun in lower three bits */
 	or      SAVED_TCL,A,SELID          
 	and     SAVED_TCL,0xf7
-	and     A,0x08,SBLKCTL			# B Channel??
+	and     A,SELBUSB,SBLKCTL	/* B Channel?? */
 	or      SAVED_TCL,A
-	call	inb_last			# ACK
-	mov	ALLZEROS	call findSCB    
-setup_SCB:
-	and	SCBARRAY+0,0xfb			# clear disconnect bit in SCB
-	or	FLAGS,IDENTIFY_SEEN		# make note of IDENTIFY
+	call	inb_last		/* ACK */
 
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to switch to the proper
+ * SCB.  Otherwise, we just use the findSCB method.
+ */
+snoop_tag_loop:
+	test	SSTAT1,BUSFREE	jnz use_findSCB
+	test	SSTAT1,REQINIT	jz snoop_tag_loop
+	test	SSTAT1,PHASEMIS	jnz use_findSCB
+	mvi	A		call inb_first
+	cmp	A,MSG_SIMPLE_TAG je get_tag
+use_findSCB:
+	mov	ALLZEROS	call findSCB	  /* Have to search */
+setup_SCB:
+	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
+	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
 	jmp	ITloop
 get_tag:
-	mvi	A		call inb_first
-	cmp	A,0x20  	jne return	# Simple Tag message?
-	mvi	A		call inb_next
-	call			inb_last
-	test	A,0xf0		jnz abort_tag	# Tag in range?
-	mov	SCBPTR,A
+	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	abort_tag
+
+/*
+ * Ensure that the SCB the tag points to is for a SCB transaction
+ * to the reconnecting target.
+ */
+	mov	SCBPTR,ARG_1
 	mov	A,SAVED_TCL
-	cmp	SCBARRAY+1,A		jne abort_tag
-	test	SCBARRAY+0,TAG_ENB	jz  abort_tag
-	ret
+	cmp	SCB_TCL,A		jne abort_tag
+	test	SCB_CONTROL,TAG_ENB	jz  abort_tag
+	call	inb_last			/* Ack Successful tag */
+	jmp	setup_SCB
 abort_tag:
-	or	SINDEX,0x10,SIGSTATE		# turn on ATNO
-	call	scsisig
-	mvi	INTSTAT,ABORT_TAG 		# let driver know
-	mvi	0xd		call mk_mesg	# ABORT TAG message
-	ret
+	or	SCSISIGO,ATNO			/* turn on ATNO */
+	mvi	INTSTAT,ABORT_TAG 		/* let driver know */
+	mvi	0xd		call mk_mesg	/* ABORT TAG message */
+	jmp	mesgin_done
 
-#  Message reject?  Let the kernel driver handle this.  If we have an 
-#  outstanding WDTR or SDTR negotiation, assume that it's a response from 
-#  the target selecting 8bit or asynchronous transfer, otherwise just ignore 
-#  it since we have no clue what it pertains to.
-#
+/*
+ * Message reject?  Let the kernel driver handle this.  If we have an 
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from 
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+ * it since we have no clue what it pertains to.
+ */
 mesgin_reject:
-	mvi	INTSTAT, MSG_REJECT
+	mvi	INTSTAT, REJECT_MSG
 	jmp	mesgin_done
 
-#  [ ADD MORE MESSAGE HANDLING HERE ]
-#
-
-#  Bus free phase.  It might be useful to interrupt the device
-#  driver if we aren't expecting this.  For now, make sure that
-#  ATN isn't being asserted and look for a new command.
-#
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * Bus free phase.  It might be useful to interrupt the device
+ * driver if we aren't expecting this.  For now, make sure that
+ * ATN isn't being asserted and look for a new command.
+ */
 p_busfree:
-	mvi	CLRSINT1,0x40			# CLRATNO
-	clr	SIGSTATE
+	mvi	CLRSINT1,CLRATNO
 
-#  if this is an immediate command, perform a psuedo command complete to
-#  notify the driver.
-	test	SCBARRAY+11,0xff	jz status_ok
-	jmp	poll_for_work
-
-#  Instead of a generic bcopy routine that requires an argument, we unroll
-#  the cases that are actually used, and call them explicitly.  This
-#  not only reduces the overhead of doing a bcopy, but ends up saving space 
-#  in the program since you don't have to put the argument into the accumulator
-#  before the call.  Both functions expect DINDEX to contain the destination 
-#  address and SINDEX to contain the source address.
+/*
+ * if this is an immediate command, perform a psuedo command complete to
+ * notify the driver.
+ */
+	test	SCB_CMDLEN,0xff	jz status_ok
+	jmp	start
+
+#if 0
+/*
+ * Instead of a generic bcopy routine that requires an argument, we unroll
+ * the cases that are actually used, and call them explicitly.  This
+ * not only reduces the overhead of doing a bcopy, but ends up saving space 
+ * in the program since you don't have to put the argument into the accumulator
+ * before the call.  Both functions expect DINDEX to contain the destination 
+ * address and SINDEX to contain the source address.
+ */
 bcopy_7:
 	mov	DINDIR,SINDIR
 	mov	DINDIR,SINDIR
@@ -913,166 +803,134 @@
 	mov	DINDIR,SINDIR
 	mov	DINDIR,SINDIR
 	mov	DINDIR,SINDIR	ret
+#endif
 	
-bcopy_7_dfdat:
-	mov	DINDIR,DFDAT
-	mov	DINDIR,DFDAT
-bcopy_5_dfdat:
-	mov	DINDIR,DFDAT
-bcopy_4_dfdat:
-	mov	DINDIR,DFDAT
-bcopy_3_dfdat:
-	mov	DINDIR,DFDAT
-	mov	DINDIR,DFDAT
-	mov	DINDIR,DFDAT	ret
-
-#  Locking the driver out, build a one-byte message passed in SINDEX
-#  if there is no active message already.  SINDEX is returned intact.
-#
+/*
+ * Locking the driver out, build a one-byte message passed in SINDEX
+ * if there is no active message already.  SINDEX is returned intact.
+ */
 mk_mesg:
-	mvi	SEQCTL,0x50			# PAUSEDIS|FASTMODE
-	test	FLAGS,ACTIVE_MSG jnz mk_mesg1	# active message?
-
-	or	FLAGS,ACTIVE_MSG		# if not, there is now
-	mvi	MSG_LEN,1			# length = 1
-	mov	MSG_START+0,SINDEX		# 1-byte message
+	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
+	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
+	
+	/*
+	 * Hmmm.  For some reason the mesg buffer is in use.
+	 * Tell the driver.  It should look at SINDEX to find
+	 * out what we wanted to use the buffer for and resolve
+	 * the conflict.
+	 */
+	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
+	mvi	INTSTAT,MSG_BUFFER_BUSY
 
 mk_mesg1:
-	mvi	SEQCTL,0x10	ret		# !PAUSEDIS|FASTMODE
+	mvi	MSG_LEN,1		/* length = 1 */
+	mov	MSG0,SINDEX		/* 1-byte message */
+	mvi	SEQCTL,0x10	ret	/* !PAUSEDIS|FASTMODE */
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
 
-#  Carefully read data in Automatic PIO mode.  I first tried this using
-#  Manual PIO mode, but it gave me continual underrun errors, probably
-#  indicating that I did something wrong, but I feel more secure leaving
-#  Automatic PIO on all the time.
-#
-#  According to Adaptec's documentation, an ACK is not sent on input from
-#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
-#  latched (the usual way), then read the data byte directly off the bus
-#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
-#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
-#  spec guarantees that the target will hold the data byte on the bus until
-#  we send our ACK.
-#
-#  The assumption here is that these are called in a particular sequence,
-#  and that REQ is already set when inb_first is called.  inb_{first,next}
-#  use the same calling convention as inb.
-#
+inb_next:
+	or	CLRSINT0, CLRSPIORDY
+	mov	NONE,SCSIDATL			/*dummy read from latch to ACK*/
+inb_next_wait:
+	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
+	test	SSTAT0,SPIORDY	jz inb_next_wait /* wait for next byte */
 inb_first:
-	clr	STCNT+2
-	clr	STCNT+1
 	mov	DINDEX,SINDEX
-	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
-
-inb_next:
-	mov	DINDEX,SINDEX			# save SINDEX
-
-        mvi     STCNT+0,1			# xfer one byte
-	mov	NONE,SCSIDATL			# dummy read from latch to ACK
-inb_next1:
-	test	SSTAT0,0x4	jz inb_next1	# SDONE
-inb_next2:
-	test	SSTAT0,0x2	jz inb_next2	# SPIORDY - wait for next byte
-	mov	DINDIR,SCSIBUSL	ret		# read byte directly from bus
-
+	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
 inb_last:
-	mvi	STCNT+0,1			# ACK with dummy read
-	mov	NONE,SCSIDATL
-inb_last1:
-	test	SSTAT0,0x4	jz inb_last1	# wait for completion
-	ret
+	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
 
-#  DMA data transfer.  HADDR and HCNT must be loaded first, and
-#  SINDEX should contain the value to load DFCNTRL with - 0x3d for
-#  host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
-#  during initialization.
-#
+mesgin_phasemis:
+/*
+ * We expected to receive another byte, but the target changed phase
+ */
+	mvi	INTSTAT, MSGIN_PHASEMIS
+	jmp	ITloop
+
+/*
+ * DMA data transfer.  HADDR and HCNT must be loaded first, and
+ * SINDEX should contain the value to load DFCNTRL with - 0x3d for
+ * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+ * during initialization.
+ */
 dma:
 	mov	DFCNTRL,SINDEX
 dma1:
-	test	SSTAT0,0x1	jnz dma3	# DMADONE
-	test	SSTAT1,0x10	jz dma1		# PHASEMIS, ie. underrun
+	test	SSTAT0,DMADONE	jnz dma3
+	test	SSTAT1,PHASEMIS	jz dma1		/* ie. underrun */
 
-#  We will be "done" DMAing when the transfer count goes to zero, or
-#  the target changes the phase (in light of this, it makes sense that
-#  the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
-#  doing a SCSI->Host transfer, the data FIFO should be flushed auto-
-#  magically on STCNT=0 or a phase change, so just wait for FIFO empty
-#  status.
-#
+/*
+ * We will be "done" DMAing when the transfer count goes to zero, or
+ * the target changes the phase (in light of this, it makes sense that
+ * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+ * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+ * magically on STCNT=0 or a phase change, so just wait for FIFO empty
+ * status.
+ */
 dma3:
-	test	SINDEX,0x4	jnz dma5	# DIRECTION
+	test	SINDEX,DIRECTION	jnz dma5
 dma4:
-	test	DFSTATUS,0x1	jz dma4		# !FIFOEMP
+	test	DFSTATUS,FIFOEMP	jz dma4
 
-#  Now shut the DMA enables off and make sure that the DMA enables are 
-#  actually off first lest we get an ILLSADDR.
-#
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are 
+ * actually off first lest we get an ILLSADDR.
+ */
 dma5:
-	and	DFCNTRL, 0x40, SINDEX		# disable DMA, but maintain
-						# WIDEODD
+	/* disable DMA, but maintain WIDEODD */
+	and	DFCNTRL,WIDEODD
 dma6:
-	test	DFCNTRL,0x38	jnz dma6	# SCSIENACK|SDMAENACK|HDMAENACK
-
-	ret
+	test	DFCNTRL,0x38	jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
 
-dma_finish:
-	test	DFSTATUS,0x8	jz dma_finish	# HDONE
-
-	clr	DFCNTRL				# disable DMA
-dma_finish2:
-	test	DFCNTRL,0x8	jnz dma_finish2	# HDMAENACK
 	ret
 
-#  Common SCSI initialization for selection and reselection.  Expects
-#  the target SCSI ID to be in the upper four bits of SINDEX, and A's
-#  contents are stomped on return.
-#
+/*
+ * Common SCSI initialization for selection and reselection.  Expects
+ * the target SCSI ID to be in the upper four bits of SINDEX, and A's
+ * contents are stomped on return.
+ */
 initialize_scsiid:
-	and	SINDEX,0xf0		# Get target ID
+	and	SINDEX,0xf0		/* Get target ID */
 	and	A,0x0f,SCSIID
 	or	SINDEX,A
 	mov	SCSIID,SINDEX ret
 
-initialize_for_target:
-#  Turn on Automatic PIO mode now, before we expect to see a REQ
-#  from the target.  It shouldn't hurt anything to leave it on.  Set
-#  CLRCHN here before the target has entered a data transfer mode -
-#  with synchronous SCSI, if you do it later, you blow away some
-#  data in the SCSI FIFO that the target has already sent to you.
-#
-	clr	SIGSTATE 
-
-	or	SXFRCTL0,0x8a			# DFON|SPIOEN|CLRCHN
-
-#  Make sure that the system knows we have not been through a DATA
-#  phase.
-	and	FLAGS, 0xfb			# !DPHASE
-
-#  Initialize SCSIRATE with the appropriate value for this target.
-#
-	call	ndx_dtr
-	mov	SCSIRATE,SINDIR	ret
-
-#  Assert that if we've been reselected, then we've seen an IDENTIFY
-#  message.
-#
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * message.
+ */
 assert:
-	test	FLAGS,RESELECTED	jz return	# reselected?
-	test	FLAGS,IDENTIFY_SEEN	jnz return	# seen IDENTIFY?
+	test	FLAGS,RESELECTED	jz return	/* reselected? */
+	test	FLAGS,IDENTIFY_SEEN	jnz return	/* seen IDENTIFY? */
 
-	mvi	INTSTAT,NO_IDENT 	ret	# no - cause a kernel panic
+	mvi	INTSTAT,NO_IDENT 	ret	/* no - cause a kernel panic */
 
-#  Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 
-#  the SCB to it.  Have the kernel print a warning message if it can't be 
-#  found, and generate an ABORT message to the target.  SINDEX should be
-#  cleared on call.
-#
+/*
+ * Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 
+ * the SCB to it.  Have the kernel print a warning message if it can't be 
+ * found, and generate an ABORT message to the target.  SINDEX should be
+ * cleared on call.
+ */
 findSCB:
 	mov	A,SAVED_TCL
-	mov	SCBPTR,SINDEX			# switch to new SCB
-	cmp	SCBARRAY+1,A	jne findSCB1	# target ID/channel/lun match?
-	test	SCBARRAY+0,DISCONNECTED	jz findSCB1 # should be disconnected
-	test	SCBARRAY+0,TAG_ENB jnz get_tag
+	mov	SCBPTR,SINDEX			/* switch to new SCB */
+	cmp	SCB_TCL,A	jne findSCB1 /* target ID/channel/lun match? */
+	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
 	ret
 
 findSCB1:
@@ -1080,130 +938,135 @@
 	mov	A,SCBCOUNT
 	cmp	SINDEX,A	jne findSCB
 
-	mvi	INTSTAT,NO_MATCH		# not found - signal kernel
-	mvi	0x6		call mk_mesg	# ABORT message
+	mvi	INTSTAT,NO_MATCH		/* not found - signal kernel */
+	mvi	MSG_ABORT	call mk_mesg	/* ABORT message */
 
-	or	SINDEX,0x10,SIGSTATE		# assert ATNO
-	call	scsisig
-	ret
+	or	SCSISIGO,ATNO	ret		/* assert ATNO */
 
-#  Make a working copy of the scatter-gather parameters from the SCB.
-#
+/*
+ * Make a working copy of the scatter-gather parameters from the SCB.
+ */
 sg_scb2ram:
-	mvi	DINDEX,HADDR
-	mvi	SCBARRAY+19	call bcopy_7
-
-	mvi	DINDEX,STCNT
-	mvi	SCBARRAY+23	call bcopy_3
-
-	mov	SG_COUNT,SCBARRAY+2
-
-	mvi	DINDEX,SG_NEXT
-	mvi	SCBARRAY+3	call bcopy_4
-	ret
-
-#  Copying RAM values back to SCB, for Save Data Pointers message, but
-#  only if we've actually been into a data phase to change them.  This
-#  protects against bogus data in scratch ram and the residual counts
-#  since they are only initialized when we go into data_in or data_out.
-#
+	mov	HADDR0, SCB_DATAPTR0
+	mov	HADDR1, SCB_DATAPTR1
+	mov	HADDR2, SCB_DATAPTR2
+	mov	HADDR3, SCB_DATAPTR3
+	mov	HCNT0, SCB_DATACNT0
+	mov	HCNT1, SCB_DATACNT1
+	mov	HCNT2, SCB_DATACNT2
+
+	mov	STCNT0, HCNT0
+	mov	STCNT1, HCNT1
+	mov	STCNT2, HCNT2
+
+	mov	SG_COUNT,SCB_SGCOUNT
+
+	mov	SG_NEXT0, SCB_SGPTR0
+	mov	SG_NEXT1, SCB_SGPTR1
+	mov	SG_NEXT2, SCB_SGPTR2
+	mov	SG_NEXT3, SCB_SGPTR3 ret
+
+/*
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
 sg_ram2scb:
 	test	FLAGS, DPHASE	jz return
-	mov	SCBARRAY+2,SG_COUNT
+	mov	SCB_SGCOUNT,SG_COUNT
 
-	mvi	DINDEX,SCBARRAY+3
-	mvi	SG_NEXT		call bcopy_4
+	mov	SCB_SGPTR0,SG_NEXT0
+	mov	SCB_SGPTR1,SG_NEXT1
+	mov	SCB_SGPTR2,SG_NEXT2
+	mov	SCB_SGPTR3,SG_NEXT3
 	
-	mvi	DINDEX,SCBARRAY+19
-	mvi	SHADDR	call bcopy_4
-
-# Use the residual number since STCNT is corrupted by any message transfer
-	mvi	SCBARRAY+15	call bcopy_3
-	ret
-
-#  Add the array base SYNCNEG to the target offset (the target address
-#  is in SCSIID), and return the result in SINDEX.  The accumulator
-#  contains the 3->8 decoding of the target ID on return.
-#
+	mov	SCB_DATAPTR0,SHADDR0
+	mov	SCB_DATAPTR1,SHADDR1
+	mov	SCB_DATAPTR2,SHADDR2
+	mov	SCB_DATAPTR3,SHADDR3
+
+/*
+ * Use the residual number since STCNT is corrupted by any message transfer
+ */
+	mov	SCB_DATACNT0,SCB_RESID_DCNT0
+	mov	SCB_DATACNT1,SCB_RESID_DCNT1
+	mov	SCB_DATACNT2,SCB_RESID_DCNT2 ret
+
+/*
+ * Add the array base TARG_SCRATCH to the target offset (the target address
+ * is in SCSIID), and return the result in SINDEX.  The accumulator
+ * contains the 3->8 decoding of the target ID on return.
+ */
 ndx_dtr:
 	shr	A,SCSIID,4
-	test	SBLKCTL,0x08	jz ndx_dtr_2
-	or	A,0x08		# Channel B entries add 8
+	test	SBLKCTL,SELBUSB	jz ndx_dtr_2
+	or	A,0x08		/* Channel B entries add 8 */
 ndx_dtr_2:
-	add	SINDEX,SYNCNEG,A
-
-	and	FUNCTION1,0x70,SCSIID		# 3-bit target address decode
-	mov	A,FUNCTION1	ret
+	add	SINDEX,TARG_SCRATCH,A ret
 
-#  If we need to negotiate transfer parameters, build the WDTR or SDTR message
-#  starting at the address passed in SINDEX.  DINDEX is modified on return.
-#  The SCSI-II spec requires that Wide negotiation occur first and you can
-#  only negotiat one or the other at a time otherwise in the event of a message
-#  reject, you wouldn't be able to tell which message was the culpret.
-#
+/*
+ * If we need to negotiate transfer parameters, build the WDTR or SDTR message
+ * starting at the address passed in SINDEX.  DINDEX is modified on return.
+ * The SCSI-II spec requires that Wide negotiation occur first and you can
+ * only negotiat one or the other at a time otherwise in the event of a message
+ * reject, you wouldn't be able to tell which message was the culpret.
+ */
 mk_dtr:
-	test	SCBARRAY+0,0x90 jz return	# NEEDWDTR|NEEDSDTR
-	test	SCBARRAY+0,NEEDWDTR jnz  mk_wdtr_16bit
-	or	FLAGS, MAX_OFFSET	# Force an offset of 15 or 8 if WIDE
+	test	SCB_CONTROL,NEEDWDTR jnz  mk_wdtr_16bit
+	or	FLAGS, MAXOFFSET	/* Force an offset of 15 or 8 if WIDE */
 
 mk_sdtr:
-	mvi	DINDIR,1			# extended message
-	mvi	DINDIR,3			# extended message length = 3
-	mvi	DINDIR,1			# SDTR code
+	mvi	DINDIR,1		/* extended message */
+	mvi	DINDIR,3		/* extended message length = 3 */
+	mvi	DINDIR,1		/* SDTR code */
 	call	sdtr_to_rate
-	mov	DINDIR,RETURN_1			# REQ/ACK transfer period
-	test	FLAGS, MAX_OFFSET jnz mk_sdtr_max_offset
-	and	DINDIR,0x0f,SINDIR		# Sync Offset
+	mov	DINDIR,RETURN_1		/* REQ/ACK transfer period */
+	test	FLAGS, MAXOFFSET jnz mk_sdtr_max_offset
+	and	DINDIR,0x0f,SINDIR	/* Sync Offset */
 
 mk_sdtr_done:
-	add	MSG_LEN,-MSG_START+0,DINDEX ret	# update message length
+	add	MSG_LEN,COMP_MSG0,DINDEX ret	/* update message length */
 
 mk_sdtr_max_offset:
-# We're initiating sync negotiation, so request the max offset we can (15 or 8)
-	xor	FLAGS, MAX_OFFSET
-	test	SCSIRATE, 0x80	jnz wmax_offset	# Talking to a WIDE device?
+/*
+ * We're initiating sync negotiation, so request the max offset we can (15 or 8)
+ */
+	xor	FLAGS, MAXOFFSET
+
+	/* Talking to a WIDE device? */
+	test	SCSIRATE, WIDEXFER	jnz wmax_offset	
 	mvi	DINDIR, MAX_OFFSET_8BIT
 	jmp	mk_sdtr_done
 
 wmax_offset:
-	mvi	DINDIR, MAX_OFFSET_WIDE
+	mvi	DINDIR, MAX_OFFSET_16BIT
 	jmp	mk_sdtr_done
 
 mk_wdtr_16bit:
 	mvi	ARG_1,BUS_16_BIT
 mk_wdtr:
-	mvi	DINDIR,1			# extended message
-	mvi	DINDIR,2			# extended message length = 2
-	mvi	DINDIR,3			# WDTR code
-	mov	DINDIR,ARG_1			# bus width
+	mvi	DINDIR,1		/* extended message */
+	mvi	DINDIR,2		/* extended message length = 2 */
+	mvi	DINDIR,3		/* WDTR code */
+	mov	DINDIR,ARG_1		/* bus width */
 
-	add	MSG_LEN,-MSG_START+0,DINDEX ret	# update message length
+	add	MSG_LEN,COMP_MSG0,DINDEX ret	/* update message length */
 	
-#  Set SCSI bus control signal state.  This also saves the last-written
-#  value into a location where the higher-level driver can read it - if
-#  it has to send an ABORT or RESET message, then it needs to know this
-#  so it can assert ATN without upsetting SCSISIGO.  The new value is
-#  expected in SINDEX.  Change the actual state last to avoid contention
-#  from the driver.
-#
-scsisig:
-	mov	SIGSTATE,SINDEX
-	mov	SCSISIGO,SINDEX	ret
-
 sdtr_to_rate:
-	call	ndx_dtr				# index scratch space for target
+	call	ndx_dtr			/* index scratch space for target */
 	shr	A,SINDIR,0x4
-	dec	SINDEX				#Preserve SINDEX
+	dec	SINDEX			/* Preserve SINDEX */
 	and	A,0x7
 	clr	RETURN_1
 sdtr_to_rate_loop:
 	test	A,0x0f	jz sdtr_to_rate_done
-	add	RETURN_1,0x18
+	add	RETURN_1,0x19
 	dec	A	
 	jmp	sdtr_to_rate_loop
 sdtr_to_rate_done:
 	shr	RETURN_1,0x2
-	add	RETURN_1,0x18
+	add	RETURN_1,0x19
 	test	SXFRCTL0,ULTRAEN jz return
 	shr	RETURN_1,0x1
 return:
diff -u --recursive --new-file v1.3.63/linux/drivers/scsi/aic7xxx_asm.c linux/drivers/scsi/aic7xxx_asm.c
--- v1.3.63/linux/drivers/scsi/aic7xxx_asm.c	Mon Oct 23 18:02:08 1995
+++ linux/drivers/scsi/aic7xxx_asm.c	Thu Feb 15 06:57:02 1996
@@ -27,12 +27,13 @@
  * A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
  * are token separators.
  *-M*************************************************************************/
-static char id[] = "$Id: aic7xxx_asm.c,v 2.1 1995/08/23 04:31:40 deang Exp $";
+static const char id[] = "$Id: aic7xxx_asm.c,v 2.4 1996/01/30 07:17:29 deang Exp $";
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #define MEMORY		448
 #define MAXLINE		1024
@@ -40,6 +41,23 @@
 #define ADOTOUT		"a.out"
 #define NOVALUE		-1
 
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+#define MAX_ARGS	16
+static const char *cpp[] = {
+  "/lib/cpp -P - -",
+  "/usr/lib/cpp -P - -",
+  "/usr/bin/cpp -P - -",
+  "/usr/bin/gcc -E -P -",
+  "/usr/bin/cc -E -P -"
+};
+
+#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
+
 /*
  * AIC-7770/AIC-7870 register definitions
  */
@@ -51,7 +69,6 @@
 int debug;
 int lineno, LC;
 char *filename;
-FILE *ifp, *ofp;
 unsigned char M[MEMORY][4];
 
 void 
@@ -207,7 +224,7 @@
 
 	i = 0;
 
-	while (fgets(buf, sizeof(buf), ifp)) {
+	while (fgets(buf, sizeof(buf), stdin)) {
 
 		lineno += 1;
 
@@ -520,7 +537,7 @@
 #undef A
 
 void
-assemble(void)
+assemble(FILE *ofile)
 {
 	int n;
 	char **a;
@@ -543,7 +560,7 @@
 			continue;
 
 		if (n == 3 && !strcmp("VERSION", *a))
-			fprintf(ofp, "#define %s \"%s\"\n", a[1], a[2]);
+			fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
 		else {
 			if (n == 3 && !strcmp("=", a[1]))
 				define(*a, strtol(a[2], NULL, 0));
@@ -553,7 +570,7 @@
 	}
 
 	backpatch();
-	output(ofp);
+	output(ofile);
 
 	if (debug)
 		output(stderr);
@@ -563,7 +580,15 @@
 main(int argc, char **argv)
 {
 	int c;
+	int pid;
+	int ifile;
+	int status;
+	FILE *ofile;
+	char *ofilename;
+	int fd[2];
 
+	ofile = NULL;
+	ofilename = NULL;
 	while ((c = getopt(argc, argv, "dho:vD")) != EOF) {
 		switch (c) {
 		    case 'd':
@@ -581,8 +606,8 @@
 			break;
 		    }
 		    case 'o':
-			ofp = fopen(optarg, "w");
-			if (!ofp) {
+		        ofilename = optarg;
+			if ((ofile = fopen(ofilename, "w")) < 0) {
 				perror(optarg);
 				exit(EXIT_FAILURE);
 			}
@@ -608,20 +633,102 @@
 	}
 	filename = argv[optind];
 
-	ifp = fopen(filename, "r");
-	if (!ifp) {
+	
+	if ((ifile = open(filename, O_RDONLY)) < 0) {
 		perror(filename);
 		exit(EXIT_FAILURE);
 	}
 
-	if (!ofp) {
-		ofp = fopen(ADOTOUT, "w");
-		if (!ofp) {
-			perror(ADOTOUT);
+	if (!ofilename) {
+		ofilename = ADOTOUT;
+		if ((ofile = fopen(ofilename, "w")) < 0) {
+			perror(ofilename);
 			exit(EXIT_FAILURE);
 		}
 	}
 
-	assemble();
-	exit(EXIT_SUCCESS);
+	if (pipe(fd) < 0) {
+		perror("pipe failed");
+		exit(1);
+	}
+
+	if ((pid = fork()) < 0 ) {
+		perror("fork failed");
+		exit(1);
+	}
+	else if (pid > 0) {		/* Parent */
+		close(fd[1]);		/* Close write end */
+		if (fd[0] != STDIN_FILENO) {
+			if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
+				perror("dup2 error on stdin");
+				exit(EXIT_FAILURE);
+			}
+			close(fd[0]);
+		}
+		assemble(ofile);
+		if (wait(&status) < 0) {
+			perror("wait error");
+		}
+
+		if (status != 0) {
+			unlink(ofilename);
+		}
+		exit(status);
+	} else {				/* Child */
+                int i, arg_cnt, found;
+		char *args[MAX_ARGS];
+		char *buf;
+
+                arg_cnt = 0;
+                found = FALSE;
+                for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
+			char *bp;
+
+			buf = strdup(cpp[i]);
+
+			for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
+                             bp != NULL;
+                             bp = strtok(NULL, " \t\n"), arg_cnt++) {
+				if (arg_cnt == 0) {
+					if (access(bp, X_OK) == 0) {
+						found = TRUE;
+					}
+				}
+
+				args[arg_cnt] = bp;
+			}
+
+                        if (!found) {
+				free(buf);
+                        }
+                }
+		args[arg_cnt] = NULL;
+
+                if (found) {
+			close(fd[0]);		/* Close Read end */
+			if (fd[1] != STDOUT_FILENO) {
+				if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+					perror("dup2 error on stdout");
+					exit(EXIT_FAILURE);
+				}
+				close(fd[1]);
+			}
+			if (ifile != STDIN_FILENO) {
+				if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
+					perror("dup2 error on stdin");
+					exit(EXIT_FAILURE);
+				}
+				close(ifile);
+			}
+
+			if (execvp(args[0], args) < 0) {
+				perror("execvp() error");
+				exit(EXIT_FAILURE);
+			}
+        	} else {
+			fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+	return(EXIT_SUCCESS);
 }
diff -u --recursive --new-file v1.3.63/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v1.3.63/linux/drivers/scsi/aic7xxx_reg.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/aic7xxx_reg.h	Thu Feb 15 06:57:02 1996
@@ -0,0 +1,746 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: aic7xxx_reg.h,v 1.2 1996/02/10 06:23:39 deang Exp $
+ *-M*************************************************************************/
+
+/*
+ * This header is shared by the sequencer code and the kernel level driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book availible from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+#define SCSISEQ			0x000
+#define		TEMODEO		0x80
+#define		ENSELO		0x40
+#define		ENSELI		0x20
+#define		ENRSELI		0x10
+#define		ENAUTOATNO	0x08
+#define		ENAUTOATNI	0x04
+#define		ENAUTOATNP	0x02
+#define		SCSIRSTO	0x01
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+#define	SXFRCTL0		0x001
+#define		DFON		0x80
+#define		DFPEXP		0x40
+#define		ULTRAEN		0x20
+#define		CLRSTCNT	0x10
+#define		SPIOEN		0x08
+#define		SCAMEN		0x04
+#define		CLRCHN		0x02
+/*  UNUSED			0x01 */
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+#define	SXFRCTL1		0x002
+#define		BITBUCKET	0x80
+#define		SWRAPEN		0x40
+#define		ENSPCHK		0x20
+#define		STIMESEL	0x18
+#define		ENSTIMER	0x04
+#define		ACTNEGEN	0x02
+#define		STPWEN		0x01	/* Powered Termination */
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+#define SCSISIGI		0x003
+#define		CDI		0x80
+#define		IOI		0x40
+#define		MSGI		0x20
+#define		ATNI		0x10
+#define		SELI		0x08
+#define		BSYI		0x04
+#define		REQI		0x02
+#define		ACKI		0x01
+
+/*
+ * Possible phases in SCSISIGI
+ */
+#define		PHASE_MASK	0xe0
+#define		P_DATAOUT	0x00
+#define		P_DATAIN	0x40
+#define		P_COMMAND	0x80
+#define		P_MESGOUT	0xa0
+#define		P_STATUS	0xc0
+#define		P_MESGIN	0xe0
+/*
+ * SCSI Contol Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+#define SCSISIGO		0x003
+#define		CDO		0x80
+#define		IOO		0x40
+#define		MSGO		0x20
+#define		ATNO		0x10
+#define		SELO		0x08
+#define		BSYO		0x04
+#define		REQO		0x02
+#define		ACKO		0x01
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+#define SCSIRATE		0x004
+#define		WIDEXFER	0x80		/* Wide transfer control */
+#define		SXFR		0x70		/* Sync transfer rate */
+#define		SOFS		0x0f		/* Sync offset */
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+#define SCSIID			0x005
+#define		TID		0xf0		/* Target ID mask */
+#define		OID		0x0f		/* Our ID mask */
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latchs used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asyncronouse data phase transfer.
+ */
+#define SCSIDATL		0x006
+#define SCSIDATH		0x007
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transfered
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transfered.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+#define STCNT			0x008
+#define STCNT0			0x008
+#define STCNT1			0x009
+#define STCNT2			0x00a
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+#define	CLRSINT0		0x00b
+#define		CLRSELDO	0x40
+#define		CLRSELDI	0x20
+#define		CLRSELINGO	0x10
+#define		CLRSWRAP	0x08
+/*  UNUSED			0x04 */
+#define		CLRSPIORDY	0x02
+/*  UNUSED			0x01 */
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+#define SSTAT0			0x00b
+#define		TARGET		0x80		/* Board acting as target */
+#define		SELDO		0x40		/* Selection Done */
+#define		SELDI		0x20		/* Board has been selected */
+#define		SELINGO		0x10		/* Selection In Progress */
+#define		SWRAP		0x08		/* 24bit counter wrap */
+#define		SDONE		0x04		/* STCNT = 0x000000 */
+#define		SPIORDY		0x02		/* SCSI PIO Ready */
+#define		DMADONE		0x01		/* DMA transfer completed */
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+#define CLRSINT1		0x00c
+#define		CLRSELTIMEO	0x80
+#define		CLRATNO		0x40
+#define		CLRSCSIRSTI	0x20
+/*  UNUSED			0x10 */
+#define		CLRBUSFREE	0x08
+#define		CLRSCSIPERR	0x04
+#define		CLRPHASECHG	0x02
+#define		CLRREQINIT	0x01
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+#define SSTAT1			0x00c
+#define		SELTO		0x80
+#define		ATNTARG 	0x40
+#define		SCSIRSTI	0x20
+#define		PHASEMIS	0x10
+#define		BUSFREE		0x08
+#define		SCSIPERR	0x04
+#define		PHASECHG	0x02
+#define		REQINIT		0x01
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+#define	SIMODE1			0x011
+#define		ENSELTIMO	0x80
+#define		ENATNTARG	0x40
+#define		ENSCSIRST	0x20
+#define		ENPHASEMIS	0x10
+#define		ENBUSFREE	0x08
+#define		ENSCSIPERR	0x04
+#define		ENPHASECHG	0x02
+#define		ENREQINIT	0x01
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+#define	SCSIBUSL		0x012
+#define	SCSIBUSH		0x013
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transfered on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transfered since HADDR
+ * can be squewed by write ahead.
+ */
+#define	SHADDR			0x014
+#define	SHADDR0			0x014
+#define	SHADDR1			0x015
+#define	SHADDR2			0x016
+#define	SHADDR3			0x017
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+#define SELID			0x019
+#define		SELID_MASK	0xf0
+#define		ONEBIT		0x08
+/*  UNUSED			0x07 */
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection.  In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+#define SBLKCTL			0x01f
+#define		DIAGLEDEN	0x80	/* Aic78X0 only */
+#define		DIAGLEDON	0x40	/* Aic78X0 only */
+#define		AUTOFLUSHDIS	0x20
+/*  UNUSED			0x10 */
+#define		SELBUS_MASK	0x0a
+#define		SELBUSB		0x08
+/*  UNUSED			0x04 */
+#define		SELWIDE		0x02
+/*  UNUSED			0x01 */
+#define		SELNARROW	0x00
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+#define SEQCTL			0x060
+#define		PERRORDIS	0x80
+#define		PAUSEDIS	0x40
+#define		FAILDIS		0x20
+#define 	FASTMODE	0x10
+#define		BRKADRINTEN	0x08
+#define		STEP		0x04
+#define		SEQRESET	0x02
+#define		LOADRAM		0x01
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in sucessesion.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+#define SEQRAM			0x061
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+#define SEQADDR0		0x062
+#define SEQADDR1		0x063
+#define 	SEQADDR1_MASK	0x01
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+#define ACCUM			0x064
+
+#define SINDEX			0x065
+#define DINDEX			0x066
+#define ALLZEROS		0x06a
+#define NONE			0x06a
+#define SINDIR			0x06c
+#define DINDIR			0x06d
+#define FUNCTION1		0x06e
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transfered across the host bus.
+ */
+#define HADDR			0x088
+#define HADDR0			0x088
+#define HADDR1			0x089
+#define HADDR2			0x08a
+#define HADDR3			0x08b
+
+#define HCNT			0x08c
+#define HCNT0			0x08c
+#define HCNT1			0x08d
+#define HCNT2			0x08e
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+#define SCBPTR			0x090
+
+/*
+ * Board Control (p. 3-43)
+ */
+#define BCTL			0x084
+/*   RSVD			0xf0 */
+#define		ACE		0x08	/* Support for external processors */
+/*   RSVD			0x06 */
+#define		ENABLE		0x01
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+#define	DSCOMMAND		0x084
+#define		CACHETHEN	0x80	/* Cache Threshold enable */
+#define		DPARCKEN	0x40	/* Data Parity Check Enable */
+#define		MPARCKEN	0x20	/* Memory Parity Check Enable */
+#define		EXTREQLCK	0x10	/* External Request Lock */
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+#define BUSTIME			0x085
+#define		BOFF		0xf0
+#define		BON		0x0f
+#define		BOFF_60BCLKS	0xf0
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+#define	BUSSPD			0x086
+#define		DFTHRSH		0xc0
+#define		STBOFF		0x38
+#define		STBON		0x07
+#define		DFTHRSH_100	0xc0
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overal host control of the device.
+ */
+#define HCNTRL			0x087
+/*    UNUSED			0x80 */
+#define		POWRDN		0x40
+/*    UNUSED			0x20 */
+#define		SWINT		0x10
+#define		IRQMS		0x08
+#define		PAUSE		0x04
+#define		INTEN		0x02
+#define		CHIPRST		0x01
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+#define INTSTAT			0x091
+#define		SEQINT_MASK	0xf1		/* SEQINT Status Codes */
+#define			BAD_PHASE	0x01	/* unknown scsi bus phase */
+#define			SEND_REJECT	0x11	/* sending a message reject */
+#define			NO_IDENT	0x21	/* no IDENTIFY after reconnect*/
+#define			NO_MATCH	0x31	/* no cmd match for reconnect */
+#define			SDTR_MSG	0x41	/* SDTR message recieved */
+#define			WDTR_MSG	0x51	/* WDTR message recieved */
+#define			REJECT_MSG	0x61	/* Reject message recieved */
+#define			BAD_STATUS	0x71	/* Bad status from target */
+#define			RESIDUAL	0x81	/* Residual byte count != 0 */
+#define			ABORT_TAG	0x91	/* Sent an ABORT_TAG message */
+#define			AWAITING_MSG	0xa1	/*
+						 * Kernel requested to specify
+                                                 * a message to this target
+                                                 * (command was null), so tell
+                                                 * it that it can fill the
+                                                 * message buffer.
+                                                 */
+#define			IMMEDDONE	0xb1	/*
+						 * An immediate command has
+						 * completed
+						 */
+#define			MSG_BUFFER_BUSY	0xc1	/*
+						 * Sequencer wants to use the
+						 * message buffer, but it
+						 * already contains a message
+						 */
+#define			MSGIN_PHASEMIS	0xd1	/*
+						 * Target changed phase on us
+						 * when we were expecting
+						 * another msgin byte.
+						 */
+#define			PARITY_ERROR	0xe1	/*
+						 * Sequencer detected a parity
+						 * error.
+						 */
+#define 	BRKADRINT 0x08
+#define		SCSIINT	  0x04
+#define		CMDCMPLT  0x02
+#define		SEQINT    0x01
+#define		INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+#define ERROR			0x092
+/*    UNUSED			0xf0 */
+#define		PARERR		0x08
+#define		ILLOPCODE	0x04
+#define		ILLSADDR	0x02
+#define		ILLHADDR	0x01
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+#define CLRINT			0x092
+#define		CLRBRKADRINT	0x08
+#define		CLRSCSIINT      0x04
+#define		CLRCMDINT 	0x02
+#define		CLRSEQINT 	0x01
+
+#define	DFCNTRL			0x093
+#define		WIDEODD		0x40
+#define		SCSIEN		0x20
+#define		SDMAEN		0x10
+#define		SDMAENACK	0x10
+#define		HDMAEN		0x08
+#define		HDMAENACK	0x08
+#define		DIRECTION	0x04
+#define		FIFOFLUSH	0x02
+#define		FIFORESET	0x01
+
+#define	DFSTATUS		0x094
+#define		HDONE		0x08
+#define		FIFOEMP		0x01
+
+#define	DFDAT			0x099
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+#define SCBCNT			0x09a
+#define		SCBAUTO		0x80
+#define		SCBCNT_MASK	0x1f
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+#define QINFIFO			0x09b
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+#define QINCNT			0x09c
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+#define QOUTFIFO		0x09d
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+#define QOUTCNT			0x09e
+
+/*
+ * SCB Definition (p. 5-4)
+ * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
+ * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
+ * whether or not to DMA an SCB from host ram. This flag prevents the
+ * "re-fetching" of transactions that are requed because the target is
+ * busy with another command. We also use bits 6 & 7 to indicate whether
+ * or not to initiate SDTR or WDTR repectively when starting this command.
+ */
+#define SCBARRAY		0x0a0
+#define	SCB_CONTROL		0x0a0
+#define		NEEDWDTR        0x80
+#define		DISCENB         0x40
+#define		TAG_ENB		0x20
+#define		NEEDSDTR	0x10
+#define		DISCONNECTED	0x04
+#define		SCB_TAG_TYPE	0x03
+#define	SCB_TCL			0x0a1
+#define	SCB_TARGET_STATUS	0x0a2
+#define	SCB_SGCOUNT		0x0a3
+#define	SCB_SGPTR		0x0a4
+#define		SCB_SGPTR0	0x0a4
+#define		SCB_SGPTR1	0x0a5
+#define		SCB_SGPTR2	0x0a6
+#define		SCB_SGPTR3	0x0a7
+#define	SCB_RESID_SGCNT		0x0a8
+#define SCB_RESID_DCNT		0x0a9
+#define		SCB_RESID_DCNT0	0x0a9
+#define		SCB_RESID_DCNT1	0x0aa
+#define		SCB_RESID_DCNT2	0x0ab
+#define SCB_DATAPTR		0x0ac
+#define		SCB_DATAPTR0	0x0ac
+#define		SCB_DATAPTR1	0x0ad
+#define		SCB_DATAPTR2	0x0ae
+#define		SCB_DATAPTR3	0x0af
+#define	SCB_DATACNT		0x0b0
+#define		SCB_DATACNT0	0x0b0
+#define		SCB_DATACNT1	0x0b1
+#define		SCB_DATACNT2	0x0b2
+/* UNUSED - QUAD PADDING	0x0b3 */
+#define SCB_CMDPTR		0x0b4
+#define		SCB_CMDPTR0	0x0b4
+#define		SCB_CMDPTR1	0x0b5
+#define		SCB_CMDPTR2	0x0b6
+#define		SCB_CMDPTR3	0x0b7
+#define	SCB_CMDLEN		0x0b8
+#define	SCB_NEXT_WAITING	0x0b9
+
+#ifdef linux
+#define	SG_SIZEOF		0x0c		/* sizeof(struct scatterlist) */
+#else
+#define	SG_SIZEOF		0x08		/* sizeof(struct ahc_dma) */
+#endif
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+#define	SEECTL_2840		0x0c0
+/*	UNUSED			0xf8 */
+#define		CS_2840		0x04
+#define		CK_2840		0x02
+#define		DO_2840		0x01
+
+#define	STATUS_2840		0x0c1
+#define		EEPROM_TF	0x80
+#define		BIOS_SEL	0x60
+#define		ADSEL		0x1e
+#define		DI_2840		0x01
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+#define DSPCISTATUS		0x086
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+#define SEECTL			0x01e
+#define		EXTARBACK	0x80
+#define		EXTARBREQ	0x40
+#define		SEEMS		0x20
+#define		SEERDY		0x10
+#define		SEECS		0x08
+#define		SEECK		0x04
+#define		SEEDO		0x02
+#define		SEEDI		0x01
+
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
+
+/*
+ * 1 byte per target starting at this address for configuration values
+ */
+#define TARG_SCRATCH		0x020
+
+/*
+ * The sequencer will stick the frist byte of any rejected message here so
+ * we can see what is getting thrown away.
+ */
+#define REJBYTE			0x031
+
+/*
+ * Bit vector of targets that have disconnection disabled.
+ */
+#define	DISC_DSB		0x032
+#define		DISC_DSB_A	0x032
+#define		DISC_DSB_B	0x033
+
+/*
+ * Length of pending message
+ */
+#define MSG_LEN			0x034
+
+#define MSG0			0x035
+#define		COMP_MSG0	0xcb      /* 2's complement of MSG0 */
+#define MSG1			0x036
+#define MSG2			0x037
+#define MSG3			0x038
+#define MSG4			0x039
+#define MSG5			0x03a
+
+/*
+ * These are offsets into the card's scratch ram.  Some of the values are
+ * specified in the AHA2742 technical reference manual and are initialized
+ * by the BIOS at boot time.
+ */
+#define LASTPHASE		0x049
+#define ARG_1			0x04a
+#define RETURN_1		0x04a
+#define		SEND_SENSE	0x80
+#define		SEND_WDTR	0x80
+#define		SEND_SDTR	0x80
+#define		SEND_REJ	0x40
+
+#define SIGSTATE		0x04b
+
+#define DMAPARAMS		0x04c	/* Parameters for DMA Logic */
+
+#define	SG_COUNT		0x04d
+#define	SG_NEXT			0x04e	/* working value of SG pointer */
+#define		SG_NEXT0	0x04e
+#define		SG_NEXT1	0x04f
+#define		SG_NEXT2	0x050
+#define		SG_NEXT3	0x051
+
+#define	SCBCOUNT		0x052	/*
+					 * Number of SCBs supported by
+					 * this card.
+					 */
+#define FLAGS			0x053
+#define		SINGLE_BUS	0x00
+#define		TWIN_BUS	0x01
+#define		WIDE_BUS	0x02
+#define		DPHASE		0x04
+#define		MAXOFFSET	0x08
+#define		IDENTIFY_SEEN	0x40
+#define		RESELECTED	0x80
+
+#define	ACTIVE_A		0x054
+#define	ACTIVE_B		0x055
+#define	SAVED_TCL		0x056	/*
+					 * Temporary storage for the
+					 * target/channel/lun of a
+					 * reconnecting target
+					 */
+#define WAITING_SCBH		0x057	/*
+					 * head of list of SCBs awaiting
+					 * selection
+					 */
+#define WAITING_SCBT		0x058	/*
+					 * tail of list of SCBs awaiting
+					 * selection
+					 */
+#define	COMP_SCBCOUNT		0x059
+#define		SCB_LIST_NULL	0xff
+
+#define SCSICONF		0x05a
+#define HOSTCONF		0x05d
+
+#define HA_274_BIOSCTRL		0x05f
+#define BIOSMODE		0x30
+#define BIOSDISABLED		0x30
+
+/* Message codes */
+#define MSG_EXTENDED		0x01
+#define		MSG_SDTR	0x01
+#define		MSG_WDTR	0x03
+#define MSG_SDPTRS		0x02
+#define MSG_RDPTRS		0x03
+#define MSG_DISCONNECT		0x04
+#define MSG_INITIATOR_DET_ERROR	0x05
+#define MSG_ABORT		0x06
+#define	MSG_REJECT		0x07
+#define MSG_NOP			0x08
+#define MSG_MSG_PARITY_ERROR	0x09
+#define MSG_BUS_DEVICE_RESET	0x0c
+#define MSG_SIMPLE_TAG		0x20
+#define MSG_IDENTIFY		0x80
+
+/* WDTR Message values */
+#define	BUS_8_BIT		0x00
+#define BUS_16_BIT		0x01
+#define BUS_32_BIT		0x02
+
+#define MAX_OFFSET_8BIT		0x0f
+#define MAX_OFFSET_16BIT	0x08
+
diff -u --recursive --new-file v1.3.63/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v1.3.63/linux/drivers/scsi/scsi_syms.c	Wed Feb  7 15:11:29 1996
+++ linux/drivers/scsi/scsi_syms.c	Thu Feb 15 09:21:30 1996
@@ -61,6 +61,7 @@
     X(need_isa_buffer),
     X(request_queueable),
     X(print_Scsi_Cmnd),
+    X(scsi_mark_host_bus_reset),
 #if defined(CONFIG_PROC_FS)
     X(proc_print_scsidevice),
 #endif
diff -u --recursive --new-file v1.3.63/linux/fs/Config.in linux/fs/Config.in
--- v1.3.63/linux/fs/Config.in	Wed Feb  7 15:11:29 1996
+++ linux/fs/Config.in	Thu Feb 15 07:21:10 1996
@@ -12,8 +12,8 @@
 
 # msdos filesystems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
-dep_tristate 'Old MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate 'vfat (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
+dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
+dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
 dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
 
 bool '/proc filesystem support' CONFIG_PROC_FS
diff -u --recursive --new-file v1.3.63/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.63/linux/fs/buffer.c	Fri Feb  9 17:53:05 1996
+++ linux/fs/buffer.c	Thu Feb 15 12:43:10 1996
@@ -100,7 +100,7 @@
 				   trim back the buffers */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{60, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{25, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 
 /* The lav constant is set for 1 minute, as long as the update process runs
    every 5 seconds.  If you change the frequency of update, the time
@@ -1111,7 +1111,7 @@
 				memcpy(next->b_data, tmp->b_data, size);
 			else {
 				memcpy(tmp->b_data, next->b_data, size);
-				set_bit(BH_Dirty, &tmp->b_state);
+				mark_buffer_dirty(tmp, 0);
 			}
 			brelse(tmp);
 			next->b_count--;
diff -u --recursive --new-file v1.3.63/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c
--- v1.3.63/linux/fs/fat/fatfs_syms.c	Fri Feb  9 17:53:06 1996
+++ linux/fs/fat/fatfs_syms.c	Thu Feb 15 09:21:30 1996
@@ -6,6 +6,7 @@
  */
 #include <linux/module.h>
 
+#include <linux/mm.h>
 #include <linux/msdos_fs.h>
 
 #include "msbuffer.h"
diff -u --recursive --new-file v1.3.63/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- v1.3.63/linux/fs/msdos/msdosfs_syms.c	Wed Feb 14 14:37:18 1996
+++ linux/fs/msdos/msdosfs_syms.c	Thu Feb 15 09:21:30 1996
@@ -7,6 +7,7 @@
 
 #include <linux/module.h>
 
+#include <linux/mm.h>
 #include <linux/msdos_fs.h>
 
 static struct symbol_table msdos_syms = {
diff -u --recursive --new-file v1.3.63/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.63/linux/fs/proc/array.c	Wed Feb 14 14:37:18 1996
+++ linux/fs/proc/array.c	Thu Feb 15 14:37:11 1996
@@ -775,6 +775,7 @@
 #endif
 extern int get_device_list(char *);
 extern int get_filesystem_list(char *);
+extern int get_filesystem_info( char * );
 extern int get_irq_list(char *);
 extern int get_dma_list(char *);
 extern int get_cpuinfo(char *);
@@ -846,6 +847,9 @@
 #endif
 		case PROC_CMDLINE:
 			return get_cmdline(page);
+
+                case PROC_MTAB:
+                       return get_filesystem_info( page );
 	}
 	return -EBADF;
 }
diff -u --recursive --new-file v1.3.63/linux/fs/proc/root.c linux/fs/proc/root.c
--- v1.3.63/linux/fs/proc/root.c	Wed Feb  7 15:11:34 1996
+++ linux/fs/proc/root.c	Thu Feb 15 14:37:11 1996
@@ -361,6 +361,9 @@
 		PROC_CMDLINE, 7, "cmdline",
 		S_IFREG | S_IRUGO, 1, 0, 0,
 	});
+
+	proc_register( &proc_root, &(struct proc_dir_entry)
+	   { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } );
 		   
 	if (prof_shift) {
 		proc_register(&proc_root, &(struct proc_dir_entry) {
diff -u --recursive --new-file v1.3.63/linux/fs/super.c linux/fs/super.c
--- v1.3.63/linux/fs/super.c	Sun Jan 14 16:30:14 1996
+++ linux/fs/super.c	Thu Feb 15 14:37:11 1996
@@ -262,6 +262,23 @@
 	return retval;
 }
 
+int get_filesystem_info( char *buf )
+{
+	struct vfsmount *tmp = vfsmntlist;
+	int len = 0;
+
+	while ( tmp && len < PAGE_SIZE - 80 )
+	{
+		len += sprintf( buf + len, "%s %s %s %s",
+			tmp->mnt_devname, tmp->mnt_dirname, tmp->mnt_sb->s_type->name,
+			tmp->mnt_flags & MS_RDONLY ? "ro" : "rw" );
+		len += sprintf( buf + len, " 0 0\n" );
+		tmp = tmp->mnt_next;
+	}
+
+	return len;
+}
+
 int get_filesystem_list(char * buf)
 {
 	int len = 0;
diff -u --recursive --new-file v1.3.63/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v1.3.63/linux/fs/vfat/namei.c	Fri Feb  9 17:53:07 1996
+++ linux/fs/vfat/namei.c	Thu Feb 15 11:59:47 1996
@@ -401,6 +401,7 @@
 		extlen = 0;
 	}
 	ext[extlen] = '\0';
+	base[baselen] = '\0';
 
 	count = 0;
 	strcpy(msdos_name, base);
diff -u --recursive --new-file v1.3.63/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h
--- v1.3.63/linux/include/asm-alpha/byteorder.h	Sun Jan 14 16:30:14 1996
+++ linux/include/asm-alpha/byteorder.h	Thu Feb 15 09:20:41 1996
@@ -37,17 +37,17 @@
 	unsigned long int res, t1, t2;
 
 	__asm__(
-	"# bswap input: %0 (aabbccdd)
-	# output: %0, used %1 %2
-	extlh	%0,5,%1		# %1 = dd000000
-	zap	%0,0xfd,%2	# %2 = 0000cc00
-	sll	%2,5,%2		# %2 = 00198000
-	s8addq	%2,%1,%1	# %1 = ddcc0000
-	zap	%0,0xfb,%2	# %2 = 00bb0000
-	srl	%2,8,%2		# %2 = 0000bb00
-	extbl	%0,3,%0		# %0 = 000000aa
-	or	%1,%0,%0	# %0 = ddcc00aa
-	or	%2,%0,%0	# %0 = ddccbbaa"
+	"# bswap input: %0 (aabbccdd)\n\t"
+	"# output: %0, used %1 %2\n\t"
+	"extlh	%0,5,%1		# %1 = dd000000\n\t"
+	"zap	%0,0xfd,%2	# %2 = 0000cc00\n\t"
+	"sll	%2,5,%2		# %2 = 00198000\n\t"
+	"s8addq	%2,%1,%1	# %1 = ddcc0000\n\t"
+	"zap	%0,0xfb,%2	# %2 = 00bb0000\n\t"
+	"srl	%2,8,%2		# %2 = 0000bb00\n\t"
+	"extbl	%0,3,%0		# %0 = 000000aa\n\t"
+	"or	%1,%0,%0	# %0 = ddcc00aa\n\t"
+	"or	%2,%0,%0	# %0 = ddccbbaa\n"
 	: "r="(res), "r="(t1), "r="(t2)
 	: "0" (x & 0xffffffffUL));
 	return res;
@@ -64,12 +64,13 @@
 {
 	unsigned long int res, t1;
 	
-	__asm__
-	    ("bis	%2,%2,%0	# v0 is result; swap in-place.  v0=aabb
-	      extwh	%0,7,%1		# t1 = bb00
-	      extbl	%0,1,%0		# v0 = 00aa
-	      bis	%0,%1,%0	# v0 = bbaa"
-	     : "r="(res), "r="(t1) : "r"(x));
+	__asm__(
+	"# v0 is result; swap in-place.\n\t"
+	"bis	%2,%2,%0	# v0 = aabb\n\t"
+	"extwh	%0,7,%1		# t1 = bb00\n\t"
+	"extbl	%0,1,%0		# v0 = 00aa\n\t"
+	"bis	%0,%1,%0	# v0 = bbaa\n"
+	: "r="(res), "r="(t1) : "r"(x));
 	return res;
 }
 
diff -u --recursive --new-file v1.3.63/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v1.3.63/linux/include/asm-alpha/system.h	Wed Feb  7 15:11:36 1996
+++ linux/include/asm-alpha/system.h	Thu Feb 15 09:20:41 1996
@@ -113,10 +113,10 @@
 /*
  * Give prototypes to shut up gcc.
  */
-extern inline unsigned long xchg_u32 (volatile int * m, unsigned long val);
-extern inline unsigned long xchg_u64 (volatile long * m, unsigned long val);
+extern __inline__ unsigned long xchg_u32 (volatile int * m, unsigned long val);
+extern __inline__ unsigned long xchg_u64 (volatile long * m, unsigned long val);
 
-extern inline unsigned long xchg_u32(volatile int * m, unsigned long val)
+extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
 {
 	unsigned long dummy, dummy2;
 
@@ -132,7 +132,7 @@
 	return val;
 }
 
-extern inline unsigned long xchg_u64(volatile long * m, unsigned long val)
+extern __inline__ unsigned long xchg_u64(volatile long * m, unsigned long val)
 {
 	unsigned long dummy, dummy2;
 
@@ -161,7 +161,7 @@
  */
 extern void __xchg_called_with_bad_pointer(void);
 
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 {
 	switch (size) {
 		case 4:
diff -u --recursive --new-file v1.3.63/linux/include/linux/cdk.h linux/include/linux/cdk.h
--- v1.3.63/linux/include/linux/cdk.h	Mon Nov 27 12:48:36 1995
+++ linux/include/linux/cdk.h	Thu Feb 15 12:07:36 1996
@@ -3,7 +3,7 @@
 /*
  *	cdk.h  -- CDK interface definitions.
  *
- *	Copyright (C) 1994,1995  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -467,6 +467,12 @@
 #define	STL_BSTART	_IO('s',21)
 #define	STL_BSTOP	_IO('s',22)
 #define	STL_BRESET	_IO('s',23)
+
+/*
+ *	Define a set of ioctl extensions, used to get at special stuff.
+ */
+#define	STL_GETPFLAG	_IO('s',80)
+#define	STL_SETPFLAG	_IO('s',81)
 
 /*****************************************************************************/
 #endif
diff -u --recursive --new-file v1.3.63/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.63/linux/include/linux/proc_fs.h	Wed Feb 14 14:37:18 1996
+++ linux/include/linux/proc_fs.h	Thu Feb 15 14:37:11 1996
@@ -40,7 +40,8 @@
 #endif
 	PROC_PROFILE, /* whether enabled or not */
 	PROC_CMDLINE,
-	PROC_SYS
+	PROC_SYS,
+	PROC_MTAB
 };
 
 enum pid_directory_inos {
diff -u --recursive --new-file v1.3.63/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.63/linux/kernel/ksyms.c	Wed Feb 14 14:37:19 1996
+++ linux/kernel/ksyms.c	Thu Feb 15 07:12:55 1996
@@ -106,15 +106,6 @@
 extern void free_dma(unsigned int dmanr);
 extern int (*rarp_ioctl_hook)(int,void*);
 
-extern void (* iABI_hook)(struct pt_regs * regs);
-
-#ifdef CONFIG_BINFMT_ELF
-#include <linux/elfcore.h>
-extern int dump_fpu(elf_fpregset_t *);
-#endif
-
-extern void dump_thread(struct pt_regs *, struct user *);
-
 struct symbol_table symbol_table = {
 #include <linux/symtab_begin.h>
 #ifdef MODVERSIONS
@@ -472,11 +463,7 @@
 	X(tr_type_trans),
 #endif
 
-#ifdef CONFIG_BINFMT_ELF
-	X(dump_fpu),
-#endif
 	/* bimfm_aout */
-	X(dump_thread),
 	X(get_write_access),
 	X(put_write_access),
 
diff -u --recursive --new-file v1.3.63/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.63/linux/net/ipv4/af_inet.c	Wed Feb 14 14:37:20 1996
+++ linux/net/ipv4/af_inet.c	Thu Feb 15 09:21:37 1996
@@ -93,6 +93,9 @@
 #ifdef CONFIG_IP_ALIAS
 #include <net/ip_alias.h>
 #endif
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 #define min(a,b)	((a)<(b)?(a):(b))
 
@@ -1292,6 +1295,10 @@
 		case SIOCDRARP:
 		case SIOCGRARP:
 		case SIOCSRARP:
+#ifdef CONFIG_KERNELD
+			if (rarp_ioctl_hook == NULL)
+				request_module("rarp");
+#endif
 			if (rarp_ioctl_hook != NULL)
 				return(rarp_ioctl_hook(cmd,(void *) arg));
 		case SIOCGIFCONF:
diff -u --recursive --new-file v1.3.63/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v1.3.63/linux/net/ipv4/ipip.c	Thu Nov  9 11:23:56 1995
+++ linux/net/ipv4/ipip.c	Thu Feb 15 14:52:54 1996
@@ -115,7 +115,9 @@
 
 static struct inet_protocol ipip_protocol = {
   ipip_rcv,             /* IPIP handler          */
+#if 0
   NULL,                 /* Will be UDP fraglist handler */
+#endif
   NULL,                 /* TUNNEL error control    */
   0,                    /* next                 */
   IPPROTO_IPIP,         /* protocol ID          */
diff -u --recursive --new-file v1.3.63/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v1.3.63/linux/net/ipv4/rarp.c	Fri Nov 17 08:42:34 1995
+++ linux/net/ipv4/rarp.c	Thu Feb 15 09:21:37 1996
@@ -105,6 +105,7 @@
 static inline void rarp_release_entry(struct rarp_table *entry)
 {
 	kfree_s(entry, sizeof(struct rarp_table));
+	MOD_DEC_USE_COUNT;
 	return;
 }
 
@@ -370,6 +371,9 @@
 	entry->htype = htype;
 	memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
 	entry->dev = dev;
+
+	/* Don't unlink if we have entries to serve. */
+	MOD_INC_USE_COUNT;
 
 	sti();  
 
diff -u --recursive --new-file v1.3.63/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v1.3.63/linux/net/ipv4/tcp_output.c	Wed Feb 14 14:37:20 1996
+++ linux/net/ipv4/tcp_output.c	Thu Feb 15 14:28:14 1996
@@ -532,7 +532,7 @@
 	}
 
 	t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr));
-	memcpy(t1, th, sizeof(*t1));
+	memset(t1, 0, sizeof(*t1));
 
 	/*
 	 *	Swap the send and the receive. 
@@ -540,19 +540,16 @@
 
 	t1->dest = th->source;
 	t1->source = th->dest;
-	t1->syn = 0;
-	t1->fin = 0;
-	t1->urg = 0;
+	t1->doff = sizeof(*t1)/4;
 	t1->rst = 1;
-	t1->psh = 0;  
   
 	if(th->ack)
 	{
-		t1->ack = 0;
 	  	t1->seq = th->ack_seq;
 	}
 	else
 	{
+		t1->ack = 1;
 	  	if(!th->syn)
 			t1->ack_seq = th->seq;
 		else
