]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.64 1.3.64
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:34 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:34 +0000 (15:10 -0500)
36 files changed:
Documentation/Configure.help
Documentation/networking/arcnet-hardware.txt
Documentation/networking/arcnet.txt
Makefile
arch/alpha/kernel/bios32.c
arch/alpha/kernel/irq.c
arch/i386/kernel/ksyms.c
drivers/block/floppy.c
drivers/block/ll_rw_blk.c
drivers/block/rd.c
drivers/char/README.stallion [new file with mode: 0644]
drivers/char/istallion.c
drivers/char/stallion.c
drivers/net/arcnet.c
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.seq
drivers/scsi/aic7xxx_asm.c
drivers/scsi/aic7xxx_reg.h [new file with mode: 0644]
drivers/scsi/scsi_syms.c
fs/Config.in
fs/buffer.c
fs/fat/fatfs_syms.c
fs/msdos/msdosfs_syms.c
fs/proc/array.c
fs/proc/root.c
fs/super.c
fs/vfat/namei.c
include/asm-alpha/byteorder.h
include/asm-alpha/system.h
include/linux/cdk.h
include/linux/proc_fs.h
kernel/ksyms.c
net/ipv4/af_inet.c
net/ipv4/ipip.c
net/ipv4/rarp.c
net/ipv4/tcp_output.c

index 092e2ebb5ecaf8d980e6433d33ec7bfc59afe90e..2fcecc4519447073a39fe774ff3498854cf5c17c 100644 (file)
@@ -2041,6 +2041,20 @@ CONFIG_XIA_FS
   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 @@ CONFIG_MSDOS_FS
   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
index 5a903b4e70688d56fd3a7094941f77d822c3d9a4..1be887e6017da65545f2ce282dbf3825693c52ad 100644 (file)
@@ -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 @@ there are others as well, but these are less common.  The different hardware
 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 @@ even if it can't possibly be delivered properly (ie. because of a cable
 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 @@ limit on their packet sizes; standard ARCnet can only send packets that are
 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 @@ All ARCnet cards should have a total of four or five different settings:
     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 @@ All ARCnet cards should have a total of four or five different settings:
        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 @@ All ARCnet cards should have a total of four or five different settings:
        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 @@ All ARCnet cards should have a total of four or five different settings:
     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 @@ Cards Listed in this file (in this order, mostly):
        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 @@ I know it works when connected to a PC110 type ARCnet board.
 *****************************************************************************
 
 ** 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 @@ JP 6  : IRQ set (ONLY ONE jumper on 1-5 for IRQ 2-6)
 ** 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 @@ guess the purpose.
 ** 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 @@ parameters.  These two switches are normally left in the OFF position.
 ** 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 @@ Setting the Timeouts
 ** 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 
index a181dc3926706cf1f24f8c9b4c936edb9080d438..551841d393d354d9ebaa56df06a3b015960d4908 100644 (file)
@@ -7,8 +7,8 @@ manual with your ARCnet card.
 
 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 @@ My e-mail address is: apenwarr@foxnet.net
 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 @@ mailing list; subscribe by sending a message with the BODY "subscribe
 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 ARCnet driver v2.10 ALPHA supports three protocols, each on its own
                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 @@ you can set up your network then:
    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 @@ you can set up your network then:
        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 @@ you can set up your network then:
    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 @@ you can set up your network then:
           |               |         *            |               |
           |               +-Freedom-*-Gatekeeper-+               |
           |               |    |    *            |               |
-          \-------+-------/    |                 \-------+-------/
+          \-------+-------/    |    *            \-------+-------/
                   |            |                         |
                Insight         |                      Patience
                            (Internet)
-                        
 
 
 
-                                                    
 It works: what now?
 -------------------
 
@@ -424,31 +422,37 @@ It doesn't work: what now?
 --------------------------
 
 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 @@ You can change the debug level without recompiling the kernel by typing:
 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.
index 4265b4d1704ee2748b30cb1c16a7891598147f6e..ee9c1bc58c211d3c0ed4ed13393f73657f73b189 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 63
+SUBLEVEL = 64
 
 ARCH = i386
 
index 2786b49607d43d1f1263f9298cecfa970ad15311..474f3a6b3aad374886cabf4ba949e2a8db1f07a9 100644 (file)
@@ -581,7 +581,7 @@ static inline void avanti_and_noname_fixup(void)
                { 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 */
        };
        /*
index 541fbef452d48f5a48e35aa4ae53f864c2fdb814..42ee611c85ade11d1058cca151b8d80cf8ee0803 100644 (file)
@@ -622,6 +622,8 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon
                        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:
index 127d165290458150c91783ce1ab8b7bc1e6702ed..2f9a73bbcf5cb98192f3a86e59c27dca8d59c230 100644 (file)
@@ -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),
index f2967d5c720669ad0fea675d0a3971b248f7814e..edcc5875c42ed929d2657840f519b5ab48277643 100644 (file)
 
 /* 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 struct translation_entry {
 
 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 normalize_0x02xx_ioctl(int *cmd, int *size)
 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;
index b2269e38171c640eecae7771dbda680fad99164e..22afe4aef45efa75332ad460abbacb04023a11e4 100644 (file)
@@ -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];
 
 /*
index 6bf9210e69dc1f7247586fa09edb4bcb61c5d798..1f4b843baa153ad308f624ec6a3faffe30f6d112 100644 (file)
@@ -431,7 +431,7 @@ void rd_load()
                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 --git a/drivers/char/README.stallion b/drivers/char/README.stallion
new file mode 100644 (file)
index 0000000..35cfecb
--- /dev/null
@@ -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.
+
index 34342e6c2b2a191f9248c22239b7427b1e535357..f6de37dd561d556279cf93c4c7495fe0f7e3f7bd 100644 (file)
@@ -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 @@ static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
 #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 @@ static int  stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
  *     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 @@ typedef struct {
        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 @@ typedef struct stlbrd {
        int             nrports;
        int             nrdevs;
        unsigned int    iobase;
+       unsigned long   memaddr;
        void            *membase;
        int             memsize;
        int             pagesize;
@@ -304,7 +312,7 @@ typedef struct stlbrd {
        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 @@ static char        *stli_brdnames[] = {
        "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 @@ static char *stli_brdnames[] = {
 #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 @@ static char *stli_brdnames[] = {
 #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 @@ static char *stli_brdnames[] = {
 #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 @@ static char *stli_brdnames[] = {
        (* 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 @@ static unsigned int stli_baudrates[] = {
 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_start(struct tty_struct *tty);
 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 long stli_mktiocm(unsigned long sigvalue);
 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 struct timer_list  stli_timerlist = {
 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 @@ void cleanup_module()
                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 @@ void cleanup_module()
                        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 @@ void cleanup_module()
 /*****************************************************************************/
 
 /*
- *     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 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        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 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                        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 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        }
 
        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 @@ static int stli_setport(stliport_t *portp)
                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 @@ static int stli_write(struct tty_struct *tty, int from_user, const unsigned char
                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 @@ static void stli_flushchars(struct tty_struct *tty)
                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 @@ static int stli_writeroom(struct tty_struct *tty)
                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 @@ static int stli_charsinbuffer(struct tty_struct *tty)
                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 int stli_charsinbuffer(struct tty_struct *tty)
 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 @@ static void stli_getserial(stliport_t *portp, struct serial_struct *sp)
        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 @@ static void stli_getserial(stliport_t *portp, struct serial_struct *sp)
        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 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                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 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                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 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
                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 @@ static void stli_stop(struct tty_struct *tty)
                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 @@ static void stli_start(struct tty_struct *tty)
                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 @@ static void stli_hangup(struct tty_struct *tty)
                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 @@ static void stli_flushbuffer(struct tty_struct *tty)
                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 @@ static void stli_flushbuffer(struct tty_struct *tty)
  *     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 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
        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 @@ static void stli_poll(unsigned long arg)
  *     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 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
                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 @@ static void stli_ecpinit(stlibrd_t *brdp)
        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 @@ static void stli_ecpeiinit(stlibrd_t *brdp)
        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 @@ static void stli_onbinit(stlibrd_t *brdp)
        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 @@ static void stli_onbreset(stlibrd_t *brdp)
        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 @@ static void stli_onbeinit(stlibrd_t *brdp)
        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 @@ static void stli_onbereset(stlibrd_t *brdp)
        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 @@ static void stli_bbyinit(stlibrd_t *brdp)
        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 @@ static void stli_bbyreset(stlibrd_t *brdp)
        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 @@ static void stli_stalinit(stlibrd_t *brdp)
 #endif
 
        outb(0x1, brdp->iobase);
-       for (i = 0; (i < 100); i++)
+       for (i = 0; (i < 1000); i++)
                udelay(1000);
 }
 
@@ -3291,7 +3378,7 @@ static void stli_stalreset(stlibrd_t *brdp)
        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 @@ static void *stli_mapbrdmem(unsigned long physaddr, unsigned int size)
  *     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,9 +3431,15 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
        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
@@ -3354,8 +3447,7 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
  */
        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 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
                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 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
                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 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
        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 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
 /*
  *     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,16 +3558,22 @@ static int stli_initecp(stlibrd_t *brdp, stlconf_t *confp)
  *     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
@@ -3489,8 +3585,7 @@ static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
        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 @@ static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
                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 @@ static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
        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 @@ static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
                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 @@ static int stli_initonb(stlibrd_t *brdp, stlconf_t *confp)
        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);
        }
@@ -3719,75 +3811,297 @@ stli_donestartup:
 
 /*****************************************************************************/
 
+/*
+ *     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
@@ -3796,10 +4110,14 @@ static int stli_brdinit()
        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 @@ static int stli_brdinit()
 
        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 @@ static int stli_memread(struct inode *ip, struct file *fp, char *buf, int count)
        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 @@ static int stli_memwrite(struct inode *ip, struct file *fp, const char *buf, int
        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 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
        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 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 
 /*****************************************************************************/
 
-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 @@ int stli_init(void)
        if (tty_register_driver(&stli_callout))
                printk("STALLION: failed to register callout driver\n");
 
-       return 0;
+       return(0);
 }
 
 /*****************************************************************************/
index 8edb5494577cf60707a03e5951107b501794b3b6..e0e3806ed08d589b9864cac7e36decdf0f0860be 100644 (file)
@@ -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 @@ static int  stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
  *     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 @@ static unsigned int stl_baudrates[] = {
 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 int  stl_waitcarrier(stlport_t *portp, struct file *filp);
 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 @@ static int  stl_findpcibrds(void);
 #ifdef MODULE
 
 /*
- *     Use the kernel version number for modules.
+ *     Loadable module initialization stuff.
  */
+
 int init_module()
 {
        unsigned long   flags;
@@ -605,15 +604,12 @@ void cleanup_module()
 /*****************************************************************************/
 
 /*
- *     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 @@ static int stl_findpcibrds()
                        }
                        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 @@ int stl_init(void)
        if (tty_register_driver(&stl_callout))
                printk("STALLION: failed to register callout driver\n");
 
-       return 0;
+       return(0);
 }
 
 /*****************************************************************************/
index a08b234f6761b1820f9d692c2e91584488707b1f..2733d48044316bc3c3865250ef42a11f0019e9f4 100644 (file)
@@ -1,4 +1,4 @@
-/* arcnet.c
+/* arcnet.c:
        Written 1994-1996 by Avery Pennarun,
        derived from skeleton.c by Donald Becker.
 
        
        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
          
        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)
 
 */
 
 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 @@ static const char *version =
 
 /**************************************************************************/
 
+/* 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 @@ static const char *version =
  */
 #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 @@ static const char *version =
  *             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);
-
-/* 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
-               
+#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
+
 
 /* The number of low I/O ports used by the ethercard. */
 #define ARCNET_TOTAL_SIZE      16
@@ -287,9 +377,11 @@ int arcnet_debug = ARCNET_DEBUG;
 
 #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 @@ int arcnet_debug = ARCNET_DEBUG;
 #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 @@ struct arcnet_local {
                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 arcnet_local {
        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_inthandler(struct device *dev);
 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 @@ void cleanup_module(void);
 
 #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 @@ void cleanup_module(void);
  *                                                                          *
  ****************************************************************************/
  
-/* 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).
+ *                         (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)
+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;
+       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 @@ arcnet_probe(struct device *dev)
        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;
        
-       BUGMSG(D_NORMAL,"ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
-               dev->base_addr, dev->irq, dev->mem_start);
+       /* find the real shared memory start/end points, including mirrors */
+       
+       #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;
 
-       /* Initialize the device structure. */
+       while (*last_mirror==TESTvalue) last_mirror+=MIRROR_SIZE;
+       last_mirror-=MIRROR_SIZE;
+
+       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,250 +1072,74 @@ arcnet_probe(struct device *dev)
        /* 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
+       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 status port is FF, there's certainly no arcnet... give up. */
-       if (inb(STATUS)==0xFF)
+       if (reset_delay)
        {
-               BUGMSG(D_INIT," probe failed.  Status port empty.\n");
-               return -ENODEV;
+               /* reset the card */
+               inb(RESET);
+               JIFFER(RESETtime);
        }
 
-#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.
-        */
+       outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
+       outb(CFLAGScmd|CONFIGclear,COMMAND);
+
+       /* verify that the ARCnet signature byte is present */
+       cardmem = (u_char *) dev->mem_start;
+       if (cardmem[0] != TESTvalue)
        {
-               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;
-               }
-       }
-#endif
-
-       BUGMSG(D_INIT," status2=%Xh\n",inb(STATUS));
-
-       /* 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 */
-       {
-               BUGMSG(D_INIT," probe failed.  eternal reset flag1...(status=%Xh)\n",
-                               inb(STATUS));
-               return -ENODEV;
-       }
-
-       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");
+               BUGMSG(D_NORMAL,"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;
@@ -949,9 +1148,11 @@ int arcnet_reset(struct device *dev)
        /* 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 @@ int arcnet_reset(struct device *dev)
 }
 
 
-/*
- * 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 @@ int arcnet_reset(struct device *dev)
  *
  * 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 @@ void arcnet_setup(struct device *dev)
 }
 
 
-/* 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 @@ arcnet_open(struct device *dev)
                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 @@ arcnet_open(struct device *dev)
        /* 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 @@ arcnet_open(struct device *dev)
        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 @@ arcnet_open(struct device *dev)
        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 @@ arcnet_close(struct device *dev)
        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 @@ arcnet_close(struct device *dev)
        /* 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 @@ arcnet_close(struct device *dev)
        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 @@ arcnet_close(struct device *dev)
        kfree(lp->sdev->name);
        kfree(lp->sdev);
        lp->sdev=NULL;
+#endif
 
        /* Update the statistics here. (not necessary in ARCnet) */
 
@@ -1229,16 +1410,14 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
                
                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,281 +1597,91 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
 }
 
 
-/* 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;
-       }
-       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");
-       }
-
-#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]);
+               arcpacket->hardheader.offset1=offset=256-length;
+               arcsoft=(struct ClientData *)
+                       (&arcpacket->raw[offset]);
        }
        else if (length>=MinTU) /* Extended (512-byte) Packet */
        {
@@ -1735,8 +1724,17 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
         */
        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 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
                printk("\n");
        }
 
-#ifdef VERIFY_ACK
        lp->lastload_dest=daddr;
-#endif
        lp->txready=lp->txbuf;  /* packet is ready for sending */
 }
 
@@ -1792,7 +1788,7 @@ arcnet_go_tx(struct device *dev,int enable_irq)
                }
                return 0;
        }
-
+       
        /* start sending */
        outb(TXcmd|(lp->txready<<3),COMMAND);
 
@@ -1800,10 +1796,8 @@ arcnet_go_tx(struct device *dev,int enable_irq)
        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 @@ static void
 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 @@ arcnet_inthandler(struct device *dev)
                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 @@ arcnet_inthandler(struct device *dev)
                        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 @@ arcnet_inthandler(struct device *dev)
                                                        lp->lasttrans_dest);
                                }
                        }
-#endif
+
                        /* send packet if there is one */
                        arcnet_go_tx(dev,0);
                        didsomething++;
@@ -2063,6 +2001,78 @@ arcnet_inthandler(struct device *dev)
                        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 @@ arcnet_rx(struct device *dev,int recbuf)
        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 @@ arcnet_rx(struct device *dev,int recbuf)
                }
 
 
+#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 @@ arcnetA_rx(struct device *dev,u_char *buf,
 
                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 @@ arcnetA_rx(struct device *dev,u_char *buf,
 }
 
 
-/* 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 @@ arcnetS_rx(struct device *dev,u_char *buf,
 }
 
 
-
-/****************************************************************************
- *                                                                          *
- * 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 @@ int arcnetS_header(struct sk_buff *skb,struct device *dev,
 }
 
 
-
 /* 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 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
  *
  * 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 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
        return htons(ETH_P_IP);
 }
 
-
+#endif /* CONFIG_ARCNET_1051 */
 
 /****************************************************************************
  *                                                                          *
index 47881aa8fac8fa589fdd13d14325ee26044550b2..fc9a83ced5d2ed4a559e7e2caec051f5611af185 100644 (file)
@@ -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 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     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 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *
  *   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 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *     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 {
 
 typedef enum {
   LIST_HEAD,
-  LIST_SECOND,
-  LIST_TAIL
+  LIST_SECOND
 } insert_type;
 
 typedef enum {
@@ -268,523 +277,52 @@ static const char * board_names[] = {
 /*
  * 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
-
-/*
- * 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
-
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#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
- */
+#define MINREG         0xC00
+#define MAXREG         0xCBF
 
-/*
- * 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)
+#define INTDEF         0x5C            /* Interrupt Definition Register */
 
 /*
- * Bit vector of targets that have disconnection disabled.
+ * Some defines for the HCNTRL register.
  */
-#define        HA_DISC_DSB(x)          ((x) + 0xC32ul)
+#define        REQ_PAUSE       IRQMS | INTEN | PAUSE
+#define        UNPAUSE_274X    IRQMS | INTEN
+#define        UNPAUSE_284X    INTEN
+#define        UNPAUSE_294X    IRQMS | INTEN
 
 /*
- * Length of pending message
+ * AIC-78X0 PCI registers
  */
-#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        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 @@ struct seeprom_config {
 
   unsigned short res_1[11];            /* words 20-30 */
   unsigned short checksum;             /* word 31 */
-
 };
 
 /*
@@ -862,8 +399,8 @@ struct seeprom_config {
  * 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 @@ struct seeprom_config {
  * 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 @@ static int aic7xxx_spurious_count;
 
 /*
  * 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 @@ struct aic7xxx_scb {
        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 struct {
 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 @@ debug_config(struct aic7xxx_host_config *p)
   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 @@ debug_scb(struct aic7xxx_scb *scb)
          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 @@ aic7xxx_loadseq(int base)
    * 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 @@ aic7xxx_loadseq(int base)
      * 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 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
  *-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 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
       {
         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 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
         }
       }
       *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 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
  * 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 @@ aic7xxx_putscb_dma(int base, struct aic7xxx_scb *scb)
  * 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*************************************************************************
@@ -1707,6 +1206,32 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
   }
 }
 
+/*+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
@@ -1718,9 +1243,9 @@ static void
 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 @@ aic7xxx_unbusy_target(unsigned char target, char channel, int base)
   {
     /*
      * 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 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
    */
   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 @@ aic7xxx_add_waiting_scb(u_long              base,
                         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;
-
-          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);
-        }
-      }
+      /* where == LIST_SECOND */
+      unsigned char third_scb;
+
+      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 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
    * 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 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
     /*
      * 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 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
    * 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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
   /*
    * 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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
    */
   {
     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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
         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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
      */
     for (queued = 0; queued < i; queued++)
     {
-      outb(saved_queue[queued], QINFIFO(base));
+      outb(saved_queue[queued], QINFIFO + base);
     }
   }
 
@@ -1988,7 +1490,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
   {
     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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
       }
       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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
        * 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 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
     }
   }
 
-  outb(active_scb, SCBPTR(base));
+  outb(active_scb, SCBPTR + base);
   return (found);
 }
 
@@ -2052,9 +1554,9 @@ aic7xxx_reset_current_bus(int base)
 #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 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
   {
     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 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
     {
       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 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
   /*
    * 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 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
     /*
      * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
   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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
    * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
    */
   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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
    * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
     }
 
     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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
      */
     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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        {
          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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
           * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
            /*
             * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
             * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
         */
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
                      "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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
              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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
         * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
          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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
            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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
           * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
                void         *req_buf;
 
                 tcl = scb->target_channel_lun;
+
                /*
                  * Send a sense command to the requesting target.
                  */
@@ -2558,8 +2061,9 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
                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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
                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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
             */
            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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
   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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
           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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
         }
         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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        */
       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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
         * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
       }
       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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
      * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
        * 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 @@ aic7xxx_isr(int irq, struct pt_regs * regs)
       }
 #endif /* AIC7XXX_PROC_STATS */
 
-    } while (inb(QOUTCNT(base)));
+    } while (inb(QOUTCNT + base));
   }
 }
 
@@ -3118,11 +2659,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
   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 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     /*
      * 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 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     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 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
       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 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     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 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
     /*
      * 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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
   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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
    * 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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
     /*
      * 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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
     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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
       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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
     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 @@ read_seeprom(int base, int offset, struct seeprom_config *sc)
     /*
      * 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 @@ detect_maxscb(aha_type type, int base, int walk_scbs)
        * 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 @@ detect_maxscb(aha_type type, int base, int walk_scbs)
        */
       break;
   }
+
   if (walk_scbs)
   {
     /*
@@ -3510,16 +3052,22 @@ detect_maxscb(aha_type type, int base, int walk_scbs)
     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 @@ aic7xxx_register(Scsi_Host_Template *template,
   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 @@ aic7xxx_register(Scsi_Host_Template *template,
   /*
    * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
        * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
       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 @@ aic7xxx_register(Scsi_Host_Template *template,
       }
       /* 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 @@ aic7xxx_register(Scsi_Host_Template *template,
     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 @@ aic7xxx_register(Scsi_Host_Template *template,
       /*
        * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
    * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
    * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
   }
 
   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 @@ aic7xxx_register(Scsi_Host_Template *template,
   /*
    * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
     /*
      * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
    * 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 @@ aic7xxx_register(Scsi_Host_Template *template,
    */
   if (have_seeprom)
   {
-    p->discenable = 0;
+    p->discenable = 0x0;
   }
   else
   {
@@ -4022,8 +3581,8 @@ aic7xxx_register(Scsi_Host_Template *template,
     }
     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 @@ aic7xxx_register(Scsi_Host_Template *template,
       {
        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 @@ aic7xxx_register(Scsi_Host_Template *template,
     }
     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 @@ aic7xxx_register(Scsi_Host_Template *template,
    */
   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 @@ aic7xxx_register(Scsi_Host_Template *template,
       /*
        * 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 @@ aic7xxx_detect(Scsi_Host_Template *template)
    */
   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 @@ aic7xxx_detect(Scsi_Host_Template *template)
       continue;
     }
 
-    config.type = aic7xxx_probe(slot, HID0(base));
+    config.type = aic7xxx_probe(slot, HID0 + base);
     if (config.type != AIC_NONE)
     {
       /*
@@ -4269,7 +3847,9 @@ aic7xxx_detect(Scsi_Host_Template *template)
     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 @@ aic7xxx_detect(Scsi_Host_Template *template)
         {
           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 @@ aic7xxx_detect(Scsi_Host_Template *template)
               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 @@ aic7xxx_detect(Scsi_Host_Template *template)
           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 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
     }
     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 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
     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 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
 
   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 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
       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 @@ aic7xxx_buildscb(struct aic7xxx_host *p,
       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 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
   long flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
-  unsigned char curscb;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
 
@@ -4562,19 +4157,19 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
   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 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
       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 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
    * 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 @@ aic7xxx_abort_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
                   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 @@ aic7xxx_abort_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
    */
   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 @@ aic7xxx_abort_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
      * 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 @@ aic7xxx_abort_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
       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 @@ aic7xxx_abort_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
       /*
        * 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 @@ aic7xxx_abort_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
         {
 #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 @@ aic7xxx_abort_reset(Scsi_Cmnd *cmd, unsigned char errcode)
        */
       /* cmd->retries = 0; */
       aic7xxx_error(cmd) = errcode;
-      aic7xxx_done (p, scb);
+      aic7xxx_done(p, scb);
     }
     else
     {
@@ -5060,3 +4638,4 @@ Scsi_Host_Template driver_template = AIC7XXX;
  * tab-width: 8
  * End:
  */
+
index f5ea6aab56c2f6eb81c060a173b34dc6a46514cf..5561e6f900b0bd03b3f01abb1f2996314b295404 100644 (file)
-##+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
-
-# 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.
-#
+       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.
+ */
        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 
-
-#  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
+start_scb2:
+       and     SINDEX,0xf7,SBLKCTL     /* Clear the channel select bit */
+       and     A,0x08,SCB_TCL          /* Get new channel bit */
+       or      SINDEX,A
+       mov     SBLKCTL,SINDEX          /* select channel */
+       mov     SCB_TCL call initialize_scsiid
+
+/*
+ * Enable selection phase as an initiator, and do automatic ATN
+ * after the selection.  We do this now so that we can overlap the
+ * rest of our work to set up this target with the arbitration and
+ * selection bus phases.
+ */
+start_selection:
+       mvi     SCSISEQ,0x58            /* ENSELO|ENAUTOATNO|ENRSELI */
+
+/*
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.  Prepare
+ * the message to send.
+ *
+ * Messages are stored in scratch RAM starting with a length byte
+ * followed by the message itself.
+ */
+       test    SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
+
+/*
+ * The kernel has sent us an SCB with no command attached.  This implies
+ * that the kernel wants to send a message of some sort to this target,
+ * so we interrupt the driver, allow it to fill the message buffer, and
+ * then go back into the arbitration loop
+ */
        mvi     INTSTAT,AWAITING_MSG
        jmp     wait_for_selection
 
-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
+mk_identify:
+       and     A,DISCENB,SCB_CONTROL   /* mask off disconnect privledge */
 
-       mov     A,SINDEX
-       test    SCBARRAY+0,0xb0 jz  !message    # WDTR, SDTR or TAG??
-       cmp     MSG_START+0,A   jne !message    # did driver beat us?
+       and     MSG0,0x7,SCB_TCL        /* lun */
+       or      MSG0,A                  /* or in disconnect privledge */
+       or      MSG0,MSG_IDENTIFY
+       mvi     MSG_LEN, 1
 
-# Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
-# value
+       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
-
- 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.
-#
+       test    SSTAT0,SELDO    jnz select 
+       test    SSTAT0,SELDI    jz wait_for_selection
+
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target
+ * yet.
+ */
 reselect:
+       clr     MSG_LEN         /* Don't have anything in the mesg buffer */
        mov     SELID           call initialize_scsiid
-       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
+
+/*
+ * 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
 
-       and     A,0xe0,SCSISIGI                 # CDI|IOI|MSGI
-
-       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
-
-       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.
-#
+       dec     SG_COUNT        /* one less segment to go */
+
+       test    SG_COUNT, 0xff  jz data_phase_finish /* Are we done? */
+
+       clr     A                       /* add sizeof(struct scatter) */
+       add     SG_NEXT0,SG_SIZEOF,SG_NEXT0
+       adc     SG_NEXT1,A,SG_NEXT1
+
+/*
+ * Load a struct scatter and set up the data address and length.
+ * If the working value of the SG count is nonzero, then
+ * we need to load a new set of values.
+ *
+ * This, like all DMA's, assumes a little-endian host data storage.
+ */
 sg_load:
-       clr     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
-
-       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
+       test    MSG_LEN, 0xff   jnz  p_mesgout_start
+       mvi     MSG_NOP         call mk_mesg    /* build NOP message */
+
+p_mesgout_start:
+/*
+ * Set up automatic PIO transfer from MSG0.  Bit 3 in
+ * SXFRCTL0 (SPIOEN) is already on.
+ */
+       mvi     SINDEX,MSG0
        mov     DINDEX,MSG_LEN
 
-#  When target asks for a byte, drop ATN if it's the last one in
-#  the message.  Otherwise, keep going until the message is exhausted.
-#  (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
+/*
+ * 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
 
-       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
+       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
-
-       mvi     0x7             call mk_mesg    # MESSAGE REJECT message
+/*
+ * We have no idea what this message in is, and there's no way
+ * to pass it up to the kernel, so we issue a message reject and
+ * hope for the best.  Since we're now using manual PIO mode to
+ * read in the message, there should no longer be a race condition
+ * present when we assert ATN.  In any case, rejection should be a
+ * rare occurrence - signal the driver when it happens.
+ */
+       or      SCSISIGO,ATNO                   /* turn on ATNO */
+       mvi     INTSTAT,SEND_REJECT             /* let driver know */
+
+       mvi     MSG_REJECT      call mk_mesg
 
 mesgin_done:
-       call    inb_last                        # ack & turn auto PIO back on
+       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    
+       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     SCBARRAY+0,0xfb                 # clear disconnect bit in SCB
-       or      FLAGS,IDENTIFY_SEEN             # make note of IDENTIFY
-
+       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 ]
-#
+/*
+ * [ 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.
-#
+/*
+ * 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
-
-#  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.
+       mvi     CLRSINT1,CLRATNO
+
+/*
+ * 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 @@ bcopy_3:
        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
-
-#  Carefully read data in Automatic PIO mode.  I first tried this using
-#  Manual PIO mode, but it gave me continual underrun errors, probably
-#  indicating that I did something wrong, but I feel more secure leaving
-#  Automatic PIO on all the time.
-#
-#  According to Adaptec's documentation, an ACK is not sent on input from
-#  the target until SCSIDATL is read from.  So we wait until SCSIDATL is
-#  latched (the usual way), then read the data byte directly off the bus
-#  using SCSIBUSL.  When we have pulled the ATN line, or we just want to
-#  acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
-#  spec guarantees that the target will hold the data byte on the bus until
-#  we send our ACK.
-#
-#  The assumption here is that these are called in a particular sequence,
-#  and that REQ is already set when inb_first is called.  inb_{first,next}
-#  use the same calling convention as inb.
-#
-inb_first:
-       clr     STCNT+2
-       clr     STCNT+1
-       mov     DINDEX,SINDEX
-       mov     DINDIR,SCSIBUSL ret             # read byte directly from bus
+       mvi     MSG_LEN,1               /* length = 1 */
+       mov     MSG0,SINDEX             /* 1-byte message */
+       mvi     SEQCTL,0x10     ret     /* !PAUSEDIS|FASTMODE */
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
 
 inb_next:
-       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
-
+       or      CLRSINT0, CLRSPIORDY
+       mov     NONE,SCSIDATL                   /*dummy read from latch to ACK*/
+inb_next_wait:
+       test    SSTAT1,PHASEMIS jnz mesgin_phasemis
+       test    SSTAT0,SPIORDY  jz inb_next_wait /* wait for next byte */
+inb_first:
+       mov     DINDEX,SINDEX
+       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*/
+
+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 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
-
-#  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.
-#
+       test    SSTAT0,DMADONE  jnz dma3
+       test    SSTAT1,PHASEMIS jz dma1         /* ie. underrun */
+
+/*
+ * We will be "done" DMAing when the transfer count goes to zero, or
+ * the target changes the phase (in light of this, it makes sense that
+ * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+ * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+ * magically on STCNT=0 or a phase change, so just wait for FIFO empty
+ * status.
+ */
 dma3:
-       test    SINDEX,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
-
-dma_finish:
-       test    DFSTATUS,0x8    jz dma_finish   # HDONE
+       test    DFCNTRL,0x38    jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
 
-       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 @@ findSCB1:
        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
-
-#  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.
-#
+       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.
+ */
 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:
index e227c22bdae19684d6704b1a3563e228727cf1fe..e8f783b29f992b326dfb18899fc14793abde8d12 100644 (file)
  * 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 @@ static char id[] = "$Id: aic7xxx_asm.c,v 2.1 1995/08/23 04:31:40 deang Exp $";
 #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 @@ static char id[] = "$Id: aic7xxx_asm.c,v 2.1 1995/08/23 04:31:40 deang Exp $";
 int debug;
 int lineno, LC;
 char *filename;
-FILE *ifp, *ofp;
 unsigned char M[MEMORY][4];
 
 void 
@@ -207,7 +224,7 @@ getl(int *n)
 
        i = 0;
 
-       while (fgets(buf, sizeof(buf), ifp)) {
+       while (fgets(buf, sizeof(buf), stdin)) {
 
                lineno += 1;
 
@@ -520,7 +537,7 @@ crack(char **a, int n)
 #undef A
 
 void
-assemble(void)
+assemble(FILE *ofile)
 {
        int n;
        char **a;
@@ -543,7 +560,7 @@ assemble(void)
                        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 @@ assemble(void)
        }
 
        backpatch();
-       output(ofp);
+       output(ofile);
 
        if (debug)
                output(stderr);
@@ -563,7 +580,15 @@ int
 main(int argc, char **argv)
 {
        int c;
-
+       int pid;
+       int ifile;
+       int status;
+       FILE *ofile;
+       char *ofilename;
+       int fd[2];
+
+       ofile = NULL;
+       ofilename = NULL;
        while ((c = getopt(argc, argv, "dho:vD")) != EOF) {
                switch (c) {
                    case 'd':
@@ -581,8 +606,8 @@ main(int argc, char **argv)
                        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 @@ main(int argc, char **argv)
        }
        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 --git a/drivers/scsi/aic7xxx_reg.h b/drivers/scsi/aic7xxx_reg.h
new file mode 100644 (file)
index 0000000..d8a7c55
--- /dev/null
@@ -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
+
index 16f09c1bfa16f0effb2c510ec98888f61cf2274e..82b4646729ebe744ed27fe582fac31b534a7e455 100644 (file)
@@ -61,6 +61,7 @@ struct symbol_table scsi_symbol_table = {
     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
index 9a4653ed8eab0c6effa2d918d7fdedf90c8ccfeb..2f83da32afd2fe1753d46c58354a221d35664bbb 100644 (file)
@@ -12,8 +12,8 @@ tristate 'xiafs filesystem support' CONFIG_XIA_FS
 
 # 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
index e090e326586dc66edd829fd423d88b5327c8d574..5ad2bc08cde0d3c45cc001afff16ac4f9f4e79bc 100644 (file)
@@ -100,7 +100,7 @@ static union bdflush_param{
                                   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 @@ int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int b
                                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--;
index 3b1b137e2a2d25ff25dad0ff8749ab5f8846408a..6047890d3349605ffef7030142e24c8b0cbfee8d 100644 (file)
@@ -6,6 +6,7 @@
  */
 #include <linux/module.h>
 
+#include <linux/mm.h>
 #include <linux/msdos_fs.h>
 
 #include "msbuffer.h"
index 6c918d8668b44a4ce0150953a0f5ada718640c14..2621fbfcc909d498e4360194037c25e9218670c8 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/module.h>
 
+#include <linux/mm.h>
 #include <linux/msdos_fs.h>
 
 static struct symbol_table msdos_syms = {
index f5539ddf1884306c8ee48f42aaeed57bab227c52..9d04e72b1c40a9c85826db7df452da64c61e2b2a 100644 (file)
@@ -775,6 +775,7 @@ extern int get_ksyms_list(char *, char **, off_t, int);
 #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 @@ static int get_root_array(char * page, int type, char **start, off_t offset, int
 #endif
                case PROC_CMDLINE:
                        return get_cmdline(page);
+
+                case PROC_MTAB:
+                       return get_filesystem_info( page );
        }
        return -EBADF;
 }
index 0abdac3514081b4d35b5972f7f9c40ec5453d62a..15b27da7b11c8e4071e39961800fb88b47c50c72 100644 (file)
@@ -361,6 +361,9 @@ void proc_root_init(void)
                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) {
index 15c584e97219c84ef873c01ba57bd973f263123e..0eaed908d76753c6766fb854bd7474b6188f18b5 100644 (file)
@@ -262,6 +262,23 @@ asmlinkage int sys_sysfs(int option, ...)
        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;
index 024c567bb312e0fade954908e7ff546340ec9ca8..c545d32dcc621d40144306675845780adc1ea4bd 100644 (file)
@@ -401,6 +401,7 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
                extlen = 0;
        }
        ext[extlen] = '\0';
+       base[baselen] = '\0';
 
        count = 0;
        strcpy(msdos_name, base);
index 27b2e7925a9b85d1fdc98bac3a5cc0c6877e3ed1..9d979b9407acf0f55def23bb92992cd1b74438fa 100644 (file)
@@ -37,17 +37,17 @@ __ntohl(unsigned long int x)
        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 @@ __ntohs(unsigned short int x)
 {
        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;
 }
 
index 8d6621c97f66b6ba0fcbaa6b6f516164ad478425..53459b7827fe8a17bfd53e45ed5cca21fb262c45 100644 (file)
@@ -113,10 +113,10 @@ extern void tbi(long type, ...);
 /*
  * 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 @@ extern inline unsigned long xchg_u32(volatile int * m, unsigned long val)
        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 inline unsigned long xchg_u64(volatile long * m, unsigned long val)
  */
 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:
index 146b72a0ba1c1858d2a21b9c708b535135725e4c..92586148b5ed6ba9043480c4ecd09a18328c4c1e 100644 (file)
@@ -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
@@ -468,5 +468,11 @@ typedef struct cdkasy {
 #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
index 0f29a2808b6c85d63a2ee73d513c0921a33a29e9..9d702e4860c70830974dd63a8f98320cd3e5aa15 100644 (file)
@@ -40,7 +40,8 @@ enum root_directory_inos {
 #endif
        PROC_PROFILE, /* whether enabled or not */
        PROC_CMDLINE,
-       PROC_SYS
+       PROC_SYS,
+       PROC_MTAB
 };
 
 enum pid_directory_inos {
index c4552d9ae0dd54b2636a5d97bf2fa5b60e977616..23e86ce5951af18a492366b6c17307b1bfad12c9 100644 (file)
@@ -106,15 +106,6 @@ extern int request_dma(unsigned int dmanr, char * deviceID);
 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 @@ struct symbol_table symbol_table = {
        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),
 
index 1f2e8862187a46b59f2cb575d523b8b82370ce23..40e627dbfb62ad6d976d92d9a225905c92f5213c 100644 (file)
@@ -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 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                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:
index a0e5ba04dced4d0e6d477511c47a2f1c9a20a3fc..8503536a1cf2030e7fa8b7e5cf313609712f2c5e 100644 (file)
@@ -115,7 +115,9 @@ int ipip_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
 
 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          */
index 650f02daabcc98092afc74cb42486be317e0edc6..d3b98a4325438d8d56e426bb0c23be3ff3d5b82e 100644 (file)
@@ -105,6 +105,7 @@ static initflag = 1;
 static inline void rarp_release_entry(struct rarp_table *entry)
 {
        kfree_s(entry, sizeof(struct rarp_table));
+       MOD_DEC_USE_COUNT;
        return;
 }
 
@@ -371,6 +372,9 @@ static int rarp_req_set(struct arpreq *req)
        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();  
 
        return 0;
index c8bf6ea6ddb192ab7c9e949a22851abc28cbb769..146864a65aeeafca5c1113e49b514ed52cb4c5b3 100644 (file)
@@ -532,7 +532,7 @@ void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
        }
 
        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 @@ void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
 
        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