]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.34pre8 2.0.34pre8
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:42 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:42 +0000 (15:11 -0500)
52 files changed:
Documentation/Configure.help
MAINTAINERS
arch/alpha/math-emu/ieee-math.c
arch/i386/kernel/process.c
arch/i386/kernel/vm86.c
arch/m68k/kernel/head.S
drivers/block/ide.c
drivers/block/triton.c
drivers/block/xd.c
drivers/char/console.c
drivers/char/wdt.c
drivers/net/3c509.c
drivers/net/3c515.c
drivers/net/3c59x.c
drivers/net/Changelog.tlan
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/at1700.c
drivers/net/dlci.c
drivers/net/eepro100.c
drivers/net/epic100.c
drivers/net/lance.c
drivers/net/pcnet32.c
drivers/net/rtl8139.c
drivers/net/sdla.c
drivers/net/smc-ultra32.c
drivers/net/tlan.c
drivers/net/tlan.h
drivers/net/tulip.c
drivers/net/yellowfin.c
drivers/pci/pci.c
drivers/scsi/Config.in
drivers/scsi/README.aic7xxx
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.h
drivers/scsi/aic7xxx/aic7xxx.reg
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/aic7xxx/scsi_message.h
drivers/scsi/aic7xxx/sequencer.h
drivers/scsi/aic7xxx_proc.c
drivers/scsi/aic7xxx_reg.h
drivers/scsi/aic7xxx_seq.h
drivers/scsi/scsi_ioctl.c
fs/devices.c
include/linux/hdreg.h
include/linux/if_frad.h
include/linux/modversions.h [new file with mode: 0644]
include/linux/pci.h
kernel/ksyms.c
net/ipx/af_ipx.c
scripts/Menuconfig

index 0dce3e96675280aaf6b509bbb3625b9f0f2ae4b6..fa828f471dd5443168c9a151b18a19762b2189cb 100644 (file)
@@ -1404,16 +1404,7 @@ CONFIG_SCSI_AIC7XXX
   394x PCI cards, 3985 PCI card, and several versions of the Adaptec
   built-in SCSI controllers on various PC motherboards.  Information on
   the configuration options for this controller can be found by checking
-  the help file for each of the available configuration options.
-
-Enable tagged command queueing
-CONFIG_AIC7XXX_TAGGED_QUEUEING
-  Tagged command queueing is used to allow acceptable devices to have more
-  than one SCSI command active on the SCSI bus at the same time.  Regardless
-  of this option setting, only devices that report they are capable of
-  tagged queueing will use this support.  This option is highly recommended
-  if you use any SCSI hard drives on your aic7xxx SCSI controller for
-  performance reasons.  Default: Y
+  the README.aic7xxx file, usually in /usr/src/linux/drivers/scsi.
 
 Override driver defaults for commands per LUN
 CONFIG_OVERRIDE_CMDS
@@ -1422,6 +1413,10 @@ CONFIG_OVERRIDE_CMDS
   active at one time.  This option only effects tagged queueing capable
   devices.  The driver uses a "failsafe" value of 8 by default.  This is
   much lower than many devices can handle, but left in place for safety sake.
+  NOTE: This does not actually enabled tagged queueing on any particular
+  device.  The driver has changed in this respect.  Please see the file
+  README.aic7xxx in /usr/src/linux/drivers/scsi for more information on how
+  to get particular devices to use tagged command queueing.
   Default: N
 
 Maximum number of commands per LUN
@@ -1437,14 +1432,6 @@ CONFIG_AIC7XXX_CMDS_PER_LUN
   per lun reduced, but is a waste of memory if all of your devices end
   up reducing this number down to a more reasonable figure.  Default: 24
 
-Enable SCB paging
-CONFIG_AIC7XXX_PAGE_ENABLE
-  This option allows the driver to issue more commands to the controller
-  than it has physical space to store.  Since some aic7xxx chipsets can only
-  store 3 commands, and the majority can only store 16, not enabling this
-  capability can effectively negate any performance increase you might get
-  from enabling Tagged Queueing.  Default: Y
-
 Collect statistics to report in /proc
 CONFIG_AIC7XXX_PROC_STATS
   This option tells the driver to keep track of how many commands have been
@@ -1466,8 +1453,8 @@ CONFIG_AIC7XXX_RESET_DELAY
   ready for the next command, but most hard drives and CD-ROM devices are
   ready in only a few seconds.  This option has a maximum upper limit of
   20 seconds to avoid bad interactions between the aic7xxx driver and the
-  rest of the linux kernel.  The default value is a "failsafe" value that
-  should work with just about any device.  Default: 15
+  rest of the linux kernel.  The default value has been reduced.  If this
+  doesn't work with your hardware, try increasing this value.  Default: 5
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
index 449858a39419560914f68155b865960dc8f7593f..7ebc979bc412d854801659e7d29e96d9e4b5b765 100644 (file)
@@ -82,7 +82,7 @@ S:    Maintained
 
 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
 P:     Paul Gortmaker
-M      gpg109@rsphy1.anu.edu.au
+M:     gpg109@rsphy1.anu.edu.au
 L:     linux-net@vger.rutgers.edu
 S:     Maintained
 
index d408eece5ae32bafe6beafea1b27b5fc5dbdebea..a58a926a5bc580ca8a3da505073dedda296411d4 100644 (file)
@@ -137,9 +137,8 @@ sub128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2])
 static inline void
 mul64 (const unsigned long a, const unsigned long b, unsigned long c[2])
 {
-       asm ("mulq  %2,%3,%0\n\t"
-            "umulh %2,%3,%1"
-            : "r="(c[0]), "r="(c[1]) : "r"(a), "r"(b));
+       c[0] = a * b;
+       asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b));
 }
 
 
@@ -276,7 +275,7 @@ make_s_ieee (long f, EXTENDED *a, unsigned long *b)
 {
        unsigned long res, sticky;
 
-       if (!a->f[0] && !a->f[1]) {
+       if (!a->e && !a->f[0] && !a->f[1]) {
                *b = (unsigned long) a->s << 63;        /* return +/-0 */
                return 0;
        }
@@ -356,7 +355,7 @@ make_t_ieee (long f, EXTENDED *a, unsigned long *b)
 {
        unsigned long res, sticky;
 
-       if (!a->f[0] && !a->f[1]) {
+       if (!a->e && !a->f[0] && !a->f[1]) {
                *b = (unsigned long) a->s << 63;        /* return +/-0 */
                return 0;
        }
@@ -384,7 +383,7 @@ make_t_ieee (long f, EXTENDED *a, unsigned long *b)
                        a->e = -0x3ff;
                }
        }
-       if (a->e > 0x3ff) {
+       if (a->e >= 0x3ff) {
                res = FPCR_OVF | FPCR_INE;
                if (f & IEEE_TRAP_ENABLE_OVF) {
                        a->e -= 0x600;  /* scale down result by 2^alpha */
@@ -1143,12 +1142,9 @@ ieee_MULS (int f, unsigned long a, unsigned long b, unsigned long *c)
                return 0;
        }
        op_c.s = op_a.s ^ op_b.s;
-       op_c.e = op_a.e + op_b.e;
+       op_c.e = op_a.e + op_b.e - 55;
        mul64(op_a.f[0], op_b.f[0], op_c.f);
 
-       normalize(&op_c);
-       op_c.e -= 55;           /* drop the 55 original bits. */
-
        return round_s_ieee(f, &op_c, c);
 }
 
@@ -1200,12 +1196,9 @@ ieee_MULT (int f, unsigned long a, unsigned long b, unsigned long *c)
                return 0;
        }
        op_c.s = op_a.s ^ op_b.s;
-       op_c.e = op_a.e + op_b.e;
+       op_c.e = op_a.e + op_b.e - 55;
        mul64(op_a.f[0], op_b.f[0], op_c.f);
 
-       normalize(&op_c);
-       op_c.e -= 55;   /* drop the 55 original bits. */
-
        return round_t_ieee(f, &op_c, c);
 }
 
index d32c147ea72138448f9f567d12ce57a23a8044c2..335ee273fcb5921597f88c3f915fe89eb9a1fc61 100644 (file)
@@ -488,7 +488,7 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
        }
        set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
        if (p->ldt)
-               set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
+               set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, LDT_ENTRIES);
        else
                set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
        p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
index d217994a432e56914e577d86eb9fe88d60fcae1d..593fcc03c3d70718f4fce9968cdb85c730baa4f0 100644 (file)
@@ -611,7 +611,7 @@ static int do_vm86_irq_handling(int subfunction, int irqnumber)
                        int sig = irqnumber >> 8;
                        int irq = irqnumber & 255;
                        handle_irq_zombies();
-                       if (!suser()) return -EPERM;
+                       if (!suser() || securelevel > 0) return -EPERM;
                        if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM;
                        if ( (irq<3) || (irq>15) ) return -EPERM;
                        if (vm86_irqs[irq].tsk) return -EPERM;
index 795d7466e8acd296354045f68587b9bc2d7a8f73..2d70bc3d89d28b242f0432c0de5cc01af5300dc3 100644 (file)
@@ -65,6 +65,7 @@
  *   d4 - machine type
  */
 
+#include <linux/config.h>
 #include <linux/autoconf.h>
 #include <linux/linkage.h>
 #include <asm/bootinfo.h>
index 85b6018db59f9f4a4c47d94350376fa593f19592..9d9432d0a515e4892d0dff59c1e6c9832aa459a0 100644 (file)
  *                     acknowledge media change on removable drives
  *                     add work-around for BMI drives
  *                     remove "LBA" from boot messages
+ * Version 5.53.1      add UDMA "CRC retry" support
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -602,6 +603,11 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
        unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
        unsigned long _10_percent = chs_sects / 10;
 
+       /* very large drives (8GB+) may lie about the number of cylinders */
+       if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+               id->cyls = lba_sects / (16 * 63); /* correct cyls */
+               return 1;       /* lba_capacity is our only option */
+       }
        /* perform a rough sanity check on lba_sects:  within 10% is "okay" */
        if ((lba_sects - chs_sects) < _10_percent)
                return 1;       /* lba_capacity is good */
@@ -636,6 +642,7 @@ static unsigned long current_capacity (ide_drive_t  *drive)
        /* Determine capacity, and use LBA if the drive properly supports it */
        if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
                if (id->lba_capacity >= capacity) {
+                       drive->cyl = id->lba_capacity / (drive->head * drive->sect);
                        capacity = id->lba_capacity;
                        drive->select.b.lba = 1;
                }
@@ -1043,12 +1050,15 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat)
        } else {
                if (drive->media == ide_disk && (stat & ERR_STAT)) {
                        /* err has different meaning on cdrom and tape */
-                       if (err & (BBD_ERR | ECC_ERR))  /* retries won't help these */
+                       if (err == ABRT_ERR) {
+                               if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+                                       return; /* some newer drives don't support WIN_SPECIFY */
+                       } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
+                               ; /* UDMA crc error -- just retry the operation */
+                       else if (err & (BBD_ERR | ECC_ERR))     /* retries won't help these */
                                rq->errors = ERROR_MAX;
                        else if (err & TRK0_ERR)        /* help it find track zero */
                                rq->errors |= ERROR_RECAL;
-                       else if (err & MC_ERR)
-                               drive->special.b.mc = 1;
                }
                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
                        try_to_flush_leftover_data(drive);
@@ -2270,7 +2280,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                {
                        byte args[4], *argbuf = args;
                        int argsize = 4;
-                       if (!suser()) return -EACCES;
+                       if (!suser() || securelevel > 0) return -EACCES;
                        if (NULL == (void *) arg) {
                                err = ide_do_drive_cmd(drive, &rq, ide_wait);
                        } else if (!(err = verify_area(VERIFY_READ,(void *)arg, 4))) {
@@ -2561,14 +2571,16 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                drive->head = id->heads;
                drive->sect = id->sectors;
        }
+
+       /* calculate drive capacity, and select LBA if possible */
+       (void) current_capacity (drive);
+
        /* Correct the number of cyls if the bios value is too small */
        if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
                if (drive->cyl > drive->bios_cyl)
                        drive->bios_cyl = drive->cyl;
        }
 
-       (void) current_capacity (drive); /* initialize LBA selection */
-
        if (!strncmp(id->model, "BMI ", 4) &&
            strstr(id->model, " ENHANCED IDE ") &&
            drive->select.b.lba)
@@ -2587,8 +2599,12 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                        drive->special.b.set_multmode = 1;
        }
        if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
-               if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
-                       printk(", DMA");
+               if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) {
+                       if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7))
+                               printk(", UDMA");
+                       else
+                               printk(", DMA");
+               }
        }
        printk("\n");
 }
index bbbeec8c7cb3e0c7ed309010eca33674dc32556c..edebf66b881b80c46e4604976a143c5228a0be07 100644 (file)
@@ -247,14 +247,21 @@ static int build_dmatable (ide_drive_t *drive)
 static int config_drive_for_dma (ide_drive_t *drive)
 {
        const char **list;
-
        struct hd_driveid *id = drive->id;
+
        if (id && (id->capability & 1)) {
-               /* Enable DMA on any drive that supports mword2 DMA */
-               if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
-                       drive->using_dma = 1;
-                       return 0;               /* DMA enabled */
-               }
+               /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+               if (id->field_valid & 4)        /* UltraDMA */
+                       if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+                               drive->using_dma = 1;
+                               return 0;       /* dma enabled */
+                       }
+               /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+               if (id->field_valid & 2)        /* regular DMA */
+                       if  ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
+                               drive->using_dma = 1;
+                               return 0;       /* dma enabled */
+                       }
                /* Consult the list of known "good" drives */
                list = good_dma_drives;
                while (*list) {
index e7e7967dcabaa482969d1011f314eacd1e870c38..8be978f3f2117f2eea2665e448db4e7a6e0ff395 100644 (file)
@@ -706,7 +706,7 @@ static void xd_dtc_init_controller (u_char *address)
        switch ((u_long) address) {
                case 0x00000:
                case 0xC8000:   break;                  /*initial: 0x320 */
-               case 0xCA000:   if (xd[3]<=0) xd_iobase = 0x324; 
+               case 0xCA000:   xd_iobase = 0x324; 
                                break;
                case 0xD0000:                           /*5150CX*/
                case 0xD8000:   break;                  /*5150CX & 5150XL*/
index 77958f28f21f7e79c5747d4de0cf3ab44203c3b1..a35bd6d0c863b4aa96b467f53f58a9838bdb7346 100644 (file)
@@ -594,13 +594,15 @@ static void set_origin(int currcons)
        __set_origin(__real_origin);
 }
 
-void scrup(int currcons, unsigned int t, unsigned int b)
+static void scrup(int currcons, unsigned int t, unsigned int b, unsigned int nr)
 {
        int hardscroll = hardscroll_enabled;
 
-       if (b > video_num_lines || t >= b)
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > video_num_lines || t >= b || nr < 1)
                return;
-       if (t || b != video_num_lines)
+       if (t || b != video_num_lines || nr > 1)
                hardscroll = 0;
        if (hardscroll) {
                origin += video_size_row;
@@ -641,40 +643,34 @@ void scrup(int currcons, unsigned int t, unsigned int b)
                set_origin(currcons);
        } else {
                unsigned short * d = (unsigned short *) (origin+video_size_row*t);
-               unsigned short * s = (unsigned short *) (origin+video_size_row*(t+1));
-               unsigned int count = (b-t-1) * video_num_columns;
+               unsigned short * s = (unsigned short *) (origin+video_size_row*(t+nr));
 
-               while (count) {
-                       count--;
-                       scr_writew(scr_readw(s++), d++);
-               }
-               count = video_num_columns;
-               while (count) {
-                       count--;
-                       scr_writew(video_erase_char, d++);
-               }
+               memcpyw(d, s, (b-t-nr) * video_size_row);
+               memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
        }
 }
 
-void
-scrdown(int currcons, unsigned int t, unsigned int b)
+static void
+scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr)
 {
-       unsigned short *d, *s;
+       unsigned short *s;
        unsigned int count;
+       unsigned int step;
 
-       if (b > video_num_lines || t >= b)
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > video_num_lines || t >= b || nr < 1)
                return;
-       d = (unsigned short *) (origin+video_size_row*b);
-       s = (unsigned short *) (origin+video_size_row*(b-1));
-       count = (b-t-1)*video_num_columns;
-       while (count) {
-               count--;
-               scr_writew(scr_readw(--s), --d);
+       s = (unsigned short *) (origin+video_size_row*(b-nr-1));
+       step = video_num_columns * nr;
+       count = b - t - nr;
+       while (count--) {
+               memcpyw(s + step, s, video_size_row);
+               s -= video_num_columns;
        }
-       count = video_num_columns;
-       while (count) {
-               count--;
-               scr_writew(video_erase_char, --d);
+       while (nr--) {
+               s += video_num_columns;
+               memsetw(s, video_erase_char, video_size_row);
        }
        has_scrolled = 1;
 }
@@ -685,7 +681,7 @@ static void lf(int currcons)
         * if below scrolling region
         */
        if (y+1 == bottom)
-               scrup(currcons,top,bottom);
+               scrup(currcons,top,bottom, 1);
        else if (y < video_num_lines-1) {
                y++;
                pos += video_size_row;
@@ -699,7 +695,7 @@ static void ri(int currcons)
         * if above scrolling region
         */
        if (y == top)
-               scrdown(currcons,top,bottom);
+               scrdown(currcons,top,bottom, 1);
        else if (y > 0) {
                y--;
                pos -= video_size_row;
@@ -1188,9 +1184,9 @@ static void insert_char(int currcons)
        need_wrap = 0;
 }
 
-static void insert_line(int currcons)
+static void insert_line(int currcons, unsigned int nr)
 {
-       scrdown(currcons,y,bottom);
+       scrdown(currcons, y, bottom, nr);
        need_wrap = 0;
 }
 
@@ -1207,9 +1203,9 @@ static void delete_char(int currcons)
        need_wrap = 0;
 }
 
-static void delete_line(int currcons)
+static void delete_line(int currcons, unsigned int nr)
 {
-       scrup(currcons,y,bottom);
+       scrup(currcons, y, bottom, nr);
        need_wrap = 0;
 }
 
@@ -1229,8 +1225,7 @@ static void csi_L(int currcons, unsigned int nr)
                nr = video_num_lines;
        else if (!nr)
                nr = 1;
-       while (nr--)
-               insert_line(currcons);
+       insert_line(currcons, nr);
 }
 
 static void csi_P(int currcons, unsigned int nr)
@@ -1249,8 +1244,7 @@ static void csi_M(int currcons, unsigned int nr)
                nr = video_num_lines;
        else if (!nr)
                nr=1;
-       while (nr--)
-               delete_line(currcons);
+       delete_line(currcons, nr);
 }
 
 static void save_cur(int currcons)
index be389996b79d94925055bfb6c2712f86725e6a61..8995222738b49cf514f8dfbbc8651a909cf944e7 100644 (file)
@@ -42,8 +42,8 @@ static int wdt_is_open=0;
  *     You must set these - there is no sane way to probe for this board.
  */
  
-int io=0x240;
-int irq=14;
+static int io=0x240;
+static int irq=14;
 
 #define WD_TIMO (100*60)               /* 1 minute */
 
index 73e932498c5f246588e09bcdd14f26396a2b4c46..7c9013390939b7ab15b18f866dd3d86a820d96ee 100644 (file)
@@ -1,8 +1,8 @@
 /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */
 /*
-       Written 1993-1998 by Donald Becker.
+       Written 1993-1997 by Donald Becker.
 
-       Copyright 1994-1998 by Donald Becker.
+       Copyright 1994-1997 by Donald Becker.
        Copyright 1993 United States Government as represented by the
        Director, National Security Agency.      This software may be used and
        distributed according to the terms of the GNU Public License,
        FIXES:
                Alan Cox:       Removed the 'Unexpected interrupt' bug.
                Michael Meskes: Upgraded to Donald Becker's version 1.07.
-               Alan Cox:       Increased the eeprom delay. Regardless of
+               Alan Cox:       Increased the eeprom delay. Regardless of 
                                what the docs say some people definitely
                                get problems with lower (but in card spec)
                                delays
                v1.10 4/21/97 Fixed module code so that multiple cards may be detected,
                                other cleanups.  -djb
-               v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb
-               v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb
-               v1.15 1/31/98 Faster recovery for Tx errors. -djb
-               v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb
 */
 
-static char *version = "3c509.c:1.16C 2/5/98 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n";
 /* A few values that may be tweaked. */
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (400*HZ/1000)
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+#define INTR_WORK      10
 
 #include <linux/module.h>
 
@@ -74,15 +70,14 @@ int el3_debug = EL3_DEBUG;
 int el3_debug = 2;
 #endif
 
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-
 /* To minimize the size of the driver source I only define operating
-   constants if they are used several times and make the code clearer.
-   You'll need the manual to understand hardware operation. */
+   constants if they are used several times.  You'll need the manual
+   anyway if you want to understand driver details. */
 /* Offsets from base I/O address. */
 #define EL3_DATA 0x00
 #define EL3_CMD 0x0e
 #define EL3_STATUS 0x0e
+#define         EEPROM_READ 0x80
 
 #define EL3_IO_EXTENT  16
 
@@ -110,52 +105,50 @@ enum RxFilter {
        RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
 
 /* Register window 1 offsets, the window used in normal operation. */
-enum Window1 {
-       TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
-       RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
-       TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
-       Wn0_IRQ = 8,                    /* Window 0: Set IRQ line in bits 12-15. */
-       Wn0EepromCmd = 10,              /* Window 0: EEPROM command register. */
-       Wn0EepromData = 12,             /* Window 0: EEPROM results register. */
-       IntrStatus=0x0E,                /* Valid in all windows. */
-};
-enum Win0_EEPROM_bits {
-       EEPROM_Read = 0x80, EEPROM_Busy = 0x8000,
-};
+#define TX_FIFO                0x00
+#define RX_FIFO                0x00
+#define RX_STATUS      0x08
+#define TX_STATUS      0x0B
+#define TX_FREE                0x0C            /* Remaining free bytes in Tx buffer. */
 
+#define WN0_IRQ                0x08            /* Window 0: Set IRQ line in bits 12-15. */
 #define WN4_MEDIA      0x0A            /* Window 4: Various transcvr/media bits. */
 #define  MEDIA_TP      0x00C0          /* Enable link beat and jabber for 10baseT. */
 
+/*
+ * Must be a power of two (we use a binary and in the
+ * circular queue)
+ */
+#define SKB_QUEUE_SIZE 64
+
 struct el3_private {
        struct enet_statistics stats;
        struct device *next_dev;
        /* skb send-queue */
        int head, size;
+       struct sk_buff *queue[SKB_QUEUE_SIZE];
 };
-
-static int id_port = 0x110;            /* Start with 0x110 to avoid new sound cards.*/
+static int id_port = 0x100;
 static struct device *el3_root_dev = NULL;
 
 static ushort id_read_eeprom(int index);
-static ushort read_eeprom(int ioaddr, int index);
+static ushort read_eeprom(short ioaddr, int index);
 static int el3_open(struct device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct device *dev);
 static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void update_stats(int addr, struct device *dev);
 static struct enet_statistics *el3_get_stats(struct device *dev);
-static int el3_rx(struct device *dev, int max_work);
+static int el3_rx(struct device *dev);
 static int el3_close(struct device *dev);
-static void set_rx_mode(struct device *dev);
+static void set_multicast_list(struct device *dev);
 
 \f
 
 int el3_probe(struct device *dev)
 {
        short lrs_state = 0xff, i;
-       int ioaddr, irq, if_port;
-       u16 phys_addr[3];
+       ushort ioaddr, irq, if_port;
+       short phys_addr[3];
        static int current_tag = 0;
 
        /* First check all slots of the EISA bus.  The next slot address to
@@ -166,19 +159,14 @@ int el3_probe(struct device *dev)
                        ioaddr = eisa_addr;
                        eisa_addr += 0x1000;
 
-                       if (check_region(ioaddr, EL3_IO_EXTENT))
-                               continue;
                        /* Check the standard EISA ID register for an encoded '3Com'. */
                        if (inw(ioaddr + 0xC80) != 0x6d50)
                                continue;
-                       /* Check for a product that we support, 3c579 any rev. */
-                       if (inb(ioaddr + 0xC82) != 0x57)
-                               continue;
 
                        /* Change the register set to the configuration window 0. */
                        outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD);
 
-                       irq = inw(ioaddr + Wn0_IRQ) >> 12;
+                       irq = inw(ioaddr + WN0_IRQ) >> 12;
                        if_port = inw(ioaddr + 6)>>14;
                        for (i = 0; i < 3; i++)
                                phys_addr[i] = htons(read_eeprom(ioaddr, i));
@@ -197,7 +185,7 @@ int el3_probe(struct device *dev)
                for (i = 0; i < 8; i++)
                        if ((mca_adaptor_id(i) | 1) == 0x627c) {
                                ioaddr = mca_pos_base_addr(i);
-                               irq = inw(ioaddr + Wn0_IRQ) >> 12;
+                               irq = inw(ioaddr + WN0_IRQ) >> 12;
                                if_port = inw(ioaddr + 6)>>14;
                                for (i = 0; i < 3; i++)
                                        phys_addr[i] = htons(read_eeprom(ioaddr, i));
@@ -214,7 +202,7 @@ int el3_probe(struct device *dev)
        outb(0x02, 0x279);           /* Select PnP config control register. */
        outb(0x02, 0xA79);           /* Return to WaitForKey state. */
        /* Select an open I/O location at 0x1*0 to do contention select. */
-       for ( ; id_port < 0x200; id_port += 0x10) {
+       for (id_port = 0x100; id_port < 0x200; id_port += 0x10) {
                if (check_region(id_port, 1))
                        continue;
                outb(0x00, id_port);
@@ -224,8 +212,7 @@ int el3_probe(struct device *dev)
        }
        if (id_port >= 0x200) {             /* GCC optimizes this test out. */
                /* Rare -- do we really need a warning? */
-               printk(KERN_WARNING " WARNING: No I/O port available for 3c509 "
-                          "activation sequence.\n");
+               printk(" WARNING: No I/O port available for 3c509 activation.\n");
                return -ENODEV;
        }
        /* Next check for all ISA bus boards by sending the ID sequence to the
@@ -259,23 +246,18 @@ int el3_probe(struct device *dev)
        }
 
        {
-               unsigned int iobase = id_read_eeprom(8);
+               unsigned short iobase = id_read_eeprom(8);
                if_port = iobase >> 14;
                ioaddr = 0x200 + ((iobase & 0x1f) << 4);
        }
-       irq = id_read_eeprom(9) >> 12;
-
-       if (dev) {                                      /* Set passed-in IRQ or I/O Addr. */
-               if (dev->irq > 1  &&  dev->irq < 16)
-                       irq = dev->irq;
-
-               if (dev->base_addr) {
-                       if (dev->mem_end == 0x3c509                     /* Magic key */
-                               && dev->base_addr >= 0x200  &&  dev->base_addr <= 0x3e0)
-                               ioaddr = dev->base_addr & 0x3f0;
-                       else if (dev->base_addr != ioaddr)
-                               return -ENODEV;
-               }
+       if (dev  &&  dev->irq > 1  &&  dev->irq < 16)
+               irq = dev->irq;
+       else
+               irq = id_read_eeprom(9) >> 12;
+
+       if (dev  &&  dev->base_addr != 0
+               &&  dev->base_addr != (unsigned short)ioaddr) {
+               return -ENODEV;
        }
 
        /* Set the adaptor tag so that the next card can be found. */
@@ -289,7 +271,7 @@ int el3_probe(struct device *dev)
                return -ENODEV;
 
        /* Free the interrupt so that some other card can use it. */
-       outw(0x0f00, ioaddr + Wn0_IRQ);
+       outw(0x0f00, ioaddr + WN0_IRQ);
  found:
        if (dev == NULL) {
                dev = init_etherdev(dev, sizeof(struct el3_private));
@@ -303,14 +285,14 @@ int el3_probe(struct device *dev)
 
        {
                const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
-               printk(KERN_INFO"%s: 3c509 at %#3.3lx tag %d, %s port, address ",
+               printk("%s: 3c509 at %#3.3lx tag %d, %s port, address ",
                           dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
        }
 
-       /* Show the station address. */
-       for (i = 0; i < 5; i++)
-               printk("%2.2x:", dev->dev_addr[i]);
-       printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], dev->irq);
+       /* Read in the station address. */
+       for (i = 0; i < 6; i++)
+               printk(" %2.2x", dev->dev_addr[i]);
+       printk(", IRQ %d.\n", dev->irq);
 
        /* Make up a EL3-specific-data structure. */
        if (dev->priv == NULL)
@@ -323,14 +305,14 @@ int el3_probe(struct device *dev)
        el3_root_dev = dev;
 
        if (el3_debug > 0)
-               printk(KERN_INFO"%s", version);
+               printk(version);
 
        /* The EL3-specific entries in the device structure. */
        dev->open = &el3_open;
        dev->hard_start_xmit = &el3_start_xmit;
        dev->stop = &el3_close;
        dev->get_stats = &el3_get_stats;
-       dev->set_multicast_list = &set_rx_mode;
+       dev->set_multicast_list = &set_multicast_list;
 
        /* Fill in the generic fields of the device structure. */
        ether_setup(dev);
@@ -340,17 +322,12 @@ int el3_probe(struct device *dev)
 /* Read a word from the EEPROM using the regular EEPROM access register.
    Assume that we are in register window zero.
  */
-static ushort read_eeprom(int ioaddr, int index)
+static ushort read_eeprom(short ioaddr, int index)
 {
-       int boguscheck;
-       outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
+       outw(EEPROM_READ + index, ioaddr + 10);
        /* Pause for at least 162 us. for the read to take place. */
-       for (boguscheck = 20; boguscheck >= 0; boguscheck--) {
-               udelay(40);
-               if ((inw(ioaddr + Wn0EepromCmd) & EEPROM_Busy) == 0)
-                       break;
-       }
-       return inw(ioaddr + Wn0EepromData);
+       udelay (500);
+       return inw(ioaddr + 12);
 }
 
 /* Read a word from the EEPROM when in the ISA ID probe state. */
@@ -360,7 +337,7 @@ static ushort id_read_eeprom(int index)
 
        /* Issue read command, and pause for at least 162 us. for it to complete.
           Assume extra-fast 16Mhz bus. */
-       outb(EEPROM_Read + index, id_port);
+       outb(EEPROM_READ + index, id_port);
 
        /* Pause for at least 162 us. for the read to take place. */
        udelay (500);
@@ -369,7 +346,7 @@ static ushort id_read_eeprom(int index)
                word = (word << 1) + (inb(id_port) & 0x01);
 
        if (el3_debug > 3)
-               printk(KERN_DEBUG"  3c509 EEPROM word %d %#4.4x.\n", index, word);
+               printk("  3c509 EEPROM word %d %#4.4x.\n", index, word);
 
        return word;
 }
@@ -386,20 +363,20 @@ el3_open(struct device *dev)
        outw(RxReset, ioaddr + EL3_CMD);
        outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
-       if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev))
+       if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev)) {
                return -EAGAIN;
+       }
 
        EL3WINDOW(0);
        if (el3_debug > 3)
-               printk(KERN_DEBUG"%s: Opening 3c509, IRQ %d status@%x %4.4x.\n",
-                          dev->name, dev->irq, ioaddr + EL3_STATUS,
-                          inw(ioaddr + EL3_STATUS));
+               printk("%s: Opening, IRQ %d      status@%x %4.4x.\n", dev->name,
+                          dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
 
-       /* Activate board: this is usually unnecessary. */
+       /* Activate board: this is probably unnecessary. */
        outw(0x0001, ioaddr + 4);
 
        /* Set the IRQ line. */
-       outw((dev->irq << 12) | 0x0f00, ioaddr + Wn0_IRQ);
+       outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
 
        /* Set the station address in window 2 each time opened. */
        EL3WINDOW(2);
@@ -428,7 +405,7 @@ el3_open(struct device *dev)
        EL3WINDOW(1);
 
        /* Accept b-case and phys addr only. */
-       set_rx_mode(dev);
+       outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
        outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
        dev->interrupt = 0;
@@ -442,76 +419,84 @@ el3_open(struct device *dev)
        /* Ack all pending events, and set active indicator mask. */
        outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
                 ioaddr + EL3_CMD);
-       outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,
+       outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull,
                 ioaddr + EL3_CMD);
 
        if (el3_debug > 3)
-               printk(KERN_DEBUG "%s: Opened 3c509  IRQ %d  status %4.4x.\n",
+               printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
                           dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
 
        MOD_INC_USE_COUNT;
        return 0;                                       /* Always succeed */
 }
 
-static void el3_tx_timeout(struct device *dev)
-{
-       struct el3_private *lp = (struct el3_private *)dev->priv;
-       int ioaddr = dev->base_addr;
-       ushort status = inw(ioaddr + EL3_STATUS);
-
-       printk(KERN_ERR"%s: transmit timed out, Tx_status %2.2x status %4.4x "
-                  "Tx FIFO room %d.\n",
-                  dev->name, inb(ioaddr + TxStatus), status,
-                  inw(ioaddr + TxFree));
-
-       /* Error-checking code for the common IRQ line block. */
-       if (status & 0x0001             /* IRQ line active, missed one. */
-               && inw(ioaddr + EL3_STATUS) & 1) {                      /* Make sure. */
-               printk(KERN_CRIT"%s: Interrupt line blocked?  3c509 status %4.4x"
-                          "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
-                          inb(ioaddr + TxStatus), inw(ioaddr + RxStatus));
-       }
-
-       lp->stats.tx_errors++;
-       dev->trans_start = jiffies;
-       /* Issue TX_RESET and TX_START commands. */
-       outw(TxReset, ioaddr + EL3_CMD);
-       outw(TxEnable, ioaddr + EL3_CMD);
-       dev->tbusy = 0;
-}
-
 static int
 el3_start_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct el3_private *lp = (struct el3_private *)dev->priv;
        int ioaddr = dev->base_addr;
 
-       if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-               if (jiffies - dev->trans_start >= TX_TIMEOUT)
-                       el3_tx_timeout(dev);
-               return 1;
+       /* Transmitter timeout, serious problems. */
+       if (dev->tbusy) {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < TX_TIMEOUT)
+                       return 1;
+               printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "
+                          "Tx FIFO room %d.\n",
+                          dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
+                          inw(ioaddr + TX_FREE));
+               lp->stats.tx_errors++;
+               dev->trans_start = jiffies;
+               /* Issue TX_RESET and TX_START commands. */
+               outw(TxReset, ioaddr + EL3_CMD);
+               outw(TxEnable, ioaddr + EL3_CMD);
+               dev->tbusy = 0;
        }
 
        if (el3_debug > 4) {
-               printk(KERN_DEBUG"%s: el3_start_xmit(length = %ld) called, status "
-                          "%4.4x.\n", dev->name, skb->len, inw(ioaddr + EL3_STATUS));
+               printk("%s: el3_start_xmit(length = %ld) called, status %4.4x.\n",
+                          dev->name, skb->len, inw(ioaddr + EL3_STATUS));
        }
-
-       /* Put out the doubleword header... */
-       outl(skb->len, ioaddr + TX_FIFO);
-
-       /* ... and the packet rounded to a doubleword. */
+#if 0
+#ifndef final_version
+       {       /* Error-checking code, delete someday. */
+               ushort status = inw(ioaddr + EL3_STATUS);
+               if (status & 0x0001             /* IRQ line active, missed one. */
+                       && inw(ioaddr + EL3_STATUS) & 1) {                      /* Make sure. */
+                       printk("%s: Missed interrupt, status then %04x now %04x"
+                                  "  Tx %2.2x Rx %4.4x.\n", dev->name, status,
+                                  inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
+                                  inw(ioaddr + RX_STATUS));
+                       /* Fake interrupt trigger by masking, acknowledge interrupts. */
+                       outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
+                       outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+                                ioaddr + EL3_CMD);
+                       outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+               }
+       }
+#endif
+#endif
+       /* Avoid timer-based retransmission conflicts. */
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk("%s: Transmitter access conflict.\n", dev->name);
+       else {
+               /* Put out the doubleword header... */
+               outw(skb->len, ioaddr + TX_FIFO);
+               outw(0x00, ioaddr + TX_FIFO);
+               /* ... and the packet rounded to a doubleword. */
 #ifdef  __powerpc__
-       outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+               outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #else
-       outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+               outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #endif
-       dev->trans_start = jiffies;
-       if (inw(ioaddr + TxFree) > 1536) {
-               dev->tbusy = 0;
-       } else
-               /* Interrupt us when the FIFO has room for max-sized packet. */
-               outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+
+               dev->trans_start = jiffies;
+               if (inw(ioaddr + TX_FREE) > 1536) {
+                       dev->tbusy = 0;
+               } else
+                       /* Interrupt us when the FIFO has room for max-sized packet. */
+                       outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+       }
 
        dev_kfree_skb (skb, FREE_WRITE);
 
@@ -520,11 +505,11 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
                short tx_status;
                int i = 4;
 
-               while (--i > 0  &&      (tx_status = inb(ioaddr + TxStatus)) > 0) {
+               while (--i > 0  &&      (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
                        if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
                        if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
                        if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
-                       outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
+                       outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
                }
        }
        return 0;
@@ -536,67 +521,61 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct device *dev = (struct device *)dev_id;
        int ioaddr, status;
-       int work_budget = max_interrupt_work;
+       int i = INTR_WORK;
 
-       if (dev->interrupt) {
-               printk(KERN_ERR"%s: Re-entering the interrupt handler.\n", dev->name);
+       if (dev == NULL) {
+               printk ("el3_interrupt(): irq %d for unknown device.\n", irq);
                return;
        }
+
+       if (dev->interrupt)
+               printk("%s: Re-entering the interrupt handler.\n", dev->name);
        dev->interrupt = 1;
 
        ioaddr = dev->base_addr;
        status = inw(ioaddr + EL3_STATUS);
 
        if (el3_debug > 4)
-               printk(KERN_DEBUG"%s: interrupt, status %4.4x.\n", dev->name, status);
+               printk("%s: interrupt, status %4.4x.\n", dev->name, status);
 
        while ((status = inw(ioaddr + EL3_STATUS)) &
                   (IntLatch | RxComplete | StatsFull)) {
 
                if (status & RxComplete)
-                       work_budget = el3_rx(dev, work_budget);
+                       el3_rx(dev);
 
                if (status & TxAvailable) {
                        if (el3_debug > 5)
-                               printk(KERN_DEBUG"      TX room bit was handled.\n");
+                               printk("        TX room bit was handled.\n");
                        /* There's room in the FIFO for a full-sized packet. */
                        outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
                        dev->tbusy = 0;
                        mark_bh(NET_BH);
                }
-               if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) {
+               if (status & (AdapterFailure | RxEarly | StatsFull)) {
                        /* Handle all uncommon interrupts. */
                        if (status & StatsFull)                         /* Empty statistics. */
                                update_stats(ioaddr, dev);
                        if (status & RxEarly) {                         /* Rx early is unused. */
-                               work_budget = el3_rx(dev, work_budget);
+                               el3_rx(dev);
                                outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
                        }
-                       if (status & TxComplete) {                      /* Really Tx error. */
-                               struct el3_private *lp = (struct el3_private *)dev->priv;
-                               short tx_status;
-                               int i = 4;
-
-                               while (--i>0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
-                                       if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
-                                       if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
-                                       if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
-                                       outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
-                               }
-                       }
                        if (status & AdapterFailure) {
                                /* Adapter failure requires Rx reset and reinit. */
                                outw(RxReset, ioaddr + EL3_CMD);
                                /* Set the Rx filter to the current state. */
-                               set_rx_mode(dev);
+                               outw(SetRxFilter | RxStation | RxBroadcast
+                                        | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)
+                                        | (dev->flags & IFF_PROMISC ? RxProm : 0),
+                                        ioaddr + EL3_CMD);
                                outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
                                outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
                        }
                }
 
-               if (--work_budget < 0) {
-                       printk(KERN_WARNING"%s: Too much work in interrupt, status "
-                                  "%4.4x.\n", dev->name, status);
+               if (--i < 0) {
+                       printk("%s: Infinite loop in interrupt, status %4.4x.\n",
+                                  dev->name, status);
                        /* Clear all interrupts. */
                        outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
                        break;
@@ -606,7 +585,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        }
 
        if (el3_debug > 4) {
-               printk(KERN_DEBUG"%s: exiting interrupt, status %4.4x.\n", dev->name,
+               printk("%s: exiting interrupt, status %4.4x.\n", dev->name,
                           inw(ioaddr + EL3_STATUS));
        }
 
@@ -638,7 +617,7 @@ static void update_stats(int ioaddr, struct device *dev)
        struct el3_private *lp = (struct el3_private *)dev->priv;
 
        if (el3_debug > 5)
-               printk(KERN_DEBUG"   Updating the statistics.\n");
+               printk("   Updating the statistics.\n");
        /* Turn off statistics updates while reading. */
        outw(StatsDisable, ioaddr + EL3_CMD);
        /* Switch to the stats window, and read everything. */
@@ -661,20 +640,19 @@ static void update_stats(int ioaddr, struct device *dev)
        return;
 }
 
-static int el3_rx(struct device *dev, int work_budget)
+static int
+el3_rx(struct device *dev)
 {
        struct el3_private *lp = (struct el3_private *)dev->priv;
        int ioaddr = dev->base_addr;
        short rx_status;
 
        if (el3_debug > 5)
-               printk(KERN_DEBUG"   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
-                          inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
-       while ((rx_status = inw(ioaddr + RxStatus)) > 0  && --work_budget >= 0) {
+               printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+                          inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
+       while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
                if (rx_status & 0x4000) { /* Error, update stats. */
                        short error = rx_status & 0x3800;
-
-                       outw(RxDiscard, ioaddr + EL3_CMD);
                        lp->stats.rx_errors++;
                        switch (error) {
                        case 0x0000:            lp->stats.rx_over_errors++; break;
@@ -690,7 +668,7 @@ static int el3_rx(struct device *dev, int work_budget)
 
                        skb = dev_alloc_skb(pkt_len+5);
                        if (el3_debug > 4)
-                               printk(KERN_DEBUG"Receiving packet size %d status %4.4x.\n",
+                               printk("Receiving packet size %d status %4.4x.\n",
                                           pkt_len, rx_status);
                        if (skb != NULL) {
                                skb->dev = dev;
@@ -705,43 +683,48 @@ static int el3_rx(struct device *dev, int work_budget)
                                         (pkt_len + 3) >> 2);
 #endif
 
-                               outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
                                skb->protocol = eth_type_trans(skb,dev);
                                netif_rx(skb);
+                               outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
                                lp->stats.rx_packets++;
                                continue;
-                       }
-                       outw(RxDiscard, ioaddr + EL3_CMD);
-                       lp->stats.rx_dropped++;
-                       if (el3_debug)
-                               printk(KERN_NOTICE"%s: Couldn't allocate a sk_buff of size "
-                                          "%d.\n", dev->name, pkt_len);
+                       } else if (el3_debug)
+                               printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+                                          dev->name, pkt_len);
                }
-               inw(ioaddr + EL3_STATUS);                               /* Delay. */
+               lp->stats.rx_dropped++;
+               outw(RxDiscard, ioaddr + EL3_CMD);
                while (inw(ioaddr + EL3_STATUS) & 0x1000)
-                       printk(KERN_NOTICE"     Waiting for 3c509 to discard packet, status %x.\n",
+                       printk("        Waiting for 3c509 to discard packet, status %x.\n",
                                   inw(ioaddr + EL3_STATUS) );
        }
 
-       return work_budget;
+       return 0;
 }
 
 /*
  *     Set or clear the multicast filter for this adaptor.
  */
 static void
-set_rx_mode(struct device *dev)
+set_multicast_list(struct device *dev)
 {
-       int ioaddr = dev->base_addr;
-
-       if (dev->flags & IFF_PROMISC) {
+       short ioaddr = dev->base_addr;
+       if (el3_debug > 1) {
+               static int old = 0;
+               if (old != dev->mc_count) {
+                       old = dev->mc_count;
+                       printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);
+               }
+       }
+       if (dev->flags&IFF_PROMISC) {
                outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
                         ioaddr + EL3_CMD);
-       } else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {
-               outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast,
-                        ioaddr + EL3_CMD);
-       } else
-               outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+       }
+       else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {
+               outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
+       }
+       else
+                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
 }
 
 static int
@@ -750,7 +733,7 @@ el3_close(struct device *dev)
        int ioaddr = dev->base_addr;
 
        if (el3_debug > 2)
-               printk(KERN_DEBUG"%s: Shutting down ethercard.\n", dev->name);
+               printk("%s: Shutting down ethercard.\n", dev->name);
 
        dev->tbusy = 1;
        dev->start = 0;
@@ -775,7 +758,7 @@ el3_close(struct device *dev)
        /* Switching back to window 0 disables the IRQ. */
        EL3WINDOW(0);
        /* But we explicitly zero the IRQ line select anyway. */
-       outw(0x0f00, ioaddr + Wn0_IRQ);
+       outw(0x0f00, ioaddr + WN0_IRQ);
 
        update_stats(ioaddr, dev);
        MOD_DEC_USE_COUNT;
@@ -783,7 +766,7 @@ el3_close(struct device *dev)
 }
 
 #ifdef MODULE
-/* Parameters that may be passed into the module. */
+/* Parameter that may be passed into the module. */
 static int debug = -1;
 static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1};
@@ -827,8 +810,8 @@ cleanup_module(void)
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c"
- *  c-indent-level: 4
- *  c-basic-offset: 4
+ *  version-control: t
+ *  kept-new-versions: 5
  *  tab-width: 4
  * End:
  */
index 83dd13f7351b20ff24f2cd372d5ed5073b8d8f20..5c895ea2c818c3d758acf1a885f4fdbe89662c75 100644 (file)
@@ -1,6 +1,6 @@
 /* 3c515.c: A 3Com ISA EtherLink XL "Corkscrew" ethernet driver for linux. */
 /*
-       Written 1997 by Donald Becker.
+       Written 1997-1998 by Donald Becker.
 
        This software may be used and distributed according to the terms
        of the GNU Public License, incorporated herein by reference.
@@ -12,7 +12,7 @@
           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 */
 
-static char *version = "3c515.c:v0.06 12/5/97 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "3c515.c:v0.99 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
 #define CORKSCREW 1
 
 /* "Knobs" that adjust features and parameters. */
@@ -116,6 +116,11 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
    */
 #define CORKSCREW_TOTAL_SIZE 0x20
 
+#ifdef HAVE_DEVLIST
+struct netdev_entry tc515_drv =
+{"3c515", tc515_probe, CORKSCREW_TOTAL_SIZE, NULL};
+#endif
+
 #ifdef DRIVER_DEBUG
 int vortex_debug = DRIVER_DEBUG;
 #else
@@ -408,7 +413,7 @@ init_module(void)
 }
 
 #else
-int isa515_probe(struct device *dev)
+int tc515_probe(struct device *dev)
 {
        int cards_found = 0;
 
index 09a3cf4f74566e92c7290671b34abb71023c7d79..d8fa645abda70c2b3d13801e3ed355f809dee166 100644 (file)
@@ -15,7 +15,7 @@
 */
 
 static char *version =
-"3c59x.c:v0.49J 2/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -612,9 +612,9 @@ static int vortex_scan(struct device *dev)
                unsigned char pci_bus, pci_device_fn;
 
                for (;pci_index < 0xff; pci_index++) {
-                       unsigned char pci_irq_line, pci_latency;
+                       u8 pci_irq_line, pci_latency;
                        u16 pci_command, new_command, vendor, device;
-                       unsigned int pci_ioaddr;
+                       u32 pci_ioaddr;
 
                        if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
                                                                        pci_index, &pci_bus, &pci_device_fn)
@@ -1420,7 +1420,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
                outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
                dev_kfree_skb (skb, FREE_WRITE);
                if (inw(ioaddr + TxFree) > 1536) {
-                       dev->tbusy = 0;
+                       clear_bit(0, (void*)&dev->tbusy);
                } else
                        /* Interrupt us when the FIFO has room for max-sized packet. */
                        outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1430,7 +1430,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
        outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
        dev_kfree_skb (skb, FREE_WRITE);
        if (inw(ioaddr + TxFree) > 1536) {
-               dev->tbusy = 0;
+               clear_bit(0, (void*)&dev->tbusy);
        } else
                /* Interrupt us when the FIFO has room for max-sized packet. */
                outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1519,7 +1519,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
                        vp->tx_full = 1;
                else {                                  /* Clear previous interrupt enable. */
                        prev_entry->status &= ~TxIntrUploaded;
-                       dev->tbusy = 0;
+                       clear_bit(0, (void*)&dev->tbusy);
                }
                dev->trans_start = jiffies;
                return 0;
@@ -1571,7 +1571,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
                                printk(KERN_DEBUG "     TX room bit was handled.\n");
                        /* There's room in the FIFO for a full-sized packet. */
                        outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-                       dev->tbusy = 0;
+                       clear_bit(0, (void*)&dev->tbusy);
                        mark_bh(NET_BH);
                }
 
@@ -1594,14 +1594,14 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
                        outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
                        if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
                                lp->tx_full= 0;
-                               dev->tbusy = 0;
+                               clear_bit(0, (void*)&dev->tbusy);
                                mark_bh(NET_BH);
                        }
                }
 #ifdef VORTEX_BUS_MASTER
                if (status & DMADone) {
                        outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-                       dev->tbusy = 0;
+                       clear_bit(0, (void*)&dev->tbusy);
                        dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
                        mark_bh(NET_BH);
                }
@@ -1636,7 +1636,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
                           dev->name, status);
 
        dev->interrupt = 0;
-       lp->in_interrupt = 0;
+       clear_bit(0, (void*)&lp->in_interrupt);
        return;
 }
 
@@ -2108,8 +2108,7 @@ cleanup_module(void)
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  compile-command-redhat: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- *  compile-command-alt0: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
  *  compile-command-alt1: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c59x_cb.o"
  *  c-indent-level: 4
  *  c-basic-offset: 4
index 4ab47bc2dd124db7b7e9bb3dfb2755001accd972..36b9d76636850f8bde97085dad2addf07ce1944a 100644 (file)
@@ -1,42 +1,5 @@
 TLan Device Driver change log.
 
-0.42   - Coverted tranceiver from misused per-tranceiver functions
-         to a timer-oriented path that covers four possible classes
-         of tranceivers:
-               1. Unmanaged
-               2. Manual configuration
-               3. Autonegotiation w/ manual configuration
-               4. Autonegotiation w/ auto configuration
-       - Added ability to force speed and duplex settings.
-       - Made speed, duplex, sa_int, etc, to be set per adapter with
-         ether= command.
-       - Added support for Olicom OC-2326
-
-0.41   - Added non-bounce buffer paths.  Added TLan_FreeLists to
-         dispose of unused sk_buff's at device close time.
-       - Discovered inlined functions aren't being inlined, or at
-         least take up more space than macros would.
-
-0.40   - Refined polarity checking to handle case when polarity
-         changes to normal from abnormal.
-       - Cleaned up TLan_Probe routine.
-       - Added an option for the SA_INTERRUPT flag to be set.
-       - Created FAQ.
-       - Removed all C++ style comments.
-       - Added error message if devices busmastering is inactive.
-         Also will now skip device.
-       - Put cli and sti back into TLan_HandleInterrupt.  It makes
-         me feel better.
-       - Moved the code that checks for boot parameter options to 
-         tlan_probe.
-
-0.39   - Minor cosmetic cleanups (especially variable declarations).
-       - Changes low level TLAN functions to use dev structures instead
-         individual data elements.
-        - Changed low level TLAN functions not to play with sti and cli
-         if in an interrupt routine.
-       - Removed cli and sti from TLan_HandleInterrupt.
-
 0.38   - Added code to isolate the external PHY if the internal PHY is
          being used for AUI/BNC connectivity.  Also set the aui and
          debug variables from mem_start and mem_end if the driver is
index 19c38314424701ad847b84d423642470741587de..5b354438c2c4778ea4a2121c71381fac7dcea67b 100644 (file)
@@ -3,11 +3,13 @@
 #
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
-tristate 'Frame relay DLCI support' CONFIG_DLCI
-if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
-  int '  Max open DLCI' CONFIG_DLCI_COUNT 24
-  int '  Max DLCI per device' CONFIG_DLCI_MAX 8
-  dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Frame relay DLCI support (EXPERIMENTAL)' CONFIG_DLCI
+  if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
+    int '  Max open DLCI' CONFIG_DLCI_COUNT 24
+    int '  Max DLCI per device' CONFIG_DLCI_MAX 8
+    dep_tristate '  SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+  fi
 fi
 tristate 'PLIP (parallel port) support' CONFIG_PLIP
 tristate 'PPP (point-to-point) support' CONFIG_PPP
@@ -39,7 +41,7 @@ fi
 #
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-  bool '3COM cards' CONFIG_NET_VENDOR_3COM
+  bool '3COM ISA, EISA and PCI cards' CONFIG_NET_VENDOR_3COM
   if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
     tristate '3c501 support' CONFIG_EL1
     tristate '3c503 support' CONFIG_EL2
@@ -48,22 +50,35 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       tristate '3c507 support' CONFIG_EL16
     fi
     tristate '3c509/3c579 support' CONFIG_EL3
-    tristate '3c515 support' CONFIG_CORKSCREW
+    tristate '3c515 ISA Fast EtherLink' CONFIG_3C515
     tristate '3c590/3c900 series (592/595/597/900/905) "Vortex/Boomerang" support' CONFIG_VORTEX
   fi
-  tristate 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
-  bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
+  bool 'Western Digital/SMC ISA and EISA cards' CONFIG_NET_VENDOR_SMC
   if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
     tristate 'WD80*3 support' CONFIG_WD80x3
     tristate 'SMC Ultra support' CONFIG_ULTRA
     tristate 'SMC Ultra32 support' CONFIG_ULTRA32
     tristate 'SMC 9194 support' CONFIG_SMC9194
   fi
+  bool 'PCI Ethernet adapters' CONFIG_NET_PCI
+  if [ "$CONFIG_NET_PCI" = "y" ]; then
+    tristate 'AMD PCI PCnet32 (PCI bus NE2100 cards) support' CONFIG_PCNET32
+    tristate 'Intel EtherExpressPro PCI 10+/100B/100+ support' CONFIG_EEXPRESS_PRO100B
+    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
+    tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+    tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
+    tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
+    tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
+    tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
+    tristate 'SMC EPIC/100 (EtherPower II) support' CONFIG_EPIC
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
+   fi
+  fi
   bool 'Other ISA cards' CONFIG_NET_ISA
   if [ "$CONFIG_NET_ISA" = "y" ]; then
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'AT1700 support (EXPERIMENTAL)' CONFIG_AT1700
-    fi
+    tristate 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+    tristate 'AT1700 (Fujitsu 86965) support' CONFIG_AT1700
     tristate 'Cabletron E21xx support' CONFIG_E2100
     tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
     tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
@@ -78,7 +93,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
     fi
-    tristate 'NE2000/NE1000 support' CONFIG_NE2000
+    tristate 'NE2000/NE1000 ISA support' CONFIG_NE2000
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'NI5210 support' CONFIG_NI52
       tristate 'NI6510 support' CONFIG_NI65
@@ -88,38 +103,24 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
     fi
     bool 'SK_G16 support' CONFIG_SK_G16
   fi
-  bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
+  bool 'EISA, VLB and other board controllers' CONFIG_NET_EISA
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
-    tristate 'AMD PCInet32 (VLB and PCI) support' CONFIG_LANCE32
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
-    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
-    tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
-    tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
-    tristate 'Intel EtherExpress/Pro 100B support' CONFIG_EEXPRESS_PRO100B
-    tristate 'NE2000 PCI support' CONFIG_PCI_NE2000
-    tristate 'RTL 8139 support' CONFIG_RTL8139
-    tristate 'SMC EtherPower II support' CONFIG_SMC_EPIC
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
       bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
     fi
   fi
   bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
   if [ "$CONFIG_NET_POCKET" = "y" ]; then
-    bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
+    tristate 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
     tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600
     tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620
   fi
 fi
 
-bool 'Ethernet (Gigabit)' CONFIG_GIGAETHER
-if [ "$CONFIG_GIGAETHER" = "y" ]; then
-  bool 'Packet Engines G-NIC PCI Gigabit Ethernet Adapter' CONFIG_YELLOWFIN
-fi
-
 bool 'Token Ring driver support' CONFIG_TR
 if [ "$CONFIG_TR" = "y" ]; then
   tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
index ef5981144a8f197e16f9ebb9776055f2aa441727..b0ab1cb5e90afcb2faffad492f29eaa4ac1a4415 100644 (file)
@@ -114,16 +114,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_PCI_NE2000),y)
-L_OBJS += ne2k-pci.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_PCI_NE2000),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += ne2k-pci.o
-  endif
-endif
-
 ifeq ($(CONFIG_HPLAN),y)
 L_OBJS += hp.o
 CONFIG_8390_BUILTIN = y
@@ -158,7 +148,7 @@ ifeq ($(CONFIG_ULTRA32),y)
 L_OBJS += smc-ultra32.o
 CONFIG_8390_BUILTIN = y
 else
-  ifeq ($(CONFIG_ULTRA32),m)
+  ifeq ($(CONFIG_ULTRA),m)
   CONFIG_8390_MODULE = y
   M_OBJS += smc-ultra32.o
   endif
@@ -257,8 +247,9 @@ endif
 
 ifeq ($(CONFIG_LANCE),y)
 L_OBJS += lance.o
-  ifeq ($(CONFIG_LANCE32),y)
-  L_OBJS += pcnet32.o
+else
+  ifeq ($(CONFIG_LANCE),m)
+  M_OBJS += lance.o
   endif
 endif
 
@@ -306,10 +297,10 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_CORKSCREW),y)
+ifeq ($(CONFIG_3C515),y)
 L_OBJS += 3c515.o
 else
-  ifeq ($(CONFIG_CORKSCREW),m)
+  ifeq ($(CONFIG_3C515),m)
   M_OBJS += 3c515.o
   endif
 endif
@@ -346,20 +337,53 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_EPIC),y)
+L_OBJS += epic100.o
+else
+  ifeq ($(CONFIG_EPIC),m)
+  M_OBJS += epic100.o
+  endif
+endif
 
-ifeq ($(CONFIG_WAVELAN),y)
-L_OBJS += wavelan.o
+ifeq ($(CONFIG_NE2K_PCI),y)
+L_OBJS += ne2k-pci.o
+CONFIG_8390_BUILTIN = y
 else
-  ifeq ($(CONFIG_WAVELAN),m)
-  M_OBJS += wavelan.o
+  ifeq ($(CONFIG_NE2K_PCI),m)
+  CONFIG_8390_MODULE = y
+  M_OBJS += ne2k-pci.o
   endif
 endif
 
-ifeq ($(CONFIG_TLAN),y)
-L_OBJS += tlan.o
+ifeq ($(CONFIG_PCNET32),y)
+L_OBJS += pcnet32.o
 else
-  ifeq ($(CONFIG_TLAN),m)
-  M_OBJS += tlan.o
+  ifeq ($(CONFIG_PCNET32),m)
+  M_OBJS += pcnet32.o
+  endif
+endif
+
+ifeq ($(CONFIG_RTL8139),y)
+L_OBJS += rtl8139.o
+else
+  ifeq ($(CONFIG_RTL8139),m)
+  M_OBJS += rtl8139.o
+  endif
+endif
+
+ifeq ($(CONFIG_YELLOWFIN),y)
+L_OBJS += yellowfin.o
+else
+  ifeq ($(CONFIG_YELLOWFIN),m)
+  M_OBJS += yellowfin.o
+  endif
+endif
+
+ifeq ($(CONFIG_WAVELAN),y)
+L_OBJS += wavelan.o
+else
+  ifeq ($(CONFIG_WAVELAN),m)
+  M_OBJS += wavelan.o
   endif
 endif
 
@@ -385,6 +409,10 @@ endif
 
 ifeq ($(CONFIG_ATP),y)
 L_OBJS += atp.o
+else
+  ifeq ($(CONFIG_ATP),m)
+  M_OBJS += atp.o
+  endif
 endif
 
 ifeq ($(CONFIG_DE4X5),y)
@@ -449,6 +477,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_TLAN),y)
+L_OBJS += tlan.o
+else
+  ifeq ($(CONFIG_TLAN),m)
+  M_OBJS += tlan.o
+  endif
+endif
+
 ifeq ($(CONFIG_ARCNET),y)
 L_OBJS += arcnet.o
 else
@@ -559,30 +595,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_YELLOWFIN),y)
-L_OBJS += yellowfin.o
-else
-  ifeq ($(CONFIG_YELLOWFIN),m)
-  M_OBJS += yellowfin.o
-  endif
-endif
-
-ifeq ($(CONFIG_SMC_EPIC),y)
-L_OBJS += epic100.o
-else
-  ifeq ($(CONFIG_SMC_EPIC),m)
-  M_OBJS += epic100.o
-  endif
-endif
-
-ifeq ($(CONFIG_RTL8139),y)
-L_OBJS += rtl8139.o
-else
-  ifeq ($(CONFIG_RTL8139),m)
-  M_OBJS += rtl8139.o
-  endif
-endif
-
 include $(TOPDIR)/Rules.make
 
 clean:
index d256092074db0867320ca79cbddff3766961c225..6eb6eb8040200cadc98e199a417aa2c33fd7c4f6 100644 (file)
@@ -45,12 +45,12 @@ extern int ultra32_probe(struct device *dev);
 extern int wd_probe(struct device *dev);
 extern int el2_probe(struct device *dev);
 extern int ne_probe(struct device *dev);
+extern int ne2k_pci_probe(struct device *dev);
 extern int hp_probe(struct device *dev);
 extern int hp_plus_probe(struct device *dev);
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
 extern int eepro_probe(struct device *);
-extern int eepro100_probe(struct device *);
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
@@ -81,7 +81,8 @@ extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
 extern int yellowfin_probe(struct device *);
-extern int epic100_probe(struct device *);
+extern int eepro100_probe(struct device *);
+extern int epic_probe(struct device *);
 extern int rtl8139_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int isa515_probe(struct device *);
@@ -101,35 +102,53 @@ ethif_probe(struct device *dev)
        return 1;               /* ENXIO */
 
     if (1
+       /* All PCI probes are safe, and thus should be first. */
+#ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
+       && de4x5_probe(dev)
+#endif
+#ifdef CONFIG_DGRS
+       && dgrs_probe(dev)
+#endif
+#ifdef CONFIG_EEXPRESS_PRO100B /* Intel EtherExpress Pro100B */
+       && eepro100_probe(dev)
+#endif
 #ifdef CONFIG_SMC_EPIC
-       && epic100_probe(dev)
+       && epic_probe(dev)
 #endif
-#ifdef CONFIG_YELLOWFIN
-       && yellowfin_probe(dev)
+#if defined(CONFIG_HP100)
+       && hp100_probe(dev)
+#endif 
+#if defined(CONFIG_NE2K_PCI)
+       && ne2k_pci_probe(dev)
+#endif
+#ifdef CONFIG_PCNET32
+       && pcnet32_probe(dev)
 #endif
 #ifdef CONFIG_RTL8139
        && rtl8139_probe(dev)
 #endif
-#ifdef CONFIG_DGRS
-       && dgrs_probe(dev)
-#endif
 #if defined(CONFIG_VORTEX)
        && tc59x_probe(dev)
 #endif
-#if defined(CONFIG_SEEQ8005)
-       && seeq8005_probe(dev)
-#endif
 #if defined(CONFIG_DEC_ELCP)
        && tulip_probe(dev)
 #endif
-#if defined(CONFIG_HP100)
-       && hp100_probe(dev)
-#endif 
-#if defined(CONFIG_ULTRA)
-       && ultra_probe(dev)
+#ifdef CONFIG_YELLOWFIN
+       && yellowfin_probe(dev)
+#endif
+       /* Next mostly-safe EISA-only drivers. */
+#ifdef CONFIG_AC3200           /* Ansel Communications EISA 3200. */
+       && ac3200_probe(dev)
 #endif
 #if defined(CONFIG_ULTRA32)
        && ultra32_probe(dev)
+#endif
+       /* Third, sensitive ISA boards. */
+#ifdef CONFIG_AT1700
+       && at1700_probe(dev)
+#endif
+#if defined(CONFIG_ULTRA)
+       && ultra_probe(dev)
 #endif
 #if defined(CONFIG_SMC9194)
        && smc_init(dev)
@@ -146,21 +165,18 @@ ethif_probe(struct device *dev)
 #if defined(CONFIG_HPLAN_PLUS)
        && hp_plus_probe(dev)
 #endif
-#ifdef CONFIG_AC3200           /* Ansel Communications EISA 3200. */
-       && ac3200_probe(dev)
+#if defined(CONFIG_SEEQ8005)
+       && seeq8005_probe(dev)
 #endif
 #ifdef CONFIG_E2100            /* Cabletron E21xx series. */
        && e2100_probe(dev)
 #endif
-#if defined(CONFIG_NE2000) || defined(NE2000)
+#if defined(CONFIG_NE2000)
        && ne_probe(dev)
 #endif
 #ifdef CONFIG_AT1500
        && at1500_probe(dev)
 #endif
-#ifdef CONFIG_AT1700
-       && at1700_probe(dev)
-#endif
 #ifdef CONFIG_FMV18X           /* Fujitsu FMV-181/182 */
        && fmv18x_probe(dev)
 #endif
@@ -170,6 +186,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_EL3              /* 3c509 */
        && el3_probe(dev)
 #endif
+#ifdef CONFIG_3C515            /* 3c515 */
+       && tc515_probe(dev)
+#endif
 #ifdef CONFIG_ZNET             /* Zenith Z-Note and some IBM Thinkpads. */
        && znet_probe(dev)
 #endif
@@ -179,18 +198,12 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_EEXPRESS_PRO     /* Intel EtherExpress Pro/10 */
        && eepro_probe(dev)
 #endif
-#ifdef CONFIG_EEXPRESS_PRO100B /* Intel EtherExpress Pro100B */
-       && eepro100_probe(dev)
-#endif
 #ifdef CONFIG_DEPCA            /* DEC DEPCA */
        && depca_probe(dev)
 #endif
 #ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
         && ewrk3_probe(dev)
 #endif
-#ifdef CONFIG_DE4X5             /* DEC DE425, DE434, DE435 adapters */
-        && de4x5_probe(dev)
-#endif
 #ifdef CONFIG_APRICOT          /* Apricot I82596 */
        && apricot_probe(dev)
 #endif
@@ -221,6 +234,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_NI65
        && ni65_probe(dev)
 #endif
+#ifdef CONFIG_LANCE    /* ISA LANCE boards */
+       && lance_probe(dev)
+#endif
 #ifdef CONFIG_ATARILANCE       /* Lance-based Atari ethernet boards */
        && atarilance_probe(dev)
 #endif
@@ -239,12 +255,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_TLAN
        && tlan_probe(dev)
 #endif
-#ifdef CONFIG_LANCE32
+#ifdef CONFIG_PCNET32
        && pcnet32_probe(dev)
 #endif
-#ifdef CONFIG_CORKSCREW
-       && isa515_probe(dev)
-#endif
 #ifdef CONFIG_LANCE
        && lance_probe(dev)
 #endif
index 41d437e0f22d1215267fe1a04dd6023a5728b14b..953c188959daac68b387fcaedbdcfbf496940e0d 100644 (file)
@@ -29,7 +29,7 @@
 */
 
 static const char *version =
-       "at1700.c:v1.13 1/31/98  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+       "at1700.c:v1.15 4/7/98  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/module.h>
 
@@ -58,9 +58,11 @@ static const char *version =
 /* When to switch from the 64-entry multicast filter to Rx-all-multicast. */
 #define MC_FILTERBREAK 64
 
-/* This unusual address order is used to verify the CONFIG register. */
+/* These unusual address orders are used to verify the CONFIG register. */
 static int at1700_probe_list[] =
 {0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0};
+static int fmv18x_probe_list[] =
+{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
 
 
 /* use 0 for production, 1 for verification, >2 for debug */
@@ -75,7 +77,9 @@ typedef unsigned char uchar;
 struct net_local {
        struct enet_statistics stats;
        unsigned char mc_filter[8];
+       uint jumpered:1;                        /* Set iff the board has jumper config. */
        uint tx_started:1;                      /* Packets are on the Tx queue. */
+       uint invalid_irq:1;
        uchar tx_queue;                         /* Number of packet on the Tx queue. */
        ushort tx_queue_len;            /* Current length of the Tx queue. */
 };
@@ -95,27 +99,14 @@ struct net_local {
 #define DATAPORT               8               /* Word-wide DMA or programmed-I/O dataport. */
 #define TX_START               10
 #define MODE13                 13
+/* Configuration registers only on the '865A/B chips. */
 #define EEPROM_Ctrl    16
 #define EEPROM_Data    17
-#define IOCONFIG               19
+#define IOCONFIG               18              /* Either read the jumper, or move the I/O. */
+#define IOCONFIG1              19
+#define        SAPROM                  20              /* The station address PROM, if no EEPROM. */
 #define RESET                  31              /* Write to reset some parts of the chip. */
 #define AT1700_IO_EXTENT       32
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK   0x40    /* EEPROM shift clock, in reg. 16. */
-#define EE_CS                  0x20    /* EEPROM chip select, in reg. 16. */
-#define EE_DATA_WRITE  0x80    /* EEPROM chip data in, in reg. 17. */
-#define EE_DATA_READ   0x80    /* EEPROM chip data out, in reg. 17. */
-
-/* Delay between EEPROM clock transitions. */
-#define eeprom_delay() do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD   (5 << 6)
-#define EE_READ_CMD            (6 << 6)
-#define EE_ERASE_CMD   (7 << 6)
-
-
 /* Index to functions, as function prototypes. */
 
 extern int at1700_probe(struct device *dev);
@@ -176,8 +167,9 @@ at1700_probe(struct device *dev)
 
 int at1700_probe1(struct device *dev, int ioaddr)
 {
-       char irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
-       unsigned int i, irq;
+       char fmv_irqmap[4] = {3, 7, 10, 15};
+       char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
+       unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
 
        /* Resetting the chip doesn't reset the ISA interface, so don't bother.
           That means we have to be careful with the register values we probe for.
@@ -187,38 +179,42 @@ int at1700_probe1(struct device *dev, int ioaddr)
                   ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5),
                   read_eeprom(ioaddr, 6), inw(ioaddr + EEPROM_Ctrl));
 #endif
-       if (at1700_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr
-               || read_eeprom(ioaddr, 4) != 0x0000
-               || (read_eeprom(ioaddr, 5) & 0xff00) != 0xF400)
+       /* We must check for the EEPROM-config boards first, else accessing
+          IOCONFIG0 will move the board! */
+       if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr
+               && read_eeprom(ioaddr, 4) == 0x0000
+               && (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400)
+               is_at1700 = 1;
+       else if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] == ioaddr
+               && inb(ioaddr + SAPROM    ) == 0x00
+               && inb(ioaddr + SAPROM + 1) == 0x00
+               && inb(ioaddr + SAPROM + 2) == 0x0e)
+               is_fmv18x = 1;
+       else
                return -ENODEV;
 
        /* Reset the internal state machines. */
        outb(0, ioaddr + RESET);
 
-       irq = irqmap[(read_eeprom(ioaddr, 12)&0x04)
-                                | (read_eeprom(ioaddr, 0)>>14)];
-
-       /* Snarf the interrupt vector now. */
-       if (request_irq(irq, &net_interrupt, 0, "at1700", NULL)) {
-               printk ("AT1700 found at %#3x, but it's unusable due to a conflict on"
-                               "IRQ %d.\n", ioaddr, irq);
-               return EAGAIN;
-       }
-
        /* Allocate a new 'dev' if needed. */
        if (dev == NULL)
                dev = init_etherdev(0, sizeof(struct net_local));
 
+       if (is_at1700)
+               irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
+                                                  | (read_eeprom(ioaddr, 0)>>14)];
+       else
+               irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
+
        /* Grab the region so that we can find another board if the IRQ request
           fails. */
-       request_region(ioaddr, AT1700_IO_EXTENT, "at1700");
+       request_region(ioaddr, AT1700_IO_EXTENT, dev->name);
 
        printk("%s: AT1700 found at %#3x, IRQ %d, address ", dev->name,
                   ioaddr, irq);
 
        dev->base_addr = ioaddr;
        dev->irq = irq;
-       irq2dev_map[irq] = dev;
 
        for(i = 0; i < 3; i++) {
                unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
@@ -241,12 +237,12 @@ int at1700_probe1(struct device *dev, int ioaddr)
        }
 
        /* Set the station address in bank zero. */
-       outb(0xe0, ioaddr + 7);
+       outb(0xe0, ioaddr + CONFIG_1);
        for (i = 0; i < 6; i++)
                outb(dev->dev_addr[i], ioaddr + 8 + i);
 
        /* Switch to bank 1 and set the multicast table to accept none. */
-       outb(0xe4, ioaddr + 7);
+       outb(0xe4, ioaddr + CONFIG_1);
        for (i = 0; i < 8; i++)
                outb(0x00, ioaddr + 8 + i);
 
@@ -255,7 +251,7 @@ int at1700_probe1(struct device *dev, int ioaddr)
        outb(0xda, ioaddr + CONFIG_0);
 
        /* Switch to bank 2 and lock our I/O address. */
-       outb(0xe8, ioaddr + 7);
+       outb(0xe8, ioaddr + CONFIG_1);
        outb(dev->if_port, MODE13);
 
        /* Power-down the chip.  Aren't we green! */
@@ -277,11 +273,38 @@ int at1700_probe1(struct device *dev, int ioaddr)
        dev->set_multicast_list = &set_rx_mode;
 
        /* Fill in the fields of 'dev' with ethernet-generic values. */
-          
        ether_setup(dev);
+
+       {
+               struct net_local *lp = (struct net_local *)dev->priv;
+               lp->jumpered = is_fmv18x;
+               /* Snarf the interrupt vector now. */
+               if (request_irq(irq, &net_interrupt, 0, dev->name, dev)) {
+                       printk ("  AT1700 at %#3x is unusable due to a conflict on"
+                                       "IRQ %d.\n", ioaddr, irq);
+                       lp->invalid_irq = 1;
+                       return 0;
+               }
+       }
+
        return 0;
 }
 
+\f
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK   0x40    /* EEPROM shift clock, in reg. 16. */
+#define EE_CS                  0x20    /* EEPROM chip select, in reg. 16. */
+#define EE_DATA_WRITE  0x80    /* EEPROM chip data in, in reg. 17. */
+#define EE_DATA_READ   0x80    /* EEPROM chip data out, in reg. 17. */
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay() do {} while (0);
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD   (5 << 6)
+#define EE_READ_CMD            (6 << 6)
+#define EE_ERASE_CMD   (7 << 6)
+
 static int read_eeprom(int ioaddr, int location)
 {
        int i;
@@ -289,35 +312,30 @@ static int read_eeprom(int ioaddr, int location)
        int ee_addr = ioaddr + EEPROM_Ctrl;
        int ee_daddr = ioaddr + EEPROM_Data;
        int read_cmd = location | EE_READ_CMD;
-       short ctrl_val = EE_CS;
-       
-       outb(ctrl_val, ee_addr);
-       
+
        /* Shift the read command bits out. */
        for (i = 9; i >= 0; i--) {
                short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+               outb(EE_CS, ee_addr);
                outb(dataval, ee_daddr);
-               outb(EE_CS | EE_SHIFT_CLK, ee_addr);    /* EEPROM clock tick. */
                eeprom_delay();
-               outb(EE_CS, ee_addr);   /* Finish EEPROM a clock tick. */
+               outb(EE_CS | EE_SHIFT_CLK, ee_addr);    /* EEPROM clock tick. */
                eeprom_delay();
        }
-       outb(EE_CS, ee_addr);
-       
+       outb(EE_DATA_WRITE, ee_daddr);
        for (i = 16; i > 0; i--) {
+               outb(EE_CS, ee_addr);
+               eeprom_delay();
                outb(EE_CS | EE_SHIFT_CLK, ee_addr);
                eeprom_delay();
                retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
-               outb(EE_CS, ee_addr);
-               eeprom_delay();
        }
 
        /* Terminate the EEPROM access. */
-       ctrl_val &= ~EE_CS;
-       outb(ctrl_val | EE_SHIFT_CLK, ee_addr);
-       eeprom_delay();
-       outb(ctrl_val, ee_addr);
+       outb(EE_CS, ee_addr);
        eeprom_delay();
+       outb(EE_SHIFT_CLK, ee_addr);
+       outb(0, ee_addr);
        return retval;
 }
 
@@ -345,10 +363,8 @@ static int net_open(struct device *dev)
           bus access, and two 4K Tx queues. */
        outb(0xda, ioaddr + CONFIG_0);
 
-       /* Same config 0, except enable the Rx and Tx. */
-       outb(0x5a, ioaddr + CONFIG_0);
-       /* Switch to register bank 2 for the run-time registers. */
-       outb(0xe8, ioaddr + CONFIG_1);
+       /* Switch to register bank 2, enable the Rx and Tx. */
+       outw(0xe85a, ioaddr + CONFIG_0);
 
        lp->tx_started = 0;
        lp->tx_queue = 0;
@@ -417,7 +433,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
 
                /* Turn off the possible Tx interrupts. */
                outb(0x00, ioaddr + TX_INTR);
-               
+
                outw(length, ioaddr + DATAPORT);
                outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
 
@@ -449,7 +465,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
 static void
 net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       struct device *dev = dev_id;
        struct net_local *lp;
        int ioaddr, status;
 
@@ -570,7 +586,7 @@ net_rx(struct device *dev)
                }
 
                if (net_debug > 5)
-                       printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", 
+                       printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
                                   dev->name, inb(ioaddr + RX_MODE), i);
        }
        return;
@@ -579,6 +595,7 @@ net_rx(struct device *dev)
 /* The inverse routine to net_open(). */
 static int net_close(struct device *dev)
 {
+       struct net_local *lp = (struct net_local *)dev->priv;
        int ioaddr = dev->base_addr;
 
        dev->tbusy = 1;
@@ -587,7 +604,15 @@ static int net_close(struct device *dev)
        /* Set configuration register 0 to disable Tx and Rx. */
        outb(0xda, ioaddr + CONFIG_0);
 
-       /* Update the statistics -- ToDo. */
+       /* No statistic counters on the chip to update. */
+
+#if 0
+       /* Disable the IRQ on boards where it is feasible. */
+       if (lp->jumpered) {
+               outb(0x00, ioaddr + IOCONFIG1);
+               free_irq(dev->irq, dev);
+       }
+#endif
 
        /* Power-down the chip.  Green, green, green! */
        outb(0x00, ioaddr + CONFIG_1);
@@ -662,20 +687,20 @@ set_rx_mode(struct device *dev)
                memset(mc_filter, 0, sizeof(mc_filter));
                for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
                         i++, mclist = mclist->next)
-                       set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+                       set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26,
                                        mc_filter);
        }
 
        save_flags(flags);
        cli();
        if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
-               int saved_bank = inb(ioaddr + CONFIG_1);
+               int saved_bank = inw(ioaddr + CONFIG_0);
                /* Switch to bank 1 and set the multicast table. */
-               outb(0xe4, ioaddr + CONFIG_1);
+               outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
                for (i = 0; i < 8; i++)
                        outb(mc_filter[i], ioaddr + 8 + i);
                memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
-               outb(saved_bank, ioaddr + CONFIG_1);
+               outw(saved_bank, ioaddr + CONFIG_0);
        }
        restore_flags(flags);
        return;
@@ -714,7 +739,6 @@ cleanup_module(void)
 
        /* If we don't do this, we can't re-insmod it later. */
        free_irq(dev_at1700.irq, NULL);
-       irq2dev_map[dev_at1700.irq] = NULL;
        release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
 }
 #endif /* MODULE */
index 555f0c64678b06979b1714d6aed542cc043899cd..5a761d380fc520ea21b2e649aab2c9ffe39ae74d 100644 (file)
@@ -27,6 +27,7 @@
  *             2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
index a446d6ade102b5df905d989d167442971a55ec5d..5c0a6a2aa35fae184921f9723b4d45686665cca9 100644 (file)
@@ -1,7 +1,7 @@
 /* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */
 /*
    NOTICE: this version tested with kernels 1.3.72 and later only!
-       Written 1996-1997 by Donald Becker.
+       Written 1996-1998 by Donald Becker.
 
        This software may be used and distributed according to the terms
        of the GNU Public License, incorporated herein by reference.
@@ -19,7 +19,7 @@
 */
 
 static const char *version =
-"eepro100.c:v0.36 10/20/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v0.99B 4/7/98 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values that apply to all boards.
    First set are undocumented and spelled per Intel recommendations. */
@@ -38,6 +38,9 @@ static int rx_copybreak = 200;
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
 
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
 #include <linux/config.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
@@ -69,73 +72,36 @@ static int max_interrupt_work = 20;
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-
-/* A nominally proper method to handle version dependencies is to use
-   LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */
-#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,0))
-#define KERNEL_1_2
-#else /* 1.3.0 */
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
-#define NEW_MULTICAST
-#define LINUX_1_4
-#else
-#warning "This driver is tested for 1.3.44 and later development kernels only."
-#endif /* 1.3.44 */
-#endif
-#else
-
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
 #include <linux/delay.h>
-#endif
 
-#ifdef HAVE_HEADER_CACHE
-#define LINUX_1_4
-#define NEW_MULTICAST
-#else
-#ifdef ETH_P_DDCMP                             /* Warning: Bogus!  This means IS_LINUX_1_3. */
-#define KERNEL_1_3
-#else
-#define KERNEL_1_2
-#endif
+/* Unused in the 2.0.* version, but retained for documentation. */
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
 #endif
 
-#endif
-/* This should be in a header file. */
-#if (LINUX_VERSION_CODE < VERSION(1,3,44))
-struct device *init_etherdev(struct device *dev, int sizeof_priv,
-                                                        unsigned long *mem_startp);
-#endif
-#if LINUX_VERSION_CODE < 0x10300
-#define RUN_AT(x) (x)                  /* What to put in timer->expires.  */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#define virt_to_bus(addr)  ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)
-#else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-#endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
 #define test_and_set_bit(val, addr) set_bit(val, addr)
 #endif
 
-/* The total I/O port extent of the board.  Nominally 0x18, but rounded up
-   for PCI allocation. */
+/* The total I/O port extent of the board.
+   The registers beyond 0x18 only exist on the i82558. */
 #define SPEEDO3_TOTAL_SIZE 0x20
 
-#ifdef HAVE_DEVLIST
-struct netdev_entry eepro100_drv =
-{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL};
-#endif
-
-#ifdef SPEEDO3_DEBUG
-int speedo_debug = SPEEDO3_DEBUG;
-#else
-int speedo_debug = 3;
-#endif
+int speedo_debug = 1;
 
 /*
                                Theory of Operation
@@ -274,7 +240,7 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
 #define PKT_BUF_SZ             1536
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((400*HZ)/1000)
+#define TX_TIMEOUT  ((800*HZ)/1000)
 
 /* How to wait for the command unit to accept a command.
    Typically this takes 0 ticks. */
@@ -287,13 +253,6 @@ static inline void wait_for_cmd_done(int cmd_ioaddr)
 
 /* Operational parameter that usually are not changed. */
 
-#ifndef PCI_VENDOR_ID_INTEL            /* Now defined in linux/pci.h */
-#define PCI_VENDOR_ID_INTEL            0x8086 /* Hmmmm, how did they pick that? */
-#endif
-#ifndef PCI_DEVICE_ID_INTEL_82557
-#define PCI_DEVICE_ID_INTEL_82557      0x1229
-#endif
-
 /* The rest of these values should never change. */
 
 /* Offsets to the various registers.
@@ -393,9 +352,6 @@ struct speedo_private {
        /* Rx descriptor ring & addresses of receive-in-place skbuffs. */
        struct RxFD *rx_ringp[RX_RING_SIZE];
        struct sk_buff* rx_skbuff[RX_RING_SIZE];
-#if (LINUX_VERSION_CODE < 0x10300)     /* Kernel v1.2.*. */
-       struct RxFD saved_skhead[RX_RING_SIZE]; /* Saved skbuff header chunk. */
-#endif
        struct RxFD *last_rxf;  /* Last command sent. */
        struct enet_statistics stats;
        struct speedo_stats lstats;
@@ -407,6 +363,7 @@ struct speedo_private {
        u8 config_cmd_data[22];                 /* .. and setup parameters. */
        int mc_setup_frm_len;                           /* The length of an allocated.. */
        struct descriptor *mc_setup_frm;        /* ..multicast setup frame. */
+       int in_interrupt;                                       /* Word-aligned dev->interrupt */
        char rx_mode;                                           /* Current PROMISC/ALLMULTI setting. */
        unsigned int tx_full:1;                         /* The Tx queue is full. */
        unsigned int full_duplex:1;                     /* Full-duplex operation requested. */
@@ -437,7 +394,7 @@ enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 
 static void speedo_found1(struct device *dev, int ioaddr, int irq,
-                                                 int options, int card_idx);
+                                                 int card_idx);
 
 static int read_eeprom(int ioaddr, int location);
 static int mdio_read(int ioaddr, int phy_id, int location);
@@ -447,16 +404,10 @@ static void speedo_timer(unsigned long data);
 static void speedo_init_rx_ring(struct device *dev);
 static int speedo_start_xmit(struct sk_buff *skb, struct device *dev);
 static int speedo_rx(struct device *dev);
-#ifdef SA_SHIRQ
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-#else
-static void speedo_interrupt(int irq, struct pt_regs *regs);
-#endif
 static int speedo_close(struct device *dev);
 static struct enet_statistics *speedo_get_stats(struct device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-#endif
 static void set_rx_mode(struct device *dev);
 
 \f
@@ -465,8 +416,8 @@ static void set_rx_mode(struct device *dev);
 /* 'options' is used to pass a transceiver override or full-duplex flag
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#ifdef MODULE
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
 static int debug = -1;                 /* The debug level */
 #endif
 
@@ -481,12 +432,9 @@ int eepro100_init(struct device *dev)
                static int pci_index = 0;
                for (; pci_index < 8; pci_index++) {
                        unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency;
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
                        int pci_ioaddr;
-#else
-                       long pci_ioaddr;
-#endif
-                       unsigned short pci_command;
+
+                       unsigned short pci_command, new_command;
 
                        if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
                                                                        PCI_DEVICE_ID_INTEL_82557,
@@ -507,29 +455,25 @@ int eepro100_init(struct device *dev)
                        /* Get and check the bus-master and latency values. */
                        pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                         PCI_COMMAND, &pci_command);
-                       if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-                               printk("  PCI Master Bit has not been set! Setting...\n");
-                               pci_command |= PCI_COMMAND_MASTER;
+                       new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+                       if (pci_command != new_command) {
+                               printk(KERN_INFO "  The PCI BIOS has not enabled this"
+                                          " device!  Updating PCI command %4.4x->%4.4x.\n",
+                                          pci_command, new_command);
                                pcibios_write_config_word(pci_bus, pci_device_fn,
-                                                                                 PCI_COMMAND, pci_command);
+                                                                                 PCI_COMMAND, new_command);
                        }
                        pcibios_read_config_byte(pci_bus, pci_device_fn,
                                                                                 PCI_LATENCY_TIMER, &pci_latency);
-                       if (pci_latency < 10) {
+                       if (pci_latency < 32) {
                                printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-                                          "  Setting to 255 clocks.\n", pci_latency);
+                                          "  Setting to 32 clocks.\n", pci_latency);
                                pcibios_write_config_byte(pci_bus, pci_device_fn,
-                                                                                 PCI_LATENCY_TIMER, 255);
+                                                                                 PCI_LATENCY_TIMER, 32);
                        } else if (speedo_debug > 1)
                                printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 
-#ifdef MODULE
-                       speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found],
-                                                 cards_found);
-#else
-                       speedo_found1(dev, pci_ioaddr, pci_irq_line,
-                                                 dev ? dev->mem_start : 0, -1);
-#endif
+                       speedo_found1(dev, pci_ioaddr, pci_irq_line, cards_found);
                        dev = NULL;
                        cards_found++;
                }
@@ -538,23 +482,26 @@ int eepro100_init(struct device *dev)
        return cards_found;
 }
 
-static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
+static void speedo_found1(struct device *dev, int ioaddr, int irq,
                                                  int card_idx)
 {
        static int did_version = 0;                     /* Already printed version info. */
        struct speedo_private *sp;
        char *product;
-       int i;
+       int i, option;
        u16 eeprom[0x40];
 
        if (speedo_debug > 0  &&  did_version++ == 0)
                printk(version);
 
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
        dev = init_etherdev(dev, sizeof(struct speedo_private));
-#else
-       dev = init_etherdev(dev, sizeof(struct speedo_private), 0);
-#endif
+
+       if (dev->mem_start > 0) 
+               option = dev->mem_start;
+       else if (card_idx >= 0  &&  options[card_idx] >= 0)
+               option = options[card_idx];
+       else
+               option = 0;
 
        /* Read the station address EEPROM before doing the reset.
           Perhaps this should even be done before accepting the device,
@@ -618,17 +565,6 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
                if (eeprom[7] & 0x0700)
                        printk(KERN_INFO "    Secondary interface chip %s.\n",
                                   phys[(eeprom[7]>>8)&7]);
-#if defined(notdef)
-               /* ToDo: Read and set PHY registers through MDIO port. */
-               for (i = 0; i < 2; i++)
-                       printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-                                  i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-               for (i = 5; i < 7; i++)
-                       printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-                                  i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-               printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-                          25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
-#endif
                if (((eeprom[6]>>8) & 0x3f) == DP83840
                        ||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
                        int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
@@ -638,13 +574,13 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
                                   mdi_reg23);
                        mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
                }
-               if ((options >= 0) && (options & 0x60)) {
+               if ((option >= 0) && (option & 0x70)) {
                        printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
-                                  (options & 0x20 ? 100 : 10),
-                                  (options & 0x10 ? "full" : "half"));
+                                  (option & 0x20 ? 100 : 10),
+                                  (option & 0x10 ? "full" : "half"));
                        mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
-                                          ((options & 0x20) ? 0x2000 : 0) |    /* 100mbps? */
-                                          ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+                                          ((option & 0x20) ? 0x2000 : 0) |     /* 100mbps? */
+                                          ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
                }
 
                /* Perform a system self-test. */
@@ -653,11 +589,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
                self_test_results[1] = -1;
                outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
                do {
-#ifdef _LINUX_DELAY_H
                        udelay(10);
-#else
-                       SLOW_DOWN_IO;
-#endif
                } while (self_test_results[1] == -1  &&  --boguscnt >= 0);
 
                if (boguscnt < 0) {             /* Test optimized out. */
@@ -694,12 +626,12 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
        sp->next_module = root_speedo_dev;
        root_speedo_dev = dev;
 
+       sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
        if (card_idx >= 0) {
                if (full_duplex[card_idx] >= 0)
                        sp->full_duplex = full_duplex[card_idx];
-       } else
-               sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
-       sp->default_port = options >= 0 ? (options & 0x0f) : 0;
+       }
+       sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
        sp->phy[0] = eeprom[6];
        sp->phy[1] = eeprom[7];
@@ -713,12 +645,8 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
        dev->hard_start_xmit = &speedo_start_xmit;
        dev->stop = &speedo_close;
        dev->get_stats = &speedo_get_stats;
-#ifdef NEW_MULTICAST
        dev->set_multicast_list = &set_rx_mode;
-#endif
-#ifdef HAVE_PRIVATE_IOCTL
        dev->do_ioctl = &speedo_ioctl;
-#endif
 
        return;
 }
@@ -735,13 +663,8 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
 #define EE_ENB                 (0x4800 | EE_CS)
 
 /* Delay between EEPROM clock transitions.
-   This is a "nasty" timing loop, but PC compatible machines are defined
-   to delay an ISA compatible period for the SLOW_DOWN_IO macro.  */
-#ifdef _LINUX_DELAY_H
+   This will actually work with no delay on 33Mhz PCI.  */
 #define eeprom_delay(nanosec)          udelay(1);
-#else
-#define eeprom_delay(nanosec)  do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD   (5 << 6)
@@ -765,8 +688,6 @@ static int read_eeprom(int ioaddr, int location)
                eeprom_delay(100);
                outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
                eeprom_delay(150);
-               outw(EE_ENB | dataval, ee_addr);        /* Finish EEPROM a clock tick. */
-               eeprom_delay(250);
        }
        outw(EE_ENB, ee_addr);
 
@@ -785,14 +706,9 @@ static int read_eeprom(int ioaddr, int location)
 
 static int mdio_read(int ioaddr, int phy_id, int location)
 {
-       int val, boguscnt = 64*4;               /* <64 usec. to complete, typ 27 ticks */
+       int val, boguscnt = 64*10;              /* <64 usec. to complete, typ 27 ticks */
        outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
        do {
-#ifdef _LINUX_DELAY_H
-               udelay(16);
-#else
-               SLOW_DOWN_IO;
-#endif
                val = inl(ioaddr + SCBCtrlMDI);
                if (--boguscnt < 0) {
                        printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
@@ -803,15 +719,10 @@ static int mdio_read(int ioaddr, int phy_id, int location)
 
 static int mdio_write(int ioaddr, int phy_id, int location, int value)
 {
-       int val, boguscnt = 64*4;               /* <64 usec. to complete, typ 27 ticks */
+       int val, boguscnt = 64*10;              /* <64 usec. to complete, typ 27 ticks */
        outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
                 ioaddr + SCBCtrlMDI);
        do {
-#ifdef _LINUX_DELAY_H
-               udelay(16);
-#else
-               SLOW_DOWN_IO;
-#endif
                val = inl(ioaddr + SCBCtrlMDI);
                if (--boguscnt < 0) {
                        printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
@@ -830,31 +741,13 @@ speedo_open(struct device *dev)
 #ifdef notdef
        /* We could reset the chip, but should not need to. */
        outl(0, ioaddr + SCBPort);
-       for (i = 40; i >= 0; i--)
-               SLOW_DOWN_IO;                   /* At least 250ns */
+       udelay(10);
 #endif
 
-#ifdef SA_SHIRQ
        if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
                                        "Intel EtherExpress Pro 10/100 Ethernet", dev)) {
                return -EAGAIN;
        }
-#else
-#ifdef USE_SHARED_IRQ
-       if (request_shared_irq(dev->irq, &speedo_interrupt, dev,
-                                                  "Intel EtherExpress Pro 10/100 Ethernet"))
-               return -EAGAIN;
-#else
-       if (dev->irq < 2  ||  dev->irq > 15  ||  irq2dev_map[dev->irq] != NULL)
-               return -EAGAIN;
-       irq2dev_map[dev->irq] = dev;
-       if (request_irq(dev->irq, &speedo_interrupt, 0, "Intel EtherExpress Pro 10/100 Ethernet")) {
-               irq2dev_map[dev->irq] = NULL;
-               return -EAGAIN;
-       }
-#endif
-#endif
-
        if (speedo_debug > 1)
                printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
@@ -899,6 +792,7 @@ speedo_open(struct device *dev)
 
        dev->if_port = sp->default_port;
 
+       sp->in_interrupt = 0;
        dev->tbusy = 0;
        dev->interrupt = 0;
        dev->start = 1;
@@ -973,36 +867,23 @@ speedo_init_rx_ring(struct device *dev)
 
        for (i = 0; i < RX_RING_SIZE; i++) {
                struct sk_buff *skb;
-#ifndef KERNEL_1_2
-               skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#else
                skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#endif
                sp->rx_skbuff[i] = skb;
                if (skb == NULL)
                        break;                  /* Bad news!  */
                skb->dev = dev;                 /* Mark as being used by this device. */
 
-#if LINUX_VERSION_CODE >= 0x10300
                rxf = (struct RxFD *)skb->tail;
                skb_reserve(skb, sizeof(struct RxFD));
-#else
-               /* Save the data in the header region -- it's restored later. */
-               rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD));
-               memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD));
-#endif
                sp->rx_ringp[i] = rxf;
                if (last_rxf)
                        last_rxf->link = virt_to_bus(rxf);
                last_rxf = rxf;
                rxf->status = 0x00000001;                       /* '1' is flag value only. */
                rxf->link = 0;                                          /* None yet. */
-#if LINUX_VERSION_CODE < 0x10300
                /* This field unused by i82557, we use it as a consistency check. */
-               rxf->rx_buf_addr = virt_to_bus(skb->data);
-#else
                rxf->rx_buf_addr = virt_to_bus(skb->tail);
-#endif
+
                rxf->count = 0;
                rxf->size = PKT_BUF_SZ;
        }
@@ -1015,27 +896,11 @@ static void speedo_tx_timeout(struct device *dev)
 {
        struct speedo_private *sp = (struct speedo_private *)dev->priv;
        int ioaddr = dev->base_addr;
-       int i;
 
        printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
                   "command %4.4x.\n",
                   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
-#ifndef final_version
-       printk(KERN_WARNING "%s:  Tx timeout  fill index %d  scavenge index %d.\n",
-                  dev->name, sp->cur_tx, sp->dirty_tx);
-       printk(KERN_WARNING "    Tx queue ");
-       for (i = 0; i < TX_RING_SIZE; i++)
-         printk(" %8.8x", (int)sp->tx_ring[i].status);
-       printk(".\n" KERN_WARNING "    Rx ring ");
-       for (i = 0; i < RX_RING_SIZE; i++)
-         printk(" %8.8x", (int)sp->rx_ringp[i]->status);
-       printk(".\n");
 
-#else
-       dev->if_port ^= 1;
-       printk(KERN_WARNING "  (Media type switching not yet implemented.)\n");
-       /* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
-#endif
        if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
          printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
                         dev->name);
@@ -1045,9 +910,14 @@ static void speedo_tx_timeout(struct device *dev)
        } else {
          outw(DRVR_INT, ioaddr + SCBCmd);
        }
-       /* Reset the MII transceiver. */
-       if ((sp->phy[0] & 0x8000) == 0)
-               mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000);
+       /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
+       if ((sp->phy[0] & 0x8000) == 0) {
+               int phy_addr = sp->phy[0] & 0x1f;
+               mdio_write(ioaddr, phy_addr, 0, 0x0400);
+               mdio_write(ioaddr, phy_addr, 1, 0x0000);
+               mdio_write(ioaddr, phy_addr, 4, 0x0000);
+               mdio_write(ioaddr, phy_addr, 0, 0x8000);
+       }
        sp->stats.tx_errors++;
        dev->trans_start = jiffies;
        return;
@@ -1060,13 +930,6 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev)
        int ioaddr = dev->base_addr;
        int entry;
 
-       if (skb == NULL || skb->len <= 0) {
-               printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
-                          dev->name);
-               dev_tint(dev);
-               return 0;
-       }
-
        /* Block a timer-based transmit from overlapping.  This could better be
           done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
           If this ever occurs the queue layer is doing something evil! */
@@ -1123,7 +986,7 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev)
        if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
                sp->tx_full = 1;
        else
-               dev->tbusy = 0;
+               clear_bit(0, (void*)&dev->tbusy);
 
        dev->trans_start = jiffies;
 
@@ -1132,21 +995,9 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev)
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-#ifdef SA_SHIRQ
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-#else
-static void speedo_interrupt(int irq, struct pt_regs *regs)
-#endif
 {
-#ifdef SA_SHIRQ
        struct device *dev = (struct device *)dev_instance;
-#else
-#ifdef USE_SHARED_IRQ
-       struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]);
-#else
-       struct device *dev = (struct device *)(irq2dev_map[irq]);
-#endif
-#endif
        struct speedo_private *sp;
        int ioaddr, boguscnt = max_interrupt_work;
        unsigned short status;
@@ -1161,8 +1012,10 @@ static void speedo_interrupt(int irq, struct pt_regs *regs)
        ioaddr = dev->base_addr;
        sp = (struct speedo_private *)dev->priv;
 #ifndef final_version
-       if (dev->interrupt) {
-               printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+       /* A lock to prevent simultaneous entry on SMP machines. */
+       if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+               printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+                          dev->name);
                return;
        }
        dev->interrupt = 1;
@@ -1184,19 +1037,6 @@ static void speedo_interrupt(int irq, struct pt_regs *regs)
                        speedo_rx(dev);
 
                if (status & 0x1000) {
-#ifdef notdef
-                 int i;
-                 printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
-                                " state -- %4.4x!  Index %d (%d).\n", dev->name, status,
-                                sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
-                 printk(KERN_WARNING "   Rx ring:\n ");
-                 for (i = 0; i < RX_RING_SIZE; i++)
-                       printk("   %d %8.8x %8.8x %8.8x %d %d.\n",
-                                  i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
-                                  sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count,
-                                  sp->rx_ringp[i]->size);
-#endif
-
                  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
                        outw(RX_RESUMENR, ioaddr + SCBCmd);
                  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
@@ -1243,7 +1083,7 @@ static void speedo_interrupt(int irq, struct pt_regs *regs)
                                && dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
                                /* The ring is no longer full, clear tbusy. */
                                sp->tx_full = 0;
-                               dev->tbusy = 0;
+                               clear_bit(0, (void*)&dev->tbusy);
                                mark_bh(NET_BH);
                        }
 
@@ -1263,23 +1103,8 @@ static void speedo_interrupt(int irq, struct pt_regs *regs)
                printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
                           dev->name, inw(ioaddr + SCBStatus));
 
-#ifndef final_version
-       /* Special code for testing *only*. */
-       {
-               static int stopit = 100;
-               if (dev->start == 0  &&  --stopit < 0) {
-                       printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n",
-                                  dev->name);
-#ifdef SA_SHIRQ
-                       free_irq(irq, dev);
-#else
-                       free_irq(irq);
-#endif
-               }
-       }
-#endif
-
        dev->interrupt = 0;
+       clear_bit(0, (void*)&sp->in_interrupt);
        return;
 }
 
@@ -1320,16 +1145,6 @@ speedo_rx(struct device *dev)
 
                                /* Pass up the skb already on the Rx ring. */
                                skb = sp->rx_skbuff[entry];
-#ifdef KERNEL_1_2
-                               temp = skb->data;
-                               if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-                                       printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
-                                                  " in speedo_rx: %p vs. %p / %p.\n", dev->name,
-                                                  bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-                                                  temp, skb->data);
-                               /* Get a fresh skbuff to replace the filled one. */
-                               newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#else
                                temp = skb_put(skb, pkt_len);
                                if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
                                        printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
@@ -1337,36 +1152,21 @@ speedo_rx(struct device *dev)
                                                   sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
                                /* Get a fresh skbuff to replace the filled one. */
                                newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#endif
+
                                if (newskb) {
                                        struct RxFD *rxf;
                                        rx_in_place = 1;
                                        sp->rx_skbuff[entry] = newskb;
                                        newskb->dev = dev;
-#ifdef KERNEL_1_2
-                                       /* Restore the data in the old header region. */
-                                       memcpy(skb->data - sizeof(struct RxFD),
-                                                  &sp->saved_skhead[entry], sizeof(struct RxFD));
-                                       /* Save the data in this header region. */
-                                       rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD));
-                                       sp->rx_ringp[entry] = rxf;
-                                       memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD));
-                                       rxf->rx_buf_addr = virt_to_bus(newskb->data);
-#else
                                        rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
                                        skb_reserve(newskb, sizeof(struct RxFD));
                                        /* Unused by i82557, consistency check only. */
                                        rxf->rx_buf_addr = virt_to_bus(newskb->tail);
-#endif
                                        rxf->status = 0x00000001;
                                } else                  /* No memory, drop the packet. */
                                  skb = 0;
                        } else
-#ifdef KERNEL_1_2
-                               skb = alloc_skb(pkt_len, GFP_ATOMIC);
-#else
                                skb = dev_alloc_skb(pkt_len + 2);
-#endif
                        if (skb == NULL) {
                                int i;
                                printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
@@ -1388,7 +1188,6 @@ speedo_rx(struct device *dev)
                                break;
                        }
                        skb->dev = dev;
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
                        if (! rx_in_place) {
                                skb_reserve(skb, 2);    /* 16 byte align the data fields */
 #if defined(__i386)   &&  notyet
@@ -1401,22 +1200,6 @@ speedo_rx(struct device *dev)
 #endif
                        }
                        skb->protocol = eth_type_trans(skb, dev);
-#else
-#ifdef KERNEL_1_3
-#warning This code has only been tested with later 1.3.* kernels.
-                       skb->len = pkt_len;
-                       memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-                                  pkt_len);
-                       /* Needed for 1.3.*. */
-                       skb->protocol = eth_type_trans(skb, dev);
-#else  /* KERNEL_1_2 */
-                       skb->len = pkt_len;
-                       if (! rx_in_place) {
-                               memcpy(skb->data,
-                                          bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
-                       }
-#endif
-#endif
                        netif_rx(skb);
                        sp->stats.rx_packets++;
                }
@@ -1460,12 +1243,7 @@ speedo_close(struct device *dev)
        outw(INT_MASK, ioaddr + SCBCmd);
        outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd);
 
-#ifdef SA_SHIRQ
        free_irq(dev->irq, dev);
-#else
-       free_irq(dev->irq);
-       irq2dev_map[dev->irq] = 0;
-#endif
 
        /* Free all the skbuffs in the Rx and Tx queues. */
        for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1549,7 +1327,6 @@ speedo_get_stats(struct device *dev)
        return &sp->stats;
 }
 
-#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
        struct speedo_private *sp = (struct speedo_private *)dev->priv;
@@ -1572,7 +1349,6 @@ static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                return -EOPNOTSUPP;
        }
 }
-#endif  /* HAVE_PRIVATE_IOCTL */
 
 /* Set or clear the multicast filter for this adaptor.
    This is very ugly with Intel chips -- we usually have to execute an
@@ -1594,7 +1370,8 @@ set_rx_mode(struct device *dev)
 
        if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
                new_rx_mode = 3;
-       } else if (dev->flags & IFF_ALLMULTI) {
+       } else if ((dev->flags & IFF_ALLMULTI)  ||
+                          dev->mc_count > multicast_filter_limit) {
                new_rx_mode = 1;
        } else
                new_rx_mode = 0;
@@ -1681,7 +1458,7 @@ set_rx_mode(struct device *dev)
                struct dev_mc_list *mclist;
                u16 *eaddrs;
                struct descriptor *mc_setup_frm = sp->mc_setup_frm;
-               u16 *setup_params = (u16 *)mc_setup_frm->params;
+               u16 *setup_params;
                int i;
 
                if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
@@ -1751,24 +1528,6 @@ set_rx_mode(struct device *dev)
 }
 \f
 #ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,38))     /* 1.3.38 and later */
-char kernel_version[] = UTS_RELEASE;
-#endif
-
-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-#endif
 
 int
 init_module(void)
@@ -1815,7 +1574,8 @@ int eepro100_probe(struct device *dev)
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
index 7e7194d161ba9936c33b654da67eb2e5786088a3..2d0f8b4f11e0b93e4e9e1ba392296e47e5655236 100644 (file)
@@ -18,7 +18,7 @@
 */
 
 static const char *version =
-"epic100.c:v0.99B 2/6/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
+"epic100.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
 
 /* A few user-configurable values. */
 
@@ -691,13 +691,13 @@ epic_start_xmit(struct sk_buff *skb, struct device *dev)
 
        if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
          flag = 0x10; /* No interrupt */
-         dev->tbusy = 0;
+         clear_bit(0, (void*)&dev->tbusy);
        } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
          flag = 0x14; /* Tx-done intr. */
-         dev->tbusy = 0;
+         clear_bit(0, (void*)&dev->tbusy);
        } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
          flag = 0x10; /* No Tx-done intr. */
-         dev->tbusy = 0;
+         clear_bit(0, (void*)&dev->tbusy);
        } else {
          /* Leave room for two additional entries. */
          flag = 0x14; /* Tx-done intr. */
@@ -801,7 +801,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
                                /* The ring is no longer full, clear tbusy. */
                                lp->tx_full = 0;
-                               dev->tbusy = 0;
+                               clear_bit(0, (void*)&dev->tbusy);
                                mark_bh(NET_BH);
                        }
 
index 4c9a79fcf87435347e752b3e5e2c7b513b2d38d2..83b889d0588279e2c83ccfb3bf2dbd759ed1bbd6 100644 (file)
@@ -340,7 +340,7 @@ int init_module(void)
                        return -EPERM;
                }
                if (register_netdev(dev) != 0) {
-                       printk(KERN_WARNING "ne.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
+                       printk(KERN_WARNING "lance.c: No PCnet/LANCE card found (i/o = 0x%x).\n", io[this_dev]);
                        if (found != 0) return 0;       /* Got at least one. */
                        return -ENXIO;
                }
index a7f6f4c2f0764b729ddf71bc10d78b194ce6ce5a..85e6711d4837b9f35092af4e3caa24f4231ed0ac 100644 (file)
@@ -12,7 +12,7 @@
  *     This driver is for AMD PCnet-PCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v0.99A 4/2/98 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v0.99B 4/4/98 DJBecker/TSBogend.\n";
 
 /* A few user-configurable values. */
 
@@ -171,6 +171,19 @@ struct pcnet32_private {
        unsigned long lock;
 };
 
+static struct pcnet_chip_type {
+       int id_number;
+       const char *name;
+       int flags;
+} chip_table[] = {
+       {0x2420, "PCnet/PCI 79C970", 0},
+       {0x2430, "PCnet32", 0},
+       {0x2621, "PCnet/PCI II 79C970A", 0},
+       {0x2623, "PCnet/PCI II 79C971A", 0},
+       {0x0,    "PCnet32 (unknown)", 0},
+};
+\f
+/* Index of functions. */
 int  pcnet32_probe(struct device *dev);
 static int  pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line);
 static int  pcnet32_open(struct device *dev);
@@ -252,7 +265,7 @@ static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char
 {
        struct pcnet32_private *lp;
        int i;
-       char *chipname;
+       const char *chipname;
 
        /* check if there is really a pcnet chip on that ioaddr */
        if ((inb(ioaddr + 14) != 0x57) || (inb(ioaddr + 15) != 0x57))
@@ -278,20 +291,10 @@ static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char
                if ((chip_version & 0xfff) != 0x003)
                        return ENODEV;
                chip_version = (chip_version >> 12) & 0xffff;
-               switch (chip_version) {
-               case 0x2420:
-                       chipname = "PCnet/PCI 79C970";
-                       break;
-               case 0x2430:
-                       chipname = "PCnet32";
-                       break;
-               case 0x2621:
-                       chipname = "PCnet/PCI II 79C970A";
-                       break;
-               default:
-                       printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
-                       return ENODEV;
-               }
+               for (i = 0; chip_table[i].id_number; i++)
+                       if (chip_table[i].id_number == chip_version)
+                               break;
+               chipname = chip_table[i].name;
        }
 
        dev = init_etherdev(dev, 0);
@@ -379,6 +382,7 @@ pcnet32_open(struct device *dev)
                                        dev->name, (void *)dev)) {
                return -EAGAIN;
        }
+       MOD_INC_USE_COUNT;
 
        /* Reset the PCNET32 */
        inw(ioaddr+PCNET32_RESET);
@@ -840,6 +844,7 @@ pcnet32_close(struct device *dev)
        outw(0x0004, ioaddr+PCNET32_DATA);
 
        free_irq(dev->irq, dev);
+       MOD_DEC_USE_COUNT;
 
        return 0;
 }
index 748ded1a323f66f0b826ecdb97e561f6aef43bab..936ae91d7e63d948239dd596572fb36dcfe91656 100644 (file)
 
        Support and updates available at
        http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
+
+       Twister-tuning code contributed by Kinston <shangh@realtek.com.tw>.
 */
 
 static const char *version =
-"rtl8139.c:v0.99A 2/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+"rtl8139.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
 
 /* A few user-configurable values. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
@@ -79,16 +81,6 @@ static int max_interrupt_work = 10;
 
 #include <linux/delay.h>
 
-#ifdef SA_SHIRQ
-#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
-#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
-#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
-#else
-#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
-#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
-#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
-#endif
-
 #if (LINUX_VERSION_CODE < 0x20123)
 #define test_and_set_bit(val, addr) set_bit(val, addr)
 #endif
@@ -178,6 +170,10 @@ enum RTL8129_registers {
        FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
        MultiIntr=0x5C, TxSummary=0x60,
        BMCR=0x62, BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A,
+       /* Undocumented registers, but required for proper operation. */
+       FIFOTMS=0x70,   /* FIFO Test Mode Select */
+       CSCR=0x74,      /* Chip Status and Configuration Register. */
+       PARA78=0x78, PARA7c=0x7c,       /* Magic transceiver parameter register. */
 };
 
 enum ChipCmdBits {
@@ -199,6 +195,20 @@ enum RxStatusBits {
        RxBadAlign=0x0002, RxStatusOK=0x0001,
 };
 
+enum CSCRBits {
+       CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
+       CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
+       CSCR_LinkDownCmd=0x0f3c0,
+};     
+
+/* Twister tuning parameters from RealTek.  Completely undocumented. */
+unsigned long param[4][4]={
+       {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
+       {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
+       {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
+       {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
+};
+
 struct rtl8129_private {
        char devname[8];                        /* Used only for kernel debugging. */
        const char *product_name;
@@ -220,7 +230,7 @@ struct rtl8129_private {
        unsigned char *tx_bufs;                         /* Tx bounce buffer region. */
        unsigned char mc_filter[8];                     /* Current multicast filter. */
        char phys[4];                                           /* MII device addresses. */
-       int in_interrupt;                                       /* Alpha need word-wide lock. */
+       int in_interrupt;                                       /* Alpha needs word-wide lock. */
        unsigned int tx_full:1;                         /* The Tx queue is full. */
        unsigned int full_duplex:1;                     /* Full-duplex operation requested. */
        unsigned int default_port:4;            /* Last dev->if_port value. */
@@ -596,8 +606,7 @@ rtl8129_open(struct device *dev)
        /* Soft reset the chip. */
        outb(CmdReset, ioaddr + ChipCmd);
 
-       if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ,
-                                       "RealTek RTL8129/39 Fast Ethernet", dev)) {
+       if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
                return -EAGAIN;
        }
 
@@ -735,6 +744,9 @@ static void rtl8129_tx_timeout(struct device *dev)
        int ioaddr = dev->base_addr;
        int i;
 
+       /* Disable interrupts by clearing the interrupt mask. */
+       outw(0x0000, ioaddr + IntrMask);
+
        if (rtl8129_debug > 0)
                printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x.\n",
                           dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus));
@@ -754,12 +766,39 @@ static void rtl8129_tx_timeout(struct device *dev)
                           dev->name, inw(ioaddr + BMSR));
        }
 
-#ifdef notdef
        /* Soft reset the chip. */
        outb(CmdReset, ioaddr + ChipCmd);
        for (i = 0; i < 6; i++)
                outb(dev->dev_addr[i], ioaddr + MAC0 + i);
-#endif
+
+       {                                                       /* Save the unsent Tx packets. */
+               struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
+               int j = 0;
+               for (; tp->cur_tx - tp->dirty_tx > 0 ; tp->dirty_tx++)
+                       saved_skb[j++] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
+               tp->dirty_tx = tp->cur_tx = 0;
+
+               for (i = 0; i < j; i++) {
+                       skb = tp->tx_skbuff[i] = saved_skb[i];
+                       if ((long)skb->data & 3) {              /* Must use alignment buffer. */
+                               memcpy(tp->tx_buf[i], skb->data, skb->len);
+                               outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4);
+                       } else
+                               outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);
+                       /* Note: the chip doesn't have auto-pad! */
+                       outl(((TX_FIFO_THRESH<<11) & 0x003f0000) |
+                                (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+                                ioaddr + TxStat0 + i*4);
+               }
+               tp->cur_tx = i;
+               while (i < NUM_TX_DESC)
+                       tp->tx_skbuff[i] = 0;
+               if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+                       dev->tbusy = 0;
+               } else {
+                       tp->tx_full = 1;
+               }
+       }
 
        /* Must enable Tx/Rx before setting transfer thresholds! */
        set_rx_mode(dev);
@@ -770,6 +809,9 @@ static void rtl8129_tx_timeout(struct device *dev)
 
        dev->trans_start = jiffies;
        tp->stats.tx_errors++;
+       /* Enable all known interrupts by setting the interrupt mask. */
+       outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+                | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
        return;
 }
 
@@ -837,7 +879,7 @@ rtl8129_start_xmit(struct sk_buff *skb, struct device *dev)
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-static void rtl8129_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
+static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
        struct device *dev = (struct device *)dev_instance;
        struct rtl8129_private *tp;
@@ -976,12 +1018,12 @@ static void rtl8129_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *r
                           dev->name, inl(ioaddr + IntrStatus));
 
        dev->interrupt = 0;
-       tp->in_interrupt = 0;
+       clear_bit(0, (void*)&tp->in_interrupt);
        return;
 }
 
-/* Todo: The data sheet doesn't describe the Rx ring at all, so I'm winging
-   it here until I have a chip to play with. 8/30/97 */
+/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
+   field alignments and semantics. */
 static int
 rtl8129_rx(struct device *dev)
 {
@@ -1025,6 +1067,12 @@ rtl8129_rx(struct device *dev)
                                tp->stats.rx_frame_errors++;
                        if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;
                        if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
+                       /* Reset the receiver, based on RealTek recommendation. (Bug?) */
+                       tp->cur_rx = 0;
+                       outb(CmdTxEnb, ioaddr + ChipCmd);
+                       outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+                       outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |
+                                (RX_DMA_BURST<<8), ioaddr + RxConfig);
                } else {
                        /* Malloc up new buffer, compatible with net-2e. */
                        /* Omit the four octet CRC from the length. */
@@ -1166,7 +1214,6 @@ static inline unsigned ether_crc_le(int length, unsigned char *data)
        return crc;
 }
 
-
 static void set_rx_mode(struct device *dev)
 {
        int ioaddr = dev->base_addr;
@@ -1245,7 +1292,8 @@ cleanup_module(void)
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
index b2e3978b6dab64dc913c0e7e65a3a98e13b273c3..6eb1efae5b574d6a628b4dcc5efab4595b458233 100644 (file)
@@ -32,6 +32,7 @@
  *             2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
index 418d59e1663d8c8932e1e71b85139745dd43c826..4043b8f24754638f092d762a30c3acbb2872103b 100644 (file)
@@ -238,8 +238,9 @@ int ultra32_probe1(struct device *dev, int ioaddr)
 static int ultra32_open(struct device *dev)
 {
        int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
+       int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : SA_SHIRQ;
 
-       if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, NULL))
+       if (request_irq(dev->irq, ei_interrupt, irq_flags, ei_status.name, dev))
                return -EAGAIN;
 
        outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
index 7f19029235e2d4822fbb7fca78314199ec52a5d2..43f0e2897625984f98f275ed833a3508f2c444bc 100644 (file)
@@ -5,20 +5,18 @@
  *  tlan.c
  *  by James Banks, james.banks@caldera.com
  *
- *  (C) 1997-1998 Caldera, Inc.
+ *  (C) 1997 Caldera, Inc.
  *
  *  This software may be used and distributed according to the terms
  *  of the GNU Public License, incorporated herein by reference.
  *
- ** This file is best viewed/edited with columns>=132.
+ ** This file is best viewed/edited with tabstop=4 and colums>=132.
  *
  ** Useful (if not required) reading:
  *
  *             Texas Instruments, ThunderLAN Programmer's Guide,
  *                     TI Literature Number SPWU013A
  *                     available in PDF format from www.ti.com
- *             Level One, LXT901 and LXT970 Data Sheets
- *                     available in PDF format from www.level1.com
  *             National Semiconductor, DP83840A Data Sheet
  *                     available in PDF format from www.national.com
  *             Microchip Technology, 24C01A/02A/04A Data Sheet
@@ -52,66 +50,48 @@ static      int             TLanDevicesInstalled = 0;
 
 static  int            debug = 0;
 static int             aui = 0;
-static int             sa_int = 0;
-static int             bbuf = 0;
-static int             duplex = 0;
-static int             speed = 0;
 static u8              *TLanPadBuffer;
 static char            TLanSignature[] = "TLAN";
 static int             TLanVersionMajor = 0;
-static int             TLanVersionMinor = 42;
+static int             TLanVersionMinor = 38;
 
 
-static TLanAdapterEntry TLanAdapterList[] = {
+static TLanPciId TLanDeviceList[] = {
        { PCI_VENDOR_ID_COMPAQ, 
          PCI_DEVICE_ID_NETELLIGENT_10,
-         "Compaq Netelligent 10",
-         TLAN_ADAPTER_ACTIVITY_LED
+         "Compaq Netelligent 10"
        },
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_NETELLIGENT_10_100,
-         "Compaq Netelligent 10/100",
-         TLAN_ADAPTER_ACTIVITY_LED
+         "Compaq Netelligent 10/100"
        }, 
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED,
-         "Compaq Integrated NetFlex-3/P",
-         TLAN_ADAPTER_NONE
+         "Compaq Integrated NetFlex-3/P"
        }, 
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_NETFLEX_3P,
-         "Compaq NetFlex-3/P",
-         TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY
+         "Compaq NetFlex-3/P"
        },
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_NETFLEX_3P_BNC,
-         "Compaq NetFlex-3/P",
-         TLAN_ADAPTER_NONE
+         "Compaq NetFlex-3/P"
        },
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT,
-         "Compaq ProLiant Netelligent 10/100",
-         TLAN_ADAPTER_NONE
+         "Compaq ProLiant Netelligent 10/100"
        },
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL,
-         "Compaq Dual Port Netelligent 10/100",
-         TLAN_ADAPTER_NONE
+         "Compaq Dual Port Netelligent 10/100"
        },
        { PCI_VENDOR_ID_COMPAQ,
          PCI_DEVICE_ID_DESKPRO_4000_5233MMX,
-         "Compaq Integrated Netelligent 10/100",
-         TLAN_ADAPTER_NONE
-       },
-       { PCI_VENDOR_ID_OLICOM,
-         PCI_DEVICE_ID_OC_2326,
-         "Olicom OC-2326",
-         TLAN_ADAPTER_USE_INTERN_10
+         "Compaq Deskpro 4000 5233MMX"
        },
        { 0,
          0,
-         NULL,
-         0
+         NULL
        } /* End of List */
 };
 
@@ -137,37 +117,28 @@ static u32        TLan_HandleRxEOC( struct device *, u16 );
 static void    TLan_Timer( unsigned long );
 
 static void    TLan_ResetLists( struct device * );
-static void    TLan_FreeLists( struct device * );
 static void    TLan_PrintDio( u16 );
 static void    TLan_PrintList( TLanList *, char *, int );
 static void    TLan_ReadAndClearStats( struct device *, int );
-static void    TLan_ResetAdapter( struct device * );
-static void    TLan_FinishReset( struct device * );
+static int     TLan_Reset( struct device * );
 static void    TLan_SetMac( struct device *, int areg, char *mac );
 
-static void    TLan_PhyPrint( struct device * );
-static void    TLan_PhyDetect( struct device * );
-static void    TLan_PhyPowerDown( struct device * );
-static void    TLan_PhyPowerUp( struct device * );
-static void    TLan_PhyReset( struct device * );
-static void    TLan_PhyStartLink( struct device * );
-static void    TLan_PhyFinishAutoNeg( struct device * );
-/*
 static int     TLan_PhyNop( struct device * );
+static void    TLan_PhyPrint( struct device * );
+static void    TLan_PhySelect( struct device * );
 static int     TLan_PhyInternalCheck( struct device * );
 static int     TLan_PhyInternalService( struct device * );
 static int     TLan_PhyDp83840aCheck( struct device * );
-*/
 
-static int     TLan_MiiReadReg( struct device *, u16, u16, u16 * );
+static int     TLan_MiiReadReg(u16, u16, u16, u16 *);
 static void    TLan_MiiSendData( u16, u32, unsigned );
-static void    TLan_MiiSync( u16 );
-static void    TLan_MiiWriteReg( struct device *, u16, u16, u16 );
+static void    TLan_MiiSync(u16);
+static void    TLan_MiiWriteReg(u16, u16, u16, u16);
 
 static void    TLan_EeSendStart( u16 );
 static int     TLan_EeSendByte( u16, u8, int );
 static void    TLan_EeReceiveByte( u16, u8 *, int );
-static int     TLan_EeReadByte( struct device *, u8, u8 * );
+static int     TLan_EeReadByte( u16, u8, u8 * );
 
 
 static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
@@ -181,25 +152,6 @@ static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
        TLan_HandleRxEOC
 };
 
-static inline void
-TLan_SetTimer( struct device *dev, u32 ticks, u32 type )
-{
-       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-
-       cli();
-       if ( priv->timer.function != NULL ) {
-               return;
-       }
-       priv->timer.function = &TLan_Timer;
-       sti();
-
-       priv->timer.data = (unsigned long) dev;
-       priv->timer.expires = jiffies + ticks;
-       priv->timerSetAt = jiffies;
-       priv->timerType = type;
-       add_timer( &priv->timer );
-
-} /* TLan_SetTimer */
 
 
 /*****************************************************************************
@@ -225,7 +177,7 @@ TLan_SetTimer( struct device *dev, u32 ticks, u32 type )
         *
         *      This function begins the setup of the driver creating a
         *      pad buffer, finding all TLAN devices (matching
-        *      TLanAdapterList entries), and creating and initializing a
+        *      TLanDeviceList entries), and creating and initializing a
         *      device structure for each adapter.
         *
         **************************************************************/
@@ -237,14 +189,14 @@ extern int init_module(void)
        struct device   *dev;
        size_t          dev_size;
        u8              dfn;
-       u32             index;
+       u32             dl_ix;
        int             failed;
        int             found;
        u32             io_base;
        u8              irq;
        u8              rev;
 
-       printk( "TLAN driver, v%d.%d, (C) 1997-8 Caldera, Inc.\n",
+       printk( "TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n",
                TLanVersionMajor,
                TLanVersionMinor
              );
@@ -260,7 +212,7 @@ extern int init_module(void)
 
        dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo);
 
-       while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index ) ) ) {
+       while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) ) {
                dev = (struct device *) kmalloc( dev_size, GFP_KERNEL );
                if ( dev == NULL ) {
                        printk( "TLAN:  Could not allocate memory for device.\n" );
@@ -275,35 +227,27 @@ extern int init_module(void)
                dev->irq = irq;
                dev->init = TLan_Init;
 
-               priv->adapter =    &TLanAdapterList[index];
-               priv->adapterRev = rev;
-               priv->aui =        aui;
-               priv->duplex =     duplex;
-               priv->speed =      speed;
-               priv->sa_int =     sa_int;
-               priv->debug =      debug;
+               priv->pciBus = bus;
+               priv->pciDeviceFn = dfn;
+               priv->pciRevision = rev;
+               priv->pciEntry = dl_ix;
 
                ether_setup( dev );
 
                failed = register_netdev( dev );
 
                if ( failed ) {
-                       printk( "TLAN:  Could not register device.\n" );
+                       printk( "TLAN:  Could not register network device.  Freeing struct.\n" );
                        kfree( dev );
                } else {
                        priv->nextDevice = TLanDevices;
                        TLanDevices = dev;
                        TLanDevicesInstalled++;
-                       printk("TLAN:  %s irq=%2d io=%04x, %s, Rev. %d\n",
-                               dev->name,
-                               (int) dev->irq,
-                               (int) dev->base_addr,
-                               priv->adapter->deviceLabel,
-                               priv->adapterRev );
+                       printk("TLAN:  %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName );
                }
        }
        
-       /* printk( "TLAN:  Found %d device(s).\n", TLanDevicesInstalled ); */
+       // printk( "TLAN:  Found %d device(s).\n", TLanDevicesInstalled );
 
     return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV );
 
@@ -332,12 +276,11 @@ extern void cleanup_module(void)
        struct device   *dev;
        TLanPrivateInfo *priv;
 
-       while ( TLanDevicesInstalled ) {
+       while (TLanDevicesInstalled) {
                dev = TLanDevices;
                priv = (TLanPrivateInfo *) dev->priv;
-               if ( priv->dmaStorage ) {
+               if ( priv->dmaStorage )
                        kfree( priv->dmaStorage );
-               }
                release_region( dev->base_addr, 0x10 );
                unregister_netdev( dev );
                TLanDevices = priv->nextDevice;
@@ -372,74 +315,53 @@ extern void cleanup_module(void)
         
 extern int tlan_probe( struct device *dev )
 {
-       TLanPrivateInfo *priv;
        static int      pad_allocated = 0;
        int             found;
+       TLanPrivateInfo *priv;
        u8              bus, dfn, irq, rev;
-       u32             io_base, index;
-
-       found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index );
+       u32             io_base, dl_ix;
 
-       if ( ! found ) {
-               return -ENODEV;
-       }
-
-       dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
-       
-       if ( dev->priv == NULL ) {
-               printk( "TLAN:  Could not allocate memory for device.\n" );
-               return  -ENOMEM;
-       }
-
-       memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
-
-       if ( ! pad_allocated ) {
-               TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, 
-//                                             ( GFP_KERNEL | GFP_DMA )
-                                               ( GFP_KERNEL )
-                                             );
-               if ( TLanPadBuffer == NULL ) {
-                       printk( "TLAN:  Could not allocate memory for padding.\n" );
-                       kfree( dev->priv );
-                       return -ENOMEM;
-               } else {
-                       pad_allocated = 1;
-                       memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
+       found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix );
+       if ( found ) {
+               dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
+               if ( dev->priv == NULL ) {
+                       printk( "TLAN:  Could not allocate memory for device.\n" );
                }
-       }
-
-       priv = (TLanPrivateInfo *) dev->priv;
-
-       dev->name = priv->devName;
-       strcpy( priv->devName, "    " );
-
-       dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
+               memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
+               priv = (TLanPrivateInfo *) dev->priv;
 
-       dev->base_addr = io_base;
-       dev->irq = irq;
+               dev->name = priv->devName;
+               strcpy( priv->devName, "    " );
 
+               dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
 
-       priv->adapter =    &TLanAdapterList[index];
-       priv->adapterRev = rev;
-       priv->aui =        dev->mem_start & 0x01;
-       priv->duplex =     ( ( dev->mem_start & 0x0C ) == 0x0C ) ? 0 : dev->mem_start & 0x0C >> 2;
-       priv->speed =      ( ( dev->mem_start & 0x30 ) == 0x30 ) ? 0 : dev->mem_start & 0x30 >> 4;
-       priv->sa_int =     dev->mem_start & 0x02;
-       priv->debug =      dev->mem_end;
+               dev->base_addr = io_base;
+               dev->irq = irq;
 
+               priv->pciBus = bus;
+               priv->pciDeviceFn = dfn;
+               priv->pciRevision = rev;
+               priv->pciEntry = dl_ix;
 
-       printk("TLAN %d.%d:  %s irq=%2d io=%04x, %s, Rev. %d\n",
-               TLanVersionMajor,
-               TLanVersionMinor,
-               dev->name, 
-               (int) irq, 
-               io_base,
-               priv->adapter->deviceLabel,
-               priv->adapterRev );
-
-       TLan_Init( dev );
+               if ( ! pad_allocated ) {
+                       TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA );
+                       if ( TLanPadBuffer == NULL ) {
+                               printk( "TLAN:  Could not allocate memory for pad buffer.\n" );
+                       } else {
+                               pad_allocated = 1;
+                               memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
+                       }
+               }
+               printk("TLAN %d.%d:  %s irq=%2d io=%04x, %s\n",TLanVersionMajor,
+                       TLanVersionMinor,
+                       dev->name, 
+                       (int) irq, 
+                       io_base, 
+                       TLanDeviceList[dl_ix].deviceName );
+               TLan_Init( dev );
+       }
                        
-       return 0;
+       return ( ( found ) ? 0 : -ENODEV );
 
 } /* tlan_probe */
 
@@ -467,7 +389,7 @@ extern int tlan_probe( struct device *dev )
         *                              of the adapter.
         *
         *      This function searches for an adapter with PCI vendor
-        *      and device IDs matching those in the TLanAdapterList.
+        *      and device IDs matching those in the TLanDeviceList.
         *      The function 'remembers' the last device it found,
         *      and so finds a new device (if anymore are to be found)
         *      each time the function is called.  It then looks up
@@ -491,11 +413,11 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_
                return 0;
        }
 
-       for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) {
+       for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) {
 
                not_found = pcibios_find_device(
-                       TLanAdapterList[dl_index].vendorId,
-                       TLanAdapterList[dl_index].deviceId,
+                       TLanDeviceList[dl_index].vendorId,
+                       TLanDeviceList[dl_index].deviceId,
                        pci_index,
                        pci_bus,
                        pci_dfn
@@ -506,8 +428,8 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_
                        TLAN_DBG(
                                TLAN_DEBUG_GNRL,
                                "TLAN:  found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
-                               TLanAdapterList[dl_index].vendorId,
-                               TLanAdapterList[dl_index].deviceId
+                               TLanDeviceList[dl_index].vendorId,
+                               TLanDeviceList[dl_index].deviceId
                        );
 
                        pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_REVISION_ID, pci_rev);
@@ -535,12 +457,8 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_
                        if ( *pci_io_base == 0 )
                                printk("TLAN:    IO mapping not available, ignoring device.\n");
 
-                       if ( ! ( pci_command & PCI_COMMAND_MASTER ) ) {
-                               pcibios_write_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND, pci_command | PCI_COMMAND_MASTER );
-                               printk( "TLAN:  Attempting to activate busmastering.\n" );
-                               printk( "TLAN:    You may need to set busmastering to on in the CMOS\n" );
-                               printk( "TLAN:    before this card will work.\n" );
-                               *pci_io_base = 0;
+                       if (pci_command & PCI_COMMAND_MASTER) {
+                               TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:    Bus mastering is active.\n");
                        }
 
                        pci_index++;
@@ -581,9 +499,9 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_
 
 int TLan_Init( struct device *dev )
 {
-       int             dma_size;
-       int             err;
-       int             i;
+       int                             dma_size;
+       int                             err;
+       int                             i;
        TLanPrivateInfo *priv;
 
        priv = (TLanPrivateInfo *) dev->priv;
@@ -598,14 +516,8 @@ int TLan_Init( struct device *dev )
        }
        request_region( dev->base_addr, 0x10, TLanSignature );
 
-       if ( bbuf ) {
-               dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
+       dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
                   * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
-       } else {
-               dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
-                  * ( sizeof(TLanList) );
-       }
-
        priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA );
        if ( priv->dmaStorage == NULL ) {
                printk( "TLAN:  Could not allocate lists and buffers for %s.\n",
@@ -616,24 +528,19 @@ int TLan_Init( struct device *dev )
        priv->rxList = (TLanList *) 
                       ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
        priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
-
-       if ( bbuf ) {
-               priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
-               priv->txBuffer = priv->rxBuffer
-                                + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
-       }
+       priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
+       priv->txBuffer = priv->rxBuffer
+                        + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
 
        err = 0;
        for ( i = 0;  i < 6 ; i++ )
-               err |= TLan_EeReadByte( dev,
+               err |= TLan_EeReadByte( dev->base_addr,
                                        (u8) 0x83 + i,
                                        (u8 *) &dev->dev_addr[i] );
-       if ( err ) {
+       if ( err )
                printk( "TLAN:  %s: Error reading MAC from eeprom: %d\n",
                        dev->name,
                        err );
-       }
-
        dev->addr_len = 6;
 
        dev->open = &TLan_Open;
@@ -642,6 +549,12 @@ int TLan_Init( struct device *dev )
        dev->get_stats = &TLan_GetStats;
        dev->set_multicast_list = &TLan_SetMulticastList;
 
+#ifndef MODULE
+
+       aui = dev->mem_start & 0x01;
+       debug = dev->mem_end;
+
+#endif /* MODULE */
 
        return 0;
 
@@ -669,21 +582,16 @@ int TLan_Init( struct device *dev )
 
 int TLan_Open( struct device *dev )
 {
+       int                             err;
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       int             err;
 
        priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
-       if ( priv->sa_int ) {
-               TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:   Using SA_INTERRUPT\n" ); 
-               err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ | SA_INTERRUPT, TLanSignature, dev );
-       } else {
-               err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
-       }
+       err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
        if ( err ) {
                printk( "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
                return -EAGAIN;
        }
-       
+
        MOD_INC_USE_COUNT;
 
        dev->tbusy = 0;
@@ -695,9 +603,27 @@ int TLan_Open( struct device *dev )
        */
        TLan_ResetLists( dev );
        TLan_ReadAndClearStats( dev, TLAN_IGNORE );
-       TLan_ResetAdapter( dev );
+       TLan_Reset( dev );
+       TLan_Reset( dev );
+       TLan_SetMac( dev, 0, dev->dev_addr );
+       outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+       if ( debug >= 1 )
+               outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+
+       init_timer( &priv->timer );
+       priv->timer.data = (unsigned long) dev;
+       priv->timer.function = &TLan_Timer;
+       if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
+               priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
+               priv->timerSetAt = jiffies;
+               priv->timerType = TLAN_TIMER_LINK;
+               add_timer( &priv->timer );
+       } else {
+               outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+               outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+       }
 
-       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Opened.  TLAN Chip Rev: %x\n", dev->name, priv->tlanRev );
+       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Device %s opened.  Revision = %x\n", dev->name, priv->tlanRev );
 
        return 0;
 
@@ -730,9 +656,9 @@ int TLan_Open( struct device *dev )
 int TLan_StartTx( struct sk_buff *skb, struct device *dev )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       TLanList        *tail_list;
-       u8              *tail_buffer;
-       int             pad;
+       TLanList                *tail_list;
+       u8                              *tail_buffer;
+       int                             pad;
 
        if ( ! priv->phyOnline ) {
                TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s PHY is not ready\n", dev->name );
@@ -741,26 +667,16 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
        }
 
        tail_list = priv->txList + priv->txTail;
-
        if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
                TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
                dev->tbusy = 1;
                priv->txBusyCount++;
                return 1;
        }
-
        tail_list->forward = 0;
-
-       if ( bbuf ) {
-               tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
-               memcpy( tail_buffer, skb->data, skb->len );
-       } else {
-               tail_list->buffer[0].address = virt_to_bus( skb->data );
-               tail_list->buffer[9].address = (u32) skb;
-       }
-
+       tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
+       memcpy( tail_buffer, skb->data, skb->len );
        pad = TLAN_MIN_FRAME_SIZE - skb->len;
-
        if ( pad > 0 ) {
                tail_list->frameSize = (u16) skb->len + pad;
                tail_list->buffer[0].count = (u32) skb->len;
@@ -772,7 +688,7 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
                tail_list->buffer[1].count = 0;
                tail_list->buffer[1].address = 0;
        }
-
+       // are we transferring?
        cli();
        tail_list->cStat = TLAN_CSTAT_READY;
        if ( ! priv->txInProgress ) {
@@ -783,19 +699,17 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
                outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
        } else {
                TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );
-               if ( priv->txTail == 0 ) {
+               if ( priv->txTail == 0 )
                        ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );
-               } else {
+               else
                        ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );
-               }
        }
        sti();
+       priv->txTail++;
+       if ( priv->txTail >= TLAN_NUM_TX_LISTS )
+               priv->txTail = 0;
 
-       CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
-
-       if ( bbuf ) {
-               dev_kfree_skb( skb, FREE_WRITE );
-       }
+       dev_kfree_skb( skb, FREE_WRITE );
                
        dev->trans_start = jiffies;
        return 0;
@@ -828,34 +742,35 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
 
 void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       u32             ack;
+       u32                             ack;
        struct device   *dev;
-       u32             host_cmd;
-       u16             host_int;
-       int             type;
+       u32                             host_cmd;
+       u16                             host_int;
+       int                             type;
 
        dev = (struct device *) dev_id;
 
-       cli();
-       if ( dev->interrupt ) {
+       if ( dev->interrupt )
                printk( "TLAN:   Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
-       }
        dev->interrupt++;
 
+       cli();
+
        host_int = inw( dev->base_addr + TLAN_HOST_INT );
-       outw( host_int, dev->base_addr + TLAN_HOST_INT );
+       outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints
 
        type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
 
        ack = TLanIntVector[type]( dev, host_int );
 
+       sti();
+
        if ( ack ) {
                host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
                outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
        }
 
        dev->interrupt--;
-       sti();
 
 } /* TLan_HandleInterrupts */
 
@@ -886,11 +801,10 @@ int TLan_Close(struct device *dev)
 
        TLan_ReadAndClearStats( dev, TLAN_RECORD );
        outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
-       if ( priv->timer.function != NULL )
+       if ( priv->timerSetAt != 0 )
                del_timer( &priv->timer );
        free_irq( dev->irq, dev );
-       TLan_FreeLists( dev );
-       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Device %s closed.\n", dev->name );
+       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:   Device %s closed.\n", dev->name );
 
        MOD_DEC_USE_COUNT;
 
@@ -967,11 +881,11 @@ struct net_device_stats *TLan_GetStats( struct device *dev )
 void TLan_SetMulticastList( struct device *dev )
 {      
        struct dev_mc_list      *dmi = dev->mc_list;
-       u32                     hash1 = 0;
-       u32                     hash2 = 0;
-       int                     i;
-       u32                     offset;
-       u8                      tmp;
+       u32                                     hash1 = 0;
+       u32                                     hash2 = 0;
+       int                                     i;
+       u32                                     offset;
+       u8                                      tmp;
 
        if ( dev->flags & IFF_PROMISC ) {
                tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
@@ -1041,7 +955,7 @@ void TLan_SetMulticastList( struct device *dev )
 u32 TLan_HandleInvalid( struct device *dev, u16 host_int )
 {
        host_int = 0;
-       /* printk( "TLAN:  Invalid interrupt on %s.\n", dev->name ); */
+       // printk( "TLAN:  Invalid interrupt on %s.\n", dev->name );
        return 0;
 
 } /* TLan_HandleInvalid */
@@ -1074,24 +988,19 @@ u32 TLan_HandleInvalid( struct device *dev, u16 host_int )
 u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       int             eoc = 0;
-       TLanList        *head_list;
-       u32             ack = 1;
+       int                             eoc = 0;
+       TLanList                *head_list;
+       u32                             ack = 1;
 
        TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
        host_int = 0;
        head_list = priv->txList + priv->txHead;
-
-       if ( ! bbuf ) {
-               dev_kfree_skb( (struct sk_buff *) head_list->buffer[9].address, FREE_WRITE );
-               head_list->buffer[9].address = 0;
-       }
-
        if ( head_list->cStat & TLAN_CSTAT_EOC )
                eoc = 1;
        if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
                printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
        }
+       // printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat );
 
 #if LINUX_KERNEL_VERSION > 0x20100
        priv->stats->tx_bytes += head_list->frameSize;
@@ -1099,7 +1008,9 @@ u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
 
        head_list->cStat = TLAN_CSTAT_UNUSED;
        dev->tbusy = 0;
-       CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
+       priv->txHead++;
+       if ( priv->txHead >= TLAN_NUM_TX_LISTS )
+               priv->txHead = 0;
        if ( eoc ) {
                TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
                head_list = priv->txList + priv->txHead;
@@ -1110,13 +1021,17 @@ u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
                        priv->txInProgress = 0;
                }
        }
-
-       if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
-               TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
-               if ( priv->timer.function == NULL ) {
-                       TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
-               } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
+       TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+       if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
+               if ( priv->timerSetAt == 0 ) {
+                       // printk("TxEOF Starting timer...\n");
+                       priv->timerSetAt = jiffies;
+                       priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+                       priv->timerType = TLAN_TIMER_ACT;
+                       add_timer( &priv->timer );
+               } else if ( priv->timerType == TLAN_TIMER_ACT ) {
                        priv->timerSetAt = jiffies;
+                       // printk("TxEOF continuing timer...\n");
                }
        }
 
@@ -1196,14 +1111,11 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
        host_int = 0;
        head_list = priv->rxList + priv->rxHead;
        tail_list = priv->rxList + priv->rxTail;
-
-       if ( head_list->cStat & TLAN_CSTAT_EOC ) {
+       if ( head_list->cStat & TLAN_CSTAT_EOC )
                eoc = 1;
-       }
-
        if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
                printk( "TLAN:  Received interrupt for uncompleted RX frame.\n" );
-       } else if ( bbuf ) {
+       } else {
                skb = dev_alloc_skb( head_list->frameSize + 7 );
                if ( skb == NULL ) { 
                        printk( "TLAN:  Couldn't allocate memory for received data.\n" );
@@ -1212,6 +1124,7 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
                        skb->dev = dev;
                        skb_reserve( skb, 2 );
                        t = (void *) skb_put( skb, head_list->frameSize );
+                       // printk( " %hd %p %p\n", head_list->frameSize, skb->data, t );
 
 #if LINUX_KERNEL_VERSION > 0x20100
                        priv->stats->rx_bytes += head_list->frameSize;
@@ -1221,39 +1134,17 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
                        skb->protocol = eth_type_trans( skb, dev );
                        netif_rx( skb );
                }
-       } else {
-               skb = (struct sk_buff *) head_list->buffer[9].address;
-               head_list->buffer[9].address = 0;
-               skb_trim( skb, head_list->frameSize );
-
-#if LINUX_KERNEL_VERSION > 0x20100
-                       priv->stats->rx_bytes += head_list->frameSize;
-#endif
-
-               skb->protocol = eth_type_trans( skb, dev );
-               netif_rx( skb );
-
-               skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
-               if ( skb == NULL ) {
-                       printk( "TLAN:  Couldn't allocate memory for received data.\n" );
-                       /* If this ever happened it would be a problem */
-               } else {
-                       skb->dev = dev;
-                       skb_reserve( skb, 2 );
-                       t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
-                       head_list->buffer[0].address = virt_to_bus( t );
-                       head_list->buffer[9].address = (u32) skb;
-               }
        }
-
        head_list->forward = 0;
        head_list->frameSize = TLAN_MAX_FRAME_SIZE;
        head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
        tail_list->forward = virt_to_bus( head_list );
-
-       CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );
-       CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );
-
+       priv->rxHead++;
+       if ( priv->rxHead >= TLAN_NUM_RX_LISTS )
+               priv->rxHead = 0;
+       priv->rxTail++;
+       if ( priv->rxTail >= TLAN_NUM_RX_LISTS )
+               priv->rxTail = 0;
        if ( eoc ) { 
                TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
                head_list = priv->rxList + priv->rxHead;
@@ -1261,16 +1152,19 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
                ack |= TLAN_HC_GO | TLAN_HC_RT;
                priv->rxEocCount++;
        }
-
-       if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
-               TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
-               if ( priv->timer.function == NULL )  {
-                       TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
-               } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
+       TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+       if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
+               if ( priv->timerSetAt == 0 )  {
+                       // printk("RxEOF Starting timer...\n");
+                       priv->timerSetAt = jiffies;
+                       priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+                       priv->timerType = TLAN_TIMER_ACT;
+                       add_timer( &priv->timer );
+               } else if ( priv->timerType == TLAN_TIMER_ACT ) {
+                       // printk("RxEOF tarting continuing timer...\n");
                        priv->timerSetAt = jiffies;
                }
        }
-
        dev->last_rx = jiffies;
 
        return ack;
@@ -1300,7 +1194,7 @@ u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
 u32 TLan_HandleDummy( struct device *dev, u16 host_int )
 {
        host_int = 0;
-       printk( "TLAN:  Test interrupt on %s.\n", dev->name );
+       printk( "TLAN:  Dummy interrupt on %s.\n", dev->name );
        return 1;
 
 } /* TLan_HandleDummy */
@@ -1375,50 +1269,45 @@ u32 TLan_HandleTxEOC( struct device *dev, u16 host_int )
 
 u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
 {      
+       u32                             ack;
+       u32                             error;
+       u8                              net_sts;
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u32             ack;
-       u32             error;
-       u8              net_sts;
-       u32             phy;
-       u16             tlphy_ctl;
-       u16             tlphy_sts;
        
        ack = 1;
        if ( host_int & TLAN_HI_IV_MASK ) {
                error = inl( dev->base_addr + TLAN_CH_PARM );
-               printk( "TLAN:  %s: Adaptor Error = 0x%x\n", dev->name, error );
+               printk( "TLAN:   Adaptor Check on device %s err = 0x%x\n", dev->name, error );
                TLan_ReadAndClearStats( dev, TLAN_RECORD );
                outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
-               TLan_FreeLists( dev );
                TLan_ResetLists( dev );
-               TLan_ResetAdapter( dev );
+               TLan_Reset( dev );
                dev->tbusy = 0;
+               TLan_SetMac( dev, 0, dev->dev_addr );
+               if ( priv->timerType == 0 ) {
+                       if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
+                               priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
+                               priv->timerSetAt = jiffies;
+                               priv->timerType = TLAN_TIMER_LINK;
+                               add_timer( &priv->timer );
+                       } else {
+                               //printk( " RX GO---->\n" );
+                               outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+                               outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+                       }
+               }
                ack = 0;
        } else {
-               TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Status Check\n", dev->name );
-               phy = priv->phy[priv->phyNum];
-
                net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
-               if ( net_sts ) {
+               if ( net_sts )
                        TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
-                       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s:    Net_Sts = %x\n", dev->name, (unsigned) net_sts );
-               }
-               if ( ( net_sts & TLAN_NET_STS_MIRQ ) &&  ( priv->phyNum == 0 ) ) {
-                       TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );
-                       TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
-                       if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
-                               tlphy_ctl |= TLAN_TC_SWAPOL;
-                               TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
-                       } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
-                               tlphy_ctl &= ~TLAN_TC_SWAPOL;
-                               TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
-                       }
-
+               if ( net_sts & TLAN_NET_STS_MIRQ ) {
+                       (*priv->phyService)( dev );
                        if (debug) {
                                TLan_PhyPrint( dev );
                        }
                }
-               udelay(10000000);
+               TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
        }
 
        return ack;
@@ -1451,8 +1340,8 @@ u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
 u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       TLanList        *head_list;
-       u32             ack = 1;
+       TLanList                *head_list;
+       u32                             ack = 1;
 
        host_int = 0;
        if (  priv->tlanRev < 0x30 ) {
@@ -1512,44 +1401,34 @@ u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
 void TLan_Timer( unsigned long data )
 {
        struct device   *dev = (struct device *) data;
+       u16             gen_sts;
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u32             elapsed;
 
-       priv->timer.function = NULL;
+       // printk( "TLAN:  %s Entered Timer, type = %d\n", dev->name, priv->timerType );
 
        switch ( priv->timerType ) {
-               case TLAN_TIMER_PHY_PDOWN:
-                       TLan_PhyPowerDown( dev );
-                       break;
-               case TLAN_TIMER_PHY_PUP:
-                       TLan_PhyPowerUp( dev );
-                       break;
-               case TLAN_TIMER_PHY_RESET:
-                       TLan_PhyReset( dev );
-                       break;
-               case TLAN_TIMER_PHY_START_LINK:
-                       TLan_PhyStartLink( dev );
-                       break;
-               case TLAN_TIMER_PHY_FINISH_AN:
-                       TLan_PhyFinishAutoNeg( dev );
-                       break;
-               case TLAN_TIMER_FINISH_RESET:
-                       TLan_FinishReset( dev );
+               case TLAN_TIMER_LINK:
+                       TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts );
+                       if ( gen_sts & MII_GS_LINK ) {
+                               priv->phyOnline = 1;
+                               outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+                               outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+                               priv->timerSetAt = 0;
+                               priv->timerType = 0;
+                       } else {
+                               priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 );
+                               add_timer( &priv->timer );
+                       }
                        break;
-               case TLAN_TIMER_ACTIVITY:
-                       cli();
-                       if ( priv->timer.function == NULL ) {
-                               elapsed = jiffies - priv->timerSetAt;
-                               if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {
-                                       TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
-                               } else  {
-                                       priv->timer.function = &TLan_Timer;
-                                       priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
-                                       sti();
-                                       add_timer( &priv->timer );
-                               }
+               case TLAN_TIMER_ACT:
+                       if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) {
+                               TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+                               priv->timerSetAt = 0;
+                               priv->timerType = 0;
+                       } else {
+                               priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+                               add_timer( &priv->timer );
                        }
-                       sti();
                        break;
                default:
                        break;
@@ -1588,19 +1467,13 @@ void TLan_ResetLists( struct device *dev )
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
        int             i;
        TLanList        *list;
-       struct sk_buff  *skb;
-       void            *t = NULL;
 
        priv->txHead = 0;
        priv->txTail = 0;
        for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
                list = priv->txList + i;
                list->cStat = TLAN_CSTAT_UNUSED;
-               if ( bbuf ) {
-                       list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
-               } else {
-                       list->buffer[0].address = 0;
-               }
+               list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
                list->buffer[2].count = 0;
                list->buffer[2].address = 0;
        }
@@ -1612,21 +1485,7 @@ void TLan_ResetLists( struct device *dev )
                list->cStat = TLAN_CSTAT_READY;
                list->frameSize = TLAN_MAX_FRAME_SIZE;
                list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
-               if ( bbuf ) {
-                       list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
-               } else {
-                       skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
-                       if ( skb == NULL ) {
-                               printk( "TLAN:  Couldn't allocate memory for received data.\n" );
-                               /* If this ever happened it would be a problem */
-                       } else {
-                               skb->dev = dev;
-                               skb_reserve( skb, 2 );
-                               t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
-                       }
-                       list->buffer[0].address = virt_to_bus( t );
-                       list->buffer[9].address = (u32) skb;
-               }
+               list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
                list->buffer[1].count = 0;
                list->buffer[1].address = 0;
                if ( i < TLAN_NUM_RX_LISTS - 1 )
@@ -1638,36 +1497,6 @@ void TLan_ResetLists( struct device *dev )
 } /* TLan_ResetLists */
 
 
-void TLan_FreeLists( struct device *dev )
-{
-       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       int             i;
-       TLanList        *list;
-       struct sk_buff  *skb;
-
-       if ( ! bbuf ) {
-               for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
-                       list = priv->txList + i;
-                       skb = (struct sk_buff *) list->buffer[9].address;
-                       if ( skb ) {
-                               dev_kfree_skb( skb, FREE_WRITE );
-                               list->buffer[9].address = 0;
-                       }
-               }
-
-               for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
-                       list = priv->rxList + i;
-                       skb = (struct sk_buff *) list->buffer[9].address;
-                       if ( skb ) {
-                               dev_kfree_skb( skb, FREE_READ );
-                               list->buffer[9].address = 0;
-                       }
-               }
-       }
-
-} /* TLan_FreeLists */
-
-
 
 
        /***************************************************************
@@ -1727,7 +1556,7 @@ void TLan_PrintList( TLanList *list, char *type, int num)
        printk( "TLAN:      Forward    = 0x%08x\n",  list->forward );
        printk( "TLAN:      CSTAT      = 0x%04hx\n", list->cStat );
        printk( "TLAN:      Frame Size = 0x%04hx\n", list->frameSize );
-       /* for ( i = 0; i < 10; i++ ) { */
+       // for ( i = 0; i < 10; i++ ) {
        for ( i = 0; i < 2; i++ ) {
                printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );
        }
@@ -1758,11 +1587,11 @@ void TLan_PrintList( TLanList *list, char *type, int num)
 void TLan_ReadAndClearStats( struct device *dev, int record )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u32             tx_good, tx_under;
-       u32             rx_good, rx_over;
-       u32             def_tx, crc, code;
-       u32             multi_col, single_col;
-       u32             excess_col, late_col, loss;
+       u32                             tx_good, tx_under;
+       u32                             rx_good, rx_over;
+       u32                             def_tx, crc, code;
+       u32                             multi_col, single_col;
+       u32                             excess_col, late_col, loss;
 
        outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR );
        tx_good  = inb( dev->base_addr + TLAN_DIO_DATA );
@@ -1830,8 +1659,7 @@ void TLan_ReadAndClearStats( struct device *dev, int record )
         *
         **************************************************************/
 
-void
-TLan_ResetAdapter( struct device *dev )
+int TLan_Reset( struct device *dev )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
        int             i;
@@ -1839,140 +1667,77 @@ TLan_ResetAdapter( struct device *dev )
        u32             data;
        u8              data8;
 
-       priv->tlanFullDuplex = FALSE;
-/*  1. Assert reset bit. */
+//  1. Assert reset bit.
 
        data = inl(dev->base_addr + TLAN_HOST_CMD);
        data |= TLAN_HC_AD_RST;
        outl(data, dev->base_addr + TLAN_HOST_CMD);
-       
-       udelay(1000);
 
-/*  2. Turn off interrupts. ( Probably isn't necessary ) */
+//  2. Turn off interrupts. ( Probably isn't necessary )
 
        data = inl(dev->base_addr + TLAN_HOST_CMD);
        data |= TLAN_HC_INT_OFF;
        outl(data, dev->base_addr + TLAN_HOST_CMD);
 
-/*  3. Clear AREGs and HASHs. */
+//  3. Clear AREGs and HASHs.
 
        for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) {
                TLan_DioWrite32( dev->base_addr, (u16) i, 0 );
        }
 
-/*  4. Setup NetConfig register. */
+//  4. Setup NetConfig register.
 
        data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
        TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );
 
-/*  5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */
+//  5. Load Ld_Tmr and Ld_Thr in HOST_CMD.
 
        outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD );
        outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD );
 
-/*  6. Unreset the MII by setting NMRST (in NetSio) to 1. */
+//  6. Unreset the MII by setting NMRST (in NetSio) to 1.
 
        outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR );
        addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
        TLan_SetBit( TLAN_NET_SIO_NMRST, addr );
 
-/*  7. Setup the remaining registers. */
+//  7. Setup the remaining registers.
 
        if ( priv->tlanRev >= 0x30 ) {
                data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
                TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 );
        }
-       TLan_PhyDetect( dev );
+       TLan_PhySelect( dev );
        data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
-       if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) {
+       if ( priv->phyFlags & TLAN_PHY_BIT_RATE ) {
                data |= TLAN_NET_CFG_BIT;
-               if ( priv->aui == 1 ) {
+               if ( aui == 1 ) {
                        TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a );
-               } else if ( priv->duplex == TLAN_DUPLEX_FULL ) {
-                       TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 );
-                       priv->tlanFullDuplex = TRUE;
                } else {
                        TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
                }
        }
-       if ( priv->phyNum == 0 ) {
+       if ( priv->phyFlags & TLAN_PHY_INTERNAL ) {
                data |= TLAN_NET_CFG_PHY_EN;
        }
        TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data );
-
-       if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
-               TLan_FinishReset( dev );
-       } else {
-               TLan_PhyPowerDown( dev );
-       }
-
-} /* TLan_ResetAdapter */
-
-
-
-
-void
-TLan_FinishReset( struct device *dev )
-{
-       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u8              data;
-       u32             phy;
-       u8              sio;
-       u16             status;
-       u16             tlphy_ctl;
-
-       phy = priv->phy[priv->phyNum];
-
-       data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
-       if ( priv->tlanFullDuplex ) {
-               data |= TLAN_NET_CMD_DUPLEX;
-       }
-       TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data );
-       data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; 
-       if ( priv->phyNum == 0 ) {
-               data |= TLAN_NET_MASK_MASK7; 
-       }
-       TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data );
+       (*priv->phyCheck)( dev ); 
+       data8 = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
+       TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data8 );
+       data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; 
+       if ( priv->phyFlags & TLAN_PHY_INTS ) {
+               data8 |= TLAN_NET_MASK_MASK7; 
+       }
+       TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 );
        TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE );
 
-       if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
-               status = MII_GS_LINK;
-               printk( "TLAN:  %s: Link forced.\n", dev->name );
-       } else {
-               TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
-               udelay( 1000 );
-               TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
-               if ( status & MII_GS_LINK ) {
-                       printk( "TLAN:  %s: Link active.\n", dev->name );
-                       TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
-               }
-       }
-
-       if ( priv->phyNum == 0 ) {
-               TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
-               tlphy_ctl |= TLAN_TC_INTEN;
-               TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl );
-               sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
-               sio |= TLAN_NET_SIO_MINTEN;
-               TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
-       }
-
-       if ( status & MII_GS_LINK ) {
-               TLan_SetMac( dev, 0, dev->dev_addr );
+       if ( priv->phyFlags & TLAN_PHY_UNMANAGED ) {
                priv->phyOnline = 1;
-               outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
-               if ( debug >= 1 ) {
-                       outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
-               }
-               outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
-               outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
-       } else {
-               printk( "TLAN:  %s: Link inactive, will retry in 10 secs...\n", dev->name );
-               TLan_SetTimer( dev, 1000, TLAN_TIMER_FINISH_RESET );
-               return;
        }
 
-} /* TLan_FinishReset */
+       return 0;
+
+} /* TLan_Reset */
 
 
 
@@ -2022,10 +1787,56 @@ void TLan_SetMac( struct device *dev, int areg, char *mac )
 
        ThunderLAN Driver PHY Layer Routines
 
+       The TLAN chip can drive any number of PHYs (physical devices).  Rather
+       than having lots of 'if' or '#ifdef' statements, I have created a
+       second driver layer for the PHYs.  Each PHY can be identified from its
+       id in registers 2 and 3, and can be given a Check and Service routine
+       that will be called when the adapter is reset and when the adapter
+       receives a Network Status interrupt, respectively.
+       
 ******************************************************************************
 *****************************************************************************/
 
 
+static TLanPhyIdEntry  TLanPhyIdTable[] = {
+         { 0x4000,
+           0x5014,
+           &TLan_PhyInternalCheck,
+           &TLan_PhyInternalService,
+           TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
+         { 0x4000,
+           0x5015,
+           &TLan_PhyInternalCheck,
+           &TLan_PhyInternalService,
+           TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
+         { 0x4000,
+           0x5016,
+           &TLan_PhyInternalCheck,
+           &TLan_PhyInternalService,
+           TLAN_PHY_ACTIVITY | TLAN_PHY_INTS | TLAN_PHY_INTERNAL },
+         { 0x2000,
+           0x5C00,
+           &TLan_PhyDp83840aCheck,
+           &TLan_PhyNop,
+           TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
+         { 0x2000,
+           0x5C01,
+           &TLan_PhyDp83840aCheck,
+           &TLan_PhyNop,
+           TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
+         { 0x7810,
+           0x0000,
+           &TLan_PhyDp83840aCheck,
+           &TLan_PhyNop,
+           TLAN_PHY_AUTONEG },
+         { 0x0000,
+           0x0000,
+           NULL,
+           NULL,
+           0
+         }
+       };
+
 
        /*********************************************************************
         *      TLan_PhyPrint
@@ -2033,10 +1844,10 @@ void TLan_SetMac( struct device *dev, int areg, char *mac )
         *      Returns:
         *              Nothing
         *      Parms:
-        *              dev     A pointer to the device structure of the
-        *                      TLAN device having the PHYs to be detailed.
+        *              dev     A pointer to the device structure of the adapter
+        *                      which the desired PHY is located.
         *                              
-        *      This function prints the registers a PHY (aka tranceiver).
+        *      This function prints the registers a PHY.
         *
         ********************************************************************/
 
@@ -2044,27 +1855,30 @@ void TLan_PhyPrint( struct device *dev )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
        u16 i, data0, data1, data2, data3, phy;
+       u32 io;
 
-       phy = priv->phy[priv->phyNum];
+       phy = priv->phyAddr;
+       io = dev->base_addr;
 
-       if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
-               printk( "TLAN:   Device %s, Unmanaged PHY.\n", dev->name );
-       } else if ( phy <= TLAN_PHY_MAX_ADDR ) {
+       if ( ( phy > 0 ) && ( phy <= TLAN_PHY_MAX_ADDR ) ) {
                printk( "TLAN:   Device %s, PHY 0x%02x.\n", dev->name, phy );
                printk( "TLAN:      Off.  +0     +1     +2     +3 \n" );
                 for ( i = 0; i < 0x20; i+= 4 ) {
                        printk( "TLAN:      0x%02x", i );
-                       TLan_MiiReadReg( dev, phy, i, &data0 );
+                       TLan_MiiReadReg( io, phy, i, &data0 );
                        printk( " 0x%04hx", data0 );
-                       TLan_MiiReadReg( dev, phy, i + 1, &data1 );
+                       TLan_MiiReadReg( io, phy, i + 1, &data1 );
                        printk( " 0x%04hx", data1 );
-                       TLan_MiiReadReg( dev, phy, i + 2, &data2 );
+                       TLan_MiiReadReg( io, phy, i + 2, &data2 );
                        printk( " 0x%04hx", data2 );
-                       TLan_MiiReadReg( dev, phy, i + 3, &data3 );
+                       TLan_MiiReadReg( io, phy, i + 3, &data3 );
                        printk( " 0x%04hx\n", data3 );
                }
        } else {
-               printk( "TLAN:   Device %s, Invalid PHY.\n", dev->name );
+               printk( "TLAN:   Device %s, PHY 0x%02x (Unmanaged/Unknown).\n",
+                       dev->name,
+                       phy
+                     );
        }
 
 } /* TLan_PhyPrint */
@@ -2073,7 +1887,7 @@ void TLan_PhyPrint( struct device *dev )
 
 
        /*********************************************************************
-        *      TLan_PhyDetect
+        *      TLan_PhySelect
         *
         *      Returns:
         *              Nothing
@@ -2081,267 +1895,355 @@ void TLan_PhyPrint( struct device *dev )
         *              dev     A pointer to the device structure of the adapter
         *                      for which the PHY needs determined.
         *
-        *      So far I've found that adapters which have external PHYs
-        *      may also use the internal PHY for part of the functionality.
-        *      (eg, AUI/Thinnet).  This function finds out if this TLAN
-        *      chip has an internal PHY, and then finds the first external
-        *      PHY (starting from address 0) if it exists).
+        *      This function decides which PHY amoung those attached to the
+        *      TLAN chip is to be used.  The TLAN chip can be attached to
+        *      multiple PHYs, and the driver needs to decide which one to
+        *      talk to.  Currently this routine picks the PHY with the lowest
+        *      address as the internal PHY address is 0x1F, the highest
+        *      possible.  This strategy assumes that there can be only one
+        *      other PHY, and, if it exists, it is the one to be used.  If
+        *      token ring PHYs are ever supported, this routine will become
+        *      a little more interesting...
         *
         ********************************************************************/
 
-void TLan_PhyDetect( struct device *dev )
+void TLan_PhySelect( struct device *dev )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u16             control;
-       u16             hi;
-       u16             lo;
-       u32             phy;
+       int                     phy;
+       int                     entry;
+       u16                     id_hi[TLAN_PHY_MAX_ADDR + 1];
+       u16                     id_lo[TLAN_PHY_MAX_ADDR + 1];
+       u16                     hi;
+       u16                     lo;
+       u16                     vendor;
+       u16                     device;
+
+       priv->phyCheck = &TLan_PhyNop;  // Make sure these aren't ever NULL
+       priv->phyService = &TLan_PhyNop;
+       
+       vendor = TLanDeviceList[priv->pciEntry].vendorId;
+       device = TLanDeviceList[priv->pciEntry].deviceId;
 
-       if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) {
-               priv->phyNum = 0xFFFF;
-               return;
-       }
+       // This is a bit uglier than I'd like, but the 0xF130 device must
+       // NOT be assigned a valid PHY as it uses an unmanaged, bit-rate
+       // PHY.  It is simplest just to use another goto, rather than
+       // nesting the two for loops in the if statement.
 
-       TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi );
+       if ( ( vendor == PCI_VENDOR_ID_COMPAQ ) &&
+            ( device == PCI_DEVICE_ID_NETFLEX_3P ) ) {
+               entry = 0;
+               phy = 0;
+               goto FINISH;
+       }
 
-       if ( hi != 0xFFFF ) {
-               priv->phy[0] = TLAN_PHY_MAX_ADDR;
-       } else {
-               priv->phy[0] = TLAN_PHY_NONE;
+       for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
+               hi = lo = 0;
+               TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &hi );
+               TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &lo );
+               id_hi[phy] = hi;
+               id_lo[phy] = lo;
+               TLAN_DBG( TLAN_DEBUG_GNRL,
+                         "TLAN: Phy %2x, hi = %hx, lo = %hx\n",
+                         phy,
+                         hi,
+                         lo
+                       );
        }
 
-       priv->phy[1] = TLAN_PHY_NONE;
        for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
-               TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control );
-               TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi );
-               TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo );
-               if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
-                       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo );
-                       if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
-                               priv->phy[1] = phy;
+               if ( ( aui == 1 ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
+                       if ( id_hi[phy] != 0xFFFF ) {
+                               TLan_MiiSync(dev->base_addr);
+                               TLan_MiiWriteReg(dev->base_addr,
+                                                phy,
+                                                MII_GEN_CTL,
+                                                MII_GC_PDOWN | 
+                                                MII_GC_LOOPBK | 
+                                                MII_GC_ISOLATE );
+
+                       }
+                       continue;
+               }
+               for ( entry = 0; TLanPhyIdTable[entry].check; entry++) {
+                       if ( ( id_hi[phy] == TLanPhyIdTable[entry].idHi ) &&
+                            ( id_lo[phy] == TLanPhyIdTable[entry].idLo ) ) {
+                               TLAN_DBG( TLAN_DEBUG_GNRL,
+                                         "TLAN: Selected Phy %hx\n",
+                                         phy
+                                       );
+                               goto FINISH;
                        }
                }
        }
 
-       if ( priv->phy[1] != TLAN_PHY_NONE ) {
-               priv->phyNum = 1;
-       } else if ( priv->phy[0] != TLAN_PHY_NONE ) {
-               priv->phyNum = 0;
-       } else {
-               printk( "TLAN:  Cannot initialize device, no PHY was found!\n" );
-       }
-
-} /* TLan_PhyDetect */
-
-
-
+       entry = 0;
+       phy = 0;
 
-void TLan_PhyPowerDown( struct device *dev )
-{
-       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u16             value;
-
-       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Powering down PHY(s).\n", dev->name );
-       value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
-       TLan_MiiSync( dev->base_addr );
-       TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
-       if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
-               TLan_MiiSync( dev->base_addr );
-               TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
+FINISH:
+       
+       if ( ( entry == 0 ) && ( phy == 0 ) ) {
+               priv->phyAddr = phy;
+               priv->phyEntry = entry;
+               priv->phyCheck = TLan_PhyNop;
+               priv->phyService = TLan_PhyNop;
+               priv->phyFlags = TLAN_PHY_BIT_RATE | 
+                                 TLAN_PHY_UNMANAGED |
+                                TLAN_PHY_ACTIVITY;
+       } else {
+               priv->phyAddr = phy;
+               priv->phyEntry = entry;
+               priv->phyCheck = TLanPhyIdTable[entry].check;
+               priv->phyService = TLanPhyIdTable[entry].service;
+               priv->phyFlags = TLanPhyIdTable[entry].flags;
        }
 
-       /* Wait for 5 jiffies (50 ms) and powerup
-        * This is abitrary.  It is intended to make sure the
-        * tranceiver settles.
-        */
-       TLan_SetTimer( dev, 5, TLAN_TIMER_PHY_PUP );
+} /* TLan_PhySelect */
 
-} /* TLan_PhyPowerDown */
 
 
 
+       /***************************************************************
+        *      TLan_PhyNop
+        *
+        *      Returns:
+        *              Nothing
+        *      Parms:
+        *              dev     A pointer to a device structure.
+        *
+        *      This function does nothing and is meant as a stand-in
+        *      for when a Check or Service function would be
+        *      meaningless.
+        *
+        **************************************************************/
 
-void TLan_PhyPowerUp( struct device *dev )
+int TLan_PhyNop( struct device *dev )
 {
-       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u16             value;
-
-       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Powering up PHY.\n", dev->name );
-       TLan_MiiSync( dev->base_addr );
-       value = MII_GC_LOOPBK;
-       TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
+       dev = NULL;
+       return 0;
 
-       /* Wait for 50 jiffies (500 ms) and reset the
-        * tranceiver.  The TLAN docs say both 50 ms and
-        * 500 ms, so do the longer, just in case
-        */
-       TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_RESET );
+} /* TLan_PhyNop */
 
-} /* TLan_PhyPowerUp */
 
 
 
+       /***************************************************************
+        *  TLan_PhyInternalCheck
+        *
+        *      Returns:
+        *              Nothing
+        *      Parms:
+        *              dev     A pointer to a device structure of the
+        *                      adapter holding the PHY to be checked.
+        *
+        *      This function resets the internal PHY on a TLAN chip.
+        *      See Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
+        *      Programmer's Guide"
+        *
+        **************************************************************/
 
-void TLan_PhyReset( struct device *dev )
+int TLan_PhyInternalCheck( struct device *dev )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u16             phy;
-       u16             value;
-
-       phy = priv->phy[priv->phyNum];
-
-       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Reseting PHY.\n", dev->name );
-       TLan_MiiSync( dev->base_addr );
-       value = MII_GC_LOOPBK | MII_GC_RESET;
-       TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value );
-       TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
-       while ( value & MII_GC_RESET ) {
-               TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value );
+       u16                             gen_ctl;
+       u32                             io;
+       u16                             phy;
+       u16                             value;
+       u8                              sio;
+
+       io = dev->base_addr;
+       phy = priv->phyAddr;
+
+       TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
+       if ( gen_ctl & MII_GC_PDOWN ) {
+               TLan_MiiSync( io );
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
+               udelay(50000);
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
+               TLan_MiiSync( io );
+       }
+
+       TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+       while ( value & MII_GC_RESET )
+               TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+
+       // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX );
+       // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
+       TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
+
+       udelay(500000);
+
+       TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+       if ( aui ) 
+               value |= TLAN_TC_AUISEL;
+       else
+               value &= ~TLAN_TC_AUISEL;
+       TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+
+       // Read Possible Latched Link Status
+       TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+       // Read Real Link Status
+               TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+       if ( ( value & MII_GS_LINK ) || aui ) {
+               priv->phyOnline = 1;
+               TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+       } else {
+               priv->phyOnline = 0;
+               TLan_DioWrite8( io, TLAN_LED_REG, 0 );
        }
-       TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 );
 
-       /* Wait for 50 jiffies (500 ms) and initialize.
-        * I don't remember why I wait this long.
-        */
-       TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_START_LINK );
+       // Enable Interrupts
+               TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+       value |= TLAN_TC_INTEN;
+       TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
 
-} /* TLan_PhyReset */
+       sio = TLan_DioRead8( io, TLAN_NET_SIO );
+       sio |= TLAN_NET_SIO_MINTEN;
+       TLan_DioWrite8( io, TLAN_NET_SIO, sio );
+                       
+       return 0;
 
+} /* TLanPhyInternalCheck */
 
 
 
-void TLan_PhyStartLink( struct device *dev )
-{
-       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u16             ability;
-       u16             control;
-       u16             data;
-       u16             phy;
-       u16             status;
-       u16             tctl;
-
-       phy = priv->phy[priv->phyNum];
-
-       TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN:  %s: Trying to activate link.\n", dev->name );
-       TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
-       if ( ( status & MII_GS_AUTONEG ) && 
-            ( priv->duplex == TLAN_DUPLEX_DEFAULT ) && 
-            ( priv->speed == TLAN_SPEED_DEFAULT ) &&
-            ( ! priv->aui ) ) {
-               ability = status >> 11;
-
-               if ( priv->speed == TLAN_SPEED_10 ) {
-                       ability &= 0x0003;
-               } else if ( priv->speed == TLAN_SPEED_100 ) {
-                       ability &= 0x001C;
-               }
 
-               if ( priv->duplex == TLAN_DUPLEX_FULL ) {
-                       ability &= 0x000A;
-               } else if ( priv->duplex == TLAN_DUPLEX_HALF ) {
-                       ability &= 0x0005;
-               }
+       /***************************************************************
+        *      TLan_PhyInternalService
+        *
+        *      Returns:
+        *              Nothing
+        *      Parms:
+        *              dev     A pointer to a device structure of the
+        *                      adapter holding the PHY to be serviced.
+        *
+        *      This function services an interrupt generated by the
+        *      internal PHY.  It can turn on/off the link LED.  See
+        *      Chap. 7, "Physical Interface (PHY)" of "ThunderLAN
+        *      Programmer's Guide".
+        *
+        **************************************************************/
 
-               TLan_MiiWriteReg( dev, phy, MII_AN_ADV, ( ability << 5 ) | 1 );
-                       TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
-               TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
-
-               /* Wait for 400 jiffies (4 sec) for autonegotiation
-                * to complete.  The max spec time is less than this
-                * but the card need additional time to start AN.
-                * .5 sec should be plenty extra.
-                */
-               printk( "TLAN:  %s: Starting autonegotiation.\n", dev->name );
-               TLan_SetTimer( dev, 400, TLAN_TIMER_PHY_FINISH_AN );
-               return;
+int TLan_PhyInternalService( struct device *dev )
+{
+       TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+       u16                     tlphy_sts;
+       u16                     gen_sts;
+       u16                     an_exp;
+       u32                     io;
+       u16                     phy;
+
+       io = dev->base_addr;
+       phy = priv->phyAddr;
+
+       TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts );
+       TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); 
+       TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); 
+       if ( ( gen_sts & MII_GS_LINK ) || aui ) {
+               priv->phyOnline = 1;
+               TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+       } else {
+               priv->phyOnline = 0;
+               TLan_DioWrite8( io, TLAN_LED_REG, 0 );
        }
 
-       if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
-               priv->phyNum = 0;
-               data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
-               TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
-               TLan_SetTimer( dev, 4, TLAN_TIMER_PHY_PDOWN );
-               return;
-       } else if ( priv->phyNum == 0 ) {
-               TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
-               if ( priv->aui ) {
-                       tctl |= TLAN_TC_AUISEL;
-               } else {
-                       tctl &= ~TLAN_TC_AUISEL;
-                       control = 0;
-                       if ( priv->duplex == TLAN_DUPLEX_FULL ) {
-                               control |= MII_GC_DUPLEX;
-                               priv->tlanFullDuplex = TRUE;
-                       }
-                       if ( priv->speed == TLAN_SPEED_100 ) {
-                               control |= MII_GC_SPEEDSEL;
-                       }
-                               TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control );
-               }
-               TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
-       }
+        if ( ( tlphy_sts & TLAN_TS_POLOK ) == 0) {
+                u16     value;
+                TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value);
+                value |= TLAN_TC_SWAPOL;
+                TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value);
+        }
 
-       /* Wait for 100 jiffies (1 sec) to give the tranceiver time
-        * to establish link.
-        */
-       TLan_SetTimer( dev, 100, TLAN_TIMER_FINISH_RESET );
+       return 0;
 
-} /* TLan_PhyStartLink */
+} /* TLan_PhyInternalService */
 
 
 
 
-void TLan_PhyFinishAutoNeg( struct device *dev )
+       /***************************************************************
+        *      TLan_PhyDp83840aCheck
+        *
+        *      Returns:
+        *              Nothing
+        *      Parms:
+        *              dev     A pointer to a device structure of the
+        *                      adapter holding the PHY to be reset.
+        *
+        *      This function resets a National Semiconductor DP83840A
+        *      10/100 Mb/s PHY device.  See National Semiconductor's
+        *      data sheet for more info.  This PHY is used on Compaq
+        *      Netelligent 10/100 cards.
+        *
+        **************************************************************/
+
+static int TLan_PhyDp83840aCheck( struct device *dev )
 {
        TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-       u16             an_adv;
-       u16             an_lpa;
-       u16             data;
-       u16             mode;
-       u16             phy;
-       u16             status;
-       
-       phy = priv->phy[priv->phyNum];
-
-       TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
-       if ( ! ( status & MII_GS_AUTOCMPLT ) ) {
-               /* Wait for 800 jiffies (8 sec) to give the process
-                * more time.  Perhaps we should fail after a while.
-                */
-               printk( "TLAN:  Giving autonegotiation more time.\n" );
-               TLan_SetTimer( dev, 800, TLAN_TIMER_PHY_FINISH_AN );
-               return;
-       }
-
-       printk( "TLAN:  %s: Autonegotiation complete.\n", dev->name );
-       TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv );
-       TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa );
-       mode = an_adv & an_lpa & 0x03E0;
-       if ( mode & 0x0100 ) {
-               priv->tlanFullDuplex = TRUE;
-       } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) {
-               priv->tlanFullDuplex = TRUE;
-       }
+       u16                     gen_ctl;
+       int                     i;
+       u32                     io;
+       u16                     phy;
+       u16                     value;
+       u8                      sio;
+
+       io = dev->base_addr;
+       phy = priv->phyAddr;
+
+       TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
+       if ( gen_ctl & MII_GC_PDOWN ) {
+               TLan_MiiSync( io );
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
+               for ( i = 0; i < 500000; i++ )
+                       SLOW_DOWN_IO;
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
+               TLan_MiiSync( io );
+       }
+
+       TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+       while ( value & MII_GC_RESET )
+               TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+
+       // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX );
+       // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
+       TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
+       TLan_MiiReadReg( io, phy, MII_AN_ADV, &value );
+       value &= ~0x0140;
+       TLan_MiiWriteReg( io, phy, MII_AN_ADV, value );
+               TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 );
+       TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 );
+
+       for ( i = 0; i < 50000; i++ )
+               SLOW_DOWN_IO;
 
-       if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) {
-               priv->phyNum = 0;
-               data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
-               TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
-               TLan_SetTimer( dev, 40, TLAN_TIMER_PHY_PDOWN );
-               return;
+/*
+       // Read Possible Latched Link Status
+       TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+       // Read Real Link Status
+       TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+       if ( value & MII_GS_LINK ) {
+               priv->phyOnline = 1;
+               TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+       } else {
+               priv->phyOnline = 0;
+               TLan_DioWrite8( io, TLAN_LED_REG, 0 );
        }
 
-       if ( priv->phyNum == 0 ) {
-               if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) {
-                       TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX );
-               }
-       }
+       // Enable Interrupts
+       TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+       value |= TLAN_TC_INTEN;
+       TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+*/
+       sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO );
+       sio &= ~TLAN_NET_SIO_MINTEN;
+       TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio );
+//     priv->phyOnline = 1;
+                       
+       return 0;
 
-       /* Wait for 10 jiffies (100 ms).  No reason in partiticular.
-        */
-       TLan_SetTimer( dev, 10, TLAN_TIMER_FINISH_RESET );
-               
-} /* TLan_PhyFinishAutoNeg */
+} /* TLan_PhyDp83840aCheck */
 
 
 
@@ -2366,10 +2268,9 @@ void TLan_PhyFinishAutoNeg( struct device *dev )
         *              1       otherwise.
         *
         *      Parms:
-        *              dev             The device structure containing
-        *                              The io address and interrupt count
-        *                              for this device.
-        *              phy             The address of the PHY to be queried.
+        *              base_port       The base IO port of the adapter in
+        *                              question.
+        *              dev             The address of the PHY to be queried.
         *              reg             The register whose contents are to be
         *                              retreived.
         *              val             A pointer to a variable to store the
@@ -2382,32 +2283,30 @@ void TLan_PhyFinishAutoNeg( struct device *dev )
         *
         **************************************************************/
 
-int TLan_MiiReadReg( struct device *dev, u16 phy, u16 reg, u16 *val )
+int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val)
 {
        u8      nack;
-       u16     sio, tmp;
-       u32     i;
+       u16 sio, tmp;
+       u32 i;
        int     err;
-       int     minten;
+       int minten;
 
        err = FALSE;
-       outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
-       sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
+       outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+       sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
 
-       if ( dev->interrupt == 0 )
-               cli();
-       dev->interrupt++;
+       cli();
 
-       TLan_MiiSync(dev->base_addr);
+       TLan_MiiSync(base_port);
 
        minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
        if ( minten )
                TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
 
-       TLan_MiiSendData( dev->base_addr, 0x1, 2 );     /* Start ( 01b ) */
-       TLan_MiiSendData( dev->base_addr, 0x2, 2 );     /* Read  ( 10b ) */
-       TLan_MiiSendData( dev->base_addr, phy, 5 );     /* Device #      */
-       TLan_MiiSendData( dev->base_addr, reg, 5 );     /* Register #    */
+       TLan_MiiSendData( base_port, 0x1, 2 );          /* Start ( 01b ) */
+       TLan_MiiSendData( base_port, 0x2, 2 );          /* Read  ( 10b ) */
+       TLan_MiiSendData( base_port, dev, 5 );          /* Device #      */
+       TLan_MiiSendData( base_port, reg, 5 );          /* Register #    */
 
 
        TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);         /* Change direction */
@@ -2443,9 +2342,7 @@ int TLan_MiiReadReg( struct device *dev, u16 phy, u16 reg, u16 *val )
 
        *val = tmp;
 
-       dev->interrupt--;
-       if ( dev->interrupt == 0 )
-               sti();
+       sti();
 
        return err;
 
@@ -2539,9 +2436,9 @@ void TLan_MiiSync( u16 base_port )
         *      Returns:
         *              Nothing
         *      Parms:
-        *              dev             The device structure for the device
-        *                              to write to.
-        *              phy             The address of the PHY to be written to.
+        *              base_port       The base IO port of the adapter in
+        *                              question.
+        *              dev             The address of the PHY to be written to.
         *              reg             The register whose contents are to be
         *                              written.
         *              val             The value to be written to the register.
@@ -2553,31 +2450,29 @@ void TLan_MiiSync( u16 base_port )
         *
         **************************************************************/
 
-void TLan_MiiWriteReg( struct device *dev, u16 phy, u16 reg, u16 val )
+void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
 {
-       u16     sio;
+       u16 sio;
        int     minten;
 
-       outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
-       sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
+       outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+       sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
 
-       if ( dev->interrupt == 0 )
-               cli();
-       dev->interrupt++;
+       cli();
 
-       TLan_MiiSync( dev->base_addr );
+       TLan_MiiSync( base_port );
 
        minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio );
        if ( minten )
                TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
 
-       TLan_MiiSendData( dev->base_addr, 0x1, 2 );     /* Start ( 01b ) */
-       TLan_MiiSendData( dev->base_addr, 0x1, 2 );     /* Write ( 01b ) */
-       TLan_MiiSendData( dev->base_addr, phy, 5 );     /* Device #      */
-       TLan_MiiSendData( dev->base_addr, reg, 5 );     /* Register #    */
+       TLan_MiiSendData( base_port, 0x1, 2 );          /* Start ( 01b ) */
+       TLan_MiiSendData( base_port, 0x1, 2 );          /* Write ( 01b ) */
+       TLan_MiiSendData( base_port, dev, 5 );          /* Device #      */
+       TLan_MiiSendData( base_port, reg, 5 );          /* Register #    */
 
-       TLan_MiiSendData( dev->base_addr, 0x2, 2 );     /* Send ACK */
-       TLan_MiiSendData( dev->base_addr, val, 16 );    /* Send Data */
+       TLan_MiiSendData( base_port, 0x2, 2 );          /* Send ACK */
+       TLan_MiiSendData( base_port, val, 16 );         /* Send Data */
 
        TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );        /* Idle cycle */
        TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
@@ -2585,15 +2480,10 @@ void TLan_MiiWriteReg( struct device *dev, u16 phy, u16 reg, u16 val )
        if ( minten )
                TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
 
-       dev->interrupt--;
-       if ( dev->interrupt == 0 )
-               sti();
+       sti();
 
 } /* TLan_MiiWriteReg */
 
-
-
-
 /*****************************************************************************
 ******************************************************************************
 
@@ -2672,7 +2562,7 @@ int TLan_EeSendByte( u16 io_base, u8 data, int stop )
        outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
        sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
 
-       /* Assume clock is low, tx is enabled; */
+       // Assume clock is low, tx is enabled;
        for ( place = 0x80; place != 0; place >>= 1 ) {
                if ( place & data )
                        TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
@@ -2688,7 +2578,7 @@ int TLan_EeSendByte( u16 io_base, u8 data, int stop )
        TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
 
        if ( ( ! err ) && stop ) {
-               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       /* STOP, raise data while clock is high */
+               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       // STOP, raise data while clock is high
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
        }
@@ -2733,7 +2623,7 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
        sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
        *data = 0;
 
-       /* Assume clock is low, tx is enabled; */
+       // Assume clock is low, tx is enabled;
        TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio );
        for ( place = 0x80; place; place >>= 1 ) {
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
@@ -2744,14 +2634,14 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
 
        TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
        if ( ! stop ) {
-               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       /* Ack = 0 */
+               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       // Ack = 0
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
        } else {
-               TLan_SetBit( TLAN_NET_SIO_EDATA, sio );         /* No ack = 1 (?) */
+               TLan_SetBit( TLAN_NET_SIO_EDATA, sio );         // No ack = 1 (?)
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
-               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       /* STOP, raise data while clock is high */
+               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       // STOP, raise data while clock is high
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
        }
@@ -2782,30 +2672,26 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
         *
         **************************************************************/
 
-int TLan_EeReadByte( struct device *dev, u8 ee_addr, u8 *data )
+int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data )
 {
        int err;
 
-       if ( dev->interrupt == 0 )
-               cli();
-       dev->interrupt++;
+       cli();
 
-       TLan_EeSendStart( dev->base_addr );
-       err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK );
+       TLan_EeSendStart( io_base );
+       err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK );
        if (err)
                return 1;
-       err = TLan_EeSendByte( dev->base_addr, ee_addr, TLAN_EEPROM_ACK );
+       err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK );
        if (err)
                return 2;
-       TLan_EeSendStart( dev->base_addr );
-       err = TLan_EeSendByte( dev->base_addr, 0xA1, TLAN_EEPROM_ACK );
+       TLan_EeSendStart( io_base );
+       err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK );
        if (err)
                return 3;
-       TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP );
+       TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP );
 
-       dev->interrupt--;
-       if ( dev->interrupt == 0 )
-               sti();
+       sti();
 
        return 0;
 
index c8f56e3e12be23df204e3f452d4b52ebaf278763..94613d3a649348f6eb1813df5e21a93a6952fb32 100644 (file)
@@ -7,7 +7,7 @@
  *  tlan.h
  *  by James Banks, james.banks@caldera.com
  *
- *  (C) 1997-1998 Caldera, Inc.
+ *  (C) 1997 Caldera, Inc.
  *
  *  This software may be used and distributed according to the terms
  *  of the GNU Public License, incorporated herein by reference.
         *
         ****************************************************************/
 
-#define FALSE                  0
-#define TRUE                   1
+#define FALSE                          0
+#define TRUE                           1
 
 #define TLAN_MIN_FRAME_SIZE    64
 #define TLAN_MAX_FRAME_SIZE    1600
 
-#define TLAN_NUM_RX_LISTS      4
-#define TLAN_NUM_TX_LISTS      8
+#define TLAN_NUM_RX_LISTS 4
+#define TLAN_NUM_TX_LISTS 8
 
-#define TLAN_IGNORE            0
-#define TLAN_RECORD            1
+#define TLAN_IGNORE    0
+#define TLAN_RECORD    1
 
 #define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk( format, ##args );
-#define TLAN_DEBUG_GNRL                0x0001
-#define TLAN_DEBUG_TX          0x0002
-#define TLAN_DEBUG_RX          0x0004 
-#define TLAN_DEBUG_LIST                0x0008
+#define TLAN_DEBUG_GNRL        0x0001
+#define TLAN_DEBUG_TX  0x0002
+#define TLAN_DEBUG_RX  0x0004 
+#define TLAN_DEBUG_LIST        0x0008
 
 
 
         *
         ****************************************************************/
                
-#define PCI_DEVICE_ID_NETELLIGENT_10                   0xAE34
-#define PCI_DEVICE_ID_NETELLIGENT_10_100               0xAE32
-#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED            0xAE35
-#define PCI_DEVICE_ID_NETFLEX_3P                       0xF130
-#define PCI_DEVICE_ID_NETFLEX_3P_BNC                   0xF150
-#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT      0xAE43
-#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL          0xAE40
-#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX             0xB011
-#define PCI_DEVICE_ID_OC_2326                          0x0014
-
-typedef struct tlan_adapter_entry {
+       /* NOTE: These have been moved to pci.h, will use them
+          eventually */
+#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
+#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
+#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35
+#define PCI_DEVICE_ID_NETFLEX_3P 0xF130
+#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43
+#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40
+#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011
+
+
+typedef struct tlan_pci_id {
        u16     vendorId;
        u16     deviceId;
-       char    *deviceLabel;
-       u32     flags;
-} TLanAdapterEntry;
-
-#define TLAN_ADAPTER_NONE              0x00000000
-#define TLAN_ADAPTER_UNMANAGED_PHY     0x00000001
-#define TLAN_ADAPTER_BIT_RATE_PHY      0x00000002
-#define TLAN_ADAPTER_USE_INTERN_10     0x00000004
-#define TLAN_ADAPTER_ACTIVITY_LED      0x00000008
-
-#define TLAN_SPEED_DEFAULT     0
-#define TLAN_SPEED_10          10
-#define TLAN_SPEED_100         100
-
-#define TLAN_DUPLEX_DEFAULT    0
-#define TLAN_DUPLEX_HALF       1
-#define TLAN_DUPLEX_FULL       2
+       char *deviceName;
+} TLanPciId;
 
 
 
@@ -134,7 +121,25 @@ typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
         ****************************************************************/
 
 #define TLAN_PHY_MAX_ADDR      0x1F
-#define TLAN_PHY_NONE          0x20
+
+#define TLAN_PHY_ACTIVITY      0x00000001
+#define TLAN_PHY_AUTONEG       0x00000002
+#define TLAN_PHY_INTS          0x00000004
+#define TLAN_PHY_BIT_RATE      0x00000008
+#define TLAN_PHY_UNMANAGED     0x00000010
+#define TLAN_PHY_INTERNAL      0x00000020
+
+
+typedef int (TLanPhyFunc)( struct device * );
+
+
+typedef struct tlan_phy_id_entry_tag {
+       u16             idHi;
+       u16             idLo;
+       TLanPhyFunc     *check;
+       TLanPhyFunc     *service;
+       u32             flags;
+} TLanPhyIdEntry;
 
 
 
@@ -159,22 +164,21 @@ typedef struct tlan_private_tag {
        u32                     txInProgress;
        u32                     txTail;
        u32                     txBusyCount;
+       u32                     phyAddr;
+       u32                     phyEntry;
        u32                     phyOnline;
+       u32                     phyFlags;
+       TLanPhyFunc             *phyCheck;
+       TLanPhyFunc             *phyService;
        u32                     timerSetAt;
        u32                     timerType;
        struct timer_list       timer;
        struct net_device_stats stats;
-       TLanAdapterEntry        *adapter;
-       u32                     adapterRev;
-       u32                     aui;
-       u32                     debug;
-       u32                     duplex;
-       u32                     phy[2];
-       u32                     phyNum;
-       u32                     sa_int;
-       u32                     speed;
+       u32                     pciEntry;
+       u8                      pciRevision;
+       u8                      pciBus;
+       u8                      pciDeviceFn;
        u8                      tlanRev;
-       u8                      tlanFullDuplex;
        char                    devName[8];
 } TLanPrivateInfo;
 
@@ -187,15 +191,10 @@ typedef struct tlan_private_tag {
         ****************************************************************/
 
 #define TLAN_TIMER_LINK                        1
-#define TLAN_TIMER_ACTIVITY            2
-#define TLAN_TIMER_PHY_PDOWN           3
-#define TLAN_TIMER_PHY_PUP             4
-#define TLAN_TIMER_PHY_RESET           5
-#define TLAN_TIMER_PHY_START_LINK      6
-#define TLAN_TIMER_PHY_FINISH_AN       7
-#define TLAN_TIMER_FINISH_RESET                8
+#define TLAN_TIMER_ACT                 2
 
-#define TLAN_TIMER_ACT_DELAY           10
+#define TLAN_TIMER_LINK_DELAY  230
+#define TLAN_TIMER_ACT_DELAY   10
 
 
 
@@ -216,29 +215,29 @@ typedef struct tlan_private_tag {
         *
         ****************************************************************/
 
-#define TLAN_HOST_CMD                  0x00
+#define TLAN_HOST_CMD          0x00
 #define        TLAN_HC_GO              0x80000000
-#define                TLAN_HC_STOP            0x40000000
+#define                TLAN_HC_STOP    0x40000000
 #define                TLAN_HC_ACK             0x20000000
-#define                TLAN_HC_CS_MASK         0x1FE00000
+#define                TLAN_HC_CS_MASK 0x1FE00000
 #define                TLAN_HC_EOC             0x00100000
 #define                TLAN_HC_RT              0x00080000
 #define                TLAN_HC_NES             0x00040000
-#define                TLAN_HC_AD_RST          0x00008000
-#define                TLAN_HC_LD_TMR          0x00004000
-#define                TLAN_HC_LD_THR          0x00002000
-#define                TLAN_HC_REQ_INT         0x00001000
-#define                TLAN_HC_INT_OFF         0x00000800
-#define                TLAN_HC_INT_ON          0x00000400
-#define                TLAN_HC_AC_MASK         0x000000FF
-#define TLAN_CH_PARM                   0x04
-#define TLAN_DIO_ADR                   0x08
-#define                TLAN_DA_ADR_INC         0x8000
-#define                TLAN_DA_RAM_ADR         0x4000
-#define TLAN_HOST_INT                  0x0A
-#define                TLAN_HI_IV_MASK         0x1FE0
-#define                TLAN_HI_IT_MASK         0x001C
-#define TLAN_DIO_DATA                  0x0C
+#define                TLAN_HC_AD_RST  0x00008000
+#define                TLAN_HC_LD_TMR  0x00004000
+#define                TLAN_HC_LD_THR  0x00002000
+#define                TLAN_HC_REQ_INT 0x00001000
+#define                TLAN_HC_INT_OFF 0x00000800
+#define                TLAN_HC_INT_ON  0x00000400
+#define                TLAN_HC_AC_MASK 0x000000FF
+#define TLAN_CH_PARM           0x04
+#define TLAN_DIO_ADR           0x08
+#define                TLAN_DA_ADR_INC 0x8000
+#define                TLAN_DA_RAM_ADR 0x4000
+#define TLAN_HOST_INT          0x0A
+#define                TLAN_HI_IV_MASK 0x1FE0
+#define                TLAN_HI_IT_MASK 0x001C
+#define TLAN_DIO_DATA          0x0C
 
 
 /* ThunderLAN Internal Register DIO Offsets */
@@ -265,7 +264,7 @@ typedef struct tlan_private_tag {
 #define                TLAN_NET_STS_MIRQ       0x80
 #define                TLAN_NET_STS_HBEAT      0x40
 #define                TLAN_NET_STS_TXSTOP     0x20
-#define                TLAN_NET_STS_RXSTOP     0x10
+#define                TLAN_NET_STS_RXSTOP 0x10
 #define                TLAN_NET_STS_RSRVD      0x0F
 #define TLAN_NET_MASK                  0x03
 #define                TLAN_NET_MASK_MASK7     0x80
@@ -284,36 +283,36 @@ typedef struct tlan_private_tag {
 #define                TLAN_NET_CFG_MTEST      0x0100
 #define                TLAN_NET_CFG_PHY_EN     0x0080
 #define                TLAN_NET_CFG_MSMASK     0x007F
-#define TLAN_MAN_TEST                  0x06
-#define TLAN_DEF_VENDOR_ID             0x08
-#define TLAN_DEF_DEVICE_ID             0x0A
-#define TLAN_DEF_REVISION              0x0C
-#define TLAN_DEF_SUBCLASS              0x0D
-#define TLAN_DEF_MIN_LAT               0x0E
-#define TLAN_DEF_MAX_LAT               0x0F
+#define TLAN_MAN_TEST          0x06
+#define TLAN_DEF_VENDOR_ID     0x08
+#define TLAN_DEF_DEVICE_ID     0x0A
+#define TLAN_DEF_REVISION      0x0C
+#define TLAN_DEF_SUBCLASS      0x0D
+#define TLAN_DEF_MIN_LAT       0x0E
+#define TLAN_DEF_MAX_LAT       0x0F
 #define TLAN_AREG_0                    0x10
 #define TLAN_AREG_1                    0x16
 #define TLAN_AREG_2                    0x1C
 #define TLAN_AREG_3                    0x22
 #define TLAN_HASH_1                    0x28
 #define TLAN_HASH_2                    0x2C
-#define TLAN_GOOD_TX_FRMS              0x30
-#define TLAN_TX_UNDERUNS               0x33
-#define TLAN_GOOD_RX_FRMS              0x34
-#define TLAN_RX_OVERRUNS               0x37
-#define TLAN_DEFERRED_TX               0x38
-#define TLAN_CRC_ERRORS                        0x3A
-#define TLAN_CODE_ERRORS               0x3B
-#define TLAN_MULTICOL_FRMS             0x3C
-#define TLAN_SINGLECOL_FRMS            0x3E
-#define TLAN_EXCESSCOL_FRMS            0x40
-#define TLAN_LATE_COLS                 0x41
-#define TLAN_CARRIER_LOSS              0x42
-#define TLAN_ACOMMIT                   0x43
-#define TLAN_LED_REG                   0x44
-#define                TLAN_LED_ACT            0x10
-#define                TLAN_LED_LINK           0x01
-#define TLAN_BSIZE_REG                 0x45
+#define TLAN_GOOD_TX_FRMS      0x30
+#define TLAN_TX_UNDERUNS       0x33
+#define TLAN_GOOD_RX_FRMS      0x34
+#define TLAN_RX_OVERRUNS       0x37
+#define TLAN_DEFERRED_TX       0x38
+#define TLAN_CRC_ERRORS                0x3A
+#define TLAN_CODE_ERRORS       0x3B
+#define TLAN_MULTICOL_FRMS     0x3C
+#define TLAN_SINGLECOL_FRMS    0x3E
+#define TLAN_EXCESSCOL_FRMS    0x40
+#define TLAN_LATE_COLS         0x41
+#define TLAN_CARRIER_LOSS      0x42
+#define TLAN_ACOMMIT           0x43
+#define TLAN_LED_REG           0x44
+#define                TLAN_LED_ACT    0x10
+#define                TLAN_LED_LINK   0x01
+#define TLAN_BSIZE_REG         0x45
 #define TLAN_MAX_RX                    0x46
 #define TLAN_INT_DIS                   0x48
 #define                TLAN_ID_TX_EOC          0x04
@@ -328,11 +327,11 @@ typedef struct tlan_private_tag {
 
 #define TLAN_INT_NONE                  0x0000
 #define TLAN_INT_TX_EOF                        0x0001
-#define TLAN_INT_STAT_OVERFLOW         0x0002
+#define TLAN_INT_STAT_OVERFLOW 0x0002
 #define TLAN_INT_RX_EOF                        0x0003
 #define TLAN_INT_DUMMY                 0x0004
 #define TLAN_INT_TX_EOC                        0x0005
-#define TLAN_INT_STATUS_CHECK          0x0006
+#define TLAN_INT_STATUS_CHECK  0x0006
 #define TLAN_INT_RX_EOC                        0x0007
 
 
@@ -341,7 +340,7 @@ typedef struct tlan_private_tag {
 
 /* Generic MII/PHY Registers */
 
-#define MII_GEN_CTL                    0x00
+#define MII_GEN_CTL                            0x00
 #define        MII_GC_RESET            0x8000
 #define                MII_GC_LOOPBK           0x4000
 #define                MII_GC_SPEEDSEL         0x2000
@@ -352,7 +351,7 @@ typedef struct tlan_private_tag {
 #define                MII_GC_DUPLEX           0x0100
 #define                MII_GC_COLTEST          0x0080
 #define                MII_GC_RESERVED         0x007F
-#define MII_GEN_STS                    0x01
+#define MII_GEN_STS                            0x01
 #define                MII_GS_100BT4           0x8000
 #define                MII_GS_100BTXFD         0x4000
 #define                MII_GS_100BTXHD         0x2000
@@ -360,19 +359,19 @@ typedef struct tlan_private_tag {
 #define                MII_GS_10BTHD           0x0800
 #define                MII_GS_RESERVED         0x07C0
 #define                MII_GS_AUTOCMPLT        0x0020
-#define                MII_GS_RFLT             0x0010
+#define                MII_GS_RFLT                     0x0010
 #define                MII_GS_AUTONEG          0x0008
-#define                MII_GS_LINK             0x0004
+#define                MII_GS_LINK                     0x0004
 #define                MII_GS_JABBER           0x0002
 #define                MII_GS_EXTCAP           0x0001
 #define MII_GEN_ID_HI                  0x02
 #define MII_GEN_ID_LO                  0x03
-#define        MII_GIL_OUI             0xFC00
+#define        MII_GIL_OUI                     0xFC00
 #define        MII_GIL_MODEL           0x03F0
 #define        MII_GIL_REVISION        0x000F
-#define MII_AN_ADV                     0x04
-#define MII_AN_LPA                     0x05
-#define MII_AN_EXP                     0x06
+#define MII_AN_ADV                             0x04
+#define MII_AN_LPA                             0x05
+#define MII_AN_EXP                             0x06
 
 /* ThunderLAN Specific MII/PHY Registers */
 
@@ -395,7 +394,6 @@ typedef struct tlan_private_tag {
 #define                TLAN_TS_RESERVED        0x0FFF
 
 
-#define CIRC_INC( a, b ) if ( ++a >= b ) a = 0
 
 /* Routines to access internal registers. */
 
@@ -458,7 +456,7 @@ inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
 
 
 
-#if 0
+
 inline void TLan_ClearBit(u8 bit, u16 port)
 {
        outb_p(inb_p(port) & ~bit, port);
@@ -479,11 +477,6 @@ inline void TLan_SetBit(u8 bit, u16 port)
 {
        outb_p(inb_p(port) | bit, port);
 }
-#endif
-
-#define TLan_ClearBit( bit, port )     outb_p(inb_p(port) & ~bit, port)
-#define TLan_GetBit( bit, port )       ((int) (inb_p(port) & bit))
-#define TLan_SetBit( bit, port )       outb_p(inb_p(port) | bit, port)
 
 
 inline u32     xor( u32 a, u32 b )
index 99d3a5f8f8bf266685072239b59987f3b1a4ada2..c4fe635e671178a677615ad4d8012fc76751a4b1 100644 (file)
        http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
 */
 
-static const char *version = "tulip.c:v0.87K 1/22/98 becker@cesdis.gsfc.nasa.gov\n";
+#define SMP_CHECK
+static const char version[] = "tulip.c:v0.88 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values. */
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 25;
 
 #define MAX_UNITS 8
 /* Used to pass the full-duplex flag, etc. */
@@ -45,9 +46,9 @@ static int reverse_probe = 0;
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
 #ifdef __alpha__
-static const rx_copybreak = 1518;
+static int rx_copybreak = 1518;
 #else
-static const rx_copybreak = 100;
+static int rx_copybreak = 100;
 #endif
 
 /* The following example shows how to always use the 10base2 port. */
@@ -137,6 +138,7 @@ char kernel_version[] = UTS_RELEASE;
 #endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
+#define hard_smp_processor_id() smp_processor_id()
 #define test_and_set_bit(val, addr) set_bit(val, addr)
 #endif
 
@@ -168,7 +170,7 @@ I. Board Compatibility
 
 This device driver is designed for the DECchip "Tulip", Digital's
 single-chip ethernet controllers for PCI.  Supported members of the family
-are the 21040, 21041, 21140, 21140A and 21142.  These chips are used on
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  These chips are used on
 many PCI boards including the SMC EtherPower series.
 
 
@@ -275,33 +277,49 @@ register of the set CSR12-15 written.  Hmmm, now how is that possible?  */
 
 #ifndef PCI_VENDOR_ID_MXIC
 #define        PCI_VENDOR_ID_MXIC              0x10d9
-#define PCI_DEVICE_ID_PMAC             0x0200
+#define PCI_DEVICE_ID_MX98713  0x0512
+#define PCI_DEVICE_ID_MX98715  0x0531
+#define PCI_DEVICE_ID_MX98725  0x0531
 #endif
 
 /* The rest of these values should never change. */
 
 static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
 
 /* A table describing the chip types. */
-enum tbl_flag { HAS_MII=1, };
+enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2};
 static struct tulip_chip_table {
-  int device_id;
-  char *chip_name;
-  int flags;
-  void (*media_timer)(unsigned long data);
+       int device_id;
+       char *chip_name;
+       int io_size;
+       int valid_intrs;                        /* CSR7 interrupt enable settings */
+       int flags;
+       void (*media_timer)(unsigned long data);
 } tulip_tbl[] = {
-  { PCI_DEVICE_ID_DEC_TULIP, "Digital DC21040 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DC21041 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", HAS_MII,
-               tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", HAS_MII,
-               tulip_timer },
-  { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 0, tulip_timer },
-  { PCI_DEVICE_ID_PMAC, "Macronix 98713 PMAC", HAS_MII, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP, "Digital DC21040 Tulip", 128, 0x0001ebef,
+       0, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DC21041 Tulip", 128, 0x0001ebef,
+       HAS_MEDIA_TABLE, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 128, 0x0001ebef,
+       HAS_MII | HAS_MEDIA_TABLE, tulip_timer },
+  { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 256, 0x0801fbff,
+       HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
+  { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+       0, pnic_timer },
+  { PCI_DEVICE_ID_MX98713, "Macronix 98713 PMAC", 128, 0x0001ebef,
+       HAS_MII | HAS_MEDIA_TABLE, tulip_timer /* Tulip-like! */ },
+  { PCI_DEVICE_ID_MX98715, "Macronix 98715 PMAC", 256, 0x0001ebef,
+       HAS_MEDIA_TABLE, mxic_timer },
+  { PCI_DEVICE_ID_MX98725, "Macronix 98725 PMAC", 256, 0x0001ebef,
+       HAS_MEDIA_TABLE, mxic_timer },
   {0, 0, 0, 0},
 };
 /* This matches the table above. */
-enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, LC82C168, MX98713};
+enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+                        LC82C168, MX98713, MX98715, MX98725};
 
 static const char * const medianame[] = {
   "10baseT", "10base2", "AUI", "100baseTx",
@@ -335,8 +353,7 @@ enum status_bits {
        TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
        NormalIntr=0x10000, AbnormalIntr=0x8000,
        RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
-       TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02,
-       TxIntr=0x01,
+       TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
 };
 
 /* The Tulip Rx and Tx buffer descriptors. */
@@ -393,6 +410,9 @@ struct tulip_private {
 #endif
        struct timer_list timer;        /* Media selection timer. */
        int interrupt;                          /* In-interrupt flag. */
+#ifdef SMP_CHECK
+       int smp_proc_id;                        /* Which processor in IRQ handler. */
+#endif
        unsigned int cur_rx, cur_tx;            /* The next free ring entry */
        unsigned int dirty_rx, dirty_tx;        /* The ring entries to be free()ed. */
        unsigned int tx_full:1;                         /* The Tx queue is full. */
@@ -409,11 +429,12 @@ struct tulip_private {
        signed char phys[4], mii_cnt;           /* MII device addresses. */
        struct mediatable *mtable;
        int cur_index;                                          /* Current media index. */
-       unsigned char pci_bus, pci_device_fn;
+       unsigned char pci_bus, pci_dev_fn;
        int pad0, pad1;                                         /* Used for 8-byte alignment */
 };
 
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,
+                                                                  struct device *dev, int ioaddr,
                                                                   int chip_id, int options);
 static void parse_eeprom(struct device *dev);
 static int read_eeprom(int ioaddr, int location);
@@ -429,6 +450,9 @@ static int tulip_rx(struct device *dev);
 static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
 static struct enet_statistics *tulip_get_stats(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
 #ifdef NEW_MULTICAST
 static void set_rx_mode(struct device *dev);
 #else
@@ -437,10 +461,8 @@ static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
 
 \f
 
-#ifdef MODULE
 /* A list of all installed Tulip devices, for removing the driver module. */
 static struct device *root_tulip_dev = NULL;
-#endif
 
 /* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
    but now receives directly into full-sized skbuffs that are allocated
@@ -462,7 +484,6 @@ int tulip_probe(struct device *dev)
                unsigned char pci_bus, pci_device_fn;
 
                for (;pci_index < 0xff; pci_index++) {
-                       unsigned char pci_irq_line;
                        u16 vendor, device, pci_command, new_command;
                        u32 pci_ioaddr;
                        int chip_idx = 0;
@@ -479,8 +500,6 @@ int tulip_probe(struct device *dev)
                                                                         PCI_VENDOR_ID, &vendor);
                        pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                         PCI_DEVICE_ID, &device);
-                       pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                                                        PCI_INTERRUPT_LINE, &pci_irq_line);
                        pcibios_read_config_dword(pci_bus, pci_device_fn,
                                                                          PCI_BASE_ADDRESS_0, &pci_ioaddr);
                        /* Remove I/O space marker in bit 0. */
@@ -493,21 +512,22 @@ int tulip_probe(struct device *dev)
                        if (vendor == PCI_VENDOR_ID_LITEON)
                                device = PCI_DEVICE_ID_PNIC_X;
                        else if (vendor == PCI_VENDOR_ID_MXIC)
-                               device = PCI_DEVICE_ID_PMAC;
+                               device = PCI_DEVICE_ID_MX98713;
 
                        for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
                                if (device == tulip_tbl[chip_idx].device_id)
                                        break;
                        if (tulip_tbl[chip_idx].chip_name == 0) {
-                               printk(KERN_INFO "Unknown Digital PCI ethernet chip type"
-                                          " %4.4x"" detected: not configured.\n", device);
+                               printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
+                                          " %4.4x %4.4x"" detected: not configured.\n",
+                                          vendor, device);
                                continue;
                        }
                        if (tulip_debug > 2)
-                               printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n",
-                                          pci_ioaddr, pci_irq_line);
+                               printk(KERN_DEBUG "Found %s at I/O %#x.\n",
+                                          tulip_tbl[chip_idx].chip_name, pci_ioaddr);
 
-                       if (check_region(pci_ioaddr, TULIP_TOTAL_SIZE))
+                       if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
                                continue;
 
                        pcibios_read_config_word(pci_bus, pci_device_fn,
@@ -521,8 +541,8 @@ int tulip_probe(struct device *dev)
                                                                                  PCI_COMMAND, new_command);
                        }
 
-                       dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
-                                                cards_found);
+                       dev = tulip_probe1(pci_bus, pci_device_fn, dev,
+                                                          pci_ioaddr, chip_idx, cards_found);
 
                        /* Get and check the bus-master and latency values. */
                        if (dev) {
@@ -552,7 +572,8 @@ int tulip_probe(struct device *dev)
        return cards_found ? 0 : -ENODEV;
 }
 
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
+                                                                  struct device *dev, int ioaddr,
                                                                   int chip_id, int board_idx)
 {
        static int did_version = 0;                     /* Already printed version info. */
@@ -560,6 +581,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
        /* See note below on the multiport cards. */
        static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
        static int last_irq = 0;
+       u8 pci_irq_line;
        int i;
        unsigned short sum;
 
@@ -568,13 +590,15 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
 
        dev = init_etherdev(dev, 0);
 
+       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                                        PCI_INTERRUPT_LINE, &pci_irq_line);
        printk(KERN_INFO "%s: %s at %#3x,",
                   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
 
        /* Stop the chip's Tx and Rx processes. */
        outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
        /* Clear the missed-packet counter. */
-       (volatile)inl(ioaddr + CSR8);
+       (volatile int)inl(ioaddr + CSR8);
 
        if (chip_id == DC21041) {
                if (inl(ioaddr + CSR9) & 0x8000) {
@@ -648,30 +672,31 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                        dev->dev_addr[i] = last_phys_addr[i];
                dev->dev_addr[i] = last_phys_addr[i] + 1;
 #if defined(__i386__)          /* This BIOS bug doesn't exist on Alphas. */
-               irq = last_irq;
+               pci_irq_line = last_irq;
 #endif
        }
        for (i = 0; i < 6; i++)
                printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
-       printk(", IRQ %d.\n", irq);
-       last_irq = irq;
+       printk(", IRQ %d.\n", pci_irq_line);
+       last_irq = pci_irq_line;
 
        /* We do a request_region() only to register /proc/ioports info. */
+       /* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
        request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name);
 
        dev->base_addr = ioaddr;
-       dev->irq = irq;
+       dev->irq = pci_irq_line;
 
        /* Make certain the data structures are quadword aligned. */
        tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
        memset(tp, 0, sizeof(*tp));
        dev->priv = tp;
 
-#ifdef MODULE
        tp->next_module = root_tulip_dev;
        root_tulip_dev = dev;
-#endif
 
+       tp->pci_bus = pci_bus;
+       tp->pci_dev_fn = pci_device_fn;
        tp->chip_id = chip_id;
 
 #ifdef TULIP_FULL_DUPLEX
@@ -688,7 +713,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
        /* The lower four bits are the media type. */
        if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
                tp->default_port = options[board_idx] & 15;
-               if ((options[board_idx]&16) || full_duplex[board_idx]>0)
+               if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
                        tp->full_duplex = 1;
                if (mtu[board_idx] > 0)
                        dev->mtu = mtu[board_idx];
@@ -704,7 +729,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                tp->full_duplex_lock = 1;
 
        /* This is logically part of probe1(), but too complex to write inline. */
-       if (chip_id != DC21040  &&  chip_id != LC82C168)
+       if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
                parse_eeprom(dev);
 
        if (media_cap[tp->default_port] & MediaIsMII) {
@@ -730,7 +755,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                                printk(KERN_INFO "%s:  MII transceiver found at MDIO address "
                                           "%d, config %4.4x status %4.4x.\n",
                                           dev->name, phy, mii_reg0, mii_status);
-                               if (media_cap[tp->default_port] & MediaIsMII) {
+                               if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
                                        printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
                                                   " previously advertising %4.4x.\n",
                                                   dev->name, reg4, phy, mdio_read(ioaddr, phy, 4));
@@ -755,6 +780,9 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
        dev->hard_start_xmit = &tulip_start_xmit;
        dev->stop = &tulip_close;
        dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+       dev->do_ioctl = &private_ioctl;
+#endif
 #ifdef HAVE_MULTICAST
        dev->set_multicast_list = &set_rx_mode;
 #endif
@@ -772,15 +800,28 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                outl(0x00000000, ioaddr + CSR13);
                outl(0x00000004, ioaddr + CSR13);
                break;
+       case DC21140: default:
+               if (tp->mtable)
+                       outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+               break;
+       case DC21142:
+               outl(0x82420200, ioaddr + CSR6);
+               outl(0x0001, ioaddr + CSR13);
+               outl(0x0003FFFF, ioaddr + CSR14);
+               outl(0x0008, ioaddr + CSR15);
+               outl(0x0001, ioaddr + CSR13);
+               outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+               break;
        case LC82C168:
                outl(0x00420000, ioaddr + CSR6);
                outl(0x30, ioaddr + CSR12);
                outl(0x0001F078, ioaddr + 0xB8);
                outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
                break;
-       case DC21140:  case DC21142: case MX98713: default:
-               if (tp->mtable)
-                       outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+       case MX98713: case MX98715: case MX98725:
+               outl(0x00000000, ioaddr + CSR6);
+               outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+               outl(0x00000001, ioaddr + CSR13);
                break;
        }
 
@@ -819,7 +860,7 @@ static struct fixups {
   {0, 0, 0, 0, {}}};
 
 static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
- "21142 non-MII PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
 
 #define EEPROM_SIZE 128
 #if defined(__i386__)
@@ -833,7 +874,7 @@ static void parse_eeprom(struct device *dev)
        /* The last media info list parsed, for multiport boards.  */
        static struct mediatable *last_mediatable = NULL;
        static unsigned char *last_ee_data = NULL;
-       static controller_index = 0;
+       static int controller_index = 0;
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        int ioaddr = dev->base_addr;
        unsigned char *ee_data = tp->eeprom;
@@ -959,6 +1000,8 @@ subsequent_board:
                                leaf->type = 0;
                                leaf->media = p[0] & 0x3f;
                                leaf->leafdata = p;
+                               if ((p[2] & 0x61) == 0x01)      /* Bogus, but Znyx boards do it. */
+                                       mtable->has_mii = 1;
                                p += 4;
                        } else {
                                leaf->type = p[1];
@@ -1168,7 +1211,7 @@ tulip_open(struct device *dev)
        /* When a module we don't have 'x86' to check. */
        outl(0x01A00000 | 0x4800, ioaddr + CSR0);
 #else
-#if (LINUX_VERSION_CODE > 0x20172)
+#if (LINUX_VERSION_CODE > 0x2014c)
 #define x86 boot_cpu_data.x86
 #endif
        outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
@@ -1183,8 +1226,7 @@ tulip_open(struct device *dev)
 #endif
 
 #ifdef SA_SHIRQ
-       if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ,
-                                       tulip_tbl[tp->chip_id].chip_name, dev)) {
+       if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
                return -EAGAIN;
        }
 #else
@@ -1232,7 +1274,7 @@ tulip_open(struct device *dev)
        outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
 
        if (dev->if_port == 0)
-         dev->if_port = tp->default_port;
+               dev->if_port = tp->default_port;
        if (tp->chip_id == DC21041  &&  dev->if_port > 4)
                /* Invalid: Select initial TP, autosense, autonegotiate.  */
                dev->if_port = 4;
@@ -1263,9 +1305,16 @@ tulip_open(struct device *dev)
          ;
 media_picked:
 
-       tp->cur_index = i;
        tp->csr6 = 0;
-       select_media(dev, 1);
+       tp->cur_index = i;
+       if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
+               tp->csr6 = 0x82420200;
+               outl(0x0003FFFF, ioaddr + CSR14);
+               outl(0x0008, ioaddr + CSR15);
+               outl(0x0001, ioaddr + CSR13);
+               outl(0x1301, ioaddr + CSR12);
+       } else
+               select_media(dev, 1);
 
        /* Start the chip's Tx to process setup frame. */
        outl(tp->csr6, ioaddr + CSR6);
@@ -1275,9 +1324,8 @@ media_picked:
        tp->interrupt = 0;
        dev->start = 1;
 
-
        /* Enable interrupts by setting the interrupt mask. */
-       outl(0x0001ebef, ioaddr + CSR7);
+       outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
        outl(tp->csr6 | 0x2002, ioaddr + CSR6);
        outl(0, ioaddr + CSR2);         /* Rx poll demand */
 
@@ -1289,9 +1337,9 @@ media_picked:
        /* Set the timer to switch to check for link beat and perhaps switch
           to an alternate media type. */
        init_timer(&tp->timer);
-       tp->timer.expires = RUN_AT((24*HZ)/10);                 /* 2.4 sec. */
+       tp->timer.expires = RUN_AT(5*HZ);
        tp->timer.data = (unsigned long)dev;
-       tp->timer.function = &tulip_timer;                              /* timer handler */
+       tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
        add_timer(&tp->timer);
 
        return 0;
@@ -1335,18 +1383,22 @@ static void select_media(struct device *dev, int startup)
                                outl(setup[1], ioaddr + CSR14);
                                outl(setup[2], ioaddr + CSR15);
                                outl(setup[0], ioaddr + CSR13);
-                               for (i = 0; i < 3; i++)
+                               for (i = 0; i < 3; i++)                 /* Re-fill setup[]  */
                                        setup[i] = get_u16(&p[i*2 + 7]);
-                       } else {
+                       } else if (dev->if_port <= 4) {
                                outl(0, ioaddr + CSR13);
                                outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
                                outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
                                outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+                       } else {
+                               outl(0, ioaddr + CSR14);
+                               outl(8, ioaddr + CSR15);
+                               outl(0, ioaddr + CSR13);
                        }
                        outl(setup[0]<<16, ioaddr + CSR15);     /* Direction */
                        outl(setup[1]<<16, ioaddr + CSR15);     /* Data */
                        if (mleaf->type == 4)
-                               new_csr6 = 0x02020000 | ((setup[2] & 0x71) << 18);
+                               new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
                        else
                                new_csr6 = 0x82420000;
                        break;
@@ -1537,34 +1589,6 @@ static void tulip_timer(unsigned long data)
                  break;
                }
                break;
-       case LC82C168: {
-               int phy_reg = inl(ioaddr + 0xB8);
-               if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
-                                  dev->name, phy_reg, inl(ioaddr + CSR5));
-               if (phy_reg & 0x04000000) {     /* Remote link fault */
-                       /*outl(0x0201F078, ioaddr + 0xB8);*/
-                       next_tick = (24*HZ)/10;
-               } else
-                       next_tick = 10*HZ;
-               if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
-                       if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
-                                          "CSR5 %8.8x, PHY %3.3x.\n",
-                                          dev->name, medianame[dev->if_port], csr12,
-                                          inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
-                       if (dev->if_port == 0) {
-                               dev->if_port = 3;
-                       } else
-                               dev->if_port = 0;
-                       next_tick = (24*HZ)/10;
-                       select_media(dev, 0);
-                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-                       dev->trans_start = jiffies;
-               }
-               break;
-       }
        case DC21140:  case DC21142: case MX98713: default: {
                struct medialeaf *mleaf;
                unsigned char *p;
@@ -1582,83 +1606,105 @@ static void tulip_timer(unsigned long data)
                p = mleaf->leafdata;
                switch (mleaf->type) {
                case 0: case 4: {
-               /* Type 0 non-MII or #4 SYM transceiver.  Check the link beat bit. */
-                 s8 bitnum = p[mleaf->type == 4 ? 5 : 2];
-                 if (tulip_debug > 2)
-                         printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is"
-                                        " %d, expecting %d.\n",
-                                        dev->name, csr12, (bitnum >> 1) & 7,
-                                        (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
-                                        (bitnum >= 0));
-                 /* Check that the specified bit has the proper value. */
-                 if ((bitnum < 0) !=
-                         ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
-                         if (tulip_debug > 1)
-                                 printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
-                                                medianame[mleaf->media]);
-                         break;
-                 }
-                 if (tp->medialock)
-                         break;
+                       /* Type 0 serial or 4 SYM transceiver.  Check the link beat bit. */
+                       int offset = mleaf->type == 4 ? 5 : 2;
+                       s8 bitnum = p[offset];
+                       if (p[offset+1] & 0x80) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_DEBUG"%s: Transceiver monitor tick "
+                                                  "CSR12=%#2.2x, no media sense.\n",
+                                                  dev->name, csr12);
+                               if (mleaf->type == 4) {
+                                       if (mleaf->media == 3 && (csr12 & 0x02))
+                                               goto select_next_media;
+                               }
+                               break;
+                       }
+                       if (tulip_debug > 2)
+                               printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+                                          " bit %d is %d, expecting %d.\n",
+                                          dev->name, csr12, (bitnum >> 1) & 7,
+                                          (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+                                          (bitnum >= 0));
+                       /* Check that the specified bit has the proper value. */
+                       if ((bitnum < 0) !=
+                               ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+                                                  medianame[mleaf->media]);
+                               if ((p[2] & 0x61) == 0x01)      /* Bogus Znyx board. */
+                                       goto actually_mii;
+                               break;
+                       }
+                       if (tp->medialock)
+                               break;
          select_next_media:
-                 if (--tp->cur_index < 0) {
-                       /* We start again, but should instead look for default. */
-                       tp->cur_index = tp->mtable->leafcount - 1;
-                 }
-                 dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
-                 if (media_cap[dev->if_port] & MediaIsFD)
-                       goto select_next_media; /* Skip FD entries. */
-                 if (tulip_debug > 1)
-                         printk(KERN_DEBUG "%s: No link beat on media %s,"
-                                        " trying transceiver type %s.\n",
-                                        dev->name, medianame[mleaf->media & 15],
-                                        medianame[tp->mtable->mleaf[tp->cur_index].media]);
-                 select_media(dev, 0);
-                 /* Restart the transmit process. */
-                 outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                 outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-                 next_tick = (24*HZ)/10;
-                 break;
-         }
-         case 1:  case 3:              /* 21140, 21142 MII */
-                 {
-                         int mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
-                         int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
-                         printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
-                                        "%4.4x, CSR12 %2.2x, %cD.\n",
-                                        dev->name, mii_reg1, mii_reg5, csr12,
-                                        tp->full_duplex ? 'F' : 'H');
-                         if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0) {
-                                 int new_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
-                                 if ((new_reg1 & 0x0004) == 0)
-                                         printk(KERN_INFO "%s: No link beat on the MII interface,"
-                                                        " status then %4.4x now %4.4x.\n",
-                                                        dev->name, mii_reg1, new_reg1);
+                       if (--tp->cur_index < 0) {
+                               /* We start again, but should instead look for default. */
+                               tp->cur_index = tp->mtable->leafcount - 1;
+                       }
+                       dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+                       if (media_cap[dev->if_port] & MediaIsFD)
+                               goto select_next_media; /* Skip FD entries. */
+                       if (tulip_debug > 1)
+                               printk(KERN_DEBUG "%s: No link beat on media %s,"
+                                          " trying transceiver type %s.\n",
+                                          dev->name, medianame[mleaf->media & 15],
+                                          medianame[tp->mtable->mleaf[tp->cur_index].media]);
+                       select_media(dev, 0);
+                       /* Restart the transmit process. */
+                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+                       next_tick = (24*HZ)/10;
+                       break;
+               }
+               case 1:  case 3: {              /* 21140, 21142 MII */
+                       int mii_reg1, mii_reg5;
+               actually_mii:
+                       mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
+                       mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+                       if (tulip_debug > 1)
+                               printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+                                          "%4.4x, CSR12 %2.2x, %cD.\n",
+                                          dev->name, mii_reg1, mii_reg5, csr12,
+                                          tp->full_duplex ? 'F' : 'H');
+                       if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0) {
+                               int new_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
+                               if ((new_reg1 & 0x0004) == 0)
+                                       printk(KERN_INFO "%s: No link beat on the MII interface,"
+                                                  " status then %4.4x now %4.4x.\n",
+                                                  dev->name, mii_reg1, new_reg1);
 #ifdef notyet
-                                 goto select_next_media;
-#endif
-                         }
-                         if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
-                                 ;                             /* No MII device or no link partner report */
-                         else if (tp->full_duplex_lock)
-                                 ;
-                         else if ((mii_reg5 & 0x0100) != 0
-                                          || (mii_reg5 & 0x00C0) == 0x0040) {
-                                 /* 100baseTx-FD  or  10T-FD, but not 100-HD */
-                                 if (tp->full_duplex == 0) {
-                                         tp->full_duplex = 1;
-                                         tp->csr6 |= 0x0200;
-                                         outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                                         outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-                                 }
-                                 if (tulip_debug > 0) /* Gurppp, should be >1 */
-                                         printk(KERN_INFO "%s: Setting %s-duplex based on MII"
-                                                        " Xcvr #%d parter capability of %4.4x.\n",
-                                                        dev->name, tp->full_duplex ? "full" : "half",
-                                                        tp->phys[0], mii_reg5);
-                         }
-                 }
-         break;
+                               goto select_next_media;
+#endif
+                       }
+                       if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
+                               ;                               /* No MII device or no link partner report */
+                       else if (tp->full_duplex_lock)
+                               ;
+                       else {
+                               int negotiated = mii_reg5 & tp->advertising[0];
+                               int duplex = ((negotiated & 0x0100) != 0
+                                                         || (negotiated & 0x00C0) == 0x0040);
+                               /* 100baseTx-FD  or  10T-FD, but not 100-HD */
+                               if (tp->full_duplex != duplex) {
+                                       tp->full_duplex = duplex;
+                                       if (tp->full_duplex)
+                                               tp->csr6 |= 0x0200;
+                                       else
+                                               tp->csr6 &= ~0x0200;
+                                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+                                       if (tulip_debug > 0) /* Gurppp, should be >1 */
+                                               printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+                                                          " Xcvr #%d parter capability of %4.4x.\n",
+                                                          dev->name, tp->full_duplex ? "full" : "half",
+                                                          tp->phys[0], mii_reg5);
+                               }
+                       }
+                       next_tick = 60*HZ;
+                       break;
+               }
                case 2:                                 /* 21142 serial block has no link beat. */
                default:
                        break;
@@ -1672,6 +1718,193 @@ static void tulip_timer(unsigned long data)
        }
 }
 
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+   of available transceivers.  */
+static void t21142_timer(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int csr12 = inl(ioaddr + CSR12);
+       int next_tick = 60*HZ;
+       int new_csr6 = 0;
+
+       if (tulip_debug > 1)
+               printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+                          dev->name, csr12, medianame[dev->if_port]);
+       if (dev->if_port == 3) {
+               if (csr12 & 2) {                /* No 100mbps link beat, revert to 10mbps. */
+                       new_csr6 = 0x82420200;
+                       outl(new_csr6, ioaddr + CSR6);
+                       outl(0x0000, ioaddr + CSR13);
+                       outl(0x0003FFFF, ioaddr + CSR14);
+                       outl(0x0008, ioaddr + CSR15);
+                       outl(0x0001, ioaddr + CSR13);
+                       outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+               }
+       } else if ((csr12 & 0x7000) != 0x5000) {
+               /* Negotiation failed.  Search media types. */
+               if (tulip_debug > 1)
+                       printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+                                  dev->name, csr12);
+               if (!(csr12 & 4)) {             /* 10mbps link beat good. */
+                       new_csr6 = 0x82420000;
+                       dev->if_port = 0;
+                       outl(0, ioaddr + CSR13);
+                       outl(0x0003FFFF, ioaddr + CSR14);
+                       outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+                       outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+               } else if (csr12 & 0x100) {
+                       new_csr6 = 0x82420200;
+                       dev->if_port = 2;
+                       outl(0, ioaddr + CSR13);
+                       outl(0x0003FFFF, ioaddr + CSR14);
+                       outl(0x0008, ioaddr + CSR15);
+                       outl(0x0001, ioaddr + CSR13);
+               } else {
+                       /* Select 100mbps port to check for link beat. */
+                       new_csr6 = 0x83860000;
+                       dev->if_port = 3;
+                       outl(0, ioaddr + CSR13);
+                       outl(0x0003FF7F, ioaddr + CSR14);
+                       outl(8, ioaddr + CSR15);
+                       outl(1, ioaddr + CSR13);
+               }
+               if (tulip_debug > 1)
+                       printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+                                  dev->name, medianame[dev->if_port]);
+               if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+                       tp->csr6 &= 0x00D5;
+                       tp->csr6 |= new_csr6;
+                       outl(0x0301, ioaddr + CSR12);
+                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               }
+       }
+       tp->timer.expires = RUN_AT(next_tick);
+       add_timer(&tp->timer);
+}
+
+static void t21142_lnk_change( struct device *dev)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int csr12 = inl(ioaddr + CSR12);
+
+       if (tulip_debug > 1)
+               printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
+                          dev->name, csr12, inl(ioaddr + CSR5));
+
+       if ((csr12 & 0x7000) == 0x5000) {
+               if (csr12 & 0x01800000) {
+                       /* Switch to 100mbps mode. */
+                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                       if (csr12 & 0x01000000) {
+                               dev->if_port = 5;
+                               tp->csr6 = 0x83860200;
+                       } else {
+                               dev->if_port = 3;
+                               tp->csr6 = 0x83860000;
+                       }
+                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               } /* Else 10baseT-FD is handled automatically. */
+       } else if (dev->if_port == 3) {
+               if (!(csr12 & 2))
+                       printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
+                                  dev->name);
+               else
+                       dev->if_port = 0;
+       } else if (dev->if_port == 0) {
+               if (!(csr12 & 4))
+                       printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+                                  dev->name);
+       } else if (!(csr12 & 4)) {              /* 10mbps link beat good. */
+                       printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+                                  dev->name);
+                       dev->if_port = 0;
+       } else  {               /* 100mbps link beat good. */
+               printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
+                          dev->name);
+               dev->if_port = 3;
+               tp->csr6 = 0x83860000;
+               outl(0x0003FF7F, ioaddr + CSR14);
+               outl(0x0301, ioaddr + CSR12);
+               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+       }
+}
+       
+
+static void mxic_timer(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int next_tick = 60*HZ;
+
+       if (tulip_debug > 3) {
+               printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+                          inl(ioaddr + CSR12));
+       }
+       if (next_tick) {
+               tp->timer.expires = RUN_AT(next_tick);
+               add_timer(&tp->timer);
+       }
+}
+
+static void pnic_timer(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int csr12 = inl(ioaddr + CSR12);
+       int phy_reg = inl(ioaddr + 0xB8);
+       int next_tick = 60*HZ;
+       int duplex;
+
+       if (tulip_debug > 1)
+               printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
+                          dev->name, phy_reg, inl(ioaddr + CSR5));
+       if (tp->full_duplex_lock)
+               return;                         /* Do not bother to set timer. */
+       duplex = phy_reg & 0x30000000 ? 1 : 0;
+       if (tp->full_duplex != duplex) {
+               tp->full_duplex = duplex;
+               if (tp->full_duplex)
+                       tp->csr6 |= 0x0200;
+               else
+                       tp->csr6 &= ~0x0200;
+               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               if (tulip_debug > 0) /* Gurppp, should be >1 */
+                       printk(KERN_INFO "%s: Setting %s-duplex based on"
+                                  " PNIC PHY report of %8.8x.\n",
+                                  dev->name, tp->full_duplex ? "full" : "half", phy_reg);
+       }
+       if (phy_reg & 0x04000000) {     /* Remote link fault */
+               /*outl(0x0201F078, ioaddr + 0xB8);*/
+               next_tick = 3*HZ;
+       }
+       if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+               if (tulip_debug > 1)
+                       printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+                                  "CSR5 %8.8x, PHY %3.3x.\n",
+                                  dev->name, medianame[dev->if_port], csr12,
+                                  inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+               if (dev->if_port == 0) {
+                       dev->if_port = 3;
+               } else
+                       dev->if_port = 0;
+               next_tick = 3*HZ;
+               select_media(dev, 0);
+               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               dev->trans_start = jiffies;
+       }
+       tp->timer.expires = RUN_AT(next_tick);
+       add_timer(&tp->timer);
+}
+
 static void tulip_tx_timeout(struct device *dev)
 {
   struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -1880,10 +2113,20 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
        ioaddr = dev->base_addr;
        tp = (struct tulip_private *)dev->priv;
        if (test_and_set_bit(0, (void*)&tp->interrupt)) {
+#ifdef SMP_CHECK
+               printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
+                          " proc %d already handling.\n", dev->name,
+                          tp->smp_proc_id, hard_smp_processor_id());
+#else
                printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
                return;
+#endif
        }
        dev->interrupt = 1;
+#ifdef SMP_CHECK
+       tp->smp_proc_id = hard_smp_processor_id();
+#endif
+
        do {
                csr5 = inl(ioaddr + CSR5);
                /* Acknowledge all of the current interrupt sources ASAP. */
@@ -1900,9 +2143,10 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
                        work_budget -= tulip_rx(dev);
 
                if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
-                       int dirty_tx;
+                       unsigned int dirty_tx;
 
-                       for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {
+                       for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+                                dirty_tx++) {
                                int entry = dirty_tx % TX_RING_SIZE;
                                int status = tp->tx_ring[entry].status;
 
@@ -1933,15 +2177,19 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
 #ifdef ETHER_STATS
                                        if (status & 0x0001) tp->stats.tx_deferred++;
 #endif
-#if LINUX_VERSION_CODE > 0x20139
-                                       tp->tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+#if LINUX_VERSION_CODE > 0x20127
+                                       tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
 #endif
                                        tp->stats.collisions += (status >> 3) & 15;
                                        tp->stats.tx_packets++;
                                }
 
                                /* Free the original skb. */
+#if (LINUX_VERSION_CODE > 0x20155)
+                               dev_kfree_skb(tp->tx_skbuff[entry]);
+#else
                                dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+#endif
                                tp->tx_skbuff[entry] = 0;
                        }
 
@@ -1954,7 +2202,7 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
 #endif
 
                        if (tp->tx_full && dev->tbusy
-                               && dirty_tx > tp->cur_tx - TX_RING_SIZE + 2) {
+                               && tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2) {
                                /* The ring is no longer full, clear tbusy. */
                                tp->tx_full = 0;
                                dev->tbusy = 0;
@@ -1985,14 +2233,22 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
                                           dev->name, csr5);
                                /* Hmmmmm, it's not clear what to do here. */
                        }
+                       if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
+                               && tp->chip_id == DC21142) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
+                                                  dev->name, csr5);
+                               t21142_lnk_change(dev);
+                       }
                        /* Clear all error sources, included undocumented ones! */
-                       outl(0x000f7ba, ioaddr + CSR5);
+                       outl(0x0800f7ba, ioaddr + CSR5);
                }
                if (--work_budget < 0) {
-                       printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n",
-                                  dev->name, csr5);
+                       if (tulip_debug > 1)
+                               printk(KERN_WARNING "%s: Too much work at interrupt, "
+                                          "csr5=0x%8.8x.\n", dev->name, csr5);
                        /* Acknowledge all interrupt sources. */
-                       outl(0x0001ffff, ioaddr + CSR5);
+                       outl(0x8001ffff, ioaddr + CSR5);
 #ifdef notdef
                        /* Clear all but standard interrupt sources. */
                        outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
@@ -2023,8 +2279,8 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
        }
 #endif
 
-       tp->interrupt = 0;
        dev->interrupt = 0;
+       clear_bit(0, (void*)&tp->interrupt);
        return;
 }
 
@@ -2108,15 +2364,15 @@ tulip_rx(struct device *dev)
                        netif_rx(skb);
                        dev->last_rx = jiffies;
                        tp->stats.rx_packets++;
-#if LINUX_VERSION_CODE > 0x20139
-                       tp->rx_bytes += pkt_len;
+#if LINUX_VERSION_CODE > 0x20127
+                       tp->stats.rx_bytes += pkt_len;
 #endif
                }
                entry = (++tp->cur_rx) % RX_RING_SIZE;
        }
 
        /* Refill the Rx ring buffers. */
-       for (; tp->dirty_rx < tp->cur_rx; tp->dirty_rx++) {
+       for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
                entry = tp->dirty_rx % RX_RING_SIZE;
                if (tp->rx_skbuff[entry] == NULL) {
                        struct sk_buff *skb;
@@ -2181,12 +2437,20 @@ tulip_close(struct device *dev)
 #if LINUX_VERSION_CODE < 0x20100
                        skb->free = 1;
 #endif
+#if (LINUX_VERSION_CODE > 0x20155)
+                       dev_kfree_skb(skb);
+#else
                        dev_kfree_skb(skb, FREE_WRITE);
+#endif
                }
        }
        for (i = 0; i < TX_RING_SIZE; i++) {
                if (tp->tx_skbuff[i])
+#if (LINUX_VERSION_CODE > 0x20155)
+                       dev_kfree_skb(tp->tx_skbuff[i]);
+#else
                        dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+#endif
                tp->tx_skbuff[i] = 0;
        }
 
@@ -2208,6 +2472,71 @@ tulip_get_stats(struct device *dev)
        return &tp->stats;
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       u16 *data = (u16 *)&rq->ifr_data;
+       int phy = tp->phys[0] & 0x1f;
+       long flags;
+
+       switch(cmd) {
+       case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
+               if (tp->mtable  &&  tp->mtable->has_mii)
+                       data[0] = phy;
+               else if (tp->chip_id == DC21142)
+                       data[0] = 32;
+               else
+                       return -ENODEV;
+               return 0;
+       case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+               if (data[0] == 32) {  /* 21142 pseudo-MII */
+                       int csr12 = inl(ioaddr + CSR12);
+                       int csr14 = inl(ioaddr + CSR14);
+                       switch (data[1]) {
+                       case 0: {
+                               data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+                               break; }
+                       case 1:
+                               data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+                                       + (csr12&0x06 ? 0x04 : 0);
+                               break;
+                       case 4: {
+                               int csr14 = inl(ioaddr + CSR14);
+                               data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+                               break;
+                       }
+                       case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+                       default: data[3] = 0; break;
+                       }
+               } else {
+                       save_flags(flags);
+                       cli();
+                       data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+                       restore_flags(flags);
+               }
+               return 0;
+       case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+               if (!suser())
+                       return -EPERM;
+               if (data[0] == 32) {  /* 21142 pseudo-MII */
+               } else {
+                       save_flags(flags);
+                       cli();
+                       mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+                       restore_flags(flags);
+               }
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
 /* Set or clear the multicast filter for this adaptor.
    Note that we only use exclusion around actually queueing the
    new frame, not around filling tp->setup_frame.  This is non-deterministic
@@ -2339,6 +2668,59 @@ static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
                outl(csr6 | 0x0000, ioaddr + CSR6);
        }
 }
+\f
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *tulip_attach(dev_locator_t *loc)
+{
+       u16 dev_id;
+       u32 io;
+       u8 bus, devfn;
+       struct device *dev;
+
+       if (loc->bus != LOC_PCI) return NULL;
+       bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+       printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
+       pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+       pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+       io &= ~3;
+       dev = tulip_probe1(bus, devfn, NULL, io, DC21142, -1);
+       if (dev) {
+               dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+               strcpy(node->dev_name, dev->name);
+               node->major = node->minor = 0;
+               node->next = NULL;
+               MOD_INC_USE_COUNT;
+               return node;
+       }
+       return NULL;
+}
+
+static void tulip_detach(dev_node_t *node)
+{
+       struct device **devp, **next;
+       printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
+       for (devp = &root_tulip_dev; *devp; devp = next) {
+               next = &((struct tulip_private *)(*devp)->priv)->next_module;
+               if (strcmp((*devp)->name, node->dev_name) == 0) break;
+       }
+       if (*devp) {
+               unregister_netdev(*devp);
+               kfree(*devp);
+               *devp = *next;
+               kfree(node);
+               MOD_DEC_USE_COUNT;
+       }
+}
+
+struct driver_operations tulip_ops = {
+       "tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+};
+
+#endif  /* Cardbus support */
+
 \f
 #ifdef MODULE
 #if LINUX_VERSION_CODE > 0x20118
@@ -2361,8 +2743,12 @@ init_module(void)
        if (debug >= 0)
                tulip_debug = debug;
 
-       root_tulip_dev = NULL;
+#ifdef CARDBUS
+       register_driver(&tulip_ops);
+       return 0;
+#else
        return tulip_probe(NULL);
+#endif
 }
 
 void
@@ -2370,6 +2756,10 @@ cleanup_module(void)
 {
        struct device *next_dev;
 
+#ifdef CARDBUS
+       unregister_driver(&tulip_ops);
+#endif
+
        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
        while (root_tulip_dev) {
                next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
@@ -2384,8 +2774,8 @@ cleanup_module(void)
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c"
- *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
index 827f2ec8fc51dd2409cccd21323acf55d5961a12..31bfd1667885802c8c2c830ecef02f0ed43cdeae 100644 (file)
@@ -16,7 +16,7 @@
        http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html
 */
 
-static const char *version = "yellowfin.c:v0.99 1/21/98 becker@cesdis.gsfc.nasa.gov\n";
+static const char *version = "yellowfin.c:v0.99A 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values. */
 
@@ -28,7 +28,7 @@ static int mtu = 0;
 static int bogus_rx = 0;
 static int dma_ctrl = 0x004A0263;                      /* Constrained by errata */
 static int fifo_cfg = 0x0020;                          /* Bypass external Tx FIFO. */
-#elif YF_NEW
+#elif YF_NEW                                   /* A future perfect board :->.  */
 static int dma_ctrl = 0x00CAC277;                      /* Override when loading module! */
 static int fifo_cfg = 0x0028;
 #else
@@ -353,9 +353,9 @@ int yellowfin_probe(struct device *dev)
                unsigned char pci_bus, pci_device_fn;
 
                for (;pci_index < 0xff; pci_index++) {
-                       unsigned char pci_irq_line, pci_latency;
-                       unsigned short pci_command, vendor, device;
-                       unsigned int pci_ioaddr, chip_idx = 0;
+                       u8 pci_irq_line, pci_latency;
+                       u16 pci_command, vendor, device;
+                       u32 pci_ioaddr, chip_idx = 0;
 
 #ifdef REVERSE_PROBE_ORDER
                        if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
@@ -770,7 +770,7 @@ yellowfin_start_xmit(struct sk_buff *skb, struct device *dev)
        outl(0x10001000, dev->base_addr + TxCtrl);
 
        if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)
-               dev->tbusy = 0;                                 /* Typical path */
+               clear_bit(0, (void*)&dev->tbusy);               /* Typical path */
        else
                yp->tx_full = 1;
        dev->trans_start = jiffies;
@@ -823,7 +823,7 @@ static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs
                        yellowfin_rx(dev);
 
 #ifdef NO_TXSTATS
-               for (; dirty_tx < lp->cur_tx; dirty_tx++) {
+               for (; lp->cur_tx - dirty_tx > 0; dirty_tx++) {
                        int entry = dirty_tx % TX_RING_SIZE;
                        if (lp->tx_ring[entry].status == 0)
                                break;
@@ -833,10 +833,10 @@ static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs
                        lp->stats.tx_packets++;
                }
                if (lp->tx_full && dev->tbusy
-                       && dirty_tx > lp->cur_tx - TX_RING_SIZE + 4) {
+                       && lp->cur_tx - dirty_tx < TX_RING_SIZE - 4) {
                        /* The ring is no longer full, clear tbusy. */
                        lp->tx_full = 0;
-                       dev->tbusy = 0;
+                       clear_bit(0, (void*)&dev->tbusy);
                        mark_bh(NET_BH);
                }
                lp->dirty_tx = dirty_tx;
@@ -844,7 +844,8 @@ static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs
                if (intr_status & IntrTxDone
                        || lp->tx_status[dirty_tx % TX_RING_SIZE].tx_errs) {
 
-                       for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+                       for (dirty_tx = lp->dirty_tx; lp->cur_tx - dirty_tx > 0;
+                                dirty_tx++) {
                                /* Todo: optimize this. */
                                int entry = dirty_tx % TX_RING_SIZE;
                                u16 tx_errs = lp->tx_status[entry].tx_errs;
@@ -890,10 +891,10 @@ static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs
 #endif
 
                        if (lp->tx_full && dev->tbusy
-                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+                               && lp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
                                /* The ring is no longer full, clear tbusy. */
                                lp->tx_full = 0;
-                               dev->tbusy = 0;
+                               clear_bit(0, (void*)&dev->tbusy);
                                mark_bh(NET_BH);
                        }
 
@@ -937,7 +938,7 @@ static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs
        }
 
        dev->interrupt = 0;
-       lp->in_interrupt = 0;
+       clear_bit(0, (void*)&lp->in_interrupt);
        return;
 }
 
@@ -1004,7 +1005,7 @@ yellowfin_rx(struct device *dev)
 #endif
                } else {
                        u8 bogus_cnt = buf_addr[frm_size - 8];
-                       short pkt_len = frm_size - 8 - bogus_cnt;
+                       int pkt_len = frm_size - 8 - bogus_cnt;
                        struct sk_buff *skb;
                        int rx_in_place = 0;
 
@@ -1207,9 +1208,8 @@ static inline unsigned ether_crc_le(int length, unsigned char *data)
 }
 
 
-static void
 #ifdef NEW_MULTICAST
-set_rx_mode(struct device *dev)
+static void set_rx_mode(struct device *dev)
 #else
 static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
 #endif
@@ -1293,7 +1293,8 @@ cleanup_module(void)
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
index 117e7c4ea4dde94c2d2e41d83ab17f9fc065208c..f7dd89311736ce65bcf55d3cc38425e1eff376f2 100644 (file)
@@ -5,7 +5,10 @@
  *
  * Copyright 1993, 1994, 1995 Drew Eckhardt, Frederic Potter,
  *     David Mosberger-Tang
+ *
+ * Apr 12, 1998 : Fixed handling of alien header types. [mj]
  */
+
 #include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/types.h>
@@ -345,6 +348,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( INTEL,          INTEL_P6,       "Orion P6"),
        DEVICE( INTEL,          INTEL_82450GX,  "82450GX Orion P6"),
        DEVICE( KTI,            KTI_ET32P2,     "ET32P2"),
+       DEVICE( ADAPTEC,        ADAPTEC_7810,   "AIC-7810 RAID Controller"),
        DEVICE( ADAPTEC,        ADAPTEC_7850,   "AIC-7850"),
        DEVICE( ADAPTEC,        ADAPTEC_7855,   "AIC-7855"),
        DEVICE( ADAPTEC,        ADAPTEC_7860,   "AIC-7860"),
@@ -354,6 +358,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( ADAPTEC,        ADAPTEC_7872,   "AIC-7872"),
        DEVICE( ADAPTEC,        ADAPTEC_7873,   "AIC-7873"),
        DEVICE( ADAPTEC,        ADAPTEC_7874,   "AIC-7874"),
+       DEVICE( ADAPTEC,        ADAPTEC_7895,   "AIC-7895U"),
        DEVICE( ADAPTEC,        ADAPTEC_7880,   "AIC-7880U"),
        DEVICE( ADAPTEC,        ADAPTEC_7881,   "AIC-7881U"),
        DEVICE( ADAPTEC,        ADAPTEC_7882,   "AIC-7882U"),
@@ -908,7 +913,7 @@ static void *pci_malloc(long size, unsigned long *mem_startp)
 static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 {
        unsigned int devfn, l, max;
-       unsigned char cmd, tmp, hdr_type = 0;
+       unsigned char cmd, tmp, hdr_type, is_multi = 0;
        struct pci_dev_info *info;
        struct pci_dev *dev;
        struct pci_bus *child;
@@ -919,32 +924,23 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 
        max = bus->secondary;
        for (devfn = 0; devfn < 0xff; ++devfn) {
-               if (PCI_FUNC(devfn) == 0) {
-                       pcibios_read_config_byte(bus->number, devfn,
-                                                PCI_HEADER_TYPE, &hdr_type);
-               } else if (!(hdr_type & 0x80)) {
-                       /* not a multi-function device */
+               if (PCI_FUNC(devfn) && !is_multi) {
+                       /* Not a multi-function device */
                        continue;
                }
+               pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type);
+               if (!PCI_FUNC(devfn))
+                       is_multi = hdr_type & 0x80;
 
-               pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID,
-                                         &l);
+               pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l);
                /* some broken boards return 0 if a slot is empty: */
                if (l == 0xffffffff || l == 0x00000000) {
-                       hdr_type = 0;
+                       is_multi = 0;
                        continue;
                }
 
                dev = pci_malloc(sizeof(*dev), mem_startp);
                dev->bus = bus;
-               /*
-                * Put it into the simple chain of devices on this
-                * bus.  It is used to find devices once everything is
-                * set up.
-                */
-               dev->next = pci_devices;
-               pci_devices = dev;
-
                dev->devfn  = devfn;
                dev->vendor = l & 0xffff;
                dev->device = (l >> 16) & 0xffff;
@@ -956,8 +952,10 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                 */
                info = pci_lookup_dev(dev->vendor, dev->device);
                if (!info) {
-                       printk("Warning : Unknown PCI device (%x:%x).  Please read include/linux/pci.h \n",
+#if 0
+                       printk("Warning : Unknown PCI device (%x:%x).  Please read include/linux/pci.h\n",
                                dev->vendor, dev->device);
+#endif
                } else {
                        /* Some BIOS' are lazy. Let's do their job: */
                        if (info->bridge_type != 0xff) {
@@ -986,6 +984,25 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
                                          PCI_CLASS_REVISION, &l);
                l = l >> 8;                     /* upper 3 bytes */
                dev->class = l;
+
+               /*
+                * Check if the header type is known and consistent with
+                * device type. Bridges should have hdr_type 1, all other
+                * devices 0.
+                */
+               if ((dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) != (hdr_type & 0x7f)) {
+                       printk(KERN_WARNING "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
+                               bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type);
+                       continue;
+               }
+
+               /*
+                * Put it into the simple chain of all PCI devices.
+                * It is used to find devices once everything is set up.
+                */
+               dev->next = pci_devices;
+               pci_devices = dev;
+
                /*
                 * Now insert it into the list of devices held
                 * by the parent bus.
index 7fbdaa58745b2956f2e301850e595d84a16cccd3..c6bac228efee1a247d88e51ca528ab8a653d0105 100644 (file)
@@ -20,14 +20,12 @@ dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-    bool '   Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
     bool '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
     if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
-      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
     fi
-    bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
     bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
 fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
index ccbf4a6e2ab26d2fad1760d4254c8c86c4715d51..7cbe9fbdc1faa661ab4030056b4f8cb342d43052 100644 (file)
@@ -1,8 +1,7 @@
                            AIC7xxx Driver for Linux
-                                April 15, 1996
 
 Introduction
-------------------------
+----------------------------
 The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
 SCSI controllers and chipsets. Major portions of the driver and driver
 development are shared between both Linux and FreeBSD. Support for the
@@ -11,31 +10,42 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
 2.1.0 or later.
 
   Supported cards/chipsets
-  ------------------------
+  ----------------------------
     Adaptec Cards
-    -----------------------
-    AHA-274x               
-    AHA-2842               
+    ----------------------------
+    AHA-274x
+    AHA-274xT               
+    AHA-2842
+    AHA-2910B               
     AHA-2940               
     AHA-2940W              
     AHA-2940U              
-    AHA-2940UW             
+    AHA-2940UW
+    AHA-2940AU             
     AHA-2944D              
     AHA-2944WD
+    AHA-2944UD
+    AHA-2944UWD
     AHA-3940
+    AHA-3940U
     AHA-3940W
+    AHA-3940UW
     AHA-3985
+    AHA-3985U
     AHA-3985W
+    AHA-3985UW
 
     Motherboard Chipsets
-    -----------------------
+    ----------------------------
     AIC-777x   
     AIC-785x
+    AIC-786x
     AIC-787x
     AIC-788x
+    AIC-7895
 
     Bus Types
-    -----------------------
+    ----------------------------
     W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
         SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
     U - Ultra SCSI, transfer rates up to 40MB/s.
@@ -49,22 +59,28 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AHA-398x - PCI RAID controllers with three separate SCSI controllers
                on-board.
 
-    NOTE: The AHA-2920 is NOT a AIC-7xxx based controller, and is not
+    NOTE: The AHA-2920 is NOT an AIC-7xxx based controller, and is not
           handled by this driver.
 
   People
-  ------------------------
-    Justin T Gibbs  gibbs@freefall.FreeBSD.org     (BSD Driver Author)
-    Dan Eischen     deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
-    Dean Gehnert    deang@teleport.com             (Linux FTP/patch maintainer)
-    Jess Johnson    jester@frenzy.com              (AIC7xxx FAQ author)
-
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@dialnet.net
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+    
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
     again for all his work!
-
+    
   Mailing list
-  ------------------------
+  ------------------------------
     There is a mailing list available for users who want to track development
     and converse with other users and developers. This list is for both
     FreeBSD and Linux support of the AIC7xxx chipsets.
@@ -82,13 +98,150 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
 
     Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
     
-  Command line options
-  ------------------------
+  Boot Command line options
+  ------------------------------
     "aic7xxx=no_reset" -  Eliminate the SCSI reset delay during startup.
         Some SCSI devices need some extra time to reset.
+    "aic7xxx=reverse_scan" - Have the driver register the SCSI cards in the
+        reverse of the normal order.  This may help those people who have more
+        than one PCI Adaptec controller force the correct controller to be
+        scsi0 under linux so that their boot hard drive is also sda under
+        linux
+    "aic7xxx=extended" - Force the driver to detect extended drive translation
+        on your controller.  This helps those people who have cards without
+        a SEEPROM make sure that linux and all other operating systems think
+        the same way about your hard drives.
+    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+        to use the correct IRQ type for your card.  This only applies to EISA
+        based controllers.  On these controllers, 0 is for Edge triggered
+        interrupts, and 1 is for Level triggered interrupts.  If you aren't
+        sure or don't know which IRQ trigger type your EISA card uses, then
+        let the kernel autodetect the trigger type.
+    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
+        simply specify aic7xxx=verbose, then the kernel will automatically pick
+        the default set of verbose messages for you to see.  Alternatively, you
+        can specify the command as "aic7xxx=verbose:0xXXXX" where the X entries
+        are replaced with hexadecimal digits.  This option is a bit field type
+        option.  For a full listing of the available options, search for the
+        #define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want verbose
+        messages, then it is recommended that you simply use the aic7xxx=verbose
+        variant of this command.
+    "aic7xxx=7895_irq_hack:x" - This option enables some work around code to
+        fix a bug in the Tyan Thunder II motherboard BIOS.  The BIOS
+        incorrectly sets the IRQs on the two channels of the 7895 to two
+        different values even though the motherboard hardware doesn't support
+        this mode of operation.  The valid values for x are: 0 to force
+        both channels to use the IRQ assigned to Channel A, 1 to force both
+        channels to use the IRQ assigned to Channel B, and -1 will disable
+        this horrible abomination of a hack.  The default is disabled (-1).
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to enable
+        tagged queueing on specific devices.  As of driver version 5.0.6, we
+        now globally enable tagged queueing by default, but we also disable
+        tagged queueing on all individual devices by default.  In order to
+        enable tagged queueing for certian devices at boot time, a user may
+        use this boot param.  The driver will then parse this message out
+        and enable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{{8,8},,{8,8}}
+          First adapter, scsi id 0 to 8, id 1 to 8, remainder stay at their
+          default.  Second adapter stays entirely at default.  Third
+          adapter, id 0 to 8, id 1 to 8, remainder at default (identical to
+          first adapter).
+
+        tag_info:{,,,{,,,64}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 to 64.  Notice that leading commas simply increment
+          what the first number effects, and there are no need for trailing
+          commas.  When you close out an adapter, or the entire entry,
+          anything not explicitly set stays at the default value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma on
+    the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the F1 key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button next
+    to the option you have questions about.  The help information from the
+    Configure.help file will then get automatically displayed.
 
   /proc support
-  ------------------------
+  ------------------------------
     The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
     directory. That directory contains a file for each SCSI controller in
     the system. Each file presents the current configuration and transfer
@@ -98,12 +251,12 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     Matthew Jacob for statistics support.
 
   FTP sites
-  ------------------------
-    ftp://ftp.teleport.com/users/deang/Linux/aic7xxx/
-      - Main Linux AIC7xxx driver release/pre-release site
-      - Experimental/development patches and bootdisks
+  ------------------------------
     ftp://ftp.dialnet.net/pub/linux/aic7xxx/
+      - Primary site for Doug Ledford developed driver releases
       - US Linux mirror of Teleport site
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
       - European Linux mirror of Teleport site
 
@@ -113,3 +266,4 @@ deang@teleport.com
 
 $Revision: 3.0 $
 
+Modified by Doug Ledford 1998
index 51b5aa538969fc1f5cfe1f456df2efc2e4b8fcaa..cc265ecb7a48d1171882dfe9d99ebe9f89927fcd 100644 (file)
@@ -38,7 +38,7 @@
  *  Parts of this driver were also based on the FreeBSD driver by
  *  Justin T. Gibbs.  His copyright follows:
  *
- * --------------------------------------------------------------------------
+ * --------------------------------------------------------------------------  
  * Copyright (c) 1994-1997 Justin Gibbs.
  * All rights reserved.
  *
  *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
  *-M*************************************************************************/
 
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@dialnet.net>
+ *
+ * Copyright (c) 1997-1998 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accomodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
+ * itself.  A diff between the two version of the driver is now a several
+ * thousand line diff.  Second, in approach to solving the same problem.  The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone.  Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible.  To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver.  He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach.  Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux.  I have no objection to those issues.  My
+ * disagreement is on the needed functionality.  There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics.  Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers.  For the time
+ * being, I see issues such as these as major stumbling blocks to the 
+ * reliability of code based upon such middle ware.  Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code.  My approach is to import the sequencer
+ * code from FreeBSD wholesale.  Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements.  But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State".  Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
 #ifdef MODULE
 #include <linux/module.h>
 #endif
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
-#include <linux/bios32.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
+#include <linux/tqueue.h>
+#include <linux/tasks.h>
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
 #include "aic7xxx_seq.h"
+
 #include <linux/stat.h>
-#include <linux/malloc.h>      /* for kmalloc() */
+#include <linux/malloc.h>        /* for kmalloc() */
 
-#include <linux/config.h>      /* for CONFIG_PCI */
+#include <linux/config.h>        /* for CONFIG_PCI */
 
 /*
  * To generate the correct addresses for the controller to issue
@@ -139,13 +209,13 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.1.1 $"
+#define AIC7XXX_C_VERSION  "5.0.13"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
 #define ALL_TARGETS -1
-#define ALL_CHANNELS '\0'
+#define ALL_CHANNELS -1
 #define ALL_LUNS -1
 #define MAX_TARGETS  16
 #define MAX_LUNS     8
@@ -156,75 +226,78 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #  define FALSE 0
 #endif
 
+#ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
 /*
- * Defines for PCI bus support, testing twin bus support, DMAing of
- * SCBs, tagged queueing, commands (SCBs) per lun, and SCSI bus reset
- * delay time.
- *
- *   o PCI bus support - this has been implemented and working since
- *     the December 1, 1994 release of this driver. If you don't have
- *     a PCI bus, then you can configure your kernel without PCI
- *     support because all PCI dependent code is bracketed with
- *     "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
- *
- *   o Twin bus support - this has been tested and does work.  It is
- *     not an option anymore.
- *
- *   o Tagged queueing - this driver is capable of tagged queueing
- *     but I am unsure as to how well the higher level driver implements
- *     tagged queueing. Therefore, the maximum commands per lun is
- *     set to 2. If you want to implement tagged queueing, ensure
- *     this define is not commented out.
- *
- *   o Commands per lun - If tagged queueing is enabled, then you
- *     may want to try increasing AIC7XXX_CMDS_PER_LUN to more
- *     than 2.  By default, we limit the SCBs per LUN to 2 with
- *     or without tagged queueing enabled.  If tagged queueing is
- *     disabled, the sequencer will keep the 2nd SCB in the input
- *     queue until the first one completes - so it is OK to to have
- *     more than 1 SCB queued.  If tagged queueing is enabled, then
- *     the sequencer will attempt to send the 2nd SCB to the device
- *     while the first SCB is executing and the device is disconnected.
- *     For adapters limited to 4 SCBs, you may want to actually
- *     decrease the commands per LUN to 1, if you often have more
- *     than 2 devices active at the same time.  This will allocate
- *     1 SCB for each device and ensure that there will always be
- *     a free SCB for up to 4 devices active at the same time.
- *     When SCB paging is enabled, set the commands per LUN to 8
- *     or higher (see SCB paging support below).  Note that if
- *     AIC7XXX_CMDS_PER_LUN is not defined and tagged queueing is
- *     enabled, the driver will attempt to set the commands per
- *     LUN using its own heuristic based on the number of available
- *     SCBs.
- *
- *   o 3985 support - The 3985 adapter is much like the 3940, but has
- *     three 7870 controllers as opposed to two for the 3940.  It will
- *     be probed and recognized as three different adapters, but all
- *     three controllers can share the same external bank of 255 SCBs.
- *     If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
- *     to use and share the common bank of SCBs between the three
- *     controllers of the 3985.  This is experimental and hasn't been
- *     been tested.  By default, we do not use external SCB RAM, and
- *     force the controllers to use their own internal bank of 16 SCBs.
- *     Please let us know if using the external SCB array works.
- *
- *   o SCB paging support - SCB paging is enabled by defining
- *     AIC7XXX_PAGE_ENABLE.  Support for this was taken from the
- *     FreeBSD driver (by Justin Gibbs) and allows for up to 255
- *     active SCBs.  This will increase performance when tagged
- *     queueing is enabled.  Note that you should increase the
- *     AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices
- *     allow at least this many.
- *
- *  Note that sharing of IRQs is not an option any longer.  Linux supports
- *  it so we support it.
- *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
+ * We need the bios32.h file if we are kernel version 2.1.92 or less.  The
+ * full set of pci_* changes wasn't in place until 2.1.93
  */
 
-/* Uncomment this for tagged queueing. */
-#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
-#define AIC7XXX_TAGGED_QUEUEING
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
+#  if defined(__sparc_v9__) || defined(__powerpc__)
+#    error "PPC and Sparc platforms are only support under 2.1.x and above"
+#  endif
+#  include <linux/bios32.h>
+#endif
+
+#if !defined(__alpha__)
+#  define MMAPIO
+#endif
+
+#if defined(__powerpc__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("eieio" ::: "memory")
+#elif defined(__i386__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
+#elif defined(__alpha__)
+#  ifdef mb
+#    undef mb
+#  endif
+#  define mb() \
+     __asm__ __volatile__("mb": : :"memory")
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+#  include <asm/spinlock.h>
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+#    define DRIVER_LOCK_INIT \
+       spin_lock_init(&p->spin_lock);
+#    define DRIVER_LOCK \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+#  else
+#    define DRIVER_LOCK_INIT
+#    define DRIVER_LOCK
+#    define DRIVER_UNLOCK
+#  endif
+#else
+#  define cpuid 0
+#  define DRIVER_LOCK_INIT
+#  define DRIVER_LOCK \
+       save_flags(cpu_flags); \
+       cli();
+#  define DRIVER_UNLOCK \
+       restore_flags(cpu_flags);
+#  define le32_to_cpu(x) (x)
+#  define cpu_to_le32(x) (x)
 #endif
 
 /*
@@ -239,7 +312,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #ifdef CONFIG_AIC7XXX_RESET_DELAY
 #define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
 #else
-#define AIC7XXX_RESET_DELAY 15
+#define AIC7XXX_RESET_DELAY 5
 #endif
 
 /*
@@ -253,32 +326,18 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #endif
 
 /*
- * Enable SCB paging.
- */
-#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
-#define AIC7XXX_PAGE_ENABLE
-#endif
-
-/*
- * Uncomment the following to enable use of the external bank
- * of 255 SCBs.  For 3985 adapters, this will also enable sharing
- * of the SCB array across all three controllers.
- */
-#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
-#define AIC7XXX_USE_EXT_SCBRAM
-#endif
-
-/*
- * For debugging the abort/reset code.
- */
-#define AIC7XXX_DEBUG_ABORT
-
-/*
- * For general debug messages
- */
-#define AIC7XXX_DEBUG
-
-/*
+ * NOTE: Uncommenting the define below no longer has any effect, the
+ *       tagged queue value array is always active now.  I've added
+ *       a setup option to set this particular array and I'm hoping
+ *       insmod will be smart enough to set it properly as well.  It's
+ *       by use of this array that a person can disable tagged queueing.
+ *       The DEFAULT_TAG_COMMANDS define has been changed to disable
+ *       tagged queueing by default, so if your devices can handle tagged
+ *       queueing you will need to add a line to their lilo.conf file like:
+ *       append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ *       which will result in the first four devices on the first two
+ *       controllers being set to a tagged queue depth of 32.
+ *
  * Set this for defining the number of tagged commands on a device
  * by device, and controller by controller basis.  The first set
  * of tagged commands will be used for the first detected aic7xxx
@@ -293,37 +352,36 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  * 
  * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
  * own algorithm to determine the commands/LUN.  If SCB paging is
- * enabled, the commands/LUN is 8.  When SCB paging is not enabled,
- * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
- * and 4 commands/LUN for adapters with 3 or 4 SCBs.
- *
+ * enabled, which is always now, the default is 8 commands per lun
+ * that indicates it supports tagged queueing.  All non-tagged devices
+ * use an internal queue depth of 3, with no more than one of those
+ * three commands active at one time.
  */
 /* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
 
-#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
 typedef struct
 {
-  unsigned char tag_commands[16];   /* Allow for wide/twin channel adapters. */
+  unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
 } adapter_tag_info_t;
 
 /*
- * Make a define that will tell the driver to use it's own algorithm
- * for determining commands/LUN (see Determining commands per LUN
- * above).
+ * Make a define that will tell the driver not to use tagged queueing
+ * by default.
  */
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
+                              255, 255, 255, 255, 255, 255, 255, 255}
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
  * to 0, the driver will use it's own algorithm for determining the
- * number of commands to use (see above).  When -1, the driver will
+ * number of commands to use (see above).  When 255, the driver will
  * not enable tagged queueing for that particular device.  When positive
- * (> 0) the values in the array are used for the queue_depth.  Note
- * that the maximum value for an entry is 127.
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
  *
- * In this example, the first line will enable tagged queueing for all
- * the devices on the first probed aic7xxx adapter and tells the driver
- * to use it's own algorithm for determining commands/LUN.
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
  *
  * The second line enables tagged queueing with 4 commands/LUN for IDs
  * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
@@ -336,107 +394,42 @@ typedef struct
  * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
  * IDs 2, 5-7, and 9-15.
  */
+
+/*
 adapter_tag_info_t aic7xxx_tag_info[] =
 {
   {DEFAULT_TAG_COMMANDS},
-  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
   {DEFAULT_TAG_COMMANDS},
-  {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+  {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
 };
-#endif
-
-/*
- * Don't define this unless you have problems with the driver
- * interrupt handler.  The old method would register the drivers
- * interrupt handler as a "fast" type interrupt handler that would
- * lock out other interrupts.  Since this driver can spend a lot
- * of time in the interrupt handler, this is _not_ a good idea.
- * It also conflicts with some of the more common ethernet drivers
- * that don't use fast interrupts.  Currently, Linux does not allow
- * IRQ sharing unless both drivers can agree on the type of interrupt
- * handler.
- */
-/* #define AIC7XXX_OLD_ISR_TYPE */
-
-
-/*
- * Controller type and options
- */
-typedef enum {
-  AIC_NONE,
-  AIC_7770,    /* EISA aic7770 on motherboard */
-  AIC_7771,    /* EISA aic7771 on 274x */
-  AIC_284x,    /* VLB  aic7770 on 284x, BIOS disabled */
-  AIC_7850,    /* PCI  aic7850 */
-  AIC_7855,    /* PCI  aic7855 */
-  AIC_7860,    /* PCI  aic7860 (7850 Ultra) */
-  AIC_7861,     /* PCI  aic7861 on 2940AU */
-  AIC_7870,    /* PCI  aic7870 on motherboard */
-  AIC_7871,    /* PCI  aic7871 on 294x */
-  AIC_7872,    /* PCI  aic7872 on 3940 */
-  AIC_7873,    /* PCI  aic7873 on 3985 */
-  AIC_7874,    /* PCI  aic7874 on 294x Differential */
-  AIC_7880,    /* PCI  aic7880 on motherboard */
-  AIC_7881,    /* PCI  aic7881 on 294x Ultra */
-  AIC_7882,    /* PCI  aic7882 on 3940 Ultra */
-  AIC_7883,    /* PCI  aic7883 on 3985 Ultra */
-  AIC_7884     /* PCI  aic7884 on 294x Ultra Differential */
-} aha_chip_type;
-
-typedef enum {
-  AIC_777x,    /* AIC-7770 based */
-  AIC_785x,    /* AIC-7850 based (3 SCBs)*/
-  AIC_786x,    /* AIC-7860 based (7850 ultra) */
-  AIC_787x,    /* AIC-7870 based */
-  AIC_788x     /* AIC-7880 based (ultra) */
-} aha_chip_class_type;
-
-typedef enum {
-  AIC_SINGLE,  /* Single Channel */
-  AIC_TWIN,    /* Twin Channel */
-  AIC_WIDE     /* Wide Channel */
-} aha_bus_type;
-
-typedef enum {
-  AIC_UNKNOWN,
-  AIC_ENABLED,
-  AIC_DISABLED
-} aha_status_type;
-
-typedef enum {
-  LIST_HEAD,
-  LIST_SECOND
-} insert_type;
-
-typedef enum {
-  ABORT_RESET_INACTIVE,
-  ABORT_RESET_PENDING,
-  ABORT_RESET_SUCCESS
-} aha_abort_reset_type;
+*/
 
 /*
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "AIC-7xxx Unknown",                                  /* AIC_NONE */
-  "Adaptec AIC-7770 SCSI host adapter",                        /* AIC_7770 */
-  "Adaptec AHA-274X SCSI host adapter",                        /* AIC_7771 */
-  "Adaptec AHA-284X SCSI host adapter",                        /* AIC_284x */
-  "Adaptec AIC-7850 SCSI host adapter",                        /* AIC_7850 */
-  "Adaptec AIC-7855 SCSI host adapter",                        /* AIC_7855 */
-  "Adaptec AIC-7860 Ultra SCSI host adapter",          /* AIC_7860 */
-  "Adaptec AHA-2940A Ultra SCSI host adapter",         /* AIC_7861 */
-  "Adaptec AIC-7870 SCSI host adapter",                        /* AIC_7870 */
-  "Adaptec AHA-294X SCSI host adapter",                        /* AIC_7871 */
-  "Adaptec AHA-394X SCSI host adapter",                        /* AIC_7872 */
-  "Adaptec AHA-398X SCSI host adapter",                        /* AIC_7873 */
-  "Adaptec AHA-2944 SCSI host adapter",                        /* AIC_7874 */
-  "Adaptec AIC-7880 Ultra SCSI host adapter",          /* AIC_7880 */
-  "Adaptec AHA-294X Ultra SCSI host adapter",          /* AIC_7881 */
-  "Adaptec AHA-394X Ultra SCSI host adapter",          /* AIC_7882 */
-  "Adaptec AHA-398X Ultra SCSI host adapter",          /* AIC_7883 */
-  "Adaptec AHA-2944 Ultra SCSI host adapter"           /* AIC_7884 */
+  "AIC-7xxx Unknown",                                   /* AIC_NONE */
+  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
+  "Adaptec AIC-7770 SCSI host adapter",                 /* AIC_7770 */
+  "Adaptec AHA-274X SCSI host adapter",                 /* AIC_7771 */
+  "Adaptec AHA-284X SCSI host adapter",                 /* AIC_284x */
+  "Adaptec AIC-7850 SCSI host adapter",                 /* AIC_7850 */
+  "Adaptec AIC-7855 SCSI host adapter",                 /* AIC_7855 */
+  "Adaptec AIC-7860 Ultra SCSI host adapter",           /* AIC_7860 */
+  "Adaptec AHA-2940A Ultra SCSI host adapter",          /* AIC_7861 */
+  "Adaptec AIC-7870 SCSI host adapter",                 /* AIC_7870 */
+  "Adaptec AHA-294X SCSI host adapter",                 /* AIC_7871 */
+  "Adaptec AHA-394X SCSI host adapter",                 /* AIC_7872 */
+  "Adaptec AHA-398X SCSI host adapter",                 /* AIC_7873 */
+  "Adaptec AHA-2944 SCSI host adapter",                 /* AIC_7874 */
+  "Adaptec AIC-7880 Ultra SCSI host adapter",           /* AIC_7880 */
+  "Adaptec AHA-294X Ultra SCSI host adapter",           /* AIC_7881 */
+  "Adaptec AHA-394X Ultra SCSI host adapter",           /* AIC_7882 */
+  "Adaptec AHA-398X Ultra SCSI host adapter",           /* AIC_7883 */
+  "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter"            /* AIC_7895 */
 };
 
 /*
@@ -461,58 +454,58 @@ static const char *board_names[] = {
 #define DID_RETRY_COMMAND DID_ERROR
 
 #define HSCSIID        0x07
-#define HWSCSIID       0x0F
 #define SCSI_RESET     0x040
 
 /*
  * EISA/VL-bus stuff
  */
-#define MINSLOT                1
-#define MAXSLOT                15
-#define SLOTBASE(x)    ((x) << 12)
+#define MINSLOT                1
+#define MAXSLOT                15
+#define SLOTBASE(x)        ((x) << 12)
 #define BASE_TO_SLOT(x) ((x) >> 12)
 
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
  */
-#define HID0           0x80   /* 0,1: msb of ID2, 2-7: ID1      */
-#define HID1           0x81   /* 0-4: ID3, 5-7: LSB ID2         */
-#define HID2           0x82   /* product                        */
-#define HID3           0x83   /* firmware revision              */
+#define HID0                0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define HID1                0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define HID2                0x82   /* product                        */
+#define HID3                0x83   /* firmware revision              */
 
 /*
  * AIC-7770 I/O range to reserve for a card
  */
-#define MINREG         0xC00
-#define MAXREG         0xCBF
+#define MINREG                0xC00
+#define MAXREG                0xCBF
 
-#define INTDEF         0x5C            /* Interrupt Definition Register */
+#define INTDEF                0x5C      /* Interrupt Definition Register */
 
 /*
  * AIC-78X0 PCI registers
  */
-#define        CLASS_PROGIF_REVID      0x08
-#define                DEVREVID        0x000000FFul
-#define                PROGINFC        0x0000FF00ul
-#define                SUBCLASS        0x00FF0000ul
-#define                BASECLASS       0xFF000000ul
-
-#define        CSIZE_LATTIME           0x0C
-#define                CACHESIZE       0x0000003Ful    /* only 5 bits */
-#define                LATTIME         0x0000FF00ul
-
-#define        DEVCONFIG               0x40
-#define                MPORTMODE       0x00000400ul    /* aic7870 only */
-#define                RAMPSM          0x00000200ul    /* aic7870 only */
-#define                VOLSENSE        0x00000100ul
-#define                SCBRAMSEL       0x00000080ul
-#define                MRDCEN          0x00000040ul
-#define                EXTSCBTIME      0x00000020ul    /* aic7870 only */
-#define                EXTSCBPEN       0x00000010ul    /* aic7870 only */
-#define                BERREN          0x00000008ul
-#define                DACEN           0x00000004ul
-#define                STPWLEVEL       0x00000002ul
-#define                DIFACTNEGEN     0x00000001ul    /* aic7870 only */
+#define        CLASS_PROGIF_REVID        0x08
+#define                DEVREVID        0x000000FFul
+#define                PROGINFC        0x0000FF00ul
+#define                SUBCLASS        0x00FF0000ul
+#define                BASECLASS        0xFF000000ul
+
+#define        CSIZE_LATTIME                0x0C
+#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
+#define                LATTIME                0x0000FF00ul
+
+#define        DEVCONFIG                0x40
+#define                SCBSIZE32        0x00010400ul        /* aic789X only */
+#define                MPORTMODE        0x00000400ul        /* aic7870 only */
+#define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                VOLSENSE         0x00000100ul
+#define                SCBRAMSEL        0x00000080ul
+#define                MRDCEN           0x00000040ul
+#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
+#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
+#define                BERREN           0x00000008ul
+#define                DACEN            0x00000004ul
+#define                STPWLEVEL        0x00000002ul
+#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
 
 
 /*
@@ -536,69 +529,72 @@ struct seeprom_config {
 /*
  * SCSI ID Configuration Flags
  */
-#define CFXFER         0x0007          /* synchronous transfer rate */
-#define CFSYNCH                0x0008          /* enable synchronous transfer */
-#define CFDISC         0x0010          /* enable disconnection */
-#define CFWIDEB                0x0020          /* wide bus device (wide card) */
-/* UNUSED              0x00C0 */
-#define CFSTART                0x0100          /* send start unit SCSI command */
-#define CFINCBIOS      0x0200          /* include in BIOS scan */
-#define CFRNFOUND      0x0400          /* report even if not found */
-/* UNUSED              0xF800 */
-  unsigned short device_flags[16];     /* words 0-15 */
+#define CFXFER                0x0007      /* synchronous transfer rate */
+#define CFSYNCH               0x0008      /* enable synchronous transfer */
+#define CFDISC                0x0010      /* enable disconnection */
+#define CFWIDEB               0x0020      /* wide bus device (wide card) */
+#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
+/* UNUSED                0x0080 */
+#define CFSTART               0x0100      /* send start unit SCSI command */
+#define CFINCBIOS             0x0200      /* include in BIOS scan */
+#define CFRNFOUND             0x0400      /* report even if not found */
+#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
+/* UNUSED                0xF000 */
+  unsigned short device_flags[16];        /* words 0-15 */
 
 /*
  * BIOS Control Bits
  */
-#define CFSUPREM       0x0001          /* support all removable drives */
-#define CFSUPREMB      0x0002          /* support removable drives for boot only */
-#define CFBIOSEN       0x0004          /* BIOS enabled */
-/* UNUSED              0x0008 */
-#define CFSM2DRV       0x0010          /* support more than two drives */
-#define CF284XEXTEND   0x0020          /* extended translation (284x cards) */
-/* UNUSED              0x0040 */
-#define CFEXTEND       0x0080          /* extended translation enabled */
-/* UNUSED              0xFF00 */
-  unsigned short bios_control;         /* word 16 */
+#define CFSUPREM        0x0001  /* support all removable drives */
+#define CFSUPREMB       0x0002  /* support removable drives for boot only */
+#define CFBIOSEN        0x0004  /* BIOS enabled */
+/* UNUSED                0x0008 */
+#define CFSM2DRV        0x0010  /* support more than two drives */
+#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
+/* UNUSED                0x0040 */
+#define CFEXTEND        0x0080  /* extended translation enabled */
+/* UNUSED                0xFF00 */
+  unsigned short bios_control;  /* word 16 */
 
 /*
  * Host Adapter Control Bits
  */
-#define CFAUTOTERM      0x0001          /* Perform Auto termination */
-#define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
-#define CF284XSELTO     0x0003          /* Selection timeout (284x cards) */
-#define CF284XFIFO      0x000C          /* FIFO Threshold (284x cards) */
-#define CFSTERM         0x0004          /* SCSI low byte termination */
-#define CFWSTERM        0x0008          /* SCSI high byte termination (wide card) */
-#define CFSPARITY      0x0010          /* SCSI parity */
-#define CF284XSTERM    0x0020          /* SCSI low byte termination (284x cards) */
-#define CFRESETB       0x0040          /* reset SCSI bus at boot */
-/* UNUSED              0xFF80 */
-  unsigned short adapter_control;      /* word 17 */
+#define CFAUTOTERM      0x0001  /* Perform Auto termination */
+#define CFULTRAEN       0x0002  /* Ultra SCSI speed enable (Ultra cards) */
+#define CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
+#define CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
+#define CFSTERM         0x0004  /* SCSI low byte termination */
+#define CFWSTERM        0x0008  /* SCSI high byte termination (wide card) */
+#define CFSPARITY       0x0010  /* SCSI parity */
+#define CF284XSTERM     0x0020  /* SCSI low byte termination (284x cards) */
+#define CFRESETB        0x0040  /* reset SCSI bus at boot */
+#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
+/* UNUSED                0xFE80 */
+  unsigned short adapter_control;        /* word 17 */
 
 /*
  * Bus Release, Host Adapter ID
  */
-#define CFSCSIID       0x000F          /* host adapter SCSI ID */
-/* UNUSED              0x00F0 */
-#define CFBRTIME       0xFF00          /* bus release time */
-  unsigned short brtime_id;            /* word 18 */
+#define CFSCSIID        0x000F                /* host adapter SCSI ID */
+/* UNUSED                0x00F0 */
+#define CFBRTIME        0xFF00                /* bus release time */
+  unsigned short brtime_id;                /* word 18 */
 
 /*
  * Maximum targets
  */
-#define CFMAXTARG      0x00FF  /* maximum targets */
-/* UNUSED              0xFF00 */
-  unsigned short max_targets;          /* word 19 */
+#define CFMAXTARG        0x00FF        /* maximum targets */
+/* UNUSED                0xFF00 */
+  unsigned short max_targets;                /* word 19 */
 
-  unsigned short res_1[11];            /* words 20-30 */
-  unsigned short checksum;             /* word 31 */
+  unsigned short res_1[11];                /* words 20-30 */
+  unsigned short checksum;                /* word 31 */
 };
 
-#define SELBUS_MASK            0x0a
-#define        SELNARROW       0x00
-#define        SELBUSB         0x08
-#define SINGLE_BUS             0x00
+#define SELBUS_MASK                0x0a
+#define         SELNARROW        0x00
+#define         SELBUSB                0x08
+#define SINGLE_BUS                0x00
 
 #define SCB_TARGET(scb)         \
        (((scb)->hscb->target_channel_lun & TID) >> 4)
@@ -613,60 +609,22 @@ struct seeprom_config {
  * condition in this location. This then will modify a DID_OK status
  * into an appropriate error for the higher-level SCSI code.
  */
-#define aic7xxx_error(cmd)     ((cmd)->SCp.Status)
+#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
 
 /*
  * Keep track of the targets returned status.
  */
-#define aic7xxx_status(cmd)    ((cmd)->SCp.sent_command)
+#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
 
 /*
  * The position of the SCSI commands scb within the scb array.
  */
-#define aic7xxx_position(cmd)  ((cmd)->SCp.have_data_in)
-
-/*
- * "Static" structures. Note that these are NOT initialized
- * to zero inside the kernel - we have to initialize them all
- * explicitly.
- *
- * We support multiple adapter cards per interrupt, but keep a
- * linked list of Scsi_Host structures for each IRQ.  On an interrupt,
- * use the IRQ as an index into aic7xxx_boards[] to locate the card
- * information.
- */
-static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
+#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
 
 /*
- * When we detect and register the card, it is possible to
- * have the card raise a spurious interrupt.  Because we need
- * to support multiple cards, we cannot tell which card caused
- * the spurious interrupt.  And, we might not even have added
- * the card info to the linked list at the time the spurious
- * interrupt gets raised.  This variable is suppose to keep track
- * of when we are registering a card and how many spurious
- * interrupts we have encountered.
- *
- *   0 - do not allow spurious interrupts.
- *   1 - allow 1 spurious interrupt
- *   2 - have 1 spurious interrupt, do not allow any more.
- *
- * I've made it an integer instead of a boolean in case we
- * want to allow more than one spurious interrupt for debugging
- * purposes.  Otherwise, it could just go from true to false to
- * true (or something like that).
- *
- * When the driver detects the cards, we'll set the count to 1
- * for each card detection and registration.  After the registration
- * of a card completes, we'll set the count back to 0.  So far, it
- * seems to be enough to allow a spurious interrupt only during
- * card registration; if a spurious interrupt is going to occur,
- * this is where it happens.
- *
- * We should be able to find a way to avoid getting the spurious
- * interrupt.  But until we do, we have to keep this ugly code.
+ * So we can keep track of our host structs
  */
-static int aic7xxx_spurious_count;
+static struct aic7xxx_host *first_aic7xxx = NULL;
 
 /*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
@@ -681,14 +639,14 @@ struct hw_scatterlist {
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define        AIC7XXX_MAX_SG 122
+#define        AIC7XXX_MAX_SG 128
 
 /*
  * The maximum number of SCBs we could have for ANY type
  * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
  * SEQUENCER CODE IF THIS IS MODIFIED!
  */
-#define AIC7XXX_MAXSCB 255
+#define AIC7XXX_MAXSCB        255
 
 
 struct aic7xxx_hwscb {
@@ -704,55 +662,118 @@ struct aic7xxx_hwscb {
 /*16*/  unsigned int  data_count;
 /*20*/  unsigned int  SCSI_cmd_pointer;
 /*24*/  unsigned char SCSI_cmd_length;
-/*25*/ u_char tag;                     /* Index into our kernel SCB array.
-                                        * Also used as the tag for tagged I/O
-                                        */
-#define SCB_PIO_TRANSFER_SIZE  26      /* amount we need to upload/download
-                                        * via PIO to initialize a transaction.
-                                        */
-/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
-                                         * or disconnected down in the sequencer.
-                                         */
+/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
+                                     * Also used as the tag for tagged I/O
+                                     */
+#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
+                                     * via PIO to initialize a transaction.
+                                     */
+/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
+                                     * or disconnected down in the sequencer.
+                                     */
 /*27*/  unsigned char prev;
-/*28*/  unsigned int pad;               /*
-                                         * Unused by the kernel, but we require
-                                         * the padding so that the array of
-                                         * hardware SCBs is alligned on 32 byte
-                                         * boundaries so the sequencer can index
-                                         */
+/*28*/  unsigned int pad;           /*
+                                     * Unused by the kernel, but we require
+                                     * the padding so that the array of
+                                     * hardware SCBs is alligned on 32 byte
+                                     * boundaries so the sequencer can index
+                                     */
 };
 
 typedef enum {
-       SCB_FREE                = 0x0000,
-       SCB_ACTIVE              = 0x0001,
-       SCB_ABORTED             = 0x0002,
-       SCB_DEVICE_RESET        = 0x0004,
-       SCB_SENSE               = 0x0008,
-       SCB_TIMEDOUT            = 0x0010,
-       SCB_QUEUED_FOR_DONE     = 0x0020,
-       SCB_RECOVERY_SCB        = 0x0040,
-       SCB_WAITINGQ            = 0x0080,
-       SCB_ASSIGNEDQ           = 0x0100,
-       SCB_SENTORDEREDTAG      = 0x0200,
-       SCB_MSGOUT_SDTR         = 0x0400,
-       SCB_MSGOUT_WDTR         = 0x0800,
-       SCB_ABORT               = 0x1000,
-       SCB_QUEUED_ABORT        = 0x2000,
-       SCB_RESET               = 0x4000,
-       SCB_WAS_BUSY            = 0x8000
+        SCB_FREE                = 0x0000,
+        SCB_WDTR_16BIT          = 0x0001,
+        SCB_WAITINGQ            = 0x0002,
+        SCB_ACTIVE              = 0x0004,
+        SCB_SENSE               = 0x0008,
+        SCB_ABORT               = 0x0010,
+        SCB_DEVICE_RESET        = 0x0020,
+        SCB_RESET               = 0x0040,
+        SCB_RECOVERY_SCB        = 0x0080,
+        SCB_WAS_BUSY            = 0x0100,
+        SCB_MSGOUT_SDTR         = 0x0400,
+        SCB_MSGOUT_WDTR         = 0x0800,
+        SCB_MSGOUT_WDTR_8BIT    = 0x0800,
+        SCB_MSGOUT_WDTR_16BIT   = 0x0801,
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_SDTR | SCB_MSGOUT_WDTR_16BIT,
+        SCB_QUEUED_ABORT        = 0x1000,
+        SCB_QUEUED_FOR_DONE     = 0x2000
 } scb_flag_type;
 
+typedef enum {
+        AHC_FNONE                 = 0x00000000,
+        AHC_PAGESCBS              = 0x00000001,
+        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
+        AHC_USEDEFAULTS           = 0x00000004,
+        AHC_INDIRECT_PAGING       = 0x00000008,
+        AHC_CHNLB                 = 0x00000020,
+        AHC_CHNLC                 = 0x00000040,
+        AHC_EXTEND_TRANS_A        = 0x00000100,
+        AHC_EXTEND_TRANS_B        = 0x00000200,
+        AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_B            = 0x00000800,
+        AHC_HANDLING_REQINITS     = 0x00001000,
+        AHC_TARGETMODE            = 0x00002000,
+        AHC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+        AHC_A_SCANNED             = 0x00100000,
+        AHC_B_SCANNED             = 0x00200000,
+        AHC_MULTI_CHANNEL         = 0x00400000,
+        AHC_BIOS_ENABLED          = 0x00800000,
+        AHC_ABORT_PENDING         = 0x02000000,
+        AHC_RESET_PENDING         = 0x04000000,
+        AHC_IN_ISR                = 0x10000000,
+        AHC_IN_ABORT              = 0x20000000,
+        AHC_IN_RESET              = 0x40000000
+} ahc_flag_type;
+
+typedef enum {
+        AHC_NONE                  = 0x00000000,
+        AHC_ULTRA                 = 0x00000001,
+        AHC_WIDE                  = 0x00000002,
+        AHC_TWIN                  = 0x00000008,
+        AHC_AIC7770               = 0x00000010,
+        AHC_AIC7850               = 0x00000020,
+        AHC_AIC7860               = 0x00000021,
+        AHC_AIC7870               = 0x00000040,
+        AHC_AIC7880               = 0x00000041,
+        AHC_AIC7895               = 0x00000081,
+        AHC_AIC78x0               = 0x000000E0,
+        AHC_274                   = 0x00000110,
+        AHC_284                   = 0x00000210,
+        AHC_294AU                 = 0x00000421,
+        AHC_294                   = 0x00000440,
+        AHC_294U                  = 0x00000441,
+        AHC_394                   = 0x00000840,
+        AHC_394U                  = 0x00000841,
+        AHC_394AU                 = 0x00000881,
+        AHC_398                   = 0x00001040,
+        AHC_398U                  = 0x00001041,
+        AHC_39x                   = 0x00001880
+} ahc_type;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
-       Scsi_Cmnd             *cmd;           /* Scsi_Cmnd for this scb */
+        Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
         struct aic7xxx_scb    *q_next;        /* next scb in queue */
-       scb_flag_type          flags;         /* current state of scb */
-       struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        scb_flag_type          flags;         /* current state of scb */
+        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          tag_action;
         unsigned char          sg_count;
-       unsigned char          sense_cmd[6];  /*
+        unsigned char          sense_cmd[6];  /*
                                                * Allocate 6 characters for
                                                * sense command.
                                                */
+        unsigned int           sg_length; /* We init this during buildscb so we
+                                           * don't have to calculate anything
+                                           * during underflow/overflow/stat code
+                                           */
 };
 
 /*
@@ -770,7 +791,7 @@ static struct {
   { ILLHADDR,  "Illegal Host Access" },
   { ILLSADDR,  "Illegal Sequencer Address referenced" },
   { ILLOPCODE, "Illegal Opcode in sequencer program" },
-  { PARERR,    "Sequencer Ram Parity Error" }
+  { SQPARERR,  "Sequencer Ram Parity Error" }
 };
 
 static unsigned char
@@ -786,62 +807,110 @@ typedef struct {
   unsigned char  maxhscbs;         /* hardware scbs */
   unsigned char  maxscbs;          /* max scbs including pageable scbs */
   struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
-  unsigned int   reserve[100];
 } scb_data_type;
 
+typedef struct {
+  unsigned char period;
+  unsigned char offset;
+} syncinfo_type;
+
 /*
- * Define a structure used for each host adapter, only one per IRQ.
+ * Define a structure used for each host adapter.  Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary.  It's also organized to try and be more
+ * cache line efficient.  Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
  */
 struct aic7xxx_host {
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
   struct Scsi_Host        *host;             /* pointer to scsi host */
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
   int                      host_no;          /* SCSI host number */
-  int                      instance;         /* aic7xxx instance number */
-  int                      scsi_id;          /* host adapter SCSI ID */
-  int                      scsi_id_b;        /*   channel B for twin adapters */
-  int                      irq;              /* IRQ for this adapter */
-  int                      base;             /* card base address */
-  unsigned int             mbase;            /* I/O memory address */
+  unsigned long            base;             /* card base address */
   volatile unsigned char  *maddr;            /* memory mapped address */
-#define A_SCANNED               0x0001
-#define B_SCANNED               0x0002
-#define EXTENDED_TRANSLATION    0x0004
-#define FLAGS_CHANNEL_B_PRIMARY 0x0008
-#define MULTI_CHANNEL           0x0010
-#define ULTRA_ENABLED           0x0020
-#define PAGE_ENABLED            0x0040
-#define USE_DEFAULTS            0x0080
-#define BIOS_ENABLED            0x0100
-#define IN_ISR                  0x0200
-#define ABORT_PENDING           0x0400
-#define SHARED_SCBDATA          0x0800
-#define HAVE_SEEPROM            0x1000
-#define RESET_PENDING           0x2000
-#define IN_ABORT               0x4000
-  unsigned int             flags;
-  unsigned long                   last_reset;
-  unsigned long                   reset_start;
-  unsigned int             isr_count;        /* Interrupt count */
-  unsigned short           needsdtr_copy;    /* default config */
-  unsigned short           needsdtr;
-  unsigned short           sdtr_pending;
-  unsigned short           needwdtr_copy;    /* default config */
-  unsigned short           needwdtr;
-  unsigned short           wdtr_pending;
-  unsigned short           orderedtag;
-  unsigned short           discenable;      /* Targets allowed to disconnect */
-  aha_chip_type            chip_type;        /* card type */
-  aha_chip_class_type      chip_class;
-  aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  unsigned char            chan_num;         /* for 39xx, channel number */
+  unsigned long            mbase;            /* I/O memory address */
+  volatile ahc_flag_type   flags;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+#endif
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+  ahc_type                 type;             /* card type */
+  unsigned long            last_reset;
+  unsigned long            isr_count;        /* Interrupt count */
+  unsigned long            spurious_int;
+  unsigned short           discenable;       /* Targets allowed to disconnect */
+  unsigned short           tagenable;        /* Targets using tagged I/O */
+  unsigned short           orderedtag;       /* Ordered Q tags allowed */
+  volatile unsigned char   activescbs;       /* active scbs */
+  unsigned char            max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
-  unsigned char            qcntmask;
-  unsigned char            qfullcount;
-  unsigned char            cmdoutcnt;
-  unsigned char            curqincnt;
-  struct Scsi_Host        *next;             /* allow for multiple IRQs */
-  unsigned char            activescbs;       /* active scbs */
-  scb_queue_type           waiting_scbs;     /*
+  volatile unsigned char   qoutfifonext;
+  volatile unsigned char   qinfifonext;
+
+  /*
+   * MAX_TARGETS is currently == 16, so that makes these entries the next
+   * 64 bytes
+   */
+
+#define  DEVICE_PRESENT                 0x01
+#define  BUS_DEVICE_RESET_PENDING       0x02
+#define  DEVICE_TIMEOUT                 0x04
+#define  DEVICE_PRINT_SDTR              0x08
+#define  DEVICE_PRINT_WDTR              0x10
+#define  DEVICE_SUCCESS                 0x20
+#define  DEVICE_TAGGED_SUCCESS          0x40
+  volatile unsigned char   dev_flags[MAX_TARGETS];
+  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
+  unsigned char            dev_temp_queue_depth[MAX_TARGETS];
+  unsigned char            dev_commands_sent[MAX_TARGETS];
+
+  /*
+   * The next 64.... 
+   */
+
+  long                     dev_last_reset[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            dev_mid_level_queue_depth[MAX_TARGETS];
+  unsigned char            dev_last_queue_full[MAX_TARGETS];
+  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+  unsigned char            dev_max_queue_depth[MAX_TARGETS];
+
+  /*
+   * The next 128....
+   */
+
+  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
+
+  /*
+   *
+   */
+
+  struct timer_list        dev_timer[MAX_TARGETS];
+
+  /*
+   * The next 64....
+   */
+
+  unsigned char            msg_buf[9];       /* The message for the target */
+  unsigned char            msg_type;
+#define MSG_TYPE_NONE              0x00
+#define MSG_TYPE_INITIATOR_MSGOUT  0x01
+#define MSG_TYPE_INITIATOR_MSGIN   0x02
+  unsigned char            msg_len;          /* Length of message */
+  unsigned char            msg_index;        /* Index into msg_buf array */
+  syncinfo_type            syncinfo[MAX_TARGETS];
+  volatile scb_queue_type  waiting_scbs;     /*
                                               * SCBs waiting for space in
                                               * the QINFIFO.
                                               */
@@ -851,23 +920,41 @@ struct aic7xxx_host {
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
   } completeq;
-  struct aic7xxx_device_status {
-    unsigned char active_cmds;
-    unsigned char max_queue_depth;
-    unsigned char temp_queue_depth;
-    unsigned char last_queue_full;
-    unsigned char last_queue_full_count;
-    struct timer_list timer;
-    long last_reset;
-#define  DEVICE_SUCCESS                 0x01
-#define  BUS_DEVICE_RESET_PENDING       0x02
-#define  DEVICE_TIMEOUT                 0x04
-    int  flags;
-    int  commands_sent;
-    scb_queue_type delayed_scbs;
-    Scsi_Cmnd *scsi_cmnd0;
-    Scsi_Cmnd *scsi_cmnd1;
-  } device_status[16];
+
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.  The only exceptions are the qinfifo, qoutfifo,
+   * and untagged_scbs array.  But, they are often accessed only once and each
+   * access into these arrays is likely to blow a cache line, so they are put
+   * down here so we can minimize the number of cache lines required to hold
+   * the preceeding entries.
+   */
+
+  volatile unsigned char   untagged_scbs[256];
+  volatile unsigned char   qoutfifo[256];
+  volatile unsigned char   qinfifo[256];
+  unsigned short           needsdtr;
+  unsigned short           sdtr_pending;
+  unsigned short           needwdtr;
+  unsigned short           wdtr_pending;
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /* channel B for twin adapters */
+  unsigned int             bios_address;
+  int                      board_name_index;
+  unsigned long            reset_start;
+  unsigned short           needsdtr_copy;    /* default config */
+  unsigned short           needwdtr_copy;    /* default config */
+  unsigned short           ultraenb;         /* Ultra mode target list */
+  unsigned short           bios_control;     /* bios control - SEEPROM */
+  unsigned short           adapter_control;  /* adapter control - SEEPROM */
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+  unsigned char            irq;              /* IRQ for this adapter */
+
 #ifdef AIC7XXX_PROC_STATS
   /*
    * Statistics Kept:
@@ -879,6 +966,10 @@ struct aic7xxx_host {
    *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
    *
    * Total amounts read/written above 512 bytes (amts under ignored)
+   *
+   * NOTE: Enabling this feature is likely to cause a noticeable performance
+   * decrease as the accesses into the stats structures blows apart multiple
+   * cache lines and is CPU time consuming.
    */
   struct aic7xxx_xferstats {
     long xfers;                              /* total xfer count */
@@ -900,7 +991,7 @@ struct aic7xxx_host {
 static struct {
   short period;
   /* Rates in Ultra mode have bit 8 of sxfr set */
-#define                ULTRA_SXFR 0x100
+#define                ULTRA_SXFR 0x100
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
@@ -920,40 +1011,6 @@ static struct {
 static int num_aic7xxx_syncrates =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
-#ifdef CONFIG_PCI
-static int number_of_3940s = 0;
-static int number_of_3985s = 0;
-#endif /* CONFIG_PCI */
-
-#ifdef AIC7XXX_DEBUG
-
-#if 0
-static void
-debug_scb(struct aic7xxx_scb *scb)
-{
-  struct aic7xxx_hwscb *hscb = scb->hscb;
-
-  printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
-    scb,
-    hscb->control,
-    hscb->target_channel_lun,
-    hscb->SCSI_cmd_length,
-    hscb->SCSI_cmd_pointer );
-  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
-    hscb->data_count,
-    hscb->data_pointer,
-    hscb->SG_segment_count,
-    hscb->SG_list_pointer);
-  printk("        sg_addr:%lx sg_len:%ld\n",
-    hscb->sg_list[0].address,
-    hscb->sg_list[0].length);
-}
-#endif
-
-#else
-#  define debug_scb(x)
-#endif AIC7XXX_DEBUG
-
 #define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
                         (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
                         ((scb->hscb)->target_channel_lun & 0x07)
@@ -962,49 +1019,26 @@ debug_scb(struct aic7xxx_scb *scb)
                         ((cmd->target) & 0x0f), \
                         ((cmd->lun) & 0x07)
 
-static inline int
-CHAN_TO_INT(char chan)
-{
-  switch(chan)
-  {
-    case ALL_CHANNELS:
-       return(-1);
-    case 'B':
-    case 'b':
-        return(1);
-    case 'A':
-    case 'a':
-        return(0);
-    default:
-        printk(KERN_WARNING "aic7xxx: Bad usage of char channel.\n");
-        return(0);
-  }
-}
-
-static inline char
-INT_TO_CHAN(int chan)
-{
-  switch(chan)
-  {
-    case -1:
-       return(ALL_CHANNELS);
-    case 1:
-        return('B');
-    case 0:
-        return('A');
-    default:
-        printk(KERN_WARNING "aic7xxx: Bad usage of int channel.\n");
-        return('A');
-  }
-}
+#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
+/*
+ * A nice little define to make doing our printks a little easier
+ */
 
-#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
 
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
  *       cards in the system.  This should be fixed.
  */
+static int aic7xxx_7895_irq_hack = -1;       /* This enables a hack to fix
+                                              * IRQ settings on buggy 7895
+                                              * MB controller setups
+                                              *  -1 == Disable this hack
+                                              *   0 == Use the Channel A IRQ
+                                              *   1 == Use the Channel B IRQ
+                                              */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
 static int aic7xxx_irq_trigger = -1;         /*
@@ -1012,8 +1046,96 @@ static int aic7xxx_irq_trigger = -1;         /*
                                               *  0 use edge triggered
                                               *  1 use level triggered
                                               */
-static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
-static int aic7xxx_verbose = 0;                     /* verbose messages */
+static int aic7xxx_reverse_scan = 0;         /*
+                                              * Set this to anything but 0
+                                              * to make the probe code
+                                              * reverse the order of PCI
+                                              * devices
+                                              */
+static int aic7xxx_override_term = 0;        /*
+                                              * Set this to non-0 to make the
+                                              * driver override any BIOS
+                                              * configured termination
+                                              * settings based upon the
+                                              * results of the cable detect
+                                              * logic.  This only applies
+                                              * to cards that have cable
+                                              * detection logic and a SEEPROM
+                                              */
+static int aic7xxx_panic_on_abort = 0;       /*
+                                              * Set this to non-0 in order
+                                              * to force the driver to panic
+                                              * the kernel and print out
+                                              * debugging info on an abort
+                                              * or reset call into the
+                                              * driver.
+                                              */
+
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+/*
+ * See the comments earlier in the file for what this item is all about
+ * If you have more than 4 controllers, you will need to increase the
+ * the number of items in the array below.  Additionally, if you don't
+ * want to have lilo pass a humongous config line to the aic7xxx driver,
+ * then you can get in and manually adjust these instead of leaving them
+ * at the default.  Pay attention to the comments earlier in this file
+ * concerning this array if you are going to hand modify these values.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+#define VERBOSE_NORMAL         0x0000
+#define VERBOSE_NEGOTIATION    0x0001
+#define VERBOSE_SEQINT         0x0002
+#define VERBOSE_SCSIINT        0x0004
+#define VERBOSE_PROBE          0x0008
+#define VERBOSE_PROBE2         0x0010
+#define VERBOSE_QUEUE          0x0020
+#define VERBOSE_MINOR_ERROR    0x0040
+#define VERBOSE_QUEUE_FULL     0x0080
+#define VERBOSE_ABORT          0x0f00
+#define VERBOSE_ABORT_MID      0x0100
+#define VERBOSE_ABORT_FIND     0x0200
+#define VERBOSE_ABORT_PROCESS  0x0400
+#define VERBOSE_ABORT_RETURN   0x0800
+#define VERBOSE_RESET          0xf000
+#define VERBOSE_RESET_MID      0x1000
+#define VERBOSE_RESET_FIND     0x2000
+#define VERBOSE_RESET_PROCESS  0x4000
+#define VERBOSE_RESET_RETURN   0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+           VERBOSE_PROBE;                     /* verbose messages */
 
 
 /****************************************************************************
@@ -1023,52 +1145,44 @@ static int aic7xxx_verbose = 0;              /* verbose messages */
  *
  ***************************************************************************/
 
+
 static inline unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
-  if (p->maddr != NULL)
-    return (p->maddr[port]);
+  unsigned char x;
+  if(p->maddr)
+    x = p->maddr[port];
   else
-    return (inb(p->base + port));
+    x = inb(p->base + port);
+  mb();
+  return(x);
 }
 
 static inline void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
     p->maddr[port] = val;
   else
     outb(val, p->base + port);
+  mb();
 }
 
 static inline void
 aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
 {
-  if (p->maddr != NULL)
+  if(p->maddr)
   {
-#ifdef __alpha__
     int i;
 
     for (i=0; i < size; i++)
     {
       p->maddr[port] = valp[i];
     }
-#else
-    __asm __volatile("
-      cld;
-    1:  lodsb;
-      movb %%al,(%0);
-      loop 1b"      :
-              :
-      "r" (p->maddr + port),
-      "S" (valp), "c" (size)  :
-      "%esi", "%ecx", "%eax");
-#endif
   }
   else
-  {
     outsb(p->base + port, valp, size);
-  }
+  mb();
 }
 
 /*+F*************************************************************************
@@ -1085,6 +1199,7 @@ aic7xxx_setup(char *s, int *dummy)
 {
   int   i, n;
   char *p;
+  char *end;
 
   static struct {
     const char *name;
@@ -1093,25 +1208,112 @@ aic7xxx_setup(char *s, int *dummy)
     { "extended",    &aic7xxx_extended },
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
-    { "ultra",       &aic7xxx_enable_ultra },
     { "verbose",     &aic7xxx_verbose },
-    { NULL,          NULL }
+    { "reverse_scan",&aic7xxx_reverse_scan },
+    { "7895_irq_hack", &aic7xxx_7895_irq_hack },
+    { "override_term", &aic7xxx_override_term },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
+    { "tag_info",    NULL }
   };
 
-  for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+  end = strchr(s, '\0');
+
+  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
   {
-    for (i = 0; options[i].name; i++)
+    for (i = 0; i < NUMBER(options); i++)
     {
       n = strlen(options[i].name);
       if (!strncmp(options[i].name, p, n))
       {
-        if (p[n] == ':')
+        if (!strncmp(p, "tag_info", n))
+        {
+          if (p[n] == ':')
+          {
+            char *base;
+            char *tok, *tok_end, *tok_end2;
+            char tok_list[] = { '.', ',', '{', '}', '\0' };
+            int i, instance = -1, device = -1;
+            unsigned char done = FALSE;
+
+            base = p;
+            tok = base + n + 1;  /* Forward us just past the ':' */
+            tok_end = strchr(tok, '\0');
+            if (tok_end < end)
+              *tok_end = ',';
+            while(!done)
+            {
+              switch(*tok)
+              {
+                case '{':
+                  if (instance == -1)
+                    instance = 0;
+                  else if (device == -1)
+                    device = 0;
+                  tok++;
+                  break;
+                case '}':
+                  if (device != -1)
+                    device = -1;
+                  else if (instance != -1)
+                    instance = -1;
+                  tok++;
+                  break;
+                case ',':
+                case '.':
+                  if (instance == -1)
+                    done = TRUE;
+                  else if (device >= 0)
+                    device++;
+                  else if (instance >= 0)
+                    instance++;
+                  if ( (device >= MAX_TARGETS) || 
+                       (instance >= NUMBER(aic7xxx_tag_info)) )
+                    done = TRUE;
+                  tok++;
+                  if (!done)
+                  {
+                    base = tok;
+                  }
+                  break;
+                case '\0':
+                  done = TRUE;
+                  break;
+                default:
+                  done = TRUE;
+                  tok_end = strchr(tok, '\0');
+                  for(i=0; tok_list[i]; i++)
+                  {
+                    tok_end2 = strchr(tok, tok_list[i]);
+                    if ( (tok_end2) && (tok_end2 < tok_end) )
+                    {
+                      tok_end = tok_end2;
+                      done = FALSE;
+                    }
+                  }
+                  if ( (instance >= 0) && (device >= 0) &&
+                       (instance < NUMBER(aic7xxx_tag_info)) &&
+                       (device < MAX_TARGETS) )
+                    aic7xxx_tag_info[instance].tag_commands[device] =
+                      simple_strtoul(tok, NULL, 0) & 0xff;
+                  tok = tok_end;
+                  break;
+              }
+            }
+            while((p != base) && (p != NULL))
+              p = strtok(NULL, ",.");
+          }
+        }
+        else if (p[n] == ':')
         {
           *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
         }
+        else if (!strncmp(p, "verbose", n))
+        {
+          *(options[i].flag) = 0xff69;
+        }
         else
         {
-          *(options[i].flag) += 1;
+          *(options[i].flag) = ~(*(options[i].flag));
         }
       }
     }
@@ -1130,8 +1332,8 @@ aic7xxx_setup(char *s, int *dummy)
 static inline void
 pause_sequencer(struct aic7xxx_host *p)
 {
-  outb(p->pause, p->base + HCNTRL);
-  while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+  aic_outb(p, p->pause, HCNTRL);
+  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
   {
     ;
   }
@@ -1149,9 +1351,10 @@ static inline void
 unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
 {
   if (unpause_always ||
-      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+        !(p->flags & AHC_HANDLING_REQINITS) ) )
   {
-    outb(p->unpause, p->base + HCNTRL);
+    aic_outb(p, p->unpause, HCNTRL);
   }
 }
 
@@ -1167,17 +1370,16 @@ static inline void
 restart_sequencer(struct aic7xxx_host *p)
 {
   /* Set the sequencer address to 0. */
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   /*
    * Reset and unpause the sequencer.  The reset is suppose to
-   * start the sequencer running, but we do an unpause to make
-   * sure.
+   * start the sequencer running, so we immediately do a pause_sequencer
+   * since some of our code expects the sequencer paused after a restart
    */
-  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
-
-  unpause_sequencer(p, /*unpause_always*/ TRUE);
+  aic_outb(p, SEQRESET | FASTMODE, SEQCTL);
+  pause_sequencer(p);
 }
 
 
@@ -1229,11 +1431,12 @@ static void
 aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
 {
   unsigned char opcode;
-  struct ins_format3 *instr;
+  struct ins_format3 instr;
+  unsigned char dconsts[4] = { 0, 0, 0, 0 };
 
-  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+  instr = *(struct ins_format3 *) &seqprog[instrptr * 4];
   /* Pull the opcode */
-  opcode = instr->opcode_addr >> 1;
+  opcode = (instr.opcode_addr & ~DOWNLOAD_CONST_IMMEDIATE) >> 1;
   switch (opcode)
   {
     case AIC_OP_JMP:
@@ -1246,15 +1449,13 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
     case AIC_OP_JZ:
     {
       int address_offset;
-      struct ins_format3 new_instr;
       unsigned int address;
       struct patch *patch;
       int i;
 
       address_offset = 0;
-      new_instr = *instr;  /* Strucure copy */
-      address = new_instr.address;
-      address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+      address = instr.address;
+      address |= (instr.opcode_addr & ADDR_HIGH_BIT) << 8;
       for (i = 0; i < NUMBER(patches); i++)
       {
         patch = &patches[i];
@@ -1268,20 +1469,23 @@ aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
         }
       }
       address -= address_offset;
-      new_instr.address = address &0xFF;
-      new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
-      new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
-      outsb(p->base + SEQRAM, &new_instr.immediate, 4);
-      break;
+      instr.address = address & 0xFF;
+      instr.opcode_addr &= ~ADDR_HIGH_BIT;
+      instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
     }
-
+       /*  Fall through  */
     case AIC_OP_OR:
     case AIC_OP_AND:
     case AIC_OP_XOR:
     case AIC_OP_ADD:
     case AIC_OP_ADC:
+      if (instr.opcode_addr & DOWNLOAD_CONST_IMMEDIATE)
+      {
+        instr.immediate = dconsts[instr.immediate];
+      }
+      instr.opcode_addr &= ~DOWNLOAD_CONST_IMMEDIATE;
     case AIC_OP_ROL:
-      outsb(p->base + SEQRAM, &instr->immediate, 4);
+      aic_outsb(p, SEQRAM, &instr.immediate, 4);
       break;
 
     default:
@@ -1306,23 +1510,60 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
   int i;
   int downloaded;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk("\n");
   options = 1;  /* Code for all options. */
   downloaded = 0;
-  if ((p->flags & ULTRA_ENABLED) != 0)
+  if (p->type & AHC_ULTRA)
+  {
     options |= ULTRA;
-  if (p->bus_type == AIC_TWIN)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option ULTRA\n",
+        p->host_no);
+  }
+  if (p->type & AHC_TWIN)
+  {
     options |= TWIN_CHANNEL;
-  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option "
+        "TWIN_CHANNEL\n", p->host_no);
+  }
+  if (p->type & AHC_WIDE)
+  {
+    options |= WIDE;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option WIDE\n",
+        p->host_no);
+  }
+  /* if (p->scb_data->maxscbs > p->scb_data->maxhscbs)  this should always
+                                                        be true, don't test,
+                                                        just do.            */
+  {
     options |= SCB_PAGING;
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(KERN_INFO "(scsi%d)   Will download code for option SCB_PAGING\n",
+        p->host_no);
+  }
+  /* We don't actually support target mode yet, so leave this out 
+  if (p->flags & AHC_TARGETMODE)
+    options |= TARGET_MODE; */
+
+  if ( (options & ~(ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01)) )
+  {
+    printk(KERN_INFO "(scsi%d) Unknown bits set in the options field, "
+      "correcting.\n", p->host_no);
+    options &= ULTRA|TWIN_CHANNEL|WIDE|SCB_PAGING|0x01;
+  }
+
 
   cur_patch = patches;
-  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, PERRORDIS | LOADRAM, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
 
   for (i = 0; i < sizeof(seqprog) / 4;  i++)
   {
@@ -1336,13 +1577,16 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
     downloaded++;
   }
 
-  outb(FASTMODE, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  aic_outb(p, FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+    printk(KERN_INFO "(scsi%d) Download complete,", p->host_no);
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE)
   {
-     printk(" %d instructions downloaded\n", downloaded);
+    printk(" %d instructions downloaded\n", downloaded);
   }
 }
 
@@ -1358,7 +1602,7 @@ aic7xxx_loadseq(struct aic7xxx_host *p)
 static void
 aic7xxx_delay(int seconds)
 {
-  int i;
+  unsigned int i;
 
   /*                        
    * Call udelay() for 1 millisecond inside a loop for  
@@ -1372,131 +1616,57 @@ aic7xxx_delay(int seconds)
 
 /*+F*************************************************************************
  * Function:
- *   rcs_version
+ *   aic7xxx_info
  *
  * Description:
- *   Return a string containing just the RCS version number from either
- *   an Id or Revision RCS clause.
+ *   Return a string describing the driver.
  *-F*************************************************************************/
 const char *
-rcs_version(const char *version_info)
+aic7xxx_info(struct Scsi_Host *dooh)
 {
-  static char buf[10];
-  char *bp, *ep;
-
-  bp = NULL;
-  strcpy(buf, "????");
-  if (!strncmp(version_info, "$Id: ", 5))
-  {
-    if ((bp = strchr(version_info, ' ')) != NULL)
-    {
-      bp++;
-      if ((bp = strchr(bp, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-  else
-  {
-    if (!strncmp(version_info, "$Revision: ", 11))
-    {
-      if ((bp = strchr(version_info, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-
-  if (bp != NULL)
-  {
-    if ((ep = strchr(bp, ' ')) != NULL)
-    {
-      register int len = ep - bp;
-
-      strncpy(buf, bp, len);
-      buf[len] = '\0';
-    }
-  }
+  static char buffer[256];
+  char *bp;
+  struct aic7xxx_host *p;
 
-  return buf;
+  bp = &buffer[0];
+  p = (struct aic7xxx_host *)dooh->hostdata;
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(bp, AIC7XXX_C_VERSION);
+  strcat(bp, "/");
+  strcat(bp, AIC7XXX_H_VERSION);
+  strcat(bp, "\n");
+  strcat(bp, "       <");
+  strcat(bp, board_names[p->board_name_index]);
+  strcat(bp, ">");
+
+  return(bp);
 }
 
+
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_info
+ *   aic7xxx_scsirate
  *
  * Description:
- *   Return a string describing the driver.
+ *   Look up the valid period to SCSIRATE conversion in our table
  *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
+static unsigned char
+aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
+    unsigned char *period, unsigned char *offset, int target, int channel,
+    int set)
 {
-  static char buffer[128];
+  int i = num_aic7xxx_syncrates;
+  unsigned char response_period;
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun;
 
-  strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
-  strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
-  strcat(buffer, "/");
-  strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
-#if 0
-  strcat(buffer, "/");
-  strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
 
-  return buffer;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_length
- *
- * Description:
- *   How much data should be transferred for this SCSI command?  Assume
- *   all segments are to be transferred except for the last sg_last
- *   segments.  This will allow us to compute underflow easily.  To
- *   calculate the total length of the command, use sg_last = 0.  To
- *   calculate the length of all but the last 2 SG segments, use
- *   sg_last = 2.
- *-F*************************************************************************/
-static unsigned
-aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
-{
-  int i, segments;
-  unsigned length;
-  struct scatterlist *sg;
-
-  segments = cmd->use_sg - sg_last;
-  sg = (struct scatterlist *) cmd->request_buffer;
-
-  if (cmd->use_sg)
-  {
-    for (i = length = 0; i < segments; i++)
-    {
-      length += sg[i].length;
-    }
-  }
-  else
-  {
-    length = cmd->request_bufflen;
-  }
-
-  return (length);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_scsirate
- *
- * Description:
- *   Look up the valid period to SCSIRATE conversion in our table
- *-F*************************************************************************/
-static void
-aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    unsigned char *period, unsigned char *offset, int target, char channel)
-{
-  int i = num_aic7xxx_syncrates;
-  unsigned long ultra_enb_addr;
-  unsigned char ultra_enb, sxfrctl0;
+  response_period = *period;
 
   /*
    * If the offset is 0, then the device is requesting asynchronous
@@ -1512,7 +1682,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
          * Watch out for Ultra speeds when ultra is not enabled and
          * vice-versa.
          */
-        if (!(p->flags & ULTRA_ENABLED) &&
+        if (!(p->type & AHC_ULTRA) &&
             (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
         {
           /*
@@ -1525,11 +1695,31 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
         *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
         *period = aic7xxx_syncrates[i].period;
 
-        if (aic7xxx_verbose)
+        /*
+         * When responding to a target that requests
+         * sync, that rate may fall between two rates
+         * that we can output, but still be a rate
+         * that we can receive.  Because of this,
+         * we may want to respond to the target with
+         * the same rate that it sent to us even
+         * if the period we use to send data to it
+         * is lower.  Only lower the response period
+         * if we must.
+         */
+        if ((i == 0) ||
+           ((aic7xxx_syncrates[i-1].rate & ULTRA_SXFR) != 0
+             && (p->type & AHC_ULTRA) == 0))
+        {
+          response_period = *period;
+        }
+
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
         {
-          printk("(scsi%d:%d:%d:%d) Synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, CHAN_TO_INT(channel), target, 0,
+          printk(INFO_LEAD "Synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, channel, target, lun,
                  aic7xxx_syncrates[i].english, *offset);
+          p->dev_flags[tindex] &= ~ DEVICE_PRINT_SDTR;
         }
         break;
       }
@@ -1544,35 +1734,43 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
     *scsirate = 0;
     *period = 0;
     *offset = 0;
-    if (aic7xxx_verbose)
+    response_period = 0;
+    if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
     {
-      printk("(scsi%d:%d:%d:%d) Using asynchronous transfers.\n",
-             p->host_no, CHAN_TO_INT(channel), target, 0);
+      printk(INFO_LEAD "Using asynchronous transfers.\n",
+             p->host_no, channel, target, lun);
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
     }
   }
 
   /*
    * Ensure Ultra mode is set properly for this target.
    */
-  ultra_enb_addr = ULTRA_ENB;
-  if ((channel == 'B') || (target > 7))
+  if ( (*scsirate != 0) && 
+       (aic7xxx_syncrates[i].rate & ULTRA_SXFR) )
   {
-    ultra_enb_addr++;
+    p->ultraenb |= target_mask;
   }
-  ultra_enb = inb(p->base + ultra_enb_addr);
-  sxfrctl0 = inb(p->base + SXFRCTL0);
-  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+  else
   {
-    ultra_enb |= 0x01 << (target & 0x07);
-    sxfrctl0 |= FAST20;
+    p->ultraenb &= ~target_mask;
   }
-  else
+  if (set)
   {
-    ultra_enb &= ~(0x01 << (target & 0x07));
+    unsigned char sxfrctl0;
+
+    sxfrctl0 = aic_inb(p, SXFRCTL0);
     sxfrctl0 &= ~FAST20;
+    if (p->ultraenb & target_mask)
+    {
+      sxfrctl0 |= FAST20;
+    }
+    aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+    aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1);
+    aic_outb(p, sxfrctl0, SXFRCTL0);
   }
-  outb(ultra_enb, p->base + ultra_enb_addr);
-  outb(sxfrctl0, p->base + SXFRCTL0);
+  return(response_period);
 }
 
 /*+F*************************************************************************
@@ -1584,7 +1782,7 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
  *
  *-F*************************************************************************/
 static inline void
-scbq_init(scb_queue_type *queue)
+scbq_init(volatile scb_queue_type *queue)
 {
   queue->head = NULL;
   queue->tail = NULL;
@@ -1599,16 +1797,12 @@ scbq_init(scb_queue_type *queue)
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
   scb->q_next = queue->head;
   queue->head = scb;
   if (queue->tail == NULL)       /* If list was empty, update tail. */
     queue->tail = queue->head;
-  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1619,17 +1813,16 @@ scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   Remove an SCB from the head of the list.
  *
  *-F*************************************************************************/
-static inline void
-scbq_remove_head(scb_queue_type *queue)
+static __inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
+  struct aic7xxx_scb * scbp;
+  scbp = queue->head;
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
-  restore_flags(processor_flags);
+  return(scbp);
 }
 
 /*+F*************************************************************************
@@ -1641,11 +1834,8 @@ scbq_remove_head(scb_queue_type *queue)
  *
  *-F*************************************************************************/
 static inline void
-scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
   if (queue->head == scb)
   {
     /* At beginning of queue, remove from head. */
@@ -1674,7 +1864,6 @@ scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
       }
     }
   }
-  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1686,19 +1875,14 @@ scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *
  *-F*************************************************************************/
 static inline void
-scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-  unsigned long processor_flags;
-  save_flags(processor_flags);
-  cli();
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
-
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
-  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1712,11 +1896,11 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   to be reset and all devices on that channel must be aborted.
  *-F*************************************************************************/
 static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
-    int lun, unsigned char tag)
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    int target, int channel, int lun, unsigned char tag)
 {
   int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
   int slun = scb->hscb->target_channel_lun & 0x07;
   int match;
 
@@ -1728,22 +1912,12 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
   if (match != 0)
     match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
 
-  if (aic7xxx_verbose > 4)
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
   {
-    if (match)
-    {
-      printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) matches search criteria"
-        " (scsi%d:%d:%d:%d:tag%d)\n", scb->cmd->device->host->host_no,
-        CTL_OF_SCB(scb), scb->hscb->tag, scb->cmd->device->host->host_no,
-        CHAN_TO_INT(channel), target, lun, tag);
-    }
-    else
-    {
-      printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) doesn't match search criteria"
-        " (scsi%d:%d:%d:%d:tag%d)\n", scb->cmd->device->host->host_no,
-        CTL_OF_SCB(scb), scb->hscb->tag, scb->cmd->device->host->host_no,
-        CHAN_TO_INT(channel), target, lun, tag);
-    }
+    printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
+      " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
+      scb->hscb->tag, (match) ? "matches" : "doesn't match",
+      p->host_no, channel, target, lun, tag);
   }
 
   return (match);
@@ -1763,10 +1937,11 @@ aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
    * Invalidate the tag so that aic7xxx_find_scb doesn't think
    * it's active
    */
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+  aic_outb(p, 0, SCB_CONTROL);
 
-  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
-  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
 }
 
 /*+F*************************************************************************
@@ -1783,29 +1958,25 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
   unsigned char next;
   unsigned char prev;
 
-  outb(scbptr, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-  prev = inb(p->base + SCB_PREV);
-
-  outb(0, p->base + SCB_CONTROL);
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
-
+  aic_outb(p, scbptr, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+  prev = aic_inb(p, SCB_PREV);
   aic7xxx_add_curscb_to_free_list(p);
 
   if (prev != SCB_LIST_NULL)
   {
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   else
   {
-    outb(next, p->base + DISCONNECTED_SCBH);
+    aic_outb(p, next, DISCONNECTED_SCBH);
   }
 
   if (next != SCB_LIST_NULL)
   {
-    outb(next, p->base + SCBPTR);
-    outb(prev, p->base + SCB_PREV);
+    aic_outb(p, next, SCBPTR);
+    aic_outb(p, prev, SCB_PREV);
   }
   return next;
 }
@@ -1817,23 +1988,10 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
  * Description:
  *   Set the specified target busy.
  *-F*************************************************************************/
-static void
-aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, unsigned char scbid)
+static __inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
-  unsigned int  scb_offset;
-
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  outb(scbid, p->base + scb_offset);
-  outb(active_scb, p->base + SCBPTR);
+  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
 }
 
 /*+F*************************************************************************
@@ -1844,28 +2002,17 @@ aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
  *   Returns the index of the busy target, and optionally sets the
  *   target inactive.
  *-F*************************************************************************/
-static unsigned char
-aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, int unbusy)
+static __inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+    int unbusy)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
   unsigned char busy_scbid;
-  unsigned int  scb_offset;
 
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  busy_scbid = inb(p->base + scb_offset);
+  busy_scbid = p->untagged_scbs[tcl];
   if (unbusy)
   {
-    outb(SCB_LIST_NULL, p->base + scb_offset);
+    p->untagged_scbs[tcl] = SCB_LIST_NULL;
   }
-  outb(active_scb, p->base + SCBPTR);
   return (busy_scbid);
 }
 
@@ -1885,17 +2032,17 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   unsigned char saved_scbptr;
   unsigned char curindex;
 
-  saved_scbptr = inb(p->base + SCBPTR);
+  saved_scbptr = aic_inb(p, SCBPTR);
   curindex = 0;
   for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
   {
-    outb(curindex, p->base + SCBPTR);
-    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+    aic_outb(p, curindex, SCBPTR);
+    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
     {
       break;
     }
   }
-  outb(saved_scbptr, p->base + SCBPTR);
+  aic_outb(p, saved_scbptr, SCBPTR);
   if (curindex >= p->scb_data->maxhscbs)
   {
     curindex = SCB_LIST_NULL;
@@ -1912,43 +2059,83 @@ aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
  *   Get an SCB from the free list or by allocating a new one.
  *-F*************************************************************************/
 static struct aic7xxx_scb *
-aic7xxx_allocate_scb(struct aic7xxx_host *p)
+aic7xxx_allocate_scb(struct aic7xxx_host *p, int force_alloc)
 {
   struct aic7xxx_scb   *scbp = NULL;
-  struct aic7xxx_hwscb *hscbp = NULL;
+  int scb_size = sizeof(struct aic7xxx_scb) +
+                 sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
+  int i;
+  unsigned long scb_count = 0;
+  struct hw_scatterlist *hsgp;
+  struct aic7xxx_scb *scb_ap;
 
-  scbp = p->scb_data->free_scbs.head;
-  if (scbp != NULL)
+
+  if (force_alloc == FALSE)
   {
-    scbq_remove_head(&p->scb_data->free_scbs);
+    scbp = scbq_remove_head(&p->scb_data->free_scbs);
+    if (scbp != NULL)
+      return(scbp);
   }
-  else
+  /*
+   * Either there wasn't an SCB or this is a strictly allocation call
+   */
+
+  if (p->scb_data->numscbs < p->scb_data->maxscbs)
   {
-    if (p->scb_data->numscbs < p->scb_data->maxscbs)
-    {
-      int scb_index = p->scb_data->numscbs;
-      int scb_size = sizeof(struct aic7xxx_scb) +
-                     sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
 
-      scbp = kmalloc(scb_size, GFP_ATOMIC);
-      if (scbp != NULL)
+    /*
+     * Optimize for 30 scbs at a time, but allow a final allocation of
+     * fewer than 30 scbs.  Except on 64 bit platforms, we optimize for
+     * 29 SCBs at a time because a pointer is 4 bytes larger and we don't
+     * want to overrun this suppossedly 32K allocation to 64K and waste
+     * tons of space.
+     */
+    if( sizeof(void *) == sizeof(int) )
+      scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+    else
+      scb_count = MIN(29, p->scb_data->maxscbs - p->scb_data->numscbs);
+    
+    scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
+    if (scb_ap != NULL)
+    {
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+      {
+        if (p->scb_data->numscbs == 0)
+          printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+        else
+          printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+            p->host_no, -1, -1, -1, scb_count);
+      }
+      memset(scb_ap, 0, scb_count * scb_size);
+      hsgp = (struct hw_scatterlist *) &scb_ap[scb_count];
+      for (i=0; i < scb_count; i++)
       {
-        memset(scbp, 0, sizeof(struct aic7xxx_scb));
-        hscbp = &p->scb_data->hscbs[scb_index];
-        scbp->hscb = hscbp;
-        scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
-        memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
-        hscbp->tag = scb_index;
-        p->scb_data->numscbs++;
+        scbp = &scb_ap[i];
+        scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+        scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+        memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+        scbp->hscb->tag = p->scb_data->numscbs;
         /*
          * Place in the scb array; never is removed
          */
-        p->scb_data->scb_array[scb_index] = scbp;
+        p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+        scbq_insert_head(&p->scb_data->free_scbs, scbp);
       }
     }
+    else
+    {
+      return(NULL);
+    }
+  }
+  if (force_alloc == TRUE)
+  {
+    return((struct aic7xxx_scb *)scb_count);
+  }
+  else
+  {
+    return(scbq_remove_head(&p->scb_data->free_scbs));
   }
-
-  return (scbp);
 }
 
 /*+F*************************************************************************
@@ -1963,12 +2150,8 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
 static inline void
 aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  unsigned int flags;
-  save_flags(flags);
-  cli();
   cmd->host_scribble = (char *)p->completeq.head;
   p->completeq.head = cmd;
-  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1982,20 +2165,21 @@ static inline void
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
-  unsigned int processor_flags;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned int cpu_flags = 0;
+#endif
   
-  save_flags(processor_flags);
-  cli();
+  DRIVER_LOCK
   while (p->completeq.head != NULL)
   {
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    restore_flags(processor_flags);
+    DRIVER_UNLOCK
     cmd->scsi_done(cmd);
-    cli();
+    DRIVER_LOCK
   }
-  restore_flags(processor_flags);
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2008,14 +2192,15 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_hwscb *hscb;
-
-  hscb = scb->hscb;
 
   scb->flags = SCB_FREE;
   scb->cmd = NULL;
-  hscb->control = 0;
-  hscb->target_status = 0;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+  scb->tag_action = 0;
+  scb->hscb->control = 0;
+  scb->hscb->target_status = 0;
+  scb->hscb->target_channel_lun = SCB_LIST_NULL;
 
   scbq_insert_head(&p->scb_data->free_scbs, scb);
 }
@@ -2037,24 +2222,24 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 
   if (scb->flags & SCB_RECOVERY_SCB)
   {
-    p->flags &= ~ABORT_PENDING;
+    p->flags &= ~AHC_ABORT_PENDING;
   }
   if (scb->flags & SCB_RESET)
   {
       cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
-       (cmd->result & 0xffff);
+        (cmd->result & 0xffff);
   }
   else if (scb->flags & SCB_ABORT)
   {
       cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
-       (cmd->result & 0xffff);
+        (cmd->result & 0xffff);
   }
   if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
 
-    mask = 0x01 << TARGET_INDEX(scb->cmd);
+    mask = 0x01 << tindex;
  
     /*
      * Check to see if we get an invalid message or a message error
@@ -2072,6 +2257,17 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       p->wdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
+        }
         p->needwdtr &= ~mask;
         p->needwdtr_copy &= ~mask;
       }
@@ -2081,54 +2277,74 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       p->sdtr_pending &= ~mask;
       if (message_error)
       {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+        }
         p->needsdtr &= ~mask;
         p->needsdtr_copy &= ~mask;
       }
     }
   }
-  queue_depth = (p->device_status[tindex].timer.expires) ?
-                p->device_status[tindex].temp_queue_depth :
-                p->device_status[tindex].max_queue_depth;
-  scbp = p->device_status[tindex].delayed_scbs.head;
-  if ( (scbp != NULL) && 
-       (queue_depth > p->device_status[tindex].active_cmds) )
+  queue_depth = p->dev_temp_queue_depth[tindex];
+  if (queue_depth >= p->dev_active_cmds[tindex])
   {
-    scbq_remove_head(&p->device_status[tindex].delayed_scbs);
-    scbq_insert_tail(&p->waiting_scbs, scbp);
-    scbp = p->device_status[tindex].delayed_scbs.head;
-    if ( (scbp != NULL) && 
-         (queue_depth > (p->device_status[tindex].active_cmds + 1)) )
-    {
-      scbq_remove_head(&p->device_status[tindex].delayed_scbs);
+    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+    if (scbp)
       scbq_insert_tail(&p->waiting_scbs, scbp);
+    if ( (queue_depth > p->dev_active_cmds[tindex]) && scbp)
+    {
+      scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+      if (scbp)
+        scbq_insert_tail(&p->waiting_scbs, scbp);
     }
   }
-  if ( (p->device_status[tindex].timer.expires) &&
-      ((p->device_status[tindex].active_cmds == 1) ||
-       (p->device_status[tindex].max_queue_depth ==
-       p->device_status[tindex].temp_queue_depth)) )
+  if ( (p->dev_timer[tindex].expires) &&
+      ((p->dev_active_cmds[tindex] == 1) ||
+       (p->dev_max_queue_depth[tindex] ==
+        p->dev_temp_queue_depth[tindex])) )
   {
-    del_timer(&p->device_status[tindex].timer);
-    p->device_status[tindex].timer.expires = 0;
-    p->device_status[tindex].temp_queue_depth = 
-          p->device_status[tindex].max_queue_depth;
+    del_timer(&p->dev_timer[tindex]);
+    p->dev_timer[tindex].expires = 0;
+    p->dev_temp_queue_depth[tindex] = 
+          p->dev_max_queue_depth[tindex];
+  }
+  p->dev_active_cmds[tindex]--;
+  p->activescbs--;
+
+  /*
+   * If this was an untagged I/O, unbusy the target so the sequencer won't
+   * mistake things later
+   */
+  if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
+      scb->hscb->tag)
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
   }
-  p->device_status[tindex].active_cmds--;
-  aic7xxx_free_scb(p, scb);
-  aic7xxx_queue_cmd_complete(p, cmd);
 
 #ifdef AIC7XXX_PROC_STATS
-  if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
-       (cmd->cmnd[0] != INQUIRY) )
   {
     int actual;
 
     /*
      * XXX: we should actually know how much actually transferred
      * XXX: for each command, but apparently that's too difficult.
+     * 
+     * We set a lower limit of 512 bytes on the transfer length.  We
+     * ignore anything less than this because we don't have a real
+     * reason to count it.  Read/Writes to tapes are usually about 20K
+     * and disks are a minimum of 512 bytes unless you want to count
+     * non-read/write commands (such as TEST_UNIT_READY) which we don't
      */
-    actual = aic7xxx_length(cmd, 0);
-    if ((actual > 0) && (((cmd->result >> 16) & 0xf) == DID_OK))
+    actual = scb->sg_length;
+    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
     {
       struct aic7xxx_xferstats *sp;
       long *ptr;
@@ -2137,7 +2353,14 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
       sp->xfers++;
 
-      if (cmd->request.cmd == WRITE)
+      /*
+       * For block devices, cmd->request.cmd is always == either READ or
+       * WRITE.  For character devices, this isn't always set properly, so
+       * we check data_cmnd[0].  This catches the conditions for st.c, but
+       * I'm still not sure if request.cmd is valid for sg devices.
+       */
+      if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
         sp->w_total512 += (actual >> 9);
@@ -2164,6 +2387,10 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     }
   }
 #endif /* AIC7XXX_PROC_STATS */
+
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
+
 }
 
 /*+F*************************************************************************
@@ -2186,17 +2413,17 @@ aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
     scb = p->scb_data->scb_array[i];
     if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
-      if (aic7xxx_verbose > 3)
-        printk("(scsi%d:%d:%d:%d) Aborting scb %d\n",
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Aborting scb %d\n",
              p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
       found++;
       aic7xxx_done(p, scb);
     }
   }
-  if (aic7xxx_verbose > 1)
+  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
   {
-    printk(KERN_WARNING "(scsi%d:-1:-1:-1) %d commands found and queued for "
-       "completion.\n", p->host_no, found);
+    printk(INFO_LEAD "%d commands found and queued for "
+        "completion.\n", p->host_no, -1, -1, -1, found);
   }
   if (complete)
   {
@@ -2221,15 +2448,9 @@ 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(p->base + SCBPTR);
-  outb(scbpos, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-
-  /*
-   * Clear the necessary fields
-   */
-  outb(0, p->base + SCB_CONTROL);
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
+  curscb = aic_inb(p, SCBPTR);
+  aic_outb(p, scbpos, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
 
   aic7xxx_add_curscb_to_free_list(p);
 
@@ -2241,24 +2462,21 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
     /*
      * First in the list
      */
-    outb(next, p->base + WAITING_SCBH);
+    aic_outb(p, next, WAITING_SCBH);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, p->base + SCBPTR);
-  scb->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-  scb->flags &= ~SCB_ACTIVE;
-
+  aic_outb(p, curscb, SCBPTR);
   return (next);
 }
 
@@ -2271,65 +2489,109 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
  *   requeue.  Returns the number of matching SCBs.
  *-F*************************************************************************/
 static int
-aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
-    int lun, unsigned char tag, int flags, int requeue, scb_queue_type *queue)
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+    int lun, unsigned char tag, int flags, int requeue,
+    volatile scb_queue_type *queue)
 {
-  unsigned char saved_queue[AIC7XXX_MAXSCB];
-  int      queued = inb(p->base + QINCNT) & p->qcntmask;
-  int      i;
   int      found;
+  unsigned char qinpos, qintail;
   struct aic7xxx_scb *scbp;
-  scb_queue_type removed_scbs;
 
   found = 0;
-  scbq_init (&removed_scbs);
-  for (i = 0; i < (queued - found); i++)
+  qinpos = aic_inb(p, QINPOS);
+  qintail = p->qinfifonext;
+
+  p->qinfifonext = qinpos;
+
+  while (qinpos != qintail)
   {
-    saved_queue[i] = inb(p->base + QINFIFO);
-    scbp = p->scb_data->scb_array[saved_queue[i]];
-    if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
     {
        /*
         * We found an scb that needs to be removed.
         */
-       if (requeue)
+       if (requeue && (queue != NULL))
+       {
+         if ( !(scbp->flags & SCB_WAITINGQ) )
+         {
+           scbq_insert_tail(queue, scbp);
+           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+           p->activescbs--;
+           scbp->flags |= SCB_WAITINGQ;
+         }
+         if ( !(scbp->tag_action & TAG_ENB) )
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       else if (requeue)
        {
-         scbq_insert_head(&removed_scbs, scbp);
+         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
        }
        else
        {
+        /*
+         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+         * flags we were called with, presumeably so aic7xxx_run_done_queue
+         * can find this scb
+         */
          scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+                                       FALSE) == scbp->hscb->tag)
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
        }
-       i--;
        found++;
     }
-  }
-  /* Now put the saved scbs back. */
-  for (queued = 0; queued < i; queued++)
-    outb(saved_queue[queued], p->base + QINFIFO);
-
-  if (requeue)
-  {
-    scbp = removed_scbs.head;
-    while (scbp != NULL)
+    else
     {
-      scbq_remove_head(&removed_scbs);
-      /*
-       * XXX - Shouldn't we be adding this to the free list?
-       */
-      if ( !(scbp->flags & SCB_WAITINGQ) )
-      {    /*  OK...we aren't already on a queue, so put us on there  */
-        p->device_status[TARGET_INDEX(scbp->cmd)].active_cmds--;
-        scbq_insert_head(queue, scbp);
-        scbp->flags |= SCB_WAITINGQ;
-      }
-      scbp = removed_scbs.head;
+      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
     }
   }
+  /*
+   * Now that we've done the work, clear out any left over commands in the
+   * qinfifo and update the KERNEL_QINPOS down on the card.
+   *
+   *  NOTE: This routine expect the sequencer to already be paused when
+   *        it is run....make sure it's that way!
+   */
+  qinpos = p->qinfifonext;
+  while(qinpos != qintail)
+  {
+    p->qinfifo[qinpos++] = SCB_LIST_NULL;
+  }
+  aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
 
   return (found);
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ *   Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i=0;
+
+  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+  {
+    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+      return TRUE;
+    else
+      i++;
+  }
+  return FALSE;
+}
+
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset_device
@@ -2346,27 +2608,26 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
  *   them.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
                      int lun, unsigned char tag)
 {
   struct aic7xxx_scb *scbp;
-  unsigned char active_scb;
+  unsigned char active_scb, tcl;
   int i = 0, j, init_lists = FALSE;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(p->base + SCBPTR);
+  active_scb = aic_inb(p, SCBPTR);
 
-  if (aic7xxx_verbose > 2)
-    printk("(scsi%d:%d:%d:%d) Reset device, active_scb %d\n",
-         p->host_no, CHAN_TO_INT(channel), target, lun, active_scb);
+  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+    printk(INFO_LEAD "Reset device, active_scb %d\n",
+         p->host_no, channel, target, lun, active_scb);
   /*
    * Deal with the busy target and linked next issues.
    */
   {
     int min_target, max_target;
-    unsigned char busy_scbid;
     struct aic7xxx_scb *scbp, *prev_scbp;
 
     /* Make all targets 'relative' to bus A. */
@@ -2374,86 +2635,124 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
     {
       switch (channel)
       {
-        case 'A':
-         min_target = 0;
-         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-         break;
-        case 'B':
-         min_target = 8;
-         max_target = 15;
-         break;
+        case 0:
+                 min_target = 0;
+                 max_target = (p->type & AHC_WIDE) ? 15 : 7;
+                 break;
+        case 1:
+                 min_target = 8;
+                 max_target = 15;
+                 break;
         case ALL_CHANNELS:
         default:
-         min_target = 0;
-         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-         break;
+                 min_target = 0;
+                 max_target = (p->type & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+                 break;
       }
     }
     else
     { 
-      min_target = target + ((channel == 'B') ? 8 : 0);
+      min_target = target | (channel << 3);
       max_target = min_target;
     }
 
 
     for (i = min_target; i <= max_target; i++)
     {
-      if (aic7xxx_verbose > 2)
-       printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning up status information "
-         "and delayed_scbs.\n", p->host_no, CHAN_TO_INT(channel), i, lun);
-      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/ TRUE);
-      p->device_status[i].flags &= ~BUS_DEVICE_RESET_PENDING;
-      p->device_status[i].last_reset = jiffies;
-      p->device_status[i].last_queue_full_count = 0;
-      p->device_status[i].last_queue_full = 0;
-      p->device_status[i].temp_queue_depth =
-        p->device_status[i].max_queue_depth;
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Cleaning up status information "
+          "and delayed_scbs.\n", p->host_no, channel, i, lun);
+      if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
+            (p->dev_active_cmds[i]) &&
+            (p->tagenable & (0x01 << i)) )
+      {
+        printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
+          p->host_no, channel, i, lun);
+        printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
+          channel, i, lun);
+        p->dev_max_queue_depth[i] = 1;
+        p->dev_temp_queue_depth[i] = 1;
+        p->tagenable &= ~(0x01 << i);
+        p->orderedtag &= ~(0x01 << i);
+      }
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+      if ( tag == SCB_LIST_NULL )
+      {
+        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+        p->dev_last_reset[i] = jiffies;
+        p->dev_last_queue_full_count[i] = 0;
+        p->dev_last_queue_full[i] = 0;
+        p->dev_temp_queue_depth[i] =
+          p->dev_max_queue_depth[i];
+  /*
+   * In case this isn't a full bus reset, we want to add a 4 second timer in
+   * here so that we can delay all re-sent commands for this device for the
+   * 4 seconds and then have our timer routine pick them back up.
+   */
+        if( (p->dev_timer[i].prev != NULL) ||
+            (p->dev_timer[i].next != NULL) )
+        {
+          del_timer(&p->dev_timer[i]);
+        }
+        p->dev_timer[i].expires = jiffies + (3 * HZ);
+        add_timer(&p->dev_timer[i]);
+      }
+      for(j=0; j<MAX_LUNS; j++)
+      {
+        if (channel == 1)
+          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
+        else
+          tcl = (i << 4) | (channel << 3) | j;
+        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+             (tag == SCB_LIST_NULL) )
+          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+      }
       j = 0; 
       prev_scbp = NULL; 
-      scbp = p->device_status[i].delayed_scbs.head;
+      scbp = p->delayed_scbs[i].head;
       while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
       {
         prev_scbp = scbp;
         scbp = scbp->q_next;
         if ( prev_scbp == scbp )
         {
-         if (aic7xxx_verbose)
-           printk(KERN_WARNING "(scsi%d:%d:%d:%d) Yikes!! scb->q_next == scb "
-             "in the delayed_scbs queue!\n", p->host_no, CHAN_TO_INT(channel),
-              i, lun);
-         scbp = NULL;
-         prev_scbp->q_next = NULL;
-         p->device_status[i].delayed_scbs.tail = prev_scbp;
+          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
+          scbp = NULL;
+          prev_scbp->q_next = NULL;
+          p->delayed_scbs[i].tail = prev_scbp;
         }
-        if (aic7xxx_match_scb(prev_scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
         {
-         scbq_remove(&p->device_status[i].delayed_scbs, prev_scbp);
-         if ( prev_scbp->flags & SCB_WAITINGQ )
-           p->device_status[i].active_cmds++;
-         prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbq_remove(&p->delayed_scbs[i], prev_scbp);
+          if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
+          {
+            p->dev_active_cmds[i]++;
+            p->activescbs++;
+          }
+          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
         }
       }
       if ( j > p->scb_data->numscbs )
       {
-        if (aic7xxx_verbose)
-         printk(KERN_WARNING "(scsi%d:%d:%d:%d) Yikes!! There's a loop in the "
-           "delayed_scbs queue!\n", p->host_no, CHAN_TO_INT(channel),
-            i, lun);
-        scbq_init(&p->device_status[i].delayed_scbs);
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! There's a loop in the "
+            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
+        scbq_init(&p->delayed_scbs[i]);
       }
-      if ( (p->device_status[i].delayed_scbs.head == NULL) &&
-           (p->device_status[i].timer.expires) )
+      if ( (p->delayed_scbs[i].head == NULL) &&
+           (p->dev_timer[i].expires) )
       {
-        del_timer(&p->device_status[i].timer);
-        p->device_status[i].timer.expires = 0;
+        del_timer(&p->dev_timer[i]);
+        p->dev_timer[i].expires = 0;
       }
     }
   }
 
-  if (aic7xxx_verbose > 2)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning QINFIFO.\n", p->host_no,
-       CHAN_TO_INT(channel), target, lun );
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
   aic7xxx_search_qinfifo(p, target, channel, lun, tag,
       SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
 
@@ -2461,9 +2760,9 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
  *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
  *  ABORT/RESET commands.
  */
-  if (aic7xxx_verbose > 2)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning waiting_scbs.\n",
-       p->host_no, CHAN_TO_INT(channel), target, lun );
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+      target, lun );
   {
     struct aic7xxx_scb *scbp, *prev_scbp;
 
@@ -2476,27 +2775,30 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
       scbp = scbp->q_next;
       if ( prev_scbp == scbp )
       {
-       if (aic7xxx_verbose)
-         printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!! scb->q_next == scb "
-           "in the waiting_scbs queue!\n", p->host_no);
-       scbp = NULL;
-       prev_scbp->q_next = NULL;
-       p->waiting_scbs.tail = prev_scbp;
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
+        scbp = NULL;
+        prev_scbp->q_next = NULL;
+        p->waiting_scbs.tail = prev_scbp;
       }
-      if (aic7xxx_match_scb(prev_scbp, target, channel, lun, tag))
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
       {
-       scbq_remove(&p->waiting_scbs, prev_scbp);
-       if ( prev_scbp->flags & SCB_WAITINGQ )
-         p->device_status[TARGET_INDEX(prev_scbp->cmd)].active_cmds++;
-       prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-       prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        scbq_remove(&p->waiting_scbs, prev_scbp);
+        if ( !(prev_scbp->flags & SCB_QUEUED_ABORT) )
+        {
+          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
     if ( j > p->scb_data->numscbs )
     {
-      if (aic7xxx_verbose)
-       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!! There's a loop in the "
-         "waiting_scbs queue!\n", p->host_no);
+      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+        printk(WARN_LEAD "Yikes!! There's a loop in the "
+          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
       scbq_init(&p->waiting_scbs);
     }
   }
@@ -2505,50 +2807,61 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
   /*
    * Search waiting for selection list.
    */
-  if (aic7xxx_verbose > 2)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning waiting for selection "
-       "list.\n", p->host_no, CHAN_TO_INT(channel), target, lun);
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting for selection "
+      "list.\n", p->host_no, channel, target, lun);
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
+    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
     j = 0;
     while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index >= p->scb_data->numscbs)
       {
-       if (aic7xxx_verbose)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Waiting List inconsistency; "
-               "SCB index=%d, numscbs=%d\n", p->host_no,
-                CHAN_TO_INT(channel), target, lun, scb_index,
-                p->scb_data->numscbs);
-       next = inb(p->base + SCB_NEXT);
-       aic7xxx_add_curscb_to_free_list(p);
+       /*
+        * No aic7xxx_verbose check here.....we want to see this since it
+        * means either the kernel driver or the sequencer screwed things up
+        */
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic_inb(p, SCB_NEXT);
+        aic7xxx_add_curscb_to_free_list(p);
       }
       else
       {
         scbp = p->scb_data->scb_array[scb_index];
-        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
           next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-         scbp->flags &= ~SCB_ACTIVE;
-         scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (prev == SCB_LIST_NULL)
+          {
+            /*
+             * This is either the first scb on the waiting list, or we
+             * have already yanked the first and haven't left any behind.
+             * Either way, we need to turn off the selection hardware if
+             * it isn't already off.
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+          }
         }
         else
         {
           prev = next;
-          next = inb(p->base + SCB_NEXT);
+          next = aic_inb(p, SCB_NEXT);
         }
       }
     }
     if ( j > p->scb_data->maxhscbs )
     {
-      if (aic7xxx_verbose)
-       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
-         "waiting for selection list!\n", p->host_no);
+      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
+        "selection list!\n", p->host_no, channel, target, lun);
       init_lists = TRUE;
     }
   }
@@ -2560,43 +2873,41 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
   {
     unsigned char next, prev, scb_index;
 
-    next = inb(p->base + DISCONNECTED_SCBH);
+    next = aic_inb(p, DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
     j = 0;
     while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
       if (scb_index > p->scb_data->numscbs)
       {
-       if (aic7xxx_verbose)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Waiting List inconsistency; "
-               "SCB index=%d, numscbs=%d\n", p->host_no,
-                CHAN_TO_INT(channel), target, lun, scb_index,
-                p->scb_data->numscbs);
-       next = aic7xxx_rem_scb_from_disc_list(p, next);
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic7xxx_rem_scb_from_disc_list(p, next);
       }
       else
       {
         scbp = p->scb_data->scb_array[scb_index];
-        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
           next = aic7xxx_rem_scb_from_disc_list(p, next);
-         scbp->flags = SCB_RESET | SCB_QUEUED_FOR_DONE;
-         scbp->hscb->control = 0;
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->hscb->control = 0;
         }
         else
         {
           prev = next;
-          next = inb(p->base + SCB_NEXT);
+          next = aic_inb(p, SCB_NEXT);
         }
       }
     }
     if ( j > p->scb_data->maxhscbs )
     {
-      if (aic7xxx_verbose)
-       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
-         "disconnected list!\n", p->host_no);
+      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
+        p->host_no, channel, target, lun);
       init_lists = TRUE;
     }
   }
@@ -2609,19 +2920,28 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
     unsigned char next;
 
     j = 0;
-    next = inb(p->base + FREE_SCBH);
+    next = aic_inb(p, FREE_SCBH);
     while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
     {
-      outb(next, p->base + SCBPTR);
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);
-      outb(0, p->base + SCB_CONTROL);
-      next = inb(p->base + SCB_NEXT);
+      aic_outb(p, next, SCBPTR);
+      if ( aic_inb(p, SCB_TAG) < p->scb_data->numscbs )
+      {
+        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+          target, lun);
+        init_lists = TRUE;
+        next = SCB_LIST_NULL;
+      }
+      else
+      {
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        next = aic_inb(p, SCB_NEXT);
+      }
     }
     if ( j > p->scb_data->maxhscbs )
     {
-      if (aic7xxx_verbose)
-       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
-         "free list!\n", p->host_no);
+      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
+        p->host_no, channel, target, lun);
       init_lists = TRUE;
     }
   }
@@ -2632,34 +2952,33 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
    */
   if (init_lists)
   {
-    outb(SCB_LIST_NULL, p->base + FREE_SCBH);
-    outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
-    outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
   }
   for (i = p->scb_data->maxhscbs; i >= 0; --i)
   {
     unsigned char scbid;
 
+    aic_outb(p, i, SCBPTR);
     if (init_lists)
     {
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);
-      outb(SCB_LIST_NULL, p->base + SCB_NEXT);
-      outb(SCB_LIST_NULL, p->base + SCB_PREV);
-      outb(SCB_LIST_NULL, p->base + SCB_LINKED_NEXT);
-      outb(0, p->base + SCB_CONTROL);
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+      aic_outb(p, SCB_LIST_NULL, SCB_PREV);
+      aic_outb(p, 0, SCB_CONTROL);
       aic7xxx_add_curscb_to_free_list(p);
     }
     else
     {
-      outb(i, p->base + SCBPTR);
-      scbid = inb(p->base + SCB_TAG);
+      scbid = aic_inb(p, SCB_TAG);
       if (scbid < p->scb_data->numscbs)
       {
         scbp = p->scb_data->scb_array[scbid];
-        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
-         outb(0, p->base + SCB_CONTROL);
-         outb(SCB_LIST_NULL, p->base + SCB_TAG);
+          aic_outb(p, 0, SCB_CONTROL);
+          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
           aic7xxx_add_curscb_to_free_list(p);
         }
       }
@@ -2670,28 +2989,25 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
    * Go through the entire SCB array now and look for commands for
    * for this target that are stillactive.  These are other (most likely
    * tagged) commands that were disconnected when the reset occurred.
+   * Any commands we find here we know this about, it wasn't on any queue,
+   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+   * lists, so it really must have been a paged out SCB.  In that case,
+   * we shouldn't need to bother with updating any counters, just mark
+   * the correct flags and go on.
    */
   for (i = 0; i < p->scb_data->numscbs; i++)
   {
     scbp = p->scb_data->scb_array[i];
-    if (((scbp->flags & SCB_ACTIVE) != 0) &&
-        aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    if ((scbp->flags & SCB_ACTIVE) &&
+        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+        !aic7xxx_scb_on_qoutfifo(p, scbp))
     {
       scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-      scbp->flags &= ~SCB_ACTIVE;
-
-      if ((scbp->flags & SCB_WAITINGQ) != 0)
-      {
-        scbq_remove(&p->waiting_scbs, scbp);
-        scbq_remove(&p->device_status[TARGET_INDEX(scbp->cmd)].delayed_scbs,
-         scbp);
-        scbp->flags &= ~SCB_WAITINGQ;
-       p->device_status[TARGET_INDEX(scbp->cmd)].active_cmds++;
-      }
+      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
     }
   }
 
-  outb(active_scb, p->base + SCBPTR);
+  aic_outb(p, active_scb, SCBPTR);
 }
 
 
@@ -2706,10 +3022,10 @@ static void
 aic7xxx_clear_intstat(struct aic7xxx_host *p)
 {
   /* Clear any interrupt conditions this may have caused. */
-  outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
-  outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
-       CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
-  outb(CLRSCSIINT, p->base + CLRINT);
+  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, CLRSINT1);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT, CLRINT);
 }
 
 /*+F*************************************************************************
@@ -2725,21 +3041,21 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
   unsigned char scsiseq;
 
   /* Disable reset interrupts. */
-  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
 
   /* Turn on the bus reset. */
-  scsiseq = inb(p->base + SCSISEQ);
-  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+  scsiseq = aic_inb(p, SCSISEQ);
+  aic_outb(p, scsiseq | SCSIRSTO, SCSISEQ);
 
   udelay(1000);
 
   /* Turn off the bus reset. */
-  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+  aic_outb(p, scsiseq & ~SCSIRSTO, SCSISEQ);
 
   aic7xxx_clear_intstat(p);
 
   /* Re-enable reset interrupts. */
-  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
 
   udelay(1000);
 }
@@ -2752,19 +3068,18 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
  *   Reset the channel.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
 {
   unsigned long offset, offset_max;
   unsigned char sblkctl;
-  char cur_channel;
+  int cur_channel;
 
-  if (aic7xxx_verbose > 1)
-    printk(KERN_WARNING "(scsi%d:%d:-1:-1) Reset channel called, %s initiate "
-       "reset.\n", p->host_no, CHAN_TO_INT(channel),
-       (initiate_reset == TRUE) ? "will" : "won't" );
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
 
 
-  if (channel == 'B')
+  if (channel == 1)
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
@@ -2773,7 +3088,7 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
   }
   else
   {
-    if (p->bus_type == AIC_WIDE)
+    if (p->type & AHC_WIDE)
     {
       p->needsdtr = p->needsdtr_copy;
       p->needwdtr = p->needwdtr_copy;
@@ -2799,76 +3114,76 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
      */
     u_char targ_scratch;
 
-    targ_scratch = inb(p->base + offset);
+    targ_scratch = aic_inb(p, offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, p->base + offset);
-    offset++;
+    aic_outb(p, targ_scratch, offset++);
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-  sblkctl = inb(p->base + SBLKCTL);
-  cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
+  sblkctl = aic_inb(p, SBLKCTL);
+  cur_channel = (sblkctl & SELBUSB) >> 3;
   if (cur_channel != channel)
   {
     /*
      * Case 1: Command for another bus is active
      */
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:-1:-1) Stealthily resetting idle "
-           "channel.\n", p->host_no, CHAN_TO_INT(channel));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+        channel, -1, -1);
     /*
      * Stealthily reset the other bus without upsetting the current bus.
      */
-    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
     }
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
-    outb(sblkctl, p->base + SBLKCTL);
+    aic_outb(p, sblkctl, SBLKCTL);
   }
   else
   {
     /*
      * Case 2: A command from this bus is active or we're idle.
      */
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:-1:-1) Resetting currently active "
-       "channel.\n", p->host_no, CHAN_TO_INT(channel));
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+        channel, -1, -1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    p->msg_type = MSG_TYPE_NONE;
+    p->msg_len = 0;
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
     }
-    outb(0, p->base + SCSISEQ);
+    aic_outb(p, 0, SCSISEQ);
     aic7xxx_clear_intstat(p);
   }
-  if (aic7xxx_verbose)
-    printk(KERN_WARNING "(scsi%d:%d:-1:-1) Channel reset\n",
-       p->host_no, CHAN_TO_INT(channel));
+  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
   /*
    * Clean up all the state information for the pending transactions
    * on this bus.
    */
   aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  if ( p->bus_type != AIC_TWIN )
+  if ( !(p->type & AHC_TWIN) )
   {
     restart_sequencer(p);
-    pause_sequencer(p);
   }
 
-  p->host->last_reset = jiffies + (HZ * AIC7XXX_RESET_DELAY);
-
   /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  if(!(p->flags & AHC_IN_ISR))
+    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
   return;
 }
 
@@ -2885,47 +3200,60 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
   int tindex;
+  int sent;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
 
 
   if (p->waiting_scbs.head == NULL)
     return;
 
+  sent = 0;
+
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  pause_sequencer(p);
-  scb = p->waiting_scbs.head;
-  while (scb != NULL)
+  DRIVER_LOCK
+  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
   {
-    if (p->curqincnt >= p->qfullcount)
-    {
-      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
-      if (p->curqincnt >= p->qfullcount)
-      {
-        break;
-      }
-    }
-
-    /*
-     * We have some space.
-     */
-    scbq_remove_head(&p->waiting_scbs);
     tindex = TARGET_INDEX(scb->cmd);
-    if ( p->device_status[tindex].active_cmds >=
-         p->device_status[tindex].temp_queue_depth )
+    if ( (p->dev_active_cmds[tindex] >=
+          p->dev_temp_queue_depth[tindex]) ||
+         (p->dev_last_reset[tindex] >= (jiffies + (3 * HZ))) )
     {
-        scbq_insert_tail(&p->device_status[tindex].delayed_scbs, scb);
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
-        p->device_status[tindex].active_cmds++;
-        outb(scb->hscb->tag, p->base + QINFIFO);
-        p->curqincnt++;
+        if ( !(scb->flags & SCB_QUEUED_ABORT) )
+        {
+          p->dev_active_cmds[tindex]++;
+          p->activescbs++;
+        }
+        if ( !(scb->tag_action) )
+        {
+          aic7xxx_busy_target(p, scb);
+        }
+        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+        sent++;
     }
-    scb = p->waiting_scbs.head;
   }
-  unpause_sequencer(p, FALSE);
+  if (sent)
+  {
+    if(p->type & AHC_AIC78x0)
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
+    }
+    if (p->activescbs > p->max_activescbs)
+      p->max_activescbs = p->activescbs;
+  }
+  DRIVER_UNLOCK
 }
 
 
@@ -2940,41 +3268,40 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 static void
 aic7xxx_timer(struct aic7xxx_host *p)
 {
-   int i;
-   unsigned long processor_flags;
-   struct aic7xxx_scb *scb;
-   
-   save_flags(processor_flags);
-   cli();
-   if (aic7xxx_verbose > 3)
-     printk(KERN_WARNING "(scsi%d:-1:-1:-1) Timer running.\n", p->host_no);
-   for(i=0; i<MAX_TARGETS; i++)
-   {
-     if ( (p->device_status[i].timer.expires) && 
-          (p->device_status[i].timer.expires <= jiffies) )
-     {
-       p->device_status[i].timer.expires = 0;
-       if ( (p->device_status[i].timer.prev != NULL) ||
-            (p->device_status[i].timer.next != NULL) )
-       {
-         del_timer(&p->device_status[i].timer);
-       }
-       p->device_status[i].temp_queue_depth = 
-        p->device_status[i].max_queue_depth;
-       scb = p->device_status[i].delayed_scbs.head;
-       while ( scb != NULL )
-       {
-         scbq_remove_head(&p->device_status[i].delayed_scbs);
-         scbq_insert_tail(&p->waiting_scbs, scb);
-         scb = p->device_status[i].delayed_scbs.head;
-       }
-     }
-   }
-   aic7xxx_run_waiting_queues(p);
-   unpause_sequencer(p, FALSE);
-   restore_flags(processor_flags);
+  int i;
+  unsigned long cpu_flags = 0;
+  struct aic7xxx_scb *scb;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
+  DRIVER_LOCK
+#else
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+#endif
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if ( (p->dev_timer[i].expires) && 
+          (p->dev_timer[i].expires <= jiffies) )
+    {
+      p->dev_timer[i].expires = 0;
+      if ( (p->dev_timer[i].prev != NULL) ||
+           (p->dev_timer[i].next != NULL) )
+      {
+        del_timer(&p->dev_timer[i]);
+      }
+      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
+      while ( (scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL )
+      {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+      }
+    }
+  }
+  aic7xxx_run_waiting_queues(p);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
+  DRIVER_UNLOCK
+#else
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#endif
 }
 
 /*+F*************************************************************************
  * Function:
@@ -2985,15 +3312,15 @@ aic7xxx_timer(struct aic7xxx_host *p)
  *   buffer on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char period, unsigned char offset)
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
+        unsigned char offset)
 {
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_SDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(period,           p->base + MSG_OUT + 3 + start_byte);
-  outb(offset,           p->base + MSG_OUT + 4 + start_byte);
-  outb(start_byte + 5,   p->base + MSG_LEN);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+  p->msg_buf[p->msg_index++] = period;
+  p->msg_buf[p->msg_index++] = offset;
+  p->msg_len += 5;
 }
 
 /*+F*************************************************************************
@@ -3005,14 +3332,13 @@ aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
  *   on the sequencer.
  *-F*************************************************************************/
 static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char bus_width)
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
 {
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_WDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(bus_width,        p->base + MSG_OUT + 3 + start_byte);
-  outb(start_byte + 4,   p->base + MSG_LEN);
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+  p->msg_buf[p->msg_index++] = bus_width;
+  p->msg_len += 4;
 }
 
 /*+F*************************************************************************
@@ -3027,7 +3353,7 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   struct aic7xxx_hwscb *hscb;
   Scsi_Cmnd *cmd;
-  int actual;
+  int actual, i;
 
   cmd = scb->cmd;
   hscb = scb->hscb;
@@ -3045,18 +3371,22 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
      *  and cmd->underflow seems to be set rather half-
      *  heartedly in the higher-level SCSI code.
      */
-    actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
-
+    actual = scb->sg_length;
+    for (i=1; i < hscb->residual_SG_segment_count; i++)
+    {
+      actual -= scb->sg_list[scb->sg_count - i].length;
+    }
     actual -= (hscb->residual_data_count[2] << 16) |
               (hscb->residual_data_count[1] <<  8) |
               hscb->residual_data_count[0];
 
-    if ( (actual < cmd->underflow) && (aic7xxx_verbose) )
+    if (actual < cmd->underflow)
     {
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Underflow - "
-             "Wanted at least %u, got %u, residual SG count %d.\n",
-             p->host_no, CTL_OF_SCB(scb), cmd->underflow, actual,
-             hscb->residual_SG_segment_count);
+      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+          (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+          hscb->residual_SG_segment_count);
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
       aic7xxx_status(cmd) = hscb->target_status;
     }
@@ -3080,31 +3410,29 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
  *   Interrupt handler for sequencer interrupts (SEQINT).
  *-F*************************************************************************/
 static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
 {
   unsigned short targ_mask;
   unsigned char  targ_scratch;
   int scratch_offset = target;
 
-  if (channel == 'B')
-  {
-    scratch_offset += 8;
-  }
+  scratch_offset += channel << 3;
+
   targ_mask = (0x01 << scratch_offset);
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
-  p->needsdtr |= p->needsdtr_copy & targ_mask;
-  p->needwdtr |= p->needwdtr_copy & targ_mask;
+  p->needsdtr |= (p->needsdtr_copy & targ_mask);
+  p->needwdtr |= (p->needwdtr_copy & targ_mask);
   p->sdtr_pending &= ~targ_mask;
   p->wdtr_pending &= ~targ_mask;
-  targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+  targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
   targ_scratch &= SXFR;
-  outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+  aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
   aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-  if (aic7xxx_verbose)
-    printk(KERN_WARNING "(scsi%d:%d:%d:-1) Bus Device Reset delivered.\n",
-         p->host_no, CHAN_TO_INT(channel), target);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+      target, -1);
   aic7xxx_run_done_queue(p, /*complete*/ TRUE);
 }
 
@@ -3124,124 +3452,47 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
   unsigned char queue_flag = FALSE;
   char channel;
 
-  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
-  {
-    target = (inb(p->base + SELID) >> 4) & 0x0F;
-  }
-  else
-  {
-    target = (inb(p->base + SCSIID) >> 4) & 0x0F;
-  }
-  scratch_offset = target;
-  channel = 'A';
-  lun = inb(p->base + SAVED_TCL) & 0x07;
-  if (inb(p->base + SBLKCTL) & SELBUSB)
-  {
-    channel = 'B';
-    scratch_offset += 8;
-  }
+  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+  channel = (aic_inb(p, SBLKCTL) >> 3) & 0x01;
+  scratch_offset = target + (channel << 3);
+  lun = aic_inb(p, SAVED_TCL) & 0x07;
   target_mask = (0x01 << scratch_offset);
 
   switch (intstat & SEQINT_MASK)
   {
     case NO_MATCH:
       {
-        /*
-         * This could be for a normal abort request.  Figure out
-         * which SCB we were trying to find and only give an error
-         * if we didn't ask for this to happen.
-         */
-        unsigned char scb_index;
-        unsigned char busy_scbid;
-        unsigned char arg1;
-
-        busy_scbid = aic7xxx_index_busy_target(p, target, channel,
-            /*unbusy*/ FALSE);
-        arg1 = inb(p->base + ARG_1);
-
-        if (arg1 == SCB_LIST_NULL)
-        {
-          /* untagged request */
-          scb_index = busy_scbid;
-        }
-        else
-        {
-          scb_index = arg1;
-        }
-
-        if (scb_index < p->scb_data->numscbs)
-        {
-          scb = p->scb_data->scb_array[scb_index];
-          if (scb->hscb->control & ABORT_SCB)
-          {
-            /*
-             * We expected this.  Let the busfree handler take care
-             * of this when we the abort is finally sent.  Set
-             * IDENTIFY_SEEN so that the busfree handler knows that
-             * there is an SCB to cleanup.
-             */
-            outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
-           if (aic7xxx_verbose > 1)
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reconnect SCB abort "
-               "successful\n", p->host_no, CTL_OF_SCB(scb));
-            break;
-          }
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) No active SCB for reconnecting "
-               "target - Issuing BUS DEVICE RESET.\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun);
-
-        printk(KERN_WARNING "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
-               inb(p->base + SAVED_TCL), arg1,
-               (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-        aic7xxx_handle_device_reset(p, target, channel);
+        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               p->host_no, channel, target, lun,
+               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       }
       break;
 
-    case NO_MATCH_BUSY:
+    case SEND_REJECT:
       {
-        /*
-         * XXX - Leave this as a panic for the time being since it
-         * indicates a bug in the timeout code for this to happen.
-         */
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + CUR_SCBID);
-        scb = p->scb_data->scb_array[scb_index];
-
-        panic("(scsi%d:%d:%d:%d) Target busy link failure, "
-              "but busy SCB exists!\n",
-              p->host_no, CHAN_TO_INT(channel), target, lun );
+        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
       }
       break;
 
-    case SEND_REJECT:
-      {
-        unsigned char rej_byte;
-
-        rej_byte = inb(p->base + REJBYTE);
-       if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Rejecting unknown message "
-               "(0x%x) received from target, SEQ_FLAGS=0x%x\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun,
-               rej_byte, inb(p->base + SEQ_FLAGS));
-      }
-      break;
-
-    case NO_IDENT:
+    case NO_IDENT:
       {
         /*
          * The reconnecting target either did not send an identify
-         * message, or did, but we didn't find and SCB to match and
+         * message, or did, but we didn't find an SCB to match and
          * before it could respond to our ATN/abort, it hit a dataphase.
          * The only safe thing to do is to blow it away with a bus
          * reset.
          */
-        if (aic7xxx_verbose)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target did not send an "
-               "IDENTIFY message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun,
-               inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
 
         aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
 
@@ -3249,252 +3500,151 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
       break;
 
     case BAD_PHASE:
-      if (inb(p->base + LASTPHASE) == P_BUSFREE)
+      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Missed busfree.\n",
-               p->host_no, CHAN_TO_INT(channel), target, lun);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+            target, lun);
         restart_sequencer(p);
       }
       else
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Unknown scsi bus phase, "
-               "continuing\n", p->host_no, CHAN_TO_INT(channel), target, lun);
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+            channel, target, lun);
       }
       break;
 
     case EXTENDED_MSG:
       {
-       unsigned char message_length;
-       unsigned char message_code;
-        unsigned char scb_index;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+        p->msg_len = 0;
+        p->msg_index = 0;
 
-       message_length = inb(p->base + MSGIN_EXT_LEN);
-       message_code = inb(p->base + MSGIN_EXT_OPCODE);
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
+       /*
+        * We have to clear the SEQINT *BEFORE* we set the REQINIT handler
+        * active or else VLB and edge triggered EISA cards could loose the
+        * first REQINIT and cause a bus hang/reset cycle.
+        */
+        aic_outb(p, CLRSEQINT, CLRINT);
 
-       switch (message_code)
-       {
-          case MSG_EXT_SDTR:
-          {
-            unsigned char period;
-            unsigned char offset;
-            unsigned char saved_offset;
-            unsigned char targ_scratch;
-            unsigned char max_offset;
-            unsigned char rate;
-
-            if (message_length != MSG_EXT_SDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
+       /*      
+        * To actually receive the message, simply turn on
+        * REQINIT interrupts and let our interrupt handler
+        * do the rest (REQINIT should already be true).
+        */
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
 
-            period = inb(p->base + MSGIN_EXT_BYTES);
-            saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
-            targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+       /*
+        * We don't want the sequencer unpaused yet so we return early
+        */
+        return;
+      }
 
-            if (targ_scratch & WIDEXFER)
-              max_offset = MAX_OFFSET_16BIT;
-            else
-              max_offset = MAX_OFFSET_8BIT;
-            offset = MIN(saved_offset, max_offset);
+    case REJECT_MSG:
+      {
+        /*
+         * What we care about here is if we had an outstanding SDTR
+         * or WDTR message for this target. If we did, this is a
+         * signal that the target is refusing negotiation.
+         */
+        unsigned char targ_scratch;
+        unsigned char scb_index;
+        unsigned char last_msg;
 
-            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        targ_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+        last_msg = aic_inb(p, LAST_MSG);
 
+        if ( (last_msg == MSG_IDENTIFYFLAG) &&
+             (scb->tag_action != 0 ) &&
+             !(p->flags & AHC_HANDLING_REQINITS) )
+        {
+          if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
+              (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
+          {
             /*
-             * Preserve the WideXfer flag.
+             * OK...the device seems able to accept tagged commands, but
+             * not ordered tag commands, only simple tag commands.  So, we
+             * disable ordered tag commands and go on with life just like
+             * normal.
              */
-            targ_scratch = rate | (targ_scratch & WIDEXFER);
-
+            p->orderedtag &= ~target_mask;
+            scb->tag_action = MSG_SIMPLE_Q_TAG;
+            scb->hscb->control &= ~SCB_TAG_TYPE;
+            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+            aic_outb(p, scb->hscb->control, SCB_CONTROL);
             /*
-             * Update both the target scratch area and current SCSIRATE.
+             * OK..we set the tag type to simple tag command, now we re-assert
+             * ATNO and hope this will take us into the identify phase again
+             * so we can resend the tag type and info to the device.
              */
-            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(targ_scratch, p->base + SCSIRATE);
-
+          }
+          else
+          {
+            unsigned char i, reset = 0;
+            struct aic7xxx_scb *scbp;
+            int old_verbose;
             /*
-             * See if we initiated Sync Negotiation and didn't have
-             * have to fall down to async transfers.
+             * Hmmmm....the device is flaking out on tagged commands.  The
+             * bad thing is that we already have tagged commands enabled in
+             * the device struct in the mid level code.  We also have a queue
+             * set according to the tagged queue depth.  Gonna have to live
+             * with it by controlling our queue depth internally and making
+             * sure we don't set the tagged command flag any more.
              */
-            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
-            {
-              /* We started it. */
-              if (saved_offset == offset)
-              {
-               /*
-                * Don't send an SDTR back to the target.
-                */
-               outb(0, p->base + RETURN_1);
-              }
-              else
-              {
-               /*
-                 * We went too low - force async and disable future
-                 * sync negotiation
-                 */
-                p->needsdtr_copy &= ~target_mask;
-               outb(SEND_REJ, p->base + RETURN_1);
-              }
-            }
-            else if ( offset != 0 )
-            {
-              /*
-               * Send our own SDTR in reply.
-               *
-               * We want to see this message as we don't expect a target
-               * to send us a SDTR request first.
-               */
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Sending reply SDTR.\n",
-                p->host_no, CTL_OF_SCB(scb));
-              aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
-              outb(SEND_MSG, p->base + RETURN_1);
-            }
-            else
-            {
-              /*
-               * The incoming SDTR was too low, reject it.
-               */
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Rejecting SDTR request.\n",
-                p->host_no, CTL_OF_SCB(scb));
-              outb(SEND_REJ, p->base + RETURN_1);
-              p->needsdtr_copy &= ~target_mask;
-            }
+            p->tagenable &= ~target_mask;
+            p->orderedtag &= ~target_mask;
+            p->dev_max_queue_depth[scratch_offset] =
+               p->dev_temp_queue_depth[scratch_offset] = 1;
             /*
-             * Clear the flags.
+             * We set this command up as a bus device reset.  However, we have
+             * to clear the tag type as it's causing us problems.  We shouldnt
+             * have to worry about any other commands being active, since if
+             * the device is refusing tagged commands, this should be the
+             * first tagged command sent to the device, however, we do have
+             * to worry about any other tagged commands that may already be
+             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
+             * send all the commands back to the mid level code, then let them
+             * come back and get rebuilt as untagged commands.
              */
-            p->needsdtr &= ~target_mask;
-            p->sdtr_pending &= ~target_mask;
-            break;
-          }
-
-          case MSG_EXT_WDTR:
-          {
-            unsigned char scratch, bus_width;
-
-            if (message_length != MSG_EXT_WDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
-
-            bus_width = inb(p->base + MSGIN_EXT_BYTES);
-            scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-            if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-            {
-              /*
-               * Don't send an WDTR back to the target, since we asked first.
-               */
-              outb(0, p->base + RETURN_1);
-              switch (bus_width)
-              {
-               case BUS_8_BIT:
-                  p->needwdtr_copy &= ~target_mask;
-                 scratch &= 0x7F;
-                 break;
-
-               case BUS_16_BIT:
-                  if (aic7xxx_verbose)
-                  {
-                   printk(KERN_INFO "(scsi%d:%d:%d:%d) Using 16 bit (Wide)"
-                        "transfers.\n", p->host_no, CTL_OF_SCB(scb));
-                  }
-                 scratch |= WIDEXFER;
-                 break;
-
-               case BUS_32_BIT:
-                 outb(SEND_REJ, p->base + RETURN_1);
-                  /* No verbose here!  We want to see this condition. */
-                 printk(KERN_WARNING "(scsi%d:%d:%d:%d) "
-                       "requesting 32 bit transfers, rejecting...\n",
-                        p->host_no, CTL_OF_SCB(scb));
-                 break;
-
-               default:
-                 break;
-              }
-            }
-            else
+            scb->tag_action = 0;
+            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+            scb->hscb->control |= MK_MESSAGE;
+            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
+
+            old_verbose = aic7xxx_verbose;
+            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+            for (i=0; i!=p->scb_data->numscbs; i++)
             {
-              int send_reject = FALSE;
-
-              /*
-               * Send our own WDTR in reply.
-               */
-              switch (bus_width)
-              {
-               case BUS_8_BIT:
-                  p->needwdtr_copy &= ~target_mask;
-                 scratch &= 0x7F;
-                 break;
-
-               case BUS_32_BIT:
-               case BUS_16_BIT:
-                 if (p->bus_type == AIC_WIDE)
-                 {
-                    printk(KERN_INFO "(scsi%d:%d:%d:%d) Using 16 bit (Wide)"
-                          "transfers.\n", p->host_no, CTL_OF_SCB(scb));
-                    bus_width = BUS_16_BIT;
-                    scratch |= WIDEXFER;
-                 }
-                 else
-                 {
-                    bus_width = BUS_8_BIT;
-                    scratch &= 0x7F;  /* XXX - FreeBSD doesn't do this. */
-                    send_reject = TRUE;
-                 }
-                 break;
-
-               default:
-                 break;
-              }
-              if (send_reject)
-              {
-                outb(SEND_REJ, p->base + RETURN_1);
-                printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target initiated "
-                       "wide negotiation on a narrow bus - rejecting!",
-                       p->host_no, CTL_OF_SCB(scb));
-              }
-              else
+              scbp = p->scb_data->scb_array[i];
+              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
               {
-                aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
-                outb(SEND_MSG, p->base + RETURN_1);
+                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+                {
+                  aic7xxx_reset_device(p, target, channel, lun, i);
+                  reset++;
+                }
               }
             }
-            p->needwdtr &= ~target_mask;
-            p->wdtr_pending &= ~target_mask;
-            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(scratch, p->base + SCSIRATE);
-            break;
-         }  /* case MSG_EXT_WDTR */
-
-          default:
+            aic7xxx_verbose = old_verbose;
             /*
-             * Unknown extended message - reject it.
+             * Wait until after the for loop to set the busy index since
+             * aic7xxx_reset_device will clear the busy index during its
+             * operation.
              */
-            outb(SEND_REJ, p->base + RETURN_1);
-            break;
-       }  /* switch (message_code) */
-      }  /* case EXTENDED_MSG */
-      break;
-
-    case REJECT_MSG:
-      {
-       /*
-        * What we care about here is if we had an outstanding SDTR
-        * or WDTR message for this target. If we did, this is a
-        * signal that the target is refusing negotiation.
-        */
-       unsigned char targ_scratch;
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-       targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-       if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-       {
+            aic7xxx_busy_target(p, scb);
+            printk(INFO_LEAD "Device is refusing tagged commands, using "
+              "untagged I/O.\n", p->host_no, channel, target, lun);
+          }
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+        }
+        else if ( (last_msg == MSG_IDENTIFYFLAG) && 
+                  (scb->flags & SCB_MSGOUT_WDTR) )
+        {
           /*
            * note 8bit xfers and clear flag
            */
@@ -3502,147 +3652,194 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
           p->wdtr_pending &= ~target_mask;
-          if (aic7xxx_verbose)
-            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Refusing WIDE "
-                "negotiation; using 8 bit transfers.\n",
-                p->host_no, CTL_OF_SCB(scb));
-       }
-       else
-       {
-          if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
           {
-            /*
-             * note asynch xfers and clear flag
-             */
-            targ_scratch &= 0xF0;
-            p->needsdtr &= ~target_mask;
-            p->needsdtr_copy &= ~target_mask;
-            p->sdtr_pending &= ~target_mask;
-           if (aic7xxx_verbose)
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Refusing "
-                  "synchronous negotiation; using asynchronous transfers.\n",
-                  p->host_no, CTL_OF_SCB(scb));
+            printk(INFO_LEAD "Refusing WIDE negotiation; using 8 bit "
+              "transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
           }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
+          if (p->needsdtr & target_mask)
+          {
+            p->sdtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_SDTR;
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+         /*
+          * note asynch xfers and clear flag
+          */
+          targ_scratch &= 0xF0;
+          p->needsdtr &= ~target_mask;
+          p->needsdtr_copy &= ~target_mask;
+          p->sdtr_pending &= ~target_mask;
+          p->syncinfo[scratch_offset].period = 0;
+          p->syncinfo[scratch_offset].offset = 0;
+          if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+               (p->dev_flags[scratch_offset] & DEVICE_PRINT_SDTR) )
+          {
+            printk(INFO_LEAD "Refusing synchronous negotiation; using "
+              "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb));
+            p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR;
+          }
+        }
+        else if (aic7xxx_verbose & VERBOSE_SEQINT)
+        {
           /*
            * Otherwise, we ignore it.
            */
-       }
-        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-        outb(targ_scratch, p->base + SCSIRATE);
+          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
+            "Ignoring.\n", p->host_no, channel, target, lun);
+        }
+        aic_outb(p, targ_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, targ_scratch, SCSIRATE);
       }
       break;
 
     case BAD_STATUS:
       {
-       unsigned char scb_index;
-       struct aic7xxx_hwscb *hscb;
-       Scsi_Cmnd *cmd;
-
-       /* The sequencer will notify us when a command has an error that
-        * would be of interest to the kernel.  This allows us to leave
-        * the sequencer running in the common case of command completes
-        * without error.  The sequencer will have DMA'd the SCB back
-        * up to us, so we can reference the drivers SCB array.
-        */
-       scb_index = inb(p->base + SCB_TAG);
-       scb = p->scb_data->scb_array[scb_index];
-       hscb = scb->hscb;
-
-       /*
-        * Set the default return value to 0 indicating not to send
-        * sense.  The sense code will change this if needed and this
-        * reduces code duplication.
-        */
-       outb(0, p->base + RETURN_1);
-       if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-       {
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Invalid SCB during "
-                "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
-                CHAN_TO_INT(channel), target, lun, intstat, scb_index,
-                 scb->flags, (unsigned int) scb->cmd);
-       }
-       else
-       {
+        unsigned char scb_index;
+        struct aic7xxx_hwscb *hscb;
+        Scsi_Cmnd *cmd;
+
+        /* The sequencer will notify us when a command has an error that
+         * would be of interest to the kernel.  This allows us to leave
+         * the sequencer running in the common case of command completes
+         * without error.  The sequencer will have DMA'd the SCB back
+         * up to us, so we can reference the drivers SCB array.
+         */
+        scb_index = aic_inb(p, SCB_TAG);
+        if (scb_index > p->scb_data->numscbs)
+        {
+          aic_outb(p, 0, RETURN_1);
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+            p->host_no, channel, target, lun, intstat, scb_index);
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        hscb = scb->hscb;
+
+        /*
+         * Set the default return value to 0 indicating not to send
+         * sense.  The sense code will change this if needed and this
+         * reduces code duplication.
+         */
+        aic_outb(p, 0, RETURN_1);
+        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+            scb_index, scb->flags, (unsigned long) scb->cmd);
+        }
+        else
+        {
           cmd = scb->cmd;
-         hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
           aic7xxx_status(cmd) = hscb->target_status;
 
-          cmd->result |= hscb->target_status;
+          cmd->result = hscb->target_status;
 
           switch (status_byte(hscb->target_status))
           {
             case GOOD:
-             printk(KERN_WARNING "(scsi%d:%d:%d:%d) Interrupted for status of "
-                     "GOOD???\n", p->host_no, CTL_OF_SCB(scb));
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+                  p->host_no, CTL_OF_SCB(scb));
               break;
 
+            case COMMAND_TERMINATED:
             case CHECK_CONDITION:
-              if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+              if ( !(scb->flags & SCB_SENSE) )
               {
-               unsigned int addr;    /* must be 32 bits */
-               /*
-                * XXX - How do we save the residual (if there is one).
-                */
-                aic7xxx_calculate_residual(p, scb);
-
-               /*
-                * Send a sense command to the requesting target.
-                * XXX - revisit this and get rid of the memcopys.
-                */
-               memcpy((void *) scb->sense_cmd, (void *) generic_sense,
-                      sizeof(generic_sense));
-
-               scb->sense_cmd[1] = (cmd->lun << 5);
-               scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
-               scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer[0]);
-               scb->sg_list[0].length = sizeof(cmd->sense_buffer);
-               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+                /*
+                 * XXX - How do we save the residual (if there is one).
+                 */
+                if ( hscb->residual_SG_segment_count != 0 )
+                  aic7xxx_calculate_residual(p, scb);
+
+                /*
+                   * Send a sense command to the requesting target.
+                 * XXX - revisit this and get rid of the memcopys.
+                   */
+                memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+                       sizeof(generic_sense));
+
+                scb->sense_cmd[1] = (cmd->lun << 5);
+                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+                scb->sg_list[0].address = 
+                  cpu_to_le32(VIRT_TO_BUS(&cmd->sense_buffer[0]));
+                scb->sg_list[0].length = 
+                  cpu_to_le32(sizeof(cmd->sense_buffer));
 
                 /*
                  * XXX - We should allow disconnection, but can't as it
                  * might allow overlapped tagged commands.
                  */
-               /* hscb->control &= DISCENB; */
+                  /* hscb->control &= DISCENB; */
                 hscb->control = 0;
-               hscb->target_status = 0;
-               hscb->SG_segment_count = 1;
-
-               addr = VIRT_TO_BUS(&scb->sg_list[0]);
-               memcpy(&hscb->SG_list_pointer, &addr,
-                      sizeof(hscb->SG_list_pointer));
-
-               memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
-                      sizeof(hscb->data_pointer));
-               /* Maintain SCB_LINKED_NEXT */
-               hscb->data_count &= 0xFF000000;
-               hscb->data_count |= scb->sg_list[0].length;
-
-               addr = VIRT_TO_BUS(&scb->sense_cmd[0]);
-               memcpy(&hscb->SCSI_cmd_pointer, &addr,
-                      sizeof(hscb->SCSI_cmd_pointer));
-               hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->target_status = 0;
+                hscb->SG_list_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+                hscb->data_pointer = scb->sg_list[0].address;
+                hscb->data_count = scb->sg_list[0].length;
+                hscb->SCSI_cmd_pointer = 
+                  cpu_to_le32(VIRT_TO_BUS(&scb->sense_cmd[0]));
+                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
                 hscb->residual_SG_segment_count = 0;
                 hscb->residual_data_count[0] = 0;
                 hscb->residual_data_count[1] = 0;
                 hscb->residual_data_count[2] = 0;
 
-                scb->sg_count = hscb->SG_segment_count;
-               scb->flags |= SCB_SENSE;
+                scb->sg_count = hscb->SG_segment_count = 1;
+                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->flags &= ~SCB_MSGOUT_BITS;
+                scb->tag_action = 0;
+                /*
+                 * This problem could be caused if the target has lost power
+                 * or found some other way to loose the negotiation settings,
+                 * so if needed, we'll re-negotiate while doing the sense cmd.
+                 * However, if this SCB already was attempting to negotiate,
+                 * then we assume this isn't the problem and skip this part.
+                 */
+                if ( !(scb->flags & SCB_MSGOUT_BITS) )
+                {
+                  if ( p->needwdtr_copy & target_mask )
+                  {
+                    p->needwdtr |= target_mask;
+                    p->wdtr_pending |= target_mask;
+                    hscb->control |= MK_MESSAGE;
+                    scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                  }
+                  if ( p->needsdtr_copy & target_mask )
+                  {
+                    p->needsdtr |= target_mask;
+                    if ((hscb->control & MK_MESSAGE) == 0)
+                    {
+                      p->sdtr_pending |= target_mask;
+                      hscb->control |= MK_MESSAGE;
+                      scb->flags |= SCB_MSGOUT_SDTR;
+                    }
+                  }
+                }
+
+                scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
                  * an untagged request.
                  */
-                aic7xxx_busy_target(p, target, channel, hscb->tag);
-               outb(SEND_SENSE, p->base + RETURN_1);
+                aic7xxx_busy_target(p, scb);
+                aic_outb(p, SEND_SENSE, RETURN_1);
+                aic7xxx_error(cmd) = DID_OK;
+                break;
               }  /* first time sense, no errors */
-              else
-             {
-               if (aic7xxx_error(cmd) == 0)
-               {
-                 aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-               }
-             }
+              aic7xxx_error(cmd) = DID_OK;
+              scb->flags &= ~SCB_SENSE;
               break;
 
             case QUEUE_FULL:
@@ -3650,212 +3847,289 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             case BUSY:              /* drop through to here */
             {
               struct aic7xxx_scb *next_scbp, *prev_scbp;
-              int ti = TARGET_INDEX(scb->cmd);
-              
+              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+              /*
+               * We have to look three places for queued commands:
+               *  1: QINFIFO
+               *  2: p->waiting_scbs queue
+               *  3: WAITING_SCBS list on card (for commands that are started
+               *     but haven't yet made it to the device)
+               */
               aic7xxx_search_qinfifo(p, target, channel, lun,
                 SCB_LIST_NULL, 0, TRUE,
-                &p->device_status[ti].delayed_scbs);
+                &p->delayed_scbs[scratch_offset]);
               next_scbp = p->waiting_scbs.head;
               while ( next_scbp != NULL )
               {
                 prev_scbp = next_scbp;
                 next_scbp = next_scbp->q_next;
-                if ( aic7xxx_match_scb(prev_scbp, target, channel, lun,
+                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
                      SCB_LIST_NULL) )
                 {
                   scbq_remove(&p->waiting_scbs, prev_scbp);
-                  scbq_insert_tail(&p->device_status[ti].delayed_scbs,
+                  scbq_insert_tail(&p->delayed_scbs[scratch_offset],
                     prev_scbp);
                 }
               }
-             scbq_insert_head(&p->device_status[ti].delayed_scbs, scb);
-             p->device_status[ti].active_cmds--;
-             scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+              next_scbp = NULL;
+              active_hscb = aic_inb(p, SCBPTR);
+              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+              next_hscb = aic_inb(p, WAITING_SCBH);
+              while (next_hscb != SCB_LIST_NULL)
+              {
+                aic_outb(p, next_hscb, SCBPTR);
+                scb_index = aic_inb(p, SCB_TAG);
+                next_scbp = p->scb_data->scb_array[scb_index];
+                if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                    SCB_LIST_NULL) )
+                {
+                  scbq_insert_head(&p->delayed_scbs[scratch_offset],
+                    next_scbp);
+                  next_scbp->flags |= SCB_WAITINGQ;
+                  p->dev_active_cmds[scratch_offset]--;
+                  p->activescbs--;
+                  next_hscb = aic_inb(p, SCB_NEXT);
+                  aic_outb(p, 0, SCB_CONTROL);
+                  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                  aic7xxx_add_curscb_to_free_list(p);
+                  if (prev_hscb == SCB_LIST_NULL)
+                  {
+                    aic_outb(p, 0, SCSISEQ);    /* We were first on the list,
+                                                 * so we kill the selection
+                                                 * hardware.  Let the sequencer
+                                                 * re-init the hardware itself
+                                                 */
+                    aic_outb(p, next_hscb, WAITING_SCBH);
+                  }
+                  else
+                  {
+                    aic_outb(p, prev_hscb, SCBPTR);
+                    aic_outb(p, next_hscb, SCB_NEXT);
+                  }
+                }
+                else
+                {
+                  prev_hscb = next_hscb;
+                  next_hscb = aic_inb(p, SCB_NEXT);
+                }
+              }
+              aic_outb(p, active_hscb, SCBPTR);
+              scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
+              p->dev_active_cmds[scratch_offset]--;
+              p->activescbs--;
+              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
                   
-              if (p->device_status[ti].timer.expires == 0) 
+              if (p->dev_timer[scratch_offset].expires == 0) 
               {
-               if ( p->device_status[ti].active_cmds )
-               {
-                  p->device_status[ti].timer.expires = jiffies + (HZ * 2);
-                  add_timer(&p->device_status[ti].timer);
-               }
-               else
-               {
-                  p->device_status[ti].timer.expires = jiffies + (HZ / 2);
-                  add_timer(&p->device_status[ti].timer);
-               }
+                if ( p->dev_active_cmds[scratch_offset] )
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ * 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
+                else
+                {
+                  p->dev_timer[scratch_offset].expires = jiffies + (HZ / 2);
+                  add_timer(&p->dev_timer[scratch_offset]);
+                }
               }
-             if (aic7xxx_verbose > 1)
+              if (aic7xxx_verbose & VERBOSE_QUEUE_FULL)
               {
                 if (queue_flag)
-                  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queue full received; "
-                     "queue depth %d, active %d\n", p->host_no,
-                     CTL_OF_SCB(scb), p->device_status[ti].max_queue_depth,
-                     p->device_status[ti].active_cmds);
+                  printk(INFO_LEAD "Queue full received; queue depth %d, "
+                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
+                    p->dev_max_queue_depth[scratch_offset],
+                    p->dev_active_cmds[scratch_offset]);
                 else
-                  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target busy\n",
-                     p->host_no, CTL_OF_SCB(scb));
+                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
 
               }
               if (queue_flag)
               {
-               p->device_status[ti].temp_queue_depth = 
-                 p->device_status[ti].active_cmds;
-                if ( (p->device_status[ti].last_queue_full <
-                     (p->device_status[ti].active_cmds - 1)) ||
-                     (p->device_status[ti].last_queue_full >
-                     (p->device_status[ti].active_cmds + 1)) )
+                p->dev_temp_queue_depth[scratch_offset] = 
+                  p->dev_active_cmds[scratch_offset];
+                if ( p->dev_last_queue_full[scratch_offset] !=
+                     p->dev_active_cmds[scratch_offset] )
                 {
-                  p->device_status[ti].last_queue_full = 
-                      p->device_status[ti].active_cmds;
-                  p->device_status[ti].last_queue_full_count = 0;
+                  p->dev_last_queue_full[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
                 }
                 else
                 {
-                  p->device_status[ti].last_queue_full_count++;
+                  p->dev_last_queue_full_count[scratch_offset]++;
                 }
-                if ( (p->device_status[ti].last_queue_full_count > 14) &&
-                     (p->device_status[ti].active_cmds > 4) )
+                if ( (p->dev_last_queue_full_count[scratch_offset] > 14) &&
+                     (p->dev_active_cmds[scratch_offset] > 4) )
                 {
-                 if (aic7xxx_verbose)
-                    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queue depth reduced "
-                      "to %d\n", p->host_no, CTL_OF_SCB(scb), 
-                      p->device_status[ti].active_cmds);
-                  p->device_status[ti].max_queue_depth = 
-                      p->device_status[ti].active_cmds;
-                  p->device_status[ti].last_queue_full = 0;
-                  p->device_status[ti].last_queue_full_count = 0;
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+                      CTL_OF_SCB(scb), p->dev_active_cmds[scratch_offset]);
+                  p->dev_max_queue_depth[scratch_offset] = 
+                      p->dev_active_cmds[scratch_offset];
+                  p->dev_last_queue_full[scratch_offset] = 0;
+                  p->dev_last_queue_full_count[scratch_offset] = 0;
                 }
               }
               break;
             }
             
             default:
-              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Unexpected target "
-                     "status 0x%x.\n", p->host_no,
-                    CTL_OF_SCB(scb), scb->hscb->target_status);
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+                     CTL_OF_SCB(scb), scb->hscb->target_status);
               if (!aic7xxx_error(cmd))
               {
-               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
               }
               break;
           }  /* end switch */
-       }  /* end else of */
+        }  /* end else of */
       }
       break;
 
     case AWAITING_MSG:
       {
-       unsigned char scb_index;
-        unsigned char message_offset;
-
-       scb_index = inb(p->base + SCB_TAG);
-       scb = p->scb_data->scb_array[scb_index];
-
-       /*
-        * This SCB had a MK_MESSAGE set in its control byte informing
-        * the sequencer that we wanted to send a special message to
-        * this target.
-        */
-        message_offset = inb(p->base + MSG_LEN);
-       if (scb->flags & SCB_DEVICE_RESET)
-       {
-          outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
-          outb(1, p->base + MSG_LEN);
-          if (aic7xxx_verbose > 1)
-            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset mailed.\n",
-                p->host_no, CTL_OF_SCB(scb));
-       }
+        unsigned char scb_index;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        p->msg_index = p->msg_len = 0;
+        /*
+         * This SCB had a MK_MESSAGE set in its control byte informing
+         * the sequencer that we wanted to send a special message to
+         * this target.
+         */
+
+        if (scb->flags & SCB_DEVICE_RESET)
+        {
+          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+            printk(INFO_LEAD "Bus device reset mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
+        }
         else if (scb->flags & SCB_ABORT)
         {
-          if ((scb->hscb->control & TAG_ENB) != 0)
+          if (scb->hscb->control & TAG_ENB)
           {
-            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+            if (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG)
+            {
+              p->msg_buf[p->msg_index++] = scb->tag_action;
+              p->msg_buf[p->msg_index++] = scb->hscb->tag;
+              p->msg_len += 2;
+            }
+            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
           }
           else
           {
-            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+            p->msg_buf[p->msg_index++] = MSG_ABORT;
           }
-          outb(message_offset + 1, p->base + MSG_LEN);
-          if (aic7xxx_verbose > 1)
-            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort message mailed.\n",
-                 p->host_no, CTL_OF_SCB(scb));
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+              CTL_OF_SCB(scb));
         }
-       else if (scb->flags & SCB_MSGOUT_WDTR)
-       {
-          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
-          unsigned char target_scratch;
-          unsigned short ultra_enable;
-          int i, sxfr;
+          unsigned char period, offset;
 
           /*
            * Pull the user defined setting from scratch RAM.
            */
-          target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-          sxfr = target_scratch & SXFR;
-          ultra_enable = inb(p->base + ULTRA_ENB) |
-              (inb(p->base + ULTRA_ENB + 1) << 8);
-          if (ultra_enable & target_mask)
-          {
-            sxfr |= 0x100;
-          }
-          for (i = 0; i < num_aic7xxx_syncrates; i++)
+          period = p->syncinfo[scratch_offset].period;
+          offset = p->syncinfo[scratch_offset].offset;
+          if ( (p->needsdtr_copy & target_mask) == 0)
           {
-            if (sxfr == aic7xxx_syncrates[i].rate)
-            break;
+            period = 0;
+            offset = 0;
           }
-          aic7xxx_construct_sdtr(p, message_offset,
-                                 aic7xxx_syncrates[i].period,
-                                 target_scratch & WIDEXFER ?
-                                 MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
+          aic7xxx_construct_sdtr(p, period, offset);
         }
         else 
         {
           panic("aic7xxx: AWAITING_MSG for an SCB that does "
-                "not have a waiting message.");
-       }
+                "not have a waiting message.\n");
+        }
+        /*
+         * We've set everything up to send our message, now to actually do
+         * so we need to enable reqinit interrupts and let the interrupt
+         * handler do the rest.  We don't want to unpause the sequencer yet
+         * though so we'll return early.  We also have to make sure that
+         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+         * or else it's possible on VLB cards to loose the first REQINIT
+         * interrupt.  Edge triggered EISA cards could also loose this
+         * interrupt, although PCI and level triggered cards should not
+         * have this problem since they continually interrupt the kernel
+         * until we take care of the situation.
+         */
+        aic_outb(p, CLRSEQINT, CLRINT);
+        p->msg_index = 0;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+        return;
       }
       break;
 
     case DATA_OVERRUN:
       {
-       unsigned char scb_index = inb(p->base + SCB_TAG);
-        unsigned char lastphase = inb(p->base + LASTPHASE);
-       unsigned int i, overrun;
-
-       scb = (p->scb_data->scb_array[scb_index]);
-       overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
-                 (inb(p->base + STCNT + 2) << 16);
-       overrun = 0x00FFFFFF - overrun;
-        if (aic7xxx_verbose)
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned char lastphase = aic_inb(p, LASTPHASE);
+        unsigned int i;
+
+        scb = (p->scb_data->scb_array[scb_index]);
+        /*
+         * XXX - What do we really want to do on an overrun?  The
+         *       mid-level SCSI code should handle this, but for now,
+         *       we'll just indicate that the command should retried.
+         *    If we retrieved sense info on this target, then the 
+         *    base SENSE info should have been saved prior to the
+         *    overrun error.  In that case, we return DID_OK and let
+         *    the mid level code pick up on the sense info.  Otherwise
+         *    we return DID_ERROR so the command will get retried.
+         */
+        if ( !(scb->flags & SCB_SENSE) )
         {
-         printk(KERN_WARNING "(scsi%d:%d:%d:%d) Data overrun of %d bytes "
-               "detected in %s phase, tag %d; forcing a retry.\n",
-               p->host_no, CTL_OF_SCB(scb), overrun,
-               lastphase == P_DATAIN ? "Data-In" : "Data-Out",
-               scb->hscb->tag);
-          printk(KERN_WARNING "%s seen Data Phase. Length=%d, NumSGs=%d.\n",
-               inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
-               aic7xxx_length(scb->cmd, 0), scb->sg_count);
+          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+            p->host_no, CTL_OF_SCB(scb), 
+            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+            scb->sg_length, scb->sg_count);
           for (i = 0; i < scb->sg_count; i++)
           {
             printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
-                   i, scb->sg_list[i].address, scb->sg_list[i].length);
+                 i, 
+                 le32_to_cpu(scb->sg_list[i].address),
+                 le32_to_cpu(scb->sg_list[i].length) );
           }
+          aic7xxx_error(scb->cmd) = DID_ERROR;
         }
-       /*
-        * XXX - What do we really want to do on an overrun?  The
-        *       mid-level SCSI code should handle this, but for now,
-        *       we'll just indicate that the command should retried.
-        */
-       aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
+        else
+          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+            p->host_no, CTL_OF_SCB(scb));
+      }
+      break;
+
+    case TRACEPOINT:
+      {
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
+          target, lun);
+      }
+      break;
+
+    case TRACEPOINT2:
+      {
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
+          target, lun);
       }
       break;
 
-/* #if AIC7XXX_NOT_YET */
+#if AIC7XXX_NOT_YET 
     /* XXX Fill these in later */
     case MSG_BUFFER_BUSY:
       printk("aic7xxx: Message buffer busy.\n");
@@ -3863,146 +4137,512 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
     case MSGIN_PHASEMIS:
       printk("aic7xxx: Message-in phasemis.\n");
       break;
-/*#endif */
-
-    case ABORT_CMDCMPLT:
-      /* This interrupt serves to pause the sequencer until we can clean
-       * up the QOUTFIFO allowing us to handle any abort SCBs that may
-       * completed yet still have an SCB in the QINFIFO or waiting for
-       * selection queue.  By the time we get here, we should have
-       * already cleaned up the queues, so all we need to do is unpause
-       * the sequencer.
-       */
-      break;
+#endif
 
-    default:              /* unknown */
-      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-             p->host_no, intstat, inb(p->base + SCSISIGI));
+    default:                   /* unknown */
+      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, channel, target, lun, intstat,
+             aic_inb(p, SCSISIGI));
       break;
   }
 
   /*
    * Clear the sequencer interrupt and unpause the sequencer.
    */
-  outb(CLRSEQINT, p->base + CLRINT);
+  aic_outb(p, CLRSEQINT, CLRINT);
   unpause_sequencer(p, /* unpause always */ TRUE);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_handle_scsiint
+ *   aic7xxx_parse_msg
  *
  * Description:
- *   Interrupt handler for SCSI interrupts (SCSIINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+ *   Parses incoming messages into actions on behalf of
+ *   aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char scb_index;
-  unsigned char status;
-  struct aic7xxx_scb *scb;
+  int reject, done;
+  unsigned char target_scratch, scratch_offset;
+  unsigned short target_mask;
 
-  scb_index = inb(p->base + SCB_TAG);
-  status = inb(p->base + SSTAT1);
+  reject = done = FALSE;
+  scratch_offset = TARGET_INDEX(scb->cmd);
+  target_scratch = aic_inb(p, TARG_SCRATCH + scratch_offset);
+  target_mask = (0x01 << scratch_offset);
 
-  if (scb_index < p->scb_data->numscbs)
-  {
-    scb = p->scb_data->scb_array[scb_index];
-    if ((scb->flags & SCB_ACTIVE) == 0)
-    {
-      scb = NULL;
-    }
-  }
-  else
-  {
-    scb = NULL;
-  }
+  /*
+   * Parse as much of the message as is availible,
+   * rejecting it if we don't support it.  When
+   * the entire message is availible and has been
+   * handled, return TRUE indicating that we have
+   * parsed an entire message.
+   */
 
-  if ((status & SCSIRSTI) != 0)
+  if (p->msg_buf[0] != MSG_EXTENDED)
   {
-    char channel;
-
-    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
-
-    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-           p->host_no, channel);
-    /*
-     * Go through and abort all commands for the channel, but do not
-     * reset the channel again.
-     */
-    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
-    scb = NULL;
+    reject = TRUE;
   }
-  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
-  {
-    /*
-     * First look at what phase we were last in.  If it's message-out,
-     * chances are pretty good that the bus free was in response to
-     * one of our abort requests.
-     */
-    unsigned char lastphase = inb(p->base + LASTPHASE);
-    unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
-    char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
-    int printerror = TRUE;
-
-    outb(0, p->base + SCSISEQ);
-    if (lastphase == P_MESGOUT)
-    {
-      unsigned char sindex;
-      unsigned char message;
 
-      sindex = inb(p->base + SINDEX);
-      message = inb(p->base + sindex - 1);
+  /*
+   * Just accept the length byte outright and perform
+   * more checking once we know the message type.
+   */
 
-      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
-      {
-       if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB %d abort delivered.\n",
-                   p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
-               (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
-       aic7xxx_run_done_queue(p, FALSE);
-        scb = NULL;
-        printerror = 0;
-      }
-      else if (message == MSG_BUS_DEV_RESET)
-      {
-        aic7xxx_handle_device_reset(p, target, channel);
-        scb = NULL;
-        printerror = 0;
-      }
-    }
-    if (printerror != 0)
+  if ( !reject && (p->msg_len > 2) )
+  {
+    switch(p->msg_buf[2])
     {
-      if (scb != NULL)
+      case MSG_EXT_SDTR:
       {
-        unsigned char tag;
+        unsigned char period, response_period, offset;
+        unsigned char max_offset, saved_offset, rate;
 
-        if ((scb->hscb->control & TAG_ENB) != 0)
+        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
         {
-          tag = scb->hscb->tag;
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        saved_offset = p->msg_buf[4];
+
+        if (target_scratch & WIDEXFER)
+        {
+          max_offset = MAX_OFFSET_16BIT;
+        }
+        else
+        {
+          max_offset = MAX_OFFSET_8BIT;
+        }
+        offset = MIN(saved_offset, max_offset);
+        response_period = aic7xxx_scsirate(p, &rate, &period,
+          &offset, scb->cmd->target, scb->cmd->channel, /* set */ TRUE);
+        /* Preserve the WideXfer flag */
+        target_scratch = rate | (target_scratch & WIDEXFER);
+
+        /*
+         * Update the TARGET_SCRATCH, the SCSIRATE, and our syncinfo
+         * areas.
+         */
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        aic_outb(p, target_scratch, SCSIRATE);
+        p->syncinfo[scratch_offset].period = response_period;
+        p->syncinfo[scratch_offset].offset = offset;
+
+        /*
+         * Did we start this, if not, or if we went to low and had to
+         * go async, then send an SDTR back to the target
+         */
+        p->needsdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          if (saved_offset != offset)
+          {
+            p->needsdtr_copy &= ~target_mask;
+            reject = TRUE; 
+          }
+          scb->flags &= ~SCB_MSGOUT_SDTR;
+          p->sdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_SDTR;
+          p->sdtr_pending |= target_mask;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_WDTR:
+      {
+        unsigned char bus_width;
+          
+        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+        {
+          break;
+        }
+
+        bus_width = p->msg_buf[3];
+        p->needwdtr &= ~target_mask;
+        if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              target_scratch |= WIDEXFER;
+              break;
+            }
+          }
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          p->wdtr_pending &= ~target_mask;
+        }
+        else
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          switch(bus_width)
+          {
+            default:
+            {
+              if (p->type & AHC_WIDE)
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                p->needwdtr_copy |= target_mask;
+                scb->flags |= SCB_MSGOUT_WDTR_16BIT;
+                target_scratch |= WIDEXFER;
+                if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                     (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+                {
+                  printk(INFO_LEAD "Using wide (16 bit) transfers.\n",
+                    p->host_no, CTL_OF_SCB(scb));
+                  p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+                }
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              scb->flags |= SCB_MSGOUT_WDTR_8BIT;
+              target_scratch &= 0x7f;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+                   (p->dev_flags[scratch_offset] & DEVICE_PRINT_WDTR) )
+              {
+                printk(INFO_LEAD "Using narrow (8 bit) transfers.\n",
+                  p->host_no, CTL_OF_SCB(scb));
+                p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_WDTR;
+              }
+              break;
+            }
+          }
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          p->wdtr_pending |= target_mask;
+        }
+        aic_outb(p, target_scratch, SCSIRATE);
+        aic_outb(p, target_scratch, TARG_SCRATCH + scratch_offset);
+        p->syncinfo[scratch_offset].offset =
+          (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ? 
+          MAX_OFFSET_8BIT : MAX_OFFSET_16BIT;
+        if ( !(p->wdtr_pending & target_mask) && !reject)
+        {
+          /*
+           * We've successfully completed the wide negotiation, so let's start
+           * up the sync negotiation now.
+           */
+          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
+          if ((p->needsdtr & target_mask) && !(p->sdtr_pending & target_mask))
+          {
+            p->sdtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_SDTR;
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          }
+        }
+        done = TRUE;
+        break;
+      }
+      default:
+      {
+        reject = TRUE;
+        break;
+      }
+    } /* end of switch(p->msg_type) */
+  } /* end of if (!reject && (p->msg_len > 2)) */
+
+  if (reject)
+  {
+    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+  }
+  return(done);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_reqinit
+ *
+ * Description:
+ *   Interrupt handler for REQINIT interrupts (used to transfer messages to
+ *    and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char lastbyte;
+  unsigned char phasemis;
+  int done;
+
+  switch(p->msg_type)
+  {
+    case MSG_TYPE_INITIATOR_MSGOUT:
+      {
+        if (p->msg_len == 0)
+          panic("aic7xxx: REQINIT with no active message!\n");
+
+        lastbyte = (p->msg_index == (p->msg_len - 1));
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
+
+        if (lastbyte || phasemis)
+        {
+          /* Time to end the message */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+
+          if (phasemis == 0)
+          {
+            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+            aic_outb(p, 0, RETURN_1);
+          }
+          else
+          {
+            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+          }
+          unpause_sequencer(p, TRUE);
+        }
+        else
+        {
+          /*
+           * Present the byte on the bus (clearing REQINIT) but don't
+           * unpause the sequencer.
+           */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
+        }
+        break;
+      }
+    case MSG_TYPE_INITIATOR_MSGIN:
+      {
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+        if (phasemis == 0)
+        {
+          p->msg_len++;
+          /* Pull the byte in without acking it */
+          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+          done = aic7xxx_parse_msg(p, scb);
+          /* Ack the byte */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_inb(p, SCSIDATL);
+          p->msg_index++;
+        }
+        if (phasemis || done)
+        {
+          /* Time to end our message session */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          p->flags &= ~AHC_HANDLING_REQINITS;
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          unpause_sequencer(p, TRUE);
+        }
+        break;
+      }
+    default:
+      {
+        panic("aic7xxx: Unknown REQINIT message type.\n");
+        break;
+      }
+  } /* End of switch(p->msg_type) */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_scsiint
+ *
+ * Description:
+ *   Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  unsigned char scb_index;
+  unsigned char status;
+  struct aic7xxx_scb *scb;
+
+  scb_index = aic_inb(p, SCB_TAG);
+  status = aic_inb(p, SSTAT1);
+
+  if (scb_index < p->scb_data->numscbs)
+  {
+    scb = p->scb_data->scb_array[scb_index];
+    if ((scb->flags & SCB_ACTIVE) == 0)
+    {
+      scb = NULL;
+    }
+  }
+  else
+  {
+    scb = NULL;
+  }
+
+
+  if ( (p->flags & AHC_HANDLING_REQINITS) && (status & REQINIT) )
+  {
+    if (scb)
+    {
+      aic7xxx_handle_reqinit(p, scb);
+    }
+    else
+    {
+      p->flags &= ~AHC_HANDLING_REQINITS;
+      aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+      aic_outb(p, CLRREQINIT, CLRSINT1);
+      aic_outb(p, CLRSCSIINT, CLRINT);
+      p->msg_type = MSG_TYPE_NONE;
+      p->msg_index = 0;
+      p->msg_len = 0;
+    }
+    return;
+  }
+
+  if ((status & SCSIRSTI) != 0)
+  {
+    int channel;
+
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+
+    if (aic7xxx_verbose & VERBOSE_RESET)
+      printk(WARN_LEAD "Someone else reset the channel!!\n",
+           p->host_no, channel, -1, -1);
+    /*
+     * Go through and abort all commands for the channel, but do not
+     * reset the channel again.
+     */
+    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    scb = NULL;
+  }
+  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
+  {
+    /*
+     * First look at what phase we were last in.  If it's message-out,
+     * chances are pretty good that the bus free was in response to
+     * one of our abort requests.
+     */
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+    unsigned char target = (saved_tcl >> 4) & 0x0F;
+    int channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    int printerror = TRUE;
+
+    aic_outb(p, 0, SCSISEQ);
+    if (lastphase == P_MESGOUT)
+    {
+      unsigned char message;
+
+      message = aic_inb(p, SINDEX);
+
+      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
+      {
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+            CTL_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+        aic7xxx_run_done_queue(p, FALSE);
+        scb = NULL;
+        printerror = 0;
+      }
+      else if (message == MSG_BUS_DEV_RESET)
+      {
+        aic7xxx_handle_device_reset(p, target, channel);
+        scb = NULL;
+        printerror = 0;
+      }
+    }
+    if (printerror != 0)
+    {
+      if (scb != NULL)
+      {
+        unsigned char tag;
+
+        if ((scb->hscb->control & TAG_ENB) != 0)
+        {
+          tag = scb->hscb->tag;
         }
         else
         {
           tag = SCB_LIST_NULL;
         }
         aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
-       aic7xxx_run_done_queue(p, FALSE);
+        aic7xxx_run_done_queue(p, FALSE);
       }
       else
       {  /* Since we don't really know what happened here, we'll wait */
-        /* for the commands to timeout and get aborted if need be    */
+         /* for the commands to timeout and get aborted if need be    */
         aic7xxx_add_curscb_to_free_list(p);
       }
-      printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
-             "SEQADDR = 0x%x\n", p->host_no, lastphase,
-             (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       scb = NULL;
     }
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
-    outb(CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if ((status & SELTO) != 0)
   {
@@ -4010,9 +4650,18 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     unsigned char nextscb;
     Scsi_Cmnd *cmd;
 
-    scbptr = inb(p->base + WAITING_SCBH);
-    outb(scbptr, p->base + SCBPTR);
-    scb_index = inb(p->base + SCB_TAG);
+    scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr >= p->scb_data->maxhscbs)
+    {
+      scb_index = SCB_LIST_NULL;
+      printk(WARN_LEAD "Bad scbptr %d during SELTO.\n", 
+        p->host_no, -1, -1, -1, scbptr);
+    }
+    else
+    {
+      aic_outb(p, scbptr, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+    }
 
     scb = NULL;
     if (scb_index < p->scb_data->numscbs)
@@ -4025,63 +4674,80 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     }
     if (scb == NULL)
     {
-      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
-             p->host_no, scb_index);
+      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, -1, -1, -1, scb_index);
       printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
-             "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
-             inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-             inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
     }
     else
     {
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       */
       cmd = scb->cmd;
       cmd->result = (DID_TIME_OUT << 16);
 
       /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
+       * Clear out this hardware SCB
+       */
+      aic_outb(p, 0, SCB_CONTROL);
+
+      /*
+       * Clear out a few values in the card that are in an undetermined
+       * state.
        */
-      outb(0, p->base + MSG_LEN);
-      aic7xxx_index_busy_target(p, cmd->target,
-          cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
-      outb(0, p->base + SCB_CONTROL);
+      aic_outb(p, MSG_NOOP, MSG_OUT);
 
       /*
        * Shift the waiting for selection queue forward
        */
-      nextscb = inb(p->base + SCB_NEXT);
-      outb(nextscb, p->base + WAITING_SCBH);
+      nextscb = aic_inb(p, SCB_NEXT);
+      aic_outb(p, nextscb, WAITING_SCBH);
 
       /*
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
+      /*
+       * XXX - If we queued an abort tag, go clean up the disconnected list.
+       * We know that this particular SCB had to be the queued abort since
+       * the disconnected SCB would have gotten a reconnect instead.
+       * However, if this is an abort command, then DID_TIMEOUT isn't
+       * appropriate, neither is returning the command for that matter.
+       * What we need to do then is to let the command timeout again so
+       * we get a reset since this abort just failed.
+       */
+      if (p->flags & SCB_QUEUED_ABORT)
+      {
+        cmd->result = 0;
+        scb->flags &= ~SCB_QUEUED_ABORT;
+        scb = NULL;
+      }
     }
     /*
      * Stop the selection.
      */
-    outb(0, p->base + SCSISEQ);
-    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
   }
   else if (scb == NULL)
   {
-    printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+    printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
            "during scsiint 0x%x scb(%d)\n"
            "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
-           p->host_no, status, scb_index, inb(p->base + SIMODE0),
-           inb(p->base + SIMODE1), inb(p->base + SSTAT0),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
     /*
      * Turn off the interrupt and set status to zero, so that it
      * falls through the rest of the SCSIINT code.
      */
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
@@ -4093,7 +4759,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
     char  *phase;
     Scsi_Cmnd *cmd;
     unsigned char mesg_out = MSG_NOOP;
-    unsigned char lastphase = inb(p->base + LASTPHASE);
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
 
     cmd = scb->cmd;
     switch (lastphase)
@@ -4128,7 +4794,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * A parity error has occurred during a data
      * transfer phase. Flag it and continue.
      */
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Parity error during phase %s.\n",
+    printk(WARN_LEAD "Parity error during phase %s.\n",
            p->host_no, CTL_OF_SCB(scb), phase);
 
     /*
@@ -4139,19 +4805,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      */
     if (mesg_out != MSG_NOOP)
     {
-      outb(mesg_out, p->base + MSG_OUT);
-      outb(1, p->base + MSG_LEN);
+      aic_outb(p, mesg_out, MSG_OUT);
       scb = NULL;
     }
-    else
-    {
-      /*
-       * Should we allow the target to make this decision for us?
-       */
-      cmd->result = DID_RETRY_COMMAND << 16;
-    }
-    outb(CLRSCSIPERR, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    aic_outb(p, CLRSCSIPERR, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause_always */ TRUE);
   }
   else
@@ -4160,9 +4818,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * We don't know what's going on. Turn off the
      * interrupt source and try to continue.
      */
-    printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
+    if (aic7xxx_verbose & VERBOSE_SCSIINT)
+      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+        p->host_no, -1, -1, -1, status);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
@@ -4172,184 +4832,215 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
   }
 }
 
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_pci_intr
+ *
+ * Description:
+ *   Check the scsi card for PCI errors and clear the interrupt
+ *
+ *   NOTE: If you don't have this function and a 2940 card encounters
+ *         a PCI error condition, the machine will end up locked as the
+ *         interrupt handler gets slammed with non-stop PCI error interrupts
+ *-F*************************************************************************/
+static void
+aic7xxx_pci_intr(struct aic7xxx_host *p)
+{
+  unsigned char status1;
+  int error;
+
+  error = 0;
+  error = pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, &status1);
+
+  if (error == 0)
+  {
+    if (status1 & DPE)
+      printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+        "phase.\n", p->host_no, -1, -1, -1);
+    if (status1 & SSE)
+      printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RMA)
+      printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & RTA)
+      printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & STA)
+      printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+        -1, -1, -1);
+    if (status1 & DPR)
+      printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+        "PERR#\n", p->host_no, -1, -1, -1);
+  }
+  else
+  {
+    printk(WARN_LEAD "Error reading PCI config register during PCI ERROR"
+      "interrupt.\n", p->host_no, -1, -1, -1);
+    aic_outb(p,  CLRPARERR, CLRINT);
+    return;
+  }
+  
+  pcibios_write_config_byte(p->pci_bus, p->pci_device_fn,
+                                            PCI_STATUS, status1);
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+}
+#endif
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_isr
  *
  * Description:
  *   SCSI controller interrupt handler.
- *
- *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- *         be disabled all through this function unless we say otherwise.
  *-F*************************************************************************/
 static void
 aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
   struct aic7xxx_host *p;
   unsigned char intstat;
-  unsigned long flags;
-  unsigned int interrupts_cleared = 0;
 
-  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+  p = (struct aic7xxx_host *)dev_id;
 
   /*
-   * Search for the host with a pending interrupt.  If we can't find
-   * one, then we've encountered a spurious interrupt.
+   * Just a few sanity checks.  Make sure p != NULL, that we have an
+   * interrupt pending, and that we aren't already in our int handler.
+   * Also, if PCI, then we are going to check for a PCI bus error status
+   * should we get too many spurious interrupts.
    */
-  while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
+  if (p == NULL)
+  {
+    printk(KERN_WARNING "aic7xxx: ISR routine called with NULL dev_id\n");
+    return;
+  }
+  else if (!(aic_inb(p, INTSTAT) & INT_PEND))
   {
-    if (p->next == NULL)
+#ifdef CONFIG_PCI
+    if ((p->type & AHC_AIC78x0) && (p->spurious_int > 500))
     {
-      p = NULL;
+      if ( aic_inb(p, ERROR) & PCIERRSTAT )
+      {
+        aic7xxx_pci_intr(p);
+      }
+      p->spurious_int = 0;
     }
     else
     {
-      p = (struct aic7xxx_host *) p->next->hostdata;
+      p->spurious_int++;
     }
+#endif
+    return;
   }
-
-  if (p == NULL)
+  else if (p->flags & AHC_IN_ISR)
+  {
     return;
+  }
 
   /*
    * Handle all the interrupt sources - especially for SCSI
    * interrupts, we won't get a second chance at them.
    */
-  intstat = inb(p->base + INTSTAT);
+  intstat = aic_inb(p, INTSTAT);
+  p->spurious_int = 0;
 
   /*
    * Keep track of interrupts for /proc/scsi
    */
   p->isr_count++;
-
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
-  {
-    /*
-     * We must only have one card at this IRQ and it must have been
-     * added to the board data before the spurious interrupt occurred.
-     * It is sufficient that we check isr_count and not the spurious
-     * interrupt count.
-     */
-    printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
-    if (intstat)
-    {
-      /* Try clearing all interrupts. */
-      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
-    }
-    return;
-  }
-
-  if (p->flags & IN_ISR)
-  {
-    panic(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
-           p->host_no);
-    return;
-  }
+  p->flags |= AHC_IN_ISR;
 
   /*
    * Indicate that we're in the interrupt handler.
    */
-  save_flags(flags);
-  p->flags |= IN_ISR;
-
   if (intstat & CMDCMPLT)
   {
     struct aic7xxx_scb *scb = NULL;
     Scsi_Cmnd *cmd;
-    unsigned char qoutcnt;
     unsigned char scb_index;
-    int i;
 
+    /*
+     * Clear interrupt status before running the completion loop.
+     * This eliminates a race condition whereby a command could
+     * complete between the last check of qoutfifo and the
+     * CLRCMDINT statement.  This would result in us thinking the
+     * qoutfifo was empty when it wasn't, and in actuality be a lost
+     * completion interrupt.  With multiple devices or tagged queueing
+     * this could be very bad if we caught all but the last completion
+     * and no more are imediately sent.
+     */
+    aic_outb(p, CLRCMDINT, CLRINT);
     /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
-    cli();
-    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
-#if 1
-  if (qoutcnt >= p->qfullcount - 1)
-    printk(KERN_WARNING "(scsi%d:-1:-1:-1) Command complete near Qfull count, "
-           "qoutcnt = %d.\n", p->host_no, qoutcnt);
-#endif
-    while (qoutcnt > 0)
+    while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
     {
-      if (p->flags & PAGE_ENABLED)
+      scb_index = p->qoutfifo[p->qoutfifonext];
+      p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+      if ( scb_index >= p->scb_data->numscbs )
+        scb = NULL;
+      else
+        scb = p->scb_data->scb_array[scb_index];
+      if (scb == NULL)
       {
-        p->cmdoutcnt += qoutcnt;
-        if ( p->cmdoutcnt >= p->qfullcount )
-        {
-          outb(0, p->base + CMDOUTCNT);
-          p->cmdoutcnt = 0;
-        }
+        printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+          -1, -1, -1, scb_index);
+        continue;
       }
-      for (i = 0; i < qoutcnt; i++)
+      else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
       {
-        scb_index = inb(p->base + QOUTFIFO);
-       if ( scb_index >= p->scb_data->numscbs )
-           scb = NULL;
-       else
-            scb = p->scb_data->scb_array[scb_index];
-        if (scb == NULL)
-        {
-         printk(KERN_WARNING "(scsi%d:-1:-1:-1) CMDCMPLT with invalid SCB "
-                "index %d, QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
-                 inb(p->base + QOUTCNT), inb(p->base + QINCNT));
-          continue;
-        }
-        else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-        {
-         printk(KERN_WARNING "(scsi%d:-1:-1:-1) CMDCMPLT without command for "
-                "SCB %d, QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
-                 p->host_no, scb_index, inb(p->base + QOUTCNT),
-                 inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
-         continue;
-        }
-       switch (status_byte(scb->hscb->target_status))
-       {
-         case QUEUE_FULL:
-         case BUSY:
-           scb->hscb->target_status = 0;
-            scb->cmd->result = 0;
-            aic7xxx_error(scb->cmd) = DID_OK;
-           break;
-         default:
-            cmd = scb->cmd;
-            if (scb->hscb->residual_SG_segment_count != 0)
-            {
-              aic7xxx_calculate_residual(p, scb);
-            }
-            cmd->result |= (aic7xxx_error(cmd) << 16);
-            p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-            aic7xxx_done(p, scb);
-       }
+        printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+          "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+          (unsigned long) scb->cmd);
+        continue;
       }
-      /*
-       * Clear interrupt status before checking the output queue again.
-       * This eliminates a race condition whereby a command could
-       * complete between the queue poll and the interrupt clearing,
-       * so notification of the command being complete never made it
-       * back up to the kernel.
-       */
-      outb(CLRCMDINT, p->base + CLRINT);
-      interrupts_cleared++;
-      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
-    }
-
-    if (interrupts_cleared == 0)
-    {
-      outb(CLRCMDINT, p->base + CLRINT);
+      switch (status_byte(scb->hscb->target_status))
+      {
+        case QUEUE_FULL:
+        case BUSY:
+          scb->hscb->target_status = 0;
+          scb->cmd->result = 0;
+          aic7xxx_error(scb->cmd) = DID_OK;
+          break;
+        default:
+          cmd = scb->cmd;
+          if (scb->hscb->residual_SG_segment_count != 0)
+          {
+            aic7xxx_calculate_residual(p, scb);
+          }
+          cmd->result |= (aic7xxx_error(cmd) << 16);
+          if (scb->tag_action)
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
+          else
+            p->dev_flags[TARGET_INDEX(cmd)] |= 
+               DEVICE_SUCCESS | DEVICE_PRESENT;
+          aic7xxx_done(p, scb);
+          break;
+      }      
     }
-    restore_flags(flags);
   }
 
   if (intstat & BRKADRINT)
   {
     int i;
-    unsigned char errno = inb(p->base + ERROR);
+    unsigned char errno = aic_inb(p, ERROR);
 
-    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+    printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
     for (i = 0; i < NUMBER(hard_error); i++)
     {
       if (errno & hard_error[i].errno)
@@ -4357,38 +5048,58 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
         printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
       }
     }
-    aic7xxx_reset_channel(p, 'A', TRUE);
-    if ( p->bus_type == AIC_TWIN )
+    printk(KERN_ERR "(scsi%d)   LINE=%d\n", p->host_no,
+      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+    aic7xxx_reset_channel(p, 0, TRUE);
+    if ( p->type & AHC_TWIN )
     {
-      aic7xxx_reset_channel(p, 'B', TRUE);
+      aic7xxx_reset_channel(p, 1, TRUE);
       restart_sequencer(p);
-      pause_sequencer(p);
     }
-    outb(CLRBRKADRINT, p->base + CLRINT);
+    aic_outb(p, CLRBRKADRINT, CLRINT);
   }
 
   if (intstat & SEQINT)
   {
-    cli();
     aic7xxx_handle_seqint(p, intstat);
-    restore_flags(flags);
   }
 
   if (intstat & SCSIINT)
   {
-    cli();
     aic7xxx_handle_scsiint(p, intstat);
-    restore_flags(flags);
   }
-
-  aic7xxx_done_cmds_complete(p);
-  cli();
-  aic7xxx_run_waiting_queues(p);
-  unpause_sequencer(p, TRUE);
-  p->flags &= ~IN_ISR;
-  restore_flags(flags);
+  if(!(p->flags & (AHC_IN_ABORT | AHC_IN_RESET)))
+  {
+    aic7xxx_done_cmds_complete(p);
+    aic7xxx_run_waiting_queues(p);
+  }
+  p->flags &= ~AHC_IN_ISR;
 }
 
+/*+F*************************************************************************
+ * Function:
+ *   do_aic7xxx_isr
+ *
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static void
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long cpu_flags;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  aic7xxx_isr(irq, dev_id, regs);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#else
+  DRIVER_LOCK
+  aic7xxx_isr(irq, dev_id, regs);
+  DRIVER_UNLOCK
+#endif
+}
 
 /*+F*************************************************************************
  * Function:
@@ -4410,55 +5121,58 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
-  int default_depth = 2;
+  int default_depth = 3;
   unsigned char tindex;
+  unsigned short target_mask;
 
   tindex = device->id | (device->channel << 3);
+  target_mask = (1 << tindex);
 
   device->queue_depth = default_depth;
-#ifdef AIC7XXX_TAGGED_QUEUEING
+  p->dev_mid_level_queue_depth[tindex] = 3;
+  p->dev_temp_queue_depth[tindex] = 1;
+  p->dev_max_queue_depth[tindex] = 1;
+  p->tagenable &= ~target_mask;
+
   if (device->tagged_supported)
   {
-    unsigned short target_mask;
     int tag_enabled = TRUE;
 
-    target_mask = (1 << (device->id | (device->channel << 3)));
-
 #ifdef AIC7XXX_CMDS_PER_LUN
     default_depth = AIC7XXX_CMDS_PER_LUN;
 #else
-    if (p->scb_data->maxhscbs <= 4)
-    {
-      default_depth = 4;  /* Not many SCBs to work with. */
-    }
-    else
-    {
-      default_depth = 8;
-    }
+    default_depth = 8;  /* Not many SCBs to work with. */
 #endif
  
     if (!(p->discenable & target_mask))
     {
-      printk(KERN_INFO "(scsi%d:%d:%d:%d) Disconnection disabled, unable to "
+      if (aic7xxx_verbose & VERBOSE_QUEUE)
+        printk(INFO_LEAD "Disconnection disabled, unable to "
              "enable tagged queueing.\n",
              p->host_no, device->channel, device->id, device->lun);
     }
     else
     {
-#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
-      device->queue_depth = default_depth;
-#else
       if (p->instance >= NUMBER(aic7xxx_tag_info))
       {
+        static int print_warning = TRUE;
+        if(print_warning)
+        {
+          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+                           " installed controllers.\n");
+          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+                           " the aic7xxx.c source file.\n");
+          print_warning = FALSE;
+        }
         device->queue_depth = default_depth;
       }
       else
       {
 
-        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
         {
           tag_enabled = FALSE;
-          device->queue_depth = 2;  /* Tagged queueing is disabled. */
+          device->queue_depth = 3;  /* Tagged queueing is disabled. */
         }
         else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
@@ -4470,23 +5184,24 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
             aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
       }
-#endif
       if ((device->tagged_queue == 0) && tag_enabled)
       {
-        if (aic7xxx_verbose)
+        if (aic7xxx_verbose & VERBOSE_QUEUE)
         {
-         printk(KERN_INFO "(scsi%d:%d:%d:%d) Enabled tagged queuing, "
-                "queue depth %d.\n", p->host_no,
-                device->channel, device->id, device->lun, device->queue_depth);
+              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
+                p->host_no, device->channel, device->id,
+                device->lun, device->queue_depth);
         }
-        p->device_status[tindex].max_queue_depth = device->queue_depth;
-        p->device_status[tindex].temp_queue_depth = device->queue_depth;
+        p->dev_max_queue_depth[tindex] = device->queue_depth;
+        p->dev_temp_queue_depth[tindex] = device->queue_depth;
+        p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
+        p->tagenable |= target_mask;
+        p->orderedtag |= target_mask;
         device->tagged_queue = 1;
         device->current_tag = SCB_LIST_NULL;
       }
     }
   }
-#endif
 }
 
 /*+F*************************************************************************
@@ -4507,14 +5222,27 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
 {
   Scsi_Device *device;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  int scbnum;
 
+  scbnum = 0;
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
       aic7xxx_device_queue_depth(p, device);
+      scbnum += device->queue_depth;
     }
   }
+  while (scbnum > p->scb_data->numscbs)
+  {
+    /*
+     * Pre-allocate the needed SCBs to get around the possibility of having
+     * to allocate some when memory is more or less exhausted and we need
+     * the SCB in order to perform a swap operation (possible deadlock)
+     */
+    if ( aic7xxx_allocate_scb(p, TRUE) == NULL )
+      return;
+  }
 }
 
 /*+F*************************************************************************
@@ -4539,8 +5267,8 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
  *-F*************************************************************************/
-static aha_chip_type
-aic7xxx_probe(int slot, int base, aha_status_type *bios)
+static ahc_type
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 {
   int i;
   unsigned char buf[4];
@@ -4548,13 +5276,13 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_chip_type type;
+    ahc_type type;
     int bios_disabled;
   } AIC7xxx[] = {
-    { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
-    { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_7770, FALSE }, /* motherboard 7770  */
-    { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x, FALSE }, /* 284x BIOS enabled */
-    { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x, TRUE }   /* 284x BIOS disabled */
+    { 4, { 0x04, 0x90, 0x77, 0x71 }, AHC_274, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x70 }, AHC_AIC7770, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x56 }, AHC_284, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 }, AHC_284, TRUE }   /* 284x BIOS disabled */
   };
 
   /*
@@ -4578,13 +5306,13 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
       {
         if (AIC7xxx[i].bios_disabled)
         {
-          *bios = AIC_DISABLED;
+          *flags |= AHC_USEDEFAULTS;
         }
         else
         {
-          *bios = AIC_ENABLED;
+          *flags |= AHC_BIOS_ENABLED;
         }
-       return (AIC7xxx[i].type);
+        return (AIC7xxx[i].type);
       }
 
       printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
@@ -4592,7 +5320,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
     }
   }
 
-  return (AIC_NONE);
+  return (AHC_NONE);
 }
 
 /*+F*************************************************************************
@@ -4630,11 +5358,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)        \
-  {                                            \
-    ;  /* Do nothing */                                \
-  }                                            \
-  (void) inb(p->base + SEECTL_2840);
+  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
+  }                                                \
+  (void) aic_inb(p, SEECTL_2840);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -4647,7 +5375,7 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
     CLOCK_PULSE(p);
 
     /*
@@ -4657,10 +5385,10 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4671,10 +5399,10 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
 
@@ -4687,11 +5415,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, p->base + SEECTL_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
-      outb(temp, p->base + SEECTL_2840);
+      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+      aic_outb(p, temp, SEECTL_2840);
       CLOCK_PULSE(p);
     }
     /*
@@ -4708,11 +5436,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(CK_2840, p->base + SEECTL_2840);
+    aic_outb(p, CK_2840, SEECTL_2840);
     CLOCK_PULSE(p);
-    outb(0, p->base + SEECTL_2840);
+    aic_outb(p, 0, SEECTL_2840);
     CLOCK_PULSE(p);
   }
 
@@ -4759,16 +5487,16 @@ acquire_seeprom(struct aic7xxx_host *p)
    * is needed.  Reason: after the 7870 chip reset, there
    * should be no contention.
    */
-  outb(SEEMS, p->base + SEECTL);
+  aic_outb(p, SEEMS, SEECTL);
   wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
   {
     wait--;
     udelay(1000);  /* 1 msec */
   }
-  if ((inb(p->base + SEECTL) & SEERDY) == 0)
+  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
-    outb(0, p->base + SEECTL);
+    aic_outb(p, 0, SEECTL);
     return (0);
   }
   return (1);
@@ -4784,7 +5512,7 @@ acquire_seeprom(struct aic7xxx_host *p)
 static inline void
 release_seeprom(struct aic7xxx_host *p)
 {
-  outb(0, p->base + SEECTL);
+  aic_outb(p, 0, SEECTL);
 }
 
 /*+F*************************************************************************
@@ -4838,8 +5566,8 @@ release_seeprom(struct aic7xxx_host *p)
  *   this case, has no implied timing.
  *-F*************************************************************************/
 static int
-read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
-    unsigned int len, seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, 
+    unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
 {
   int i = 0, k;
   unsigned char temp;
@@ -4851,9 +5579,9 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + SEECTL) & SEERDY) == 0)        \
-  {                                            \
-    ;  /* Do nothing */                                \
+  while ((aic_inb(p, SEECTL) & SEERDY) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
   }
 
   /*
@@ -4876,7 +5604,7 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
     CLOCK_PULSE(p);
 
     /*
@@ -4886,10 +5614,10 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
     /*
@@ -4900,10 +5628,10 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4916,11 +5644,11 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, p->base + SEECTL);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
       temp = temp ^ SEECK;
-      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
-      outb(temp, p->base + SEECTL);
+      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+      aic_outb(p, temp, SEECTL);
       CLOCK_PULSE(p);
     }
 
@@ -4938,11 +5666,11 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS | SEECK, p->base + SEECTL);
+    aic_outb(p, SEEMS | SEECK, SEECTL);
     CLOCK_PULSE(p);
-    outb(SEEMS, p->base + SEECTL);
+    aic_outb(p, SEEMS, SEECTL);
     CLOCK_PULSE(p);
   }
 
@@ -4965,7 +5693,6 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
   }
   printk("\n");
 #endif
-
   if (checksum != scarray[len - 1])
   {
     return (0);
@@ -4988,13 +5715,13 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
   unsigned char brdctl;
 
   brdctl = BRDCS | BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl |= value;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
   brdctl &= ~BRDCS;
-  outb(brdctl, p->base + BRDCTL);
+  aic_outb(p, brdctl, BRDCTL);
 }
 
 /*+F*************************************************************************
@@ -5004,11 +5731,80 @@ write_brdctl(struct aic7xxx_host *p, unsigned char value)
  * Description:
  *   Reads the BRDCTL register.
  *-F*************************************************************************/
-static inline unsigned char
-read_brdctl(struct aic7xxx_host *p)
+static inline unsigned char
+read_brdctl(struct aic7xxx_host *p)
+{
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  return (aic_inb(p, BRDCTL));
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic785x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  aic_outb(p, 0, BRDCTL);
+  brdctl = aic_inb(p, BRDCTL);
+  *int_50 = !(brdctl & BRDDAT5);
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = ( aic_inb(p, SPIOCAP) & EEPROM ) != 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This functions assumes the SEEPROM will have already been aquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+    int *ext_present, int *eeprom)
 {
-  outb(BRDRW | BRDCS, p->base + BRDCTL);
-  return (inb(p->base + BRDCTL));
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the two internal connectors.  BRDDAT6
+   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_50 = !(brdctl & BRDDAT6);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = (brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+  
 }
 
 /*+F*************************************************************************
@@ -5023,82 +5819,72 @@ static void
 configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
     unsigned short adapter_control, unsigned char max_targ)
 {
-  unsigned char brdctl_int, brdctl_ext;
   int internal50_present;
   int internal68_present = 0;
   int external_present = 0;
   int eprom_present;
   int high_on;
   int low_on;
-  int old_verbose;
 
   if (acquire_seeprom(p))
   {
     if (adapter_control & CFAUTOTERM)
     {
-      old_verbose = aic7xxx_verbose;
-      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
-                       "verify driver\n");
-      printk(KERN_INFO "         detected settings and use manual termination "
-                       "if necessary.\n"); 
-
+      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination on "
+                       "controller:\n");
+      printk(KERN_INFO "aic7xxx: <%s> at ", board_names[p->board_name_index]);
+      switch(p->type & 0x1ff1)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+          printk("EISA slot %d\n", p->pci_device_fn);
+          break;
+        case AHC_284:
+          printk("VLB slot %d\n", p->pci_device_fn);
+          break;
+        default:
+          printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+            PCI_FUNC(p->pci_device_fn));
+          break;
+      }
+      printk(KERN_INFO "aic7xxx: Please verify driver detected settings are "
+        "correct.\n");
+      printk(KERN_INFO "aic7xxx: If not, then please properly set the device "
+        "termination\n");
+      printk(KERN_INFO "aic7xxx: in the Adaptec SCSI BIOS by hitting CTRL-A "
+        "when prompted\n");
+      printk(KERN_INFO "aic7xxx: during machine bootup.\n");
       /* Configure auto termination. */
-      outb(SEECS | SEEMS, p->base + SEECTL);
-
-      /*
-       * First read the status of our cables.  Set the rom bank to
-       * 0 since the bank setting serves as a multiplexor for the
-       * cable detection logic.  BRDDAT5 controls the bank switch.
-       */
-      write_brdctl(p, 0);
+      aic_outb(p, SEECS | SEEMS, SEECTL);
 
-      /*
-       * Now read the state of the internal connectors.  The
-       * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
-       * set when cables are not present (BRDDAT6 is INT50 and
-       * BRDDAT7 is INT68).
-       */
-      brdctl_int = read_brdctl(p);
-      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+      if ( (p->type & AHC_AIC7860) == AHC_AIC7860 )
+      {
+        aic785x_cable_detect(p, &internal50_present, &external_present,
+          &eprom_present);
+      }
+      else
+      {
+        aic787x_cable_detect(p, &internal50_present, &internal68_present,
+          &external_present, &eprom_present);
+      }
       if (max_targ > 8)
       {
-        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+               "Ext-68 %s)\n",
+               internal50_present ? "YES" : "NO",
+               internal68_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
       }
-
-      /*
-       * Set the rom bank to 1 and determine
-       * the other signals.
-       */
-      write_brdctl(p, BRDDAT5);
-
-      /*
-       * Now read the state of the external connectors.  BRDDAT6 is
-       * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
-       * set when the eprom is present.
-       */
-      brdctl_ext = read_brdctl(p);
-      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
-      eprom_present = brdctl_ext & BRDDAT7;
-      if (aic7xxx_verbose)
+      else
       {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
-                 "Ext-68 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 internal68_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
-               "brdctl_ext=0x%x\n",
-               eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
+        printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+               internal50_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
+        internal68_present = 0;
       }
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "aic7xxx: EEPROM %s present.\n",
+             eprom_present ? "is" : "is not");
 
       /*
        * Now set the termination based on what we found.  BRDDAT6
@@ -5112,16 +5898,18 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
         high_on = TRUE;
       }
 
-      if ((internal50_present + internal68_present + external_present) <= 1)
+      if ( ( (internal50_present ? 1 : 0) +
+             (internal68_present ? 1 : 0) +
+             (external_present   ? 1 : 0) ) <= 1)
       {
         low_on = TRUE;
       }
           
       if (internal50_present && internal68_present && external_present)
       {
-        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
-               "         Only two connectors on the adapter may be "
-               "used at a time!\n");
+        printk(KERN_INFO "aic7xxx: Illegal cable configuration!!  Only two\n");
+        printk(KERN_INFO "aic7xxx: connectors on the SCSI controller may be "
+               "in use at a time!\n");
       }
 
       if (high_on == TRUE)
@@ -5132,28 +5920,23 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
       if (low_on == TRUE)
         *sxfrctl1 |= STPWEN;
 
-      if (aic7xxx_verbose)
+      if (max_targ > 8)
       {
-        if (max_targ > 8)
-        {
-          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-                 low_on ? "ON" : "OFF",
-                 high_on ? "ON" : "OFF");
-        }
-        else
-        {
-          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
-        }
+        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+              low_on ? "ON" : "OFF", high_on ? "ON" : "OFF");
+      }
+      else
+      {
+        printk(KERN_INFO "aic7xxx: Termination %s\n",
+          low_on ? "Enabled" : "Disabled");
       }
-      aic7xxx_verbose = old_verbose;
     }
     else
     {
       if (adapter_control & CFSTERM)
-      {
         *sxfrctl1 |= STPWEN;
-      }
-      outb(SEEMS | SEECS, p->base + SEECTL);
+
+      aic_outb(p, SEEMS | SEECS, SEECTL);
       /*
        * Configure high byte termination.
        */
@@ -5165,7 +5948,7 @@ configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
       {
         write_brdctl(p, 0);
       }
-      if (aic7xxx_verbose)
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
       {
         printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
                (adapter_control & CFSTERM) ? "ON" : "OFF",
@@ -5188,7 +5971,6 @@ static void
 detect_maxscb(struct aic7xxx_host *p)
 {
   int i;
-  unsigned char max_scbid = 255;
 
   /*
    * It's possible that we've already done this for multichannel
@@ -5200,90 +5982,35 @@ detect_maxscb(struct aic7xxx_host *p)
      * We haven't initialized the SCB settings yet.  Walk the SCBs to
      * determince how many there are.
      */
-    outb(0, p->base + FREE_SCBH);
+    aic_outb(p, 0, FREE_SCBH);
 
     for (i = 0; i < AIC7XXX_MAXSCB; i++)
     {
-      outb(i, p->base + SCBPTR);
-      outb(i, p->base + SCB_CONTROL);
-      if (inb(p->base + SCB_CONTROL) != i)
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, i, SCB_CONTROL);
+      if (aic_inb(p, SCB_CONTROL) != i)
         break;
-      outb(0, p->base + SCBPTR);
-      if (inb(p->base + SCB_CONTROL) != 0)
+      aic_outb(p, 0, SCBPTR);
+      if (aic_inb(p, SCB_CONTROL) != 0)
         break;
 
-      outb(i, p->base + SCBPTR);
-      outb(0, p->base + SCB_CONTROL);   /* Clear the control byte. */
-      outb(i + 1, p->base + SCB_NEXT);  /* Set the next pointer. */
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);  /* Make the tag invalid. */
-
-      /* Make the non-tagged targets not busy. */
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
+      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
     }
 
     /* Make sure the last SCB terminates the free list. */
-    outb(i - 1, p->base + SCBPTR);
-    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+    aic_outb(p, i - 1, SCBPTR);
+    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
 
     /* Ensure we clear the first (0) SCBs control byte. */
-    outb(0, p->base + SCBPTR);
-    outb(0, p->base + SCB_CONTROL);
+    aic_outb(p, 0, SCBPTR);
+    aic_outb(p, 0, SCB_CONTROL);
 
     p->scb_data->maxhscbs = i;
   }
 
-  if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
-  {
-    /* Determine the number of valid bits in the FIFOs. */
-    outb(max_scbid, p->base + QINFIFO);
-    max_scbid = inb(p->base + QINFIFO);
-    p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
-  }
-  else
-  {
-    p->scb_data->maxscbs = p->scb_data->maxhscbs;
-  }
-  if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
-  {
-    /*
-     * Disable paging if the QINFIFO doesn't allow more SCBs than
-     * we have in hardware.
-     */
-    p->flags &= ~PAGE_ENABLED;
-  }
-
-  /*
-   * Set the Queue Full Count.  Some cards have more queue space than
-   * SCBs.
-   */
-  switch (p->chip_class)
-  {
-    case AIC_777x:
-      p->qfullcount = 4;
-      p->qcntmask = 0x07;
-      break;
-    case AIC_785x:
-    case AIC_786x:
-      p->qfullcount = 8;
-      p->qcntmask = 0x0f;
-      break;
-    case AIC_787x:
-    case AIC_788x:
-      if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
-      {
-        p->qfullcount = AIC7XXX_MAXSCB;
-        p->qcntmask = 0xFF;
-      }
-      else
-      {
-        p->qfullcount = 16;
-        p->qcntmask = 0x1F;
-      }
-      break;
-  }
 }
 
 /*+F*************************************************************************
@@ -5294,15 +6021,14 @@ detect_maxscb(struct aic7xxx_host *p)
  *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
 static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+  int reset_delay)
 {
-  int i;
-  unsigned char sblkctl, flags = 0;
+  int i, result;
   int max_targets;
   int found = 1;
-  char channel_ids[] = {'A', 'B', 'C'};
   unsigned char target_settings;
-  unsigned char scsi_conf, sxfrctl1;
+  unsigned char term, scsi_conf, sxfrctl1;
   unsigned short ultraenable = 0;
   struct Scsi_Host *host;
 
@@ -5311,78 +6037,12 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    */
   request_region(p->base, MAXREG - MINREG, "aic7xxx");
 
-  /*
-   * Read the bus type from the SBLKCTL register. Set the FLAGS
-   * register in the sequencer for twin and wide bus cards.
-   */
-  sblkctl = inb(p->base + SBLKCTL);
-  if (p->flags & PAGE_ENABLED)
-    flags = PAGESCBS;
-
-  switch (sblkctl & SELBUS_MASK)
-  {
-    case SELNARROW:     /* narrow/normal bus */
-      p->scsi_id = inb(p->base + SCSICONF) & 0x07;
-      p->bus_type = AIC_SINGLE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    case SELWIDE:     /* Wide bus */
-      p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
-      p->bus_type = AIC_WIDE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    case SELBUSB:     /* Twin bus */
-      p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
-      p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
-      p->bus_type = AIC_TWIN;
-      printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
-             p->scsi_id, p->scsi_id_b);
-      outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
-      break;
-
-    default:
-      printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
-            "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
-      outb(0, p->base + SEQ_FLAGS);
-      return (0);
-  }
-
-  /*
-   * Detect SCB parameters and initialize the SCB array.
-   */
-  detect_maxscb(p);
-  printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
-         p->scb_data->maxhscbs, p->scb_data->maxscbs,
-         p->qfullcount, p->qcntmask);
 
   host = p->host;
 
-  host->can_queue = p->scb_data->maxscbs;
-  host->cmd_per_lun = 2;
+  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+  host->can_queue = AIC7XXX_MAXSCB;
+  host->cmd_per_lun = 3;
   host->sg_tablesize = AIC7XXX_MAX_SG;
   host->select_queue_depths = aic7xxx_select_queue_depth;
   host->this_id = p->scsi_id;
@@ -5390,11 +6050,11 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   host->n_io_port = 0xFF;
   host->base = (unsigned char *) p->mbase;
   host->irq = p->irq;
-  if (p->bus_type == AIC_WIDE)
+  if (p->type & AHC_WIDE)
   {
     host->max_id = 16;
   }
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     host->max_channel = 1;
   }
@@ -5409,141 +6069,212 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
 
-  for (i = 0; i < NUMBER(p->device_status); i++)
-  {
-    p->device_status[i].commands_sent = 0;
-    p->device_status[i].flags = 0;
-    p->device_status[i].active_cmds = 0;
-    p->device_status[i].last_reset = 0;
-    p->device_status[i].last_queue_full = 0;
-    p->device_status[i].last_queue_full_count = 0;
-    p->device_status[i].max_queue_depth = 2;
-    p->device_status[i].temp_queue_depth = 2;
-    scbq_init(&p->device_status[i].delayed_scbs);
-    init_timer(&p->device_status[i].timer);
-    p->device_status[i].timer.expires = 0;
-    p->device_status[i].timer.data = (unsigned long)p;
-    p->device_status[i].timer.function = (void *)aic7xxx_timer;
-  }
-  if (aic7xxx_boards[p->irq] == NULL)
-  {
-    int result;
-    int irq_flags = 0;
-
-#ifdef AIC7XXX_OLD_ISR_TYPE
-    irq_flags = SA_INTERRUPT;
-#endif
-    /*
-     * Warning! This must be done before requesting the irq.  It is
-     * possible for some boards to raise an interrupt as soon as
-     * they are enabled.  So when we request the irq from the Linux
-     * kernel, an interrupt is triggered immediately.  Therefore, we
-     * must ensure the board data is correctly set before the request.
-     */
-    aic7xxx_boards[p->irq] = host;
+  for (i = 0; i < NUMBER(p->untagged_scbs); i++)
+  {
+    p->untagged_scbs[i] = SCB_LIST_NULL;
+    p->qinfifo[i] = SCB_LIST_NULL;
+    p->qoutfifo[i] = SCB_LIST_NULL;
+  }
+  /*
+   * We currently have no commands of any type
+   */
+  p->qinfifonext = 0;
+  p->qoutfifonext = 0;
+
+  for (i = 0; i < MAX_TARGETS; i++)
+  {
+    p->dev_commands_sent[i] = 0;
+    p->dev_flags[i] = DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
+    p->dev_active_cmds[i] = 0;
+    p->dev_last_reset[i] = 0;
+    p->dev_last_queue_full[i] = 0;
+    p->dev_last_queue_full_count[i] = 0;
+    p->dev_max_queue_depth[i] = 1;
+    p->dev_temp_queue_depth[i] = 1;
+    p->dev_mid_level_queue_depth[i] = 3;
+    scbq_init(&p->delayed_scbs[i]);
+    init_timer(&p->dev_timer[i]);
+    p->dev_timer[i].expires = 0;
+    p->dev_timer[i].data = (unsigned long)p;
+    p->dev_timer[i].function = (void *)aic7xxx_timer;
+    p->syncinfo[i].period = 0;
+    p->syncinfo[i].offset = 0;
+  }
+
+  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+    board_names[p->board_name_index]);
+  switch(p->type & 0x1ff1)
+  {
+    case AHC_AIC7770:
+    case AHC_274:
+      printk("EISA slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_284:
+      printk("VLB slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      printk("PCI %d/%d\n", PCI_SLOT(p->pci_device_fn),
+        PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if (p->type & AHC_TWIN)
+  {
+    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+           p->host_no, p->scsi_id, p->scsi_id_b);
+  }
+  else
+  {
+    char *channel;
 
-    /*
-     * Register IRQ with the kernel.  Only allow sharing IRQs with
-     * PCI devices.
-     */
-    if (p->chip_class == AIC_777x)
+    channel = "";
+
+    if ((p->type & AHC_39x) != 0)
+    {
+      channel = " A";
+
+      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+      {
+        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+    }
+    if (p->type & AHC_WIDE)
     {
-      result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
     }
     else
     {
-      result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
-                "aic7xxx", NULL));
-      if (result < 0)
-      {
-        irq_flags = (irq_flags & SA_INTERRUPT) ? 0 : SA_INTERRUPT;
-        result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
-                "aic7xxx", NULL));
-      }
+      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
     }
+    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
+  }
+  aic_outb(p, 0, SEQ_FLAGS);
+
+  /*
+   * Detect SCB parameters and initialize the SCB array.
+   */
+  detect_maxscb(p);
+  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+    p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+    p->base, p->irq);
+  printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
+    p->host_no, p->mbase, (unsigned long)p->maddr);
+
+
+
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if ((p->type & AHC_AIC7770) == AHC_AIC7770)
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
     if (result < 0)
     {
-      printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-             p->irq);
-      aic7xxx_boards[p->irq] = NULL;
-      return (0);
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
     }
   }
-  else
+  if (result < 0)
   {
-    /*
-     * We have found a host adapter sharing an IRQ of a previously
-     * registered host adapter. Add this host adapter's Scsi_Host
-     * to the beginning of the linked list of hosts at the same IRQ.
-     */
-    p->next = aic7xxx_boards[p->irq];
-    aic7xxx_boards[p->irq] = host;
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring.\n",
+           p->host_no, p->irq);
+    return (0);
   }
 
   /*
    * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
-  if (p->bus_type == AIC_TWIN)
+  if (p->type & AHC_TWIN)
   {
     /*
      * The controller is gated to channel B after a chip reset; set
      * bus B values first.
      */
-    outb(p->scsi_id_b, p->base + SCSIID);
-    scsi_conf = inb(p->base + SCSICONF + 1);
-    sxfrctl1 = inb(p->base + SXFRCTL1);
-    outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-         ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
-    if (p->flags & ULTRA_ENABLED)
+    term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0;
+    aic_outb(p, p->scsi_id_b, SCSIID);
+    scsi_conf = aic_inb(p, SCSICONF + 1);
+    sxfrctl1 = aic_inb(p, SXFRCTL1);
+    aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    if (p->type & AHC_ULTRA)
     {
-      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+      aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
     }
     else
     {
-      outb(DFON | SPIOEN, p->base + SXFRCTL0);
+      aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    }
+    if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+    {
+      scsi_conf &= ~0x07;
+      scsi_conf |= p->scsi_id_b;
+      aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
     }
-
     if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
     {
       /* Reset SCSI bus B. */
-      if (aic7xxx_verbose)
-        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+      if (aic7xxx_verbose & VERBOSE_PROBE)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
 
       aic7xxx_reset_current_bus(p);
     }
 
     /* Select channel A */
-    outb(SELNARROW, p->base + SBLKCTL);
+    aic_outb(p, SELNARROW, SBLKCTL);
   }
 
-  outb(p->scsi_id, p->base + SCSIID);
-  scsi_conf = inb(p->base + SCSICONF);
-  sxfrctl1 = inb(p->base + SXFRCTL1);
-  outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-       ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
-  if (p->flags & ULTRA_ENABLED)
+  term = ((p->flags & AHC_TERM_ENB_A) != 0) ? STPWEN : 0;
+  aic_outb(p, p->scsi_id, SCSIID);
+  scsi_conf = aic_inb(p, SCSICONF);
+  sxfrctl1 = aic_inb(p, SXFRCTL1);
+  aic_outb(p, (scsi_conf & (ENSPCHK | STIMESEL)) | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  if (p->type & AHC_ULTRA)
   {
-    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN | FAST20, SXFRCTL0);
   }
   else
   {
-    outb(DFON | SPIOEN, p->base + SXFRCTL0);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  }
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
+  {
+    scsi_conf &= ~0x07;
+    scsi_conf |= p->scsi_id;
+    aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF);
   }
 
+
   if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
   {
     /* Reset SCSI bus A. */
-    if (aic7xxx_verbose)
-      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+    if (aic7xxx_verbose & VERBOSE_PROBE)
+    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
+      char *channel = "";
+      if (p->flags & AHC_MULTI_CHANNEL)
+      {
+        channel = " A";
+        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+    }
 
     aic7xxx_reset_current_bus(p);
 
     /*
      * Delay for the reset delay.
      */
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    if (!reset_delay)
+      aic7xxx_delay(AIC7XXX_RESET_DELAY);
   }
 
   /*
@@ -5558,7 +6289,10 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   p->sdtr_pending = 0x0;
   p->needwdtr_copy = 0x0;
   p->wdtr_pending = 0x0;
-  if (p->bus_type == AIC_SINGLE)
+  p->tagenable = 0x0;
+  p->ultraenb = 0x0;
+  p->discenable = 0xffff;
+  if ((p->type & (AHC_TWIN|AHC_WIDE)) == 0)
   {
     max_targets = 8;
   }
@@ -5570,31 +6304,36 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (p->flags & USE_DEFAULTS)
+  if (p->flags & AHC_USEDEFAULTS)
   {
-    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
-           "device parameters.\n");
-    p->discenable = 0xFFFF;
+    printk(KERN_INFO "(scsi%d) Host adapter BIOS disabled. Using default SCSI "
+           "device parameters.\n", p->host_no);
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = 0xffff;
+    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
   }
   else
   {
-    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
-        inb(p->base + DISC_DSB));
+    p->discenable = ~((aic_inb(p, DISC_DSB + 1) << 8) |
+        aic_inb(p, DISC_DSB));
+    if (p->type & AHC_ULTRA)
+      p->ultraenb = (aic_inb(p, ULTRA_ENB + 1) << 8) | 
+          aic_inb(p, ULTRA_ENB);
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (p->flags & USE_DEFAULTS)
+    if (p->flags & AHC_USEDEFAULTS)
     {
       target_settings = 0;  /* 10 or 20 MHz depending on Ultra enable */
       p->needsdtr_copy |= (0x01 << i);
       p->needwdtr_copy |= (0x01 << i);
-      if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+      if (p->type & AHC_ULTRA)
         ultraenable |= (0x01 << i);
     }
     else
     {
-      target_settings = inb(p->base + TARG_SCRATCH + i);
+      target_settings = aic_inb(p, TARG_SCRATCH + i);
       if (target_settings & 0x0F)
       {
         p->needsdtr_copy |= (0x01 << i);
@@ -5612,24 +6351,33 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
          */
         target_settings &= 0x7F;
       }
-      if (p->flags & ULTRA_ENABLED)
+    }
+
+    aic_outb(p, target_settings, TARG_SCRATCH + i);
+    if (p->needsdtr_copy & (0x01 << i))
+    {
+      short sxfr, j;
+
+      sxfr = target_settings & SXFR;
+      if ((p->ultraenb & (1 << i)) != 0)
       {
-        switch (target_settings & 0x70)
-        {
-          case 0x00:
-          case 0x10:
-          case 0x20:
-            ultraenable |= (0x01 << i);
-            break;
-          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
-            target_settings &= ~(0x70);
-            break;
-          default:
-            break;
-        }
+        /* Want an ultra speed in the table */
+        sxfr |= 0x100;
+      }
+      for (j = 0; j < NUMBER(aic7xxx_syncrates); j++)
+      {
+        if (sxfr == aic7xxx_syncrates[j].rate)
+          break;
       }
+      p->syncinfo[i].period = aic7xxx_syncrates[j].period;
+      p->syncinfo[i].offset =
+       (p->type & AHC_WIDE) ? MAX_OFFSET_16BIT : MAX_OFFSET_8BIT;
+    }
+    else
+    {
+      p->syncinfo[i].period = 0;
+      p->syncinfo[i].offset = 0;
     }
-    outb(target_settings, p->base + TARG_SCRATCH + i);
   }
 
   /*
@@ -5637,26 +6385,14 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    * work on some cards that don't leave these fields cleared
    * when BIOS is not installed.
    */
-  if (p->bus_type != AIC_WIDE)
+  if ( !(p->type & AHC_WIDE))
   {
     p->needwdtr_copy = 0;
   }
   p->needsdtr = p->needsdtr_copy;
   p->needwdtr = p->needwdtr_copy;
-  p->orderedtag = 0;
-  outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
-  outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
-
-  /*
-   * Set the number of available hardware SCBs.
-   */
-  outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
-
-  /*
-   * 2s compliment of maximum tag value.
-   */
-  i = p->scb_data->maxscbs;
-  outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
+  aic_outb(p, 0, ULTRA_ENB);
+  aic_outb(p, 0, ULTRA_ENB + 1);
 
   /*
    * Allocate enough hardware scbs to handle the maximum number of
@@ -5674,20 +6410,10 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
     p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
     if (p->scb_data->hscbs == NULL)
     {
-      printk("aic7xxx: Unable to allocate hardware SCB array; "
-             "failing detection.\n");
+      printk("(scsi%d) Unable to allocate hardware SCB array; "
+             "failing detection.\n", p->host_no);
       release_region(p->base, MAXREG - MINREG);
-      /*
-       * Ensure that we only free the IRQ when there is _not_ another
-       * aic7xxx adapter sharing this IRQ.  The adapters are always
-       * added to the beginning of the list, so we can grab the next
-       * pointer and place it back in the board array.
-       */
-      if (p->next == NULL)
-      {
-        free_irq(p->irq, aic7xxx_isr);
-      }
-      aic7xxx_boards[p->irq] = p->next;
+      free_irq(p->irq, p);
       return(0);
     }
     /* At least the control byte of each SCB needs to be 0. */
@@ -5695,41 +6421,35 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
 
     /* Tell the sequencer where it can find the hardware SCB array. */
     hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
-    outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
-    outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
-    outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
-    outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
-  }
+    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
 
-  /*
-   * QCount mask to deal with broken aic7850s that sporadically get
-   * garbage in the upper bits of their QCNT registers.
-    */
-  outb(p->qcntmask, p->base + QCNTMASK);
+    /* Set up the fifo areas at the same time */
+    hscb_physaddr = VIRT_TO_BUS(&p->untagged_scbs[0]);
+    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+
+    /* The Q-FIFOs we just set up are all empty */
+    aic_outb(p, 0, QINPOS);
+    aic_outb(p, 0, KERNEL_QINPOS);
+    aic_outb(p, 0, QOUTPOS);
 
-  /*
-   * Set FIFO depth and command out count.  These are only used when
-   * paging is enabled and should not be touched for AIC-7770 based
-   * adapters; FIFODEPTH and CMDOUTCNT overlay SCSICONF and SCSICONF+1
-   * which are used to control termination.
-   */
-  if (p->flags & PAGE_ENABLED)
-  {
-    outb(p->qfullcount, p->base + FIFODEPTH);
-    outb(0, p->base + CMDOUTCNT);
-    p->cmdoutcnt = 0;
   }
 
   /*
    * We don't have any waiting selections or disconnected SCBs.
    */
-  outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
-  outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
 
   /*
    * Message out buffer starts empty
    */
-  outb(0, p->base + MSG_LEN);
+  aic_outb(p, MSG_NOOP, MSG_OUT);
 
   /*
    * Load the sequencer program, then re-enable the board -
@@ -5740,11 +6460,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
    */
   aic7xxx_loadseq(p);
 
-  if (p->chip_class == AIC_777x)
+  if ( (p->type & AHC_AIC7770) == AHC_AIC7770 )
   {
-    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
   }
 
+  /*
+   * Link us into the list of valid hosts
+   */
+  p->next = first_aic7xxx;
+  first_aic7xxx = p;
+
   /*
    * Unpause the sequencer before returning and enable
    * interrupts - we shouldn't get any until the first
@@ -5763,38 +6489,56 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
  *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
  *   is paused upon return.
  *-F*************************************************************************/
-static void
+int
 aic7xxx_chip_reset(struct aic7xxx_host *p)
 {
   unsigned char hcntrl;
   int wait;
 
   /* Retain the IRQ type across the chip reset. */
-  hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+  hcntrl = (aic_inb(p, HCNTRL) & IRQMS) | INTEN;
 
   /*
    * For some 274x boards, we must clear the CHIPRST bit and pause
    * the sequencer. For some reason, this makes the driver work.
    */
-  outb(PAUSE | CHIPRST, p->base + HCNTRL);
+  aic_outb(p, PAUSE | CHIPRST, HCNTRL);
 
   /*
    * In the future, we may call this function as a last resort for
    * error handling.  Let's be nice and not do any unecessary delays.
    */
   wait = 1000;  /* 1 second (1000 * 1000 usec) */
-  while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+  while ((wait > 0) && ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0))
   {
     udelay(1000);  /* 1 msec = 1000 usec */
     wait = wait - 1;
   }
 
-  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+  if ((aic_inb(p, HCNTRL) & CHIPRSTACK) == 0)
   {
     printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
   }
 
-  outb(hcntrl | PAUSE, p->base + HCNTRL);
+  aic_outb(p, hcntrl | PAUSE, HCNTRL);
+
+  switch( aic_inb(p, SBLKCTL) & 0x0a )
+  {
+    case 0:  /* normal narrow card */
+      break;
+    case 2:  /* Wide card */
+      p->type |= AHC_WIDE;
+      break;
+    case 8:  /* Twin card */
+      p->type |= AHC_TWIN;
+      p->flags |= AHC_MULTI_CHANNEL;
+      break;
+    default: /* hmmm...we don't know what this is */
+      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+        aic_inb(p, SBLKCTL) & 0x0a);
+      return(-1);
+  }
+  return(0);
 }
 
 /*+F*************************************************************************
@@ -5806,8 +6550,7 @@ aic7xxx_chip_reset(struct aic7xxx_host *p)
  *   and a pointer to a aic7xxx_host struct upon success.
  *-F*************************************************************************/
 static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
-    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
@@ -5824,46 +6567,45 @@ aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
     memset(p, 0, sizeof(struct aic7xxx_host));
     p->host = host;
 
-    if (scb_data != NULL)
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
     {
-      /*
-       * We are sharing SCB data areas; use the SCB data pointer
-       * provided.
-       */
-      p->scb_data = scb_data;
-      p->flags |= SHARED_SCBDATA;
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
     }
     else
     {
       /*
-       * We are not sharing SCB data; allocate one.
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the aic7xxx_host struct, and return NULL.
        */
-      p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
-      if (p->scb_data != NULL)
-      {
-        memset(p->scb_data, 0, sizeof(scb_data_type));
-        scbq_init (&p->scb_data->free_scbs);
-      }
-      else
-      {
-        /*
-         * For some reason we don't have enough memory.  Free the
-         * allocated memory for the aic7xxx_host struct, and return NULL.
-         */
-        scsi_unregister(host);
-        p = NULL;
-      }
+      scsi_unregister(host);
+      p = NULL;
     }
     if (p != NULL)
     {
       p->host_no = host->host_no;
-      p->base = base;
-      p->mbase = mbase;
-      p->maddr = NULL;
-      p->flags = flags;
-      p->chip_type = chip_type;
-      p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
-      p->pause = p->unpause | PAUSE;
+      p->base = temp->base;
+      p->mbase = temp->mbase;
+      p->maddr = temp->maddr;
+      p->flags = temp->flags;
+      p->type = temp->type;
+      p->unpause = temp->unpause;
+      p->pause = temp->pause;
+      p->pci_bus = temp->pci_bus;
+      p->pci_device_fn = temp->pci_device_fn;
+      p->bios_address = temp->bios_address;
+      p->irq = temp->irq;
+      p->scsi_id = temp->scsi_id;
+      p->scsi_id_b = temp->scsi_id_b;
+      p->discenable = temp->discenable;
+      p->ultraenb = temp->ultraenb;
+      p->tagenable = 0;
+      p->orderedtag = 0;
+      p->board_name_index = temp->board_name_index;
+      p->adapter_control = temp->adapter_control;
+      p->bios_control = temp->bios_control;
+      DRIVER_LOCK_INIT
     }
   }
   return (p);
@@ -5878,49 +6620,48 @@ aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
  *   the driver (struct aic7xxx_host *).
  *-F*************************************************************************/
 static void
-aic7xxx_free (struct aic7xxx_host *p)
+aic7xxx_free(struct aic7xxx_host *p)
 {
-  int i;
+  int i, jump;
 
   /*
-   * We should be careful in freeing the scb_data area.  For those
-   * adapters sharing external SCB RAM(398x), there will be only one
-   * scb_data area allocated.  The flag SHARED_SCBDATA indicates if
-   * one adapter is sharing anothers SCB RAM.
+   * Free the allocated hardware SCB space.
    */
-  if (!(p->flags & SHARED_SCBDATA))
+  if (p->scb_data->hscbs != NULL)
   {
-    /*
-     * Free the allocated hardware SCB space.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-    /*
-     * Free the driver SCBs.  These were allocated on an as-need
-     * basis.
-     */
-    for (i = 0; i < p->scb_data->numscbs; i++)
-    {
-      kfree(p->scb_data->scb_array[i]);
-    }
-    /*
-     * Free the hardware SCBs.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-
-    /*
-     * Free the SCB data area.
-     */
-    kfree(p->scb_data);
+    kfree(p->scb_data->hscbs);
+  }
+  /*
+   * Free the driver SCBs.  These were allocated on an as-need
+   * basis. However, we allocated them 30 at a time up until the
+   * very last allocation (if there was one).  So, we need to free
+   * every 30th pointer to free the array (this also frees the
+   * SG_array structs as well).
+   *
+   * Note, on 64 bit machines we allocate 29 at a time instead.
+   */
+  jump = (sizeof(int) == sizeof(void *)) ? 30 : 29;
+  for (i = 0; i < p->scb_data->numscbs; i += jump)
+  {
+    kfree(p->scb_data->scb_array[i]);
   }
+  /*
+   * Free the SCB data area.
+   */
+  kfree(p->scb_data);
+
   /*
    * Free the instance of the device structure.
    */
+
+  /*
+   * XXXXXXXX  FIXXXXXMEEEEEE.  How do we unmap the I/O range we have mapped
+   * if we are doing MMAPed I/O ??????????  Our biggest concern is the issue
+   * of possibly calling unmap on an area that *might* be used on another
+   * controller as well (aka, the 4096 byte MMAPed area is back to back
+   * with another controller, and the PAGE_SIZE is greater then 4096, allowing
+   * us to remap in a shared page).
+   */
   scsi_unregister(p->host);
 }
 
@@ -5941,46 +6682,42 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
   unsigned short scarray[128];
   struct seeprom_config *sc = (struct seeprom_config *) scarray;
 
-  if (aic7xxx_verbose)
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
     printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
   }
-  switch (p->chip_type)
+  switch (p->type & 0x00001ff1)
   {
-    case AIC_7770:  /* None of these adapters have seeproms. */
-    case AIC_7771:
-    case AIC_7855:
+    case AHC_AIC7770:  /* None of these adapters have seeproms. */
+    case AHC_274:
       break;
 
-    case AIC_284x:
+    case AHC_284:
       have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
       break;
 
-    case AIC_7850:  /* The 2910B is a 7850 with a seeprom. */
-    case AIC_7861:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7874:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7884:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+    case AHC_AIC7850:  /* The 2910B is a 7850 with a seeprom. */
+    case AHC_294AU:
+    case AHC_AIC7870:  /* For these controllers we try the three possible */
+    case AHC_AIC7895:  /* SEEPROM read types.  If none works, then we are */
+    case AHC_294:      /* SOL.  This should catch any SEEPROM variety     */
+    case AHC_394:      /* Adaptec or some motherboard manufacturer might  */
+    case AHC_294U:     /* throw at us, and since we perform a checksum    */
+    case AHC_394U:     /* during the read, we should get bogus seeprom    */
+    case AHC_AIC7860:  /* reads. */
+    case AHC_AIC7880:
+    case AHC_398:
+    case AHC_398U:
+      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(*sc)/2, C46);
-      break;
-
-    case AIC_7860:  /* Motherboard Ultra controllers might have RAID port. */
-    case AIC_7880:
-      have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
-      if (!have_seeprom)
-      {
-        have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
-      }
-      break;
-
-    case AIC_7873:  /* The 3985 adapters use the 93c56 serial EEPROM. */
-    case AIC_7883:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(scarray)/2, C46);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, sizeof(*sc)/2, C56_66);
+      if (!have_seeprom)
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                   scarray, sizeof(scarray)/2, C56_66);
       break;
 
@@ -5990,19 +6727,19 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
 
   if (!have_seeprom)
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("\naic7xxx: No SEEPROM available; using defaults.\n");
     }
-    p->flags |= USE_DEFAULTS;
+    p->flags |= AHC_USEDEFAULTS;
+    p->flags &= ~AHC_BIOS_ENABLED;
   }
   else
   {
-    if (aic7xxx_verbose)
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
     {
       printk("done\n");
     }
-    p->flags |= HAVE_SEEPROM;
 
     /*
      * Update the settings in sxfrctl1 to match the termination settings.
@@ -6013,14 +6750,17 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
      * First process the settings that are different between the VLB
      * and PCI adapter seeproms.
      */
-    if (p->chip_class == AIC_777x)
+    if (p->type & AHC_284)
     {
       /* VLB adapter seeproms */
       if (sc->bios_control & CF284XEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CF284XSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
       /*
        * The 284x SEEPROM doesn't have a max targets field.  We
        * set it to 16 to make sure we take care of the 284x-wide
@@ -6038,30 +6778,90 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
     {
       /* PCI adapter seeproms */
       if (sc->bios_control & CFEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+        p->flags |= AHC_EXTEND_TRANS_A;
 
       if (sc->adapter_control & CFSTERM)
+      {
         *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_A;
+      }
 
       /* Limit to 16 targets just in case. */
       max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
     }
 
+    p->discenable = 0;
+
+    for (i = 0; i < max_targets; i++)
+    {
+      if( (p->type & AHC_ULTRA) &&
+         !(sc->adapter_control & CFULTRAEN) &&
+          (sc->device_flags[i] & CFSYNCHISULTRA) )
+      {
+        p->flags |= AHC_NEWEEPROM_FMT;
+        break;
+      }
+    }
+
     for (i = 0; i < max_targets; i++)
     {
       target_settings = (sc->device_flags[i] & CFXFER) << 4;
       if (sc->device_flags[i] & CFSYNCH)
+      {
         target_settings |= SOFS;
+      }
       if (sc->device_flags[i] & CFWIDEB)
+      {
         target_settings |= WIDEXFER;
+      }
       if (sc->device_flags[i] & CFDISC)
+      {
         p->discenable |= (0x01 << i);
-      outb(target_settings, p->base + TARG_SCRATCH + i);
+      }
+      if (p->flags & AHC_NEWEEPROM_FMT)
+      {
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= (0x01 << i);
+        }
+      }
+      else if (sc->adapter_control & CFULTRAEN)
+      {
+        p->ultraenb |= (0x01 << i);
+      }
+      if ( ((target_settings & 0x70) == 0x40) &&
+           (p->ultraenb & (0x01 << i)) )
+      {
+        target_settings &= ~0x70;
+        p->ultraenb &= ~(0x01 << i);
+      }
+      aic_outb(p, target_settings, TARG_SCRATCH + i);
     }
-    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
-    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
+    aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+    aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+    aic_outb(p,  (p->ultraenb & 0xFF), ULTRA_ENB);
+    aic_outb(p,  ((p->ultraenb >> 8) & 0xFF), ULTRA_ENB + 1);
 
     p->scsi_id = sc->brtime_id & CFSCSIID;
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
+
+    if (p->bios_control & CFBIOSEN)
+    {
+      p->flags &= ~AHC_USEDEFAULTS;
+      p->flags |= AHC_BIOS_ENABLED;
+    }
+    else
+    {
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->flags |= AHC_USEDEFAULTS;
+    }
+
+    if ((p->type & 0x1ff1) == AHC_AIC7895)
+    {
+      if (p->adapter_control & CFBPRIMARY)
+        p->flags |= AHC_CHANNEL_B_PRIMARY;
+    }
 
     scsi_conf = (p->scsi_id & 0x7);
     if (sc->adapter_control & CFSPARITY)
@@ -6070,37 +6870,39 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
      * The 7850 controllers with a seeprom, do not honor the CFRESETB
      * flag in the seeprom.  Assume that we want to reset the SCSI bus.
      */
-    if ((sc->adapter_control & CFRESETB) || (p->chip_class == AIC_7850))
+    if (sc->adapter_control & CFRESETB)
       scsi_conf |= RESET_SCSI;
-
-    if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
-    {
-      /*
-       * We allow the operator to override ultra enable through
-       * the boot prompt.
-       */
-      if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
-      {
-        /* Treat us as a non-ultra card */
-        p->flags &= ~ULTRA_ENABLED;
-      }
-    }
+    /*
+     * We may be a 2842, if so, preserve the TERM_ENB bit in scsi conf
+     */
+    if ( (p->flags & AHC_TERM_ENB_A) && 
+        ((p->type & AHC_AIC7770) == AHC_AIC7770) )
+      scsi_conf |= TERM_ENB;
+    /*
+     * If this is an Ultra card, is Ultra mode enabled?  If not, disable
+     * it in the host struct as well
+     */
+    if ( (p->type & AHC_ULTRA) && 
+        !(sc->adapter_control & CFULTRAEN) &&
+        !(p->flags & AHC_NEWEEPROM_FMT) )
+      p->type &= ~AHC_ULTRA;
 
     /* Set the host ID */
-    outb(scsi_conf, p->base + SCSICONF);
+    aic_outb(p, scsi_conf, SCSICONF);
     /* In case we are a wide card */
-    outb(p->scsi_id, p->base + SCSICONF + 1);
+    aic_outb(p, p->scsi_id, SCSICONF + 1);
 
-    if (p->chip_class != AIC_777x)
+    if ((p->type & AHC_AIC7860) == AHC_AIC7860)
     {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
       /*
        * Update the settings in sxfrctl1 to match the termination
        * settings.
        */
-      *sxfrctl1 = 0;
-      configure_termination(p, sxfrctl1, sc->adapter_control,
-        (unsigned char) sc->max_targets & CFMAXTARG);
+        configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
     }
+    else if (have_seeprom && ((p->type & AHC_AIC7770) != AHC_AIC7770))
+      configure_termination(p, sxfrctl1, sc->adapter_control, max_targets);
   }
   return (have_seeprom);
 }
@@ -6120,41 +6922,40 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
 int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
   int found = 0;
-  aha_status_type adapter_bios;
-  aha_chip_class_type chip_class;
-  aha_chip_type chip_type;
-  int slot, base;
-  int chan_num = 0;
-  unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
-  int i;
-  struct aic7xxx_host *p;
+  ahc_flag_type flags = 0;
+  ahc_type type;
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
 
+#ifdef MODULE
   /*
-   * Since we may allow sharing of IRQs, it is imperative
-   * that we "null-out" the aic7xxx_boards array. It is
-   * not guaranteed to be initialized to 0 (NULL). We use
-   * a NULL entry to indicate that no prior hosts have
-   * been found/registered for that IRQ.
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
    */
-  for (i = 0; i < NUMBER(aic7xxx_boards); i++)
-  {
-    aic7xxx_boards[i] = NULL;
-  }
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx, NULL);
+
+#endif
 
   template->proc_dir = &proc_scsi_aic7xxx;
-  template->name = aic7xxx_info(NULL);
   template->sg_tablesize = AIC7XXX_MAX_SG;
 
-  /*
-   * Initialize the spurious count to 0.
-   */
-  aic7xxx_spurious_count = 0;
 
+#if defined(__i386__) || defined(__alpha__)
   /*
    * EISA/VL-bus card signature probe.
    */
-  for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+  slot = MINSLOT;
+  while (slot <= MAXSLOT)
   {
     base = SLOTBASE(slot) + MINREG;
 
@@ -6164,185 +6965,256 @@ aic7xxx_detect(Scsi_Host_Template *template)
        * Some other driver has staked a
        * claim to this i/o region already.
        */
-      continue;
+      slot++;
+      continue; /* back to the beginning of the for loop */
     }
-
-    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
-    if (chip_type != AIC_NONE)
+    flags = 0;
+    type = aic7xxx_probe(slot, base + HID0, &flags);
+    switch (type)
     {
-
-      switch (chip_type)
-      {
-        case AIC_7770:
-        case AIC_7771:
+      case AHC_AIC7770:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at EISA %d\n",
-                 board_names[chip_type], slot);
-          break;
-        case AIC_284x:
+               board_names[2], slot);
+        break;
+      case AHC_274:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[3], slot);
+        break;
+      case AHC_284:
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
           printk("aic7xxx: <%s> at VLB %d\n",
-                 board_names[chip_type], slot);
-          break;
-        default:
-          break;
-      }
+               board_names[4], slot);
+        break;
+      default:
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
+    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+    if (temp_p == NULL)
+    {
+      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+      slot++;
+      continue; /* back to the beginning of the while loop */
+    }
+    /*
+     * Pause the card preserving the IRQ type.  Allow the operator
+     * to override the IRQ trigger.
+     */
+    if (aic7xxx_irq_trigger == 1)
+      hcntrl = IRQMS;  /* Level */
+    else if (aic7xxx_irq_trigger == 0)
+      hcntrl = 0;  /* Edge */
+    else
+      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+    memset(temp_p, 0, sizeof(struct aic7xxx_host));
+    temp_p->unpause = hcntrl | INTEN;
+    temp_p->pause = hcntrl | PAUSE | INTEN;
+    temp_p->base = base;
+    temp_p->type = type;
+    temp_p->flags = flags | AHC_PAGESCBS;
+    temp_p->mbase = 0;
+    temp_p->maddr = 0;
+    temp_p->pci_bus = 0;
+    temp_p->pci_device_fn = slot;
+    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+    if (aic7xxx_chip_reset(temp_p) == -1)
+      temp_p->irq = 0;
+    else
+      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    switch (temp_p->irq)
+    {
+      case 9:
+      case 10:
+      case 11:
+      case 12:
+      case 14:
+      case 15:
+        break;
 
-      /*
-       * We found a card, allow 1 spurious interrupt.
-       */
-      aic7xxx_spurious_count = 1;
+      default:
+        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level %d, ignoring.\n", temp_p->irq);
+        kfree(temp_p);
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
 
-      /*
-       * Pause the card preserving the IRQ type.  Allow the operator
-       * to override the IRQ trigger.
-       */
-      if (aic7xxx_irq_trigger == 1)
-        hcntrl = IRQMS;  /* Level */
-      else if (aic7xxx_irq_trigger == 0)
-        hcntrl = 0;  /* Edge */
-      else
-        hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
-      outb(hcntrl | PAUSE, base + HCNTRL);
-      p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
-      if (p == NULL)
-      {
-        printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-        continue;
-      }
-      aic7xxx_chip_reset(p);
+    /*
+     * We are commited now, everything has been checked and this card
+     * has been found, now we just set it up
+     */
+    /*
+     * Insert our new struct into the list at the end
+     */
+    if (list_p == NULL)
+    {
+      list_p = current_p = temp_p;
+    }
+    else
+    {
+      current_p = list_p;
+      while (current_p->next != NULL)
+        current_p = current_p->next;
+      current_p->next = temp_p;
+    }
+    if (aic7xxx_extended)
+    {
+      temp_p->flags |= AHC_EXTEND_TRANS_A;
+      if (temp_p->flags & AHC_MULTI_CHANNEL)
+        temp_p->flags |= AHC_EXTEND_TRANS_B;
+    }
 
-      irq = inb(INTDEF + base) & 0x0F;
-      switch (irq)
+    switch (temp_p->type & 0x1ff1)
+    {
+      case AHC_AIC7770:
+        temp_p->board_name_index = 2;
+      case AHC_274:
       {
-        case 9:
-        case 10:
-        case 11:
-        case 12:
-        case 14:
-        case 15:
-          break;
+        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
 
-        default:
-          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
-          "level %d, ignoring.\n", irq);
-          irq = 0;
-          aic7xxx_free(p);
-          break;
-      }
-
-      if (irq != 0)
-      {
-        p->irq = irq & 0x0F;
-        p->chip_class = AIC_777x;
-#ifdef AIC7XXX_PAGE_ENABLE
-        p->flags |= PAGE_ENABLED;
-#endif
-        p->instance = found;
-        if (aic7xxx_extended)
+        /*
+         * Get the primary channel information.  Right now we don't
+         * do anything with this, but someday we will be able to inform
+         * the mid-level SCSI code which channel is primary.
+         */
+        if (temp_p->board_name_index == 0)
+          temp_p->board_name_index = 3;
+        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
         {
-          p->flags |= EXTENDED_TRANSLATION;
+          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
         }
 
-        switch (p->chip_type)
+        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+        {
+          temp_p->flags |= AHC_USEDEFAULTS;
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        }
+        else
         {
-          case AIC_7770:
-          case AIC_7771:
+          temp_p->flags &= ~AHC_USEDEFAULTS;
+          temp_p->flags |= AHC_BIOS_ENABLED;
+          if ( (temp_p->bios_control & 0x20) == 0 )
           {
-            unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
-
-            /*
-             * Get the primary channel information.  Right now we don't
-             * do anything with this, but someday we will be able to inform
-             * the mid-level SCSI code which channel is primary.
-             */
-            if (biosctrl & CHANNEL_B_PRIMARY)
-            {
-              p->flags |= FLAGS_CHANNEL_B_PRIMARY;
-            }
-
-            if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+            switch(temp_p->bios_control & 0x07)
             {
-              p->flags |= USE_DEFAULTS;
+              case 0x0:
+                temp_p->bios_address = 0xcc000;
+                break;
+              case 0x1:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd4000;
+                break;
+              case 0x3:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xdc000;
+                break;
+              case 0x5:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe4000;
+                break;
+              case 0x7:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
           }
-
-          case AIC_284x:
-            if (!load_seeprom(p, &sxfrctl1))
+          else
+          {
+            switch(temp_p->bios_control & 0x06)
             {
-              if (aic7xxx_verbose)
-                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+              case 0x0:
+                temp_p->bios_address = 0xd0000;
+                break;
+              case 0x2:
+                temp_p->bios_address = 0xd8000;
+                break;
+              case 0x4:
+                temp_p->bios_address = 0xe0000;
+                break;
+              case 0x6:
+                temp_p->bios_address = 0xe8000;
+                break;
+              default:
+                break; /* can't get here */
             }
-            break;
-
-          default:  /* Won't get here. */
-            break;
+          }
         }
-        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
-               (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
-               (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
-        /*
-         * Check for Rev C or E boards. Rev E boards can supposedly have
-         * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
-         * It's still not clear extactly what is different about the Rev E
-         * boards, but we think it allows 8 bit entries in the QOUTFIFO to
-         * support "paging" SCBs (more than 4 commands can be active at once).
-         *
-         * The Rev E boards have a read/write autoflush bit in the
-         * SBLKCTL register, while in the Rev C boards it is read only.
-         */
-        sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
-        outb(sblkctl, p->base + SBLKCTL);
-        if (inb(p->base + SBLKCTL) == sblkctl)
+        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+        if (temp_p->flags & AHC_USEDEFAULTS)
         {
-          /*
-           * We detected a Rev E board, we allow paging on this board.
-           */
-          printk("Revision >= E\n");
-          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+          temp_p->scsi_id = temp_p->scsi_id_b = 7;
+          temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
         }
         else
         {
-          /* Do not allow paging. */
-          p->flags &= ~PAGE_ENABLED;
-          printk("Revision <= C\n");
+          if ( ((temp_p->adapter_control >> 8) & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_A;
+          if ( (temp_p->adapter_control & TERM_ENB) != 0 )
+            temp_p->flags |= AHC_TERM_ENB_B;
+          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
         }
+        break;
+      }
 
-        if (aic7xxx_verbose)
-          printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                 (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
-
-        /*
-         * Set the FIFO threshold and the bus off time.
-         */
-        hostconf = inb(p->base + HOSTCONF);
-        outb(hostconf & DFTHRSH, p->base + BUSSPD);
-        outb((hostconf << 2) & BOFF, p->base + BUSTIME);
-
-        /*
-         * Try to initialize the card and register it with the kernel.
-         */
-        if (aic7xxx_register(template, p))
-        {
-          /*
-           * We successfully found a board and registered it.
-           */
-          found = found + 1;
-        }
-        else
+      case AHC_284:
+        load_seeprom(temp_p, &sxfrctl1);
+        temp_p->board_name_index = 4;
+        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
         {
-          /*
-           * Something went wrong; release and free all resources.
-           */
-          aic7xxx_free(p);
+          case 0x00:
+            temp_p->bios_address = 0xe0000;
+            break;
+          case 0x20:
+            temp_p->bios_address = 0xc8000;
+            break;
+          case 0x40:
+            temp_p->bios_address = 0xd0000;
+            break;
+          case 0x60:
+            temp_p->bios_address = 0xd8000;
+            break;
+          default:
+            break; /* can't get here */
         }
-      }
-      /*
-       * Disallow spurious interrupts.
-       */
-      aic7xxx_spurious_count = 0;
+        break;
+
+      default:  /* Won't get here. */
+        break;
+    }
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+        temp_p->irq,
+        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
     }
+
+    /*
+     * Set the FIFO threshold and the bus off time.
+     */
+    hostconf = aic_inb(temp_p, HOSTCONF);
+    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+    slot++;
+    found++;
   }
 
+#endif /* defined(__i386__) || defined(__alpha__) */
+
 #ifdef CONFIG_PCI
   /*
    * PCI-bus probe.
@@ -6353,180 +7225,311 @@ aic7xxx_detect(Scsi_Host_Template *template)
     {
       unsigned short      vendor_id;
       unsigned short      device_id;
-      aha_chip_type       chip_type;
-      aha_chip_class_type chip_class;
+      ahc_type            type;
+      ahc_flag_type       flags;
+      int                 board_name_index;
     } const aic7xxx_pci_devices[] = {
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AIC_7873, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AIC_7874, AIC_787x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AIC_7880, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AIC_7881, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AIC_7882, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AIC_7883, AIC_788x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+       AHC_FNONE,                                            1 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       5 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+       AHC_PAGESCBS | AHC_USEDEFAULTS,                       6 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  7 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_294AU,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  8 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                      9 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     10 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_394,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     11 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_398,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     12 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_294,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     13 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     14 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     15 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_394U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     16 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_398U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     17 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_294U,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED,                     18 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
     };
 
-    int error, flags;
-    int done = 0;
-    unsigned int iobase, mbase;
-    unsigned short index = 0;
-    unsigned char pci_bus, pci_device_fn;
-    unsigned char ultra_enb = 0;
-    unsigned int  devconfig, class_revid;
-    scb_data_type *shared_scb_data = NULL;
-    char rev_id[] = {'B', 'C', 'D'};
+    unsigned short command;
+    unsigned int  devconfig, i;
+#ifdef MMAPIO
+    unsigned long page_offset;
+#endif
+    struct aic7xxx_host *first_7895 = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+    struct pci_dev *pdev = NULL;
+#else
+    int index;
+    unsigned int piobase, mmapbase;
+    unsigned char pci_bus, pci_devfn;
+#endif
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
     {
-      done = FALSE;
-      while (!done)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+      pdev = NULL;
+      while ((pdev = pci_find_device(aic7xxx_pci_devices[i].vendor_id,
+                                     aic7xxx_pci_devices[i].device_id,
+                                     pdev)))
+#else
+      index = 0;
+      while (!(pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
+                                   aic7xxx_pci_devices[i].device_id,
+                                   index++, &pci_bus, &pci_devfn)) )
+#endif
       {
-        if (pcibios_find_device(aic7xxx_pci_devices[i].vendor_id,
-                                aic7xxx_pci_devices[i].device_id,
-                                index, &pci_bus, &pci_device_fn))
-        {
-          index = 0;
-          done = TRUE;
-        }
-        else  /* Found an Adaptec PCI device. */
+        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
         {
-          chip_class = aic7xxx_pci_devices[i].chip_class;
-          chip_type = aic7xxx_pci_devices[i].chip_type;
-          chan_num = 0;
-          flags = 0;
-          switch (aic7xxx_pci_devices[i].chip_type)
+          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
           {
-            case AIC_7855:
-              flags |= USE_DEFAULTS;
-              break;
-
-            case AIC_7872:  /* 3940 */
-            case AIC_7882:  /* 3940-Ultra */
-              flags |= MULTI_CHANNEL;
-              chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
-              number_of_3940s++;
-              break;
-
-            case AIC_7873:  /* 3985 */
-            case AIC_7883:  /* 3985-Ultra */
-              chan_num = number_of_3985s;  /* Has 3 controllers */
-              flags |= MULTI_CHANNEL;
-              number_of_3985s++;
-              if (number_of_3985s == 3)
-              {
-                number_of_3985s = 0;
-                shared_scb_data = NULL;
-              }
-              break;
-
-            default:
-              break;
+            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+              "supported by\n");
+            printk(KERN_INFO "         this driver, we are ignoring it.\n");
           }
+        }
+        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+                                    GFP_ATOMIC)) != NULL )
+        {
+          memset(temp_p, 0, sizeof(struct aic7xxx_host));
+          temp_p->type = aic7xxx_pci_devices[i].type;
+          temp_p->flags = aic7xxx_pci_devices[i].flags;
+          temp_p->board_name_index = aic7xxx_pci_devices[i].board_name_index;
 
           /*
            * Read sundry information from PCI BIOS.
            */
-          error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                            PCI_BASE_ADDRESS_0, &iobase);
-          error += pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                            PCI_INTERRUPT_LINE, &irq);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                            PCI_BASE_ADDRESS_1, &mbase);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             DEVCONFIG, &devconfig);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CLASS_PROGIF_REVID, &class_revid);
-
-          printk("aic7xxx: <%s> at PCI %d\n",
-                 board_names[chip_type], PCI_SLOT(pci_device_fn));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+          temp_p->irq = pdev->irq;
+          temp_p->pci_bus = pdev->bus->number;
+          temp_p->pci_device_fn = pdev->devfn;
+          temp_p->base = pdev->base_address[0];
+          temp_p->mbase = pdev->base_address[1];
+          pci_read_config_word(pdev, PCI_COMMAND, &command);
+          pci_write_config_word(pdev, PCI_COMMAND,
+             command | PCI_COMMAND_MASTER |
+             PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+#else
+          temp_p->pci_bus = pci_bus;
+          temp_p->pci_device_fn = pci_devfn;
+          pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
+            &temp_p->irq);
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
+            &piobase);
+          temp_p->base = piobase;
+          pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
+            &mmapbase);
+          temp_p->mbase = mmapbase;
+          pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
+          pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
+            command | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+            PCI_COMMAND_IO);
+#endif
+
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic7xxx_pci_devices[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
 
           /*
            * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
            * we mask it off.
            */
-          iobase &= PCI_BASE_ADDRESS_IO_MASK;
-
-          p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
-                            shared_scb_data);
-
-          if (p == NULL)
+          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          temp_p->unpause = (aic_inb(temp_p, HCNTRL) & IRQMS) | INTEN;
+          temp_p->pause = temp_p->unpause | PAUSE;
+
+#ifdef MMAPIO
+          base = temp_p->mbase & PAGE_MASK;
+          page_offset = temp_p->mbase - base;
+          /*
+           * replace the next line with this one if you are using 2.1.x:
+           * temp_p->maddr = ioremap(base, page_offset + 256);
+           */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+          temp_p->maddr = ioremap(base, page_offset + 256);
+#else
+          temp_p->maddr = vremap(base, page_offset + 256);
+#endif
+          if(temp_p->maddr)
           {
-            printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-            continue;
+            temp_p->maddr += page_offset;
           }
-
-          /* Remember to set the channel number, irq, and chip class. */
-          p->chan_num = chan_num;
-          p->irq = irq;
-          p->chip_class = chip_class;
-#ifdef AIC7XXX_PAGE_ENABLE
-          p->flags |= PAGE_ENABLED;
 #endif
-          p->instance = found;
+
+          aic_outb(temp_p, temp_p->pause, HCNTRL);
+          while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+
+          temp_p->bios_address = 0;
 
           /*
            * Remember how the card was setup in case there is no seeprom.
            */
-          p->scsi_id = inb(p->base + SCSIID) & OID;
-          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+          temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          /*
+           * Get current termination setting
+           */
+          sxfrctl1 = aic_inb(temp_p, SXFRCTL1) & STPWEN;
+
+          if (aic7xxx_chip_reset(temp_p) == -1)
           {
-            p->flags |= ULTRA_ENABLED;
-            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
           }
-         sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
-
-          aic7xxx_chip_reset(p);
 
-#ifdef AIC7XXX_USE_EXT_SCBRAM
-          if (devconfig & RAMPSM)
+          switch (temp_p->type & 0x1ff1)
           {
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            /*
-             * XXX - Assume 9 bit SRAM and enable parity checking.
-             */
-            devconfig |= EXTSCBPEN;
+            case AHC_394:   /* 3940 */
+            case AHC_394U:  /* 3940-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 5:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                default:
+                  break;
+              }
+              break;
 
-            /*
-             * XXX - Assume fast SRAM and only enable 2 cycle access if we
-             *       are sharing the SRAM across multiple adapters (398x).
-             */
-            if ((devconfig & MPORTMODE) == 0)
-            {
-              devconfig |= EXTSCBTIME;
-            }
-            devconfig &= ~SCBRAMSEL;
-            pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                       DEVCONFIG, devconfig);
+            case AHC_398:   /* 3985 */
+            case AHC_398U:  /* 3985-Ultra */
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              switch(PCI_SLOT(temp_p->pci_device_fn))
+              {
+                case 8:
+                  temp_p->flags |= AHC_CHNLB;
+                  break;
+                case 12:
+                  temp_p->flags |= AHC_CHNLC;
+                  break;
+                default:
+                  break;
+              }
+              break;
+
+            case AHC_AIC7895:
+              temp_p->flags |= AHC_MULTI_CHANNEL;
+              if (PCI_FUNC(temp_p->pci_device_fn) != 0)
+              {
+                temp_p->flags |= AHC_CHNLB;
+              }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              devconfig |= SCBSIZE32;
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#else
+              pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                &devconfig);
+              devconfig |= SCBSIZE32;
+              pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG,
+                devconfig);
+#endif
+              if (aic7xxx_7895_irq_hack != -1)
+              {
+                if (first_7895 == NULL)
+                {
+                  printk(KERN_INFO "aic7xxx: Using 7895_irq_hack.  Please "
+                    "upgrade your motherboard BIOS\n");
+                  first_7895 = temp_p;
+                }
+                else if (aic7xxx_7895_irq_hack == 0)
+                {
+                  if (temp_p->flags & AHC_CHNLB)
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+                else
+                {
+                  if ( !(temp_p->flags & AHC_CHNLB) )
+                    temp_p->irq = first_7895->irq;
+                  else
+                    first_7895->irq = temp_p->irq;
+                  first_7895 = NULL;
+                }
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * Loading of the SEEPROM needs to come after we've set the flags
+           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
+           * on 394x and 398x cards we'll end up reading the wrong settings
+           * for channels B and C
+           */
+          if ( !(load_seeprom(temp_p, &sxfrctl1)) )
+          {
+            temp_p->flags |= AHC_USEDEFAULTS;
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
+            temp_p->scsi_id = temp_p->scsi_id_b = 7;
           }
-#endif
 
-          if ((p->flags & USE_DEFAULTS) == 0)
+          /*
+           * and then we need another switch based on the type in order to
+           * make sure the channel B primary flag is set properly on 7895
+           * controllers....Arrrgggghhh!!!
+           */
+          switch(temp_p->type & 0x1ff1)
           {
-            load_seeprom(p, &sxfrctl1);
+            case AHC_AIC7895:
+              current_p = list_p;
+              while(current_p != NULL)
+              {
+                if ( (current_p->pci_bus == temp_p->pci_bus) &&
+                     (PCI_SLOT(current_p->pci_device_fn) ==
+                      PCI_SLOT(temp_p->pci_device_fn)) )
+                {
+                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+                    temp_p->flags |= 
+                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+                  else
+                    current_p->flags |=
+                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                }
+                current_p = current_p->next;
+              }
+              break;
+            default:
+              break;
           }
 
           /*
            * Take the LED out of diagnostic mode
            */
-          sblkctl = inb(p->base + SBLKCTL);
-          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+          aic_outb(temp_p, 
+            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+            SBLKCTL);
 
           /*
            * We don't know where this is set in the SEEPROM or by the
            * BIOS, so we default to 100%.
            */
-          outb(DFTHRSH_100, p->base + DSPCISTATUS);
+          aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
 
-          if (p->flags & USE_DEFAULTS)
+          if (temp_p->flags & AHC_USEDEFAULTS)
           {
             int j;
+            unsigned char k;
             /*
              * Default setup; should only be used if the adapter does
              * not have a SEEPROM.
@@ -6538,158 +7541,315 @@ aic7xxx_detect(Scsi_Host_Template *template)
              */
             for (j = TARG_SCRATCH; j < 0x60; j++)
             {
-              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
+              k = aic_inb(temp_p, j);
+              /* Check for all zeros and ones.  Break out if we pass */
+              if( (k != 0x00) && (k != 0xff) )
                 break;
             }
-            if (j == TARG_SCRATCH)
-            {
-              for (j = TARG_SCRATCH; j < 0x60; j++)
-              {
-                if (inb(p->base + 1) != 0xFF)    /* Check for all ones. */
-                  break;
-              }
-            }
-            if ((j != 0x60) && (p->scsi_id != 0))
+            /* If j makes it to 0x60, then all entries are either 0x00 or
+             * 0xff.  We would then assume we have *not* been initialized
+             * and drop through here.  OTOH, if even one entry is inited,
+             * then as long as we appear to have a valid SCSI ID, we'll use
+             * the leftover BIOS values.
+             */
+            if ((j != 0x60) && (temp_p->scsi_id != 0))
             {
-              p->flags &= ~USE_DEFAULTS;
-              if (aic7xxx_verbose)
+              temp_p->flags &= ~AHC_USEDEFAULTS;
+              if (aic7xxx_verbose & VERBOSE_PROBE2)
               {
                 printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
               }
             }
             else
             {
-              if (aic7xxx_verbose)
-              {
-                printk(KERN_INFO "aic7xxx: No BIOS found; using default "
-                       "settings.\n");
-              }
               /*
                * Assume only one connector and always turn on
                * termination.
                */
+              temp_p->flags &= ~AHC_BIOS_ENABLED;
+              temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
               sxfrctl1 = STPWEN;
-              p->scsi_id = 7;
+              temp_p->scsi_id = 7;
             }
-            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
-                 p->base + SCSICONF);
+            aic_outb(temp_p, (temp_p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+                 SCSICONF);
             /* In case we are a wide card. */
-            outb(p->scsi_id, p->base + SCSICONF + 1);
-            if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
-            {
-              /*
-               * If there wasn't a BIOS or the board wasn't in this mode
-               * to begin with, turn off Ultra.
-               */
-              p->flags &= ~ULTRA_ENABLED;
-            }
+            aic_outb(temp_p, temp_p->scsi_id, SCSICONF + 1);
           }
-
-          /*
-           * Print some additional information about the adapter.
-           */
-          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
-                 "IO Mem 0x%x, IRQ %d",
-                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
-                 p->base, p->mbase, p->irq);
-          if ((class_revid & DEVREVID) < 3)
+          else /* not using defaults */
           {
-            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+            if (sxfrctl1 & STPWEN)
+              temp_p->flags |= AHC_TERM_ENB_A;
           }
-          printk("\n");
-
-          /*
-           * I don't think we need to bother with allowing
-           * spurious interrupts for the 787x/785x, but what
-           * the hey.
-           */
-          aic7xxx_spurious_count = 1;
 
           if (aic7xxx_extended)
-            p->flags |= EXTENDED_TRANSLATION;
-
-          if (aic7xxx_verbose)
-            printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-                   (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+            temp_p->flags |= AHC_EXTEND_TRANS_A;
 
           /*
            * Put our termination setting into sxfrctl1 now that the
            * generic initialization is complete.
            */
-          sxfrctl1 |= inb(p->base + SXFRCTL1);
-          outb(sxfrctl1, p->base + SXFRCTL1);
-
-          if (aic7xxx_register(template, p) == 0)
+          sxfrctl1 |= aic_inb(temp_p, SXFRCTL1);
+          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+          if ( list_p == NULL )
           {
-            aic7xxx_free(p);
+            list_p = current_p = temp_p;
           }
           else
           {
-            found = found + 1;
+            current_p = list_p;
+            while(current_p->next != NULL)
+              current_p = current_p->next;
+            current_p->next = temp_p;
+          }
+          temp_p->next = NULL;
+          found++;
+        }  /* Found an Adaptec PCI device. */
+        else /* Well, we found one, but we couldn't get any memory */
+        {
+          printk("aic7xxx: Found <%s>\n", 
+            board_names[aic7xxx_pci_devices[i].board_name_index]);
+          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+            "skipping.\n");
+        }
+      } /* while(pdev=....) */
+    } /* for PCI_DEVICES */
+  } /* PCI BIOS present */
+#endif CONFIG_PCI
+  /*
+   * Now, we re-order the probed devices by BIOS address and BUS class.
+   * In general, we follow this algorithm to make the adapters show up
+   * in the same order under linux that the computer finds them.
+   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+   *     address, going from lowest to highest.
+   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+   *     address, going from lowest to highest.
+   *  3: Remaining VLB/EISA controllers going in slot order.
+   *  4: Remaining PCI controllers, going in PCI device order (reversable)
+   */
+
+  {
+    struct aic7xxx_host *vlb_enab, *vlb_disab, *pci;
+    struct aic7xxx_host *prev_p;
+    struct aic7xxx_host *p;
+    unsigned char left;
 
-#ifdef AIC7XXX_USE_EXT_SCBRAM
+    prev_p = vlb_enab = vlb_disab = pci = NULL;
+
+    temp_p = list_p;
+    while (temp_p != NULL)
+    {
+      switch(temp_p->type)
+      {
+        case AHC_AIC7770:
+        case AHC_274:
+        case AHC_284:
+          if (temp_p->flags & AHC_BIOS_ENABLED)
+          {
+            if (vlb_enab == NULL)
+            {
+              vlb_enab = temp_p;
+              temp_p = temp_p->next;
+              vlb_enab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_enab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->bios_address < temp_p->bios_address))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_enab = temp_p;
+                temp_p = temp_p->next;
+                vlb_enab->next = current_p;
+              }
+            }
+          }
+          else
+          {
+            if (vlb_disab == NULL)
+            {
+              vlb_disab = temp_p;
+              temp_p = temp_p->next;
+              vlb_disab->next = NULL;
+            }
+            else
+            {
+              current_p = vlb_disab;
+              prev_p = NULL;
+              while ( (current_p != NULL) &&
+                      (current_p->base < temp_p->base))
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+              if (prev_p != NULL)
+              {
+                prev_p->next = temp_p;
+                temp_p = temp_p->next;
+                prev_p->next->next = current_p;
+              }
+              else
+              {
+                vlb_disab = temp_p;
+                temp_p = temp_p->next;
+                vlb_disab->next = current_p;
+              }
+            }
+          }
+          break;
+        default:  /* All PCI controllers fall through to default */
+          if (pci == NULL)
+          {
+            pci = temp_p;
+            temp_p = temp_p->next;
+            pci->next = NULL;
+          }
+          else
+          {
+            current_p = pci;
+            prev_p = NULL;
+            if (!aic7xxx_reverse_scan)
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) < 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            else
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) > 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
             /*
-             * Set the shared SCB data once we've successfully probed a
-             * 398x adapter.
-             *
-             * Note that we can only do this if the use of external
-             * SCB RAM is enabled.
+             * Are we dealing with a 7985 where we need to sort the
+             * channels as well, if so, the bios_address values should
+             * be the same
              */
-            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+                 (temp_p->pci_bus == current_p->pci_bus) &&
+                 (PCI_SLOT(temp_p->pci_device_fn) ==
+                  PCI_SLOT(current_p->pci_device_fn)) )
             {
-              if (shared_scb_data == NULL)
+              if (temp_p->flags & AHC_CHNLB)
+              {
+                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+              else
               {
-                shared_scb_data = p->scb_data;
+                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
               }
             }
-#endif
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              pci = temp_p;
+              temp_p = temp_p->next;
+              pci->next = current_p;
+            }
           }
-
-          index++;
-          /*
-           * Disable spurious interrupts.
-           */
-          aic7xxx_spurious_count = 0;
-        }  /* Found an Adaptec PCI device. */
+          break;
+      }  /* End of switch(temp_p->type) */
+    } /* End of while (temp_p != NULL) */
+    /*
+     * At this point, the cards have been broken into 4 sorted lists, now
+     * we run through the lists in order and register each controller
+     */
+    left = found;
+    temp_p = vlb_enab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = pci;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
+      }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
+    }
+    temp_p = vlb_disab;
+    while(temp_p != NULL)
+    {
+      template->name = board_names[temp_p->board_name_index];
+      p = aic7xxx_alloc(template, temp_p);
+      if (p != NULL)
+      {
+        p->instance = found - left;
+        if (aic7xxx_register(template, p, (--left)) == 0)
+        {
+          found--;
+          aic7xxx_free(p);
+        }
       }
+      current_p = temp_p;
+      temp_p = (struct aic7xxx_host *)temp_p->next;
+      kfree(current_p);
     }
   }
-#endif CONFIG_PCI
   return (found);
 }
 
-static void
-aic7xxx_fake_scsi_done(Scsi_Cmnd *cmd)
-{
-  memset(&cmd->sense_buffer[0], '\0', sizeof(cmd->sense_buffer));
-}
-
-static void
-aic7xxx_make_fake_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *cmd, int which)
-{
-  Scsi_Cmnd *cmd2;
-
-  if (which == 0)
-    p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 = cmd2 =
-       kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
-  else
-    p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 = cmd2 =
-       kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
-  if (cmd2 != NULL)
-  {
-    memcpy(cmd2, cmd, sizeof(Scsi_Cmnd));
-    memset(&cmd2->cmnd[0], '\0', sizeof(cmd2->cmnd));
-    cmd2->cmnd[0] = TEST_UNIT_READY;
-    cmd2->cmd_len = 6;
-    cmd2->bufflen = 0;
-    cmd2->request_bufflen = 0;
-    cmd2->buffer = NULL;
-    cmd2->request_buffer = NULL;
-    cmd2->use_sg = 0;
-    cmd2->underflow = 0;
-  }
-}
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_buildscb
@@ -6711,85 +7871,61 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
+  hscb->control = 0;
+  scb->tag_action = 0;
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-    if (cmd->device->tagged_queue)
+    if (p->tagenable & mask)
     {
       cmd->tag = hscb->tag;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 200)
+      p->dev_commands_sent[TARGET_INDEX(cmd)]++;
+      if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
       {
         hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
       }
       else
       {
-        hscb->control |= MSG_ORDERED_Q_TAG;
-        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+        if (p->orderedtag & mask)
+        {
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+        }
+        else
+        {
+          hscb->control |= MSG_SIMPLE_Q_TAG;
+          scb->tag_action = MSG_SIMPLE_Q_TAG;
+        }
+        p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
       }
     }
-#endif  /* Tagged queueing */
   }
-  if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
+  if ( (p->needwdtr & mask) &&
+      !(p->wdtr_pending & mask) &&
+      !(scb->tag_action))
   {
-    if ( cmd->cmnd[0] == TEST_UNIT_READY )
-    {
-      p->wdtr_pending |= mask;
-      hscb->control |= MK_MESSAGE;
-      scb->flags |= SCB_MSGOUT_WDTR;
-    }
+    p->wdtr_pending |= mask;
+    hscb->control |= MK_MESSAGE;
+    if (p->needwdtr_copy & mask)
+      scb->flags |= SCB_MSGOUT_WDTR_16BIT;
     else
-    {
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 == NULL )
-        aic7xxx_make_fake_cmnd(p, cmd, 0);
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 == NULL )
-        aic7xxx_make_fake_cmnd(p, cmd, 1);
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 != NULL )
-        aic7xxx_queue(p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0,
-          aic7xxx_fake_scsi_done);
-      if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 != NULL )
-        aic7xxx_queue(p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1,
-          aic7xxx_fake_scsi_done);
-    }
-#if 0
-    printk("scsi%d: Sending WDTR request to target %d.\n",
-           p->host_no, cmd->target);
-#endif
+      scb->flags |= SCB_MSGOUT_WDTR_8BIT;
   }
   else
   {
-    if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
+    if ( (p->needsdtr & mask) &&
+        !(p->sdtr_pending & mask) &&
+        !(p->wdtr_pending & mask) &&
+        !(scb->tag_action) )
     {
-      if ( cmd->cmnd[0] == TEST_UNIT_READY )
-      {
-        p->sdtr_pending |= mask;
-        hscb->control |= MK_MESSAGE;
-        scb->flags |= SCB_MSGOUT_SDTR;
-      }
-      else
-      {
-        if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd0 == NULL )
-          aic7xxx_make_fake_cmnd(p, cmd, 0);
-        if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 == NULL )
-          aic7xxx_make_fake_cmnd(p, cmd, 1);
-        if ( p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1 != NULL )
-          aic7xxx_queue(p->device_status[TARGET_INDEX(cmd)].scsi_cmnd1,
-            aic7xxx_fake_scsi_done);
-      }
-#if 0
-      printk("scsi%d: Sending SDTR request to target %d.\n",
-             p->host_no, cmd->target);
-#endif
+      p->sdtr_pending |= mask;
+      hscb->control |= MK_MESSAGE;
+      scb->flags |= SCB_MSGOUT_SDTR;
     }
   }
-#if 0
-  printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
-         "mask(0x%x).\n",
-        cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
-#endif
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
-       ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
 
   /*
    * The interpretation of request_buffer and request_bufflen
@@ -6803,7 +7939,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
    *       little-endian format.
    */
   hscb->SCSI_cmd_length = cmd->cmd_len;
-  hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
+  hscb->SCSI_cmd_pointer = cpu_to_le32(VIRT_TO_BUS(cmd->cmnd));
 
   if (cmd->use_sg)
   {
@@ -6818,46 +7954,42 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     int i;
 
     sg = (struct scatterlist *)cmd->request_buffer;
+    scb->sg_length = 0;
     for (i = 0; i < cmd->use_sg; i++)
     {
-      scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
-      scb->sg_list[i].length = (unsigned int) sg[i].length;
+      scb->sg_list[i].address = cpu_to_le32(VIRT_TO_BUS(sg[i].address));
+      scb->sg_list[i].length = cpu_to_le32(sg[i].length);
+      scb->sg_length += sg[i].length;
     }
-    hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+    hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(scb->sg_list));
     hscb->SG_segment_count = cmd->use_sg;
-    scb->sg_count = hscb->SG_segment_count;
+    scb->sg_count = cmd->use_sg;
 
     /* Copy the first SG into the data pointer area. */
     hscb->data_pointer = scb->sg_list[0].address;
-    hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
-#if 0
-    printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
-           cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
-#endif
+    hscb->data_count = scb->sg_list[0].length;
   }
   else
   {
-#if 0
-  printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
-       (unsigned long) cmd->request_buffer, cmd->request_bufflen);
-#endif
     if (cmd->request_bufflen)
     {
-      hscb->SG_segment_count = 1;
       scb->sg_count = 1;
-      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
-      scb->sg_list[0].length = cmd->request_bufflen;
-      hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
-      hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
-      hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
+      scb->sg_list[0].address = cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+      scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+      scb->sg_length = cmd->request_bufflen;
+      hscb->SG_segment_count = 1;
+      hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[0]));
+      hscb->data_count = scb->sg_list[0].length;
+      hscb->data_pointer = scb->sg_list[0].address;
     }
     else
     {
-      hscb->SG_segment_count = 0;
       scb->sg_count = 0;
+      scb->sg_length = 0;
+      hscb->SG_segment_count = 0;
       hscb->SG_list_pointer = 0;
+      hscb->data_count = 0;
       hscb->data_pointer = 0;
-      hscb->data_count = SCB_LIST_NULL << 24;
     }
   }
 }
@@ -6872,57 +8004,53 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
 int
 aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
-  long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
   int tindex = TARGET_INDEX(cmd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-
   /*
    * Check to see if channel was scanned.
    */
-  if (!(p->flags & A_SCANNED) && (cmd->channel == 0))
+  if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
   {
-    printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no);
-    p->flags |= A_SCANNED;
+    printk(INFO_LEAD "Scanning channel for devices.\n",
+      p->host_no, 0, -1, -1);
+    p->flags |= AHC_A_SCANNED;
   }
   else
   {
-    if (!(p->flags & B_SCANNED) && (cmd->channel == 1))
+    if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
     {
-      printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no);
-      p->flags |= B_SCANNED;
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 1, -1, -1);
+      p->flags |= AHC_B_SCANNED;
     }
   }
 
-#if 0
-  printk("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
-       cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
-       cmd->lun & 0x07);
-#endif
-
-  if ( (p->device_status[tindex].active_cmds > cmd->device->queue_depth) &&
-      !(p->wdtr_pending & (0x1 << tindex)) && 
-      !(p->sdtr_pending & (0x1 << tindex)) )
+  if (p->dev_active_cmds[tindex] > cmd->device->queue_depth)
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Commands queued exceeds queue "
-          "depth, active=%d\n",
+    printk(WARN_LEAD "Commands queued exceeds queue "
+           "depth, active=%d\n",
            p->host_no, CTL_OF_CMD(cmd), 
-          p->device_status[tindex].active_cmds);
+           p->dev_active_cmds[tindex]);
+    if ( p->dev_active_cmds[tindex] > 220 )
+      p->dev_active_cmds[tindex] = 0;
   }
-  scb = aic7xxx_allocate_scb(p);
+  DRIVER_LOCK
+  scb = aic7xxx_allocate_scb(p, FALSE);
+  DRIVER_UNLOCK
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
+    panic("(scsi%d) aic7xxx_queue:Couldn't get a free SCB.\n", p->host_no);
   }
   else
   {
     scb->cmd = cmd;
     aic7xxx_position(cmd) = scb->hscb->tag;
-#if 0
-    debug_scb(scb);
-#endif;
 
     /*
      * Construct the SCB beforehand, so the sequencer is
@@ -6930,17 +8058,6 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
      */
     aic7xxx_buildscb(p, cmd, scb);
 
-#if 0
-    if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
-    {
-      printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
-             "address.\n");
-    }
-    printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
-          scb->hscb->tag, (unsigned int) scb->cmd,
-          scb->flags, (unsigned int) p->free_scb);
-#endif
-
     /*
      * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
      * is set up properly, and the parity error flag is reset, then send
@@ -6955,26 +8072,20 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 
     scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    save_flags(processor_flags);
-    cli();
-    if (p->device_status[tindex].delayed_scbs.head != NULL) 
+    DRIVER_LOCK
+    if (p->delayed_scbs[tindex].head != NULL) 
     {
-        scbq_insert_tail(&p->device_status[tindex].delayed_scbs, scb);
+        scbq_insert_tail(&p->delayed_scbs[tindex], scb);
     }
     else
     {
         scbq_insert_tail(&p->waiting_scbs, scb);
     }
-    if ((p->flags & (IN_ISR | IN_ABORT | RESET_PENDING)) == 0)
+    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
     {
       aic7xxx_run_waiting_queues(p);
     }
-    restore_flags(processor_flags);
-
-#if 0
-    printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
-           (long) cmd, (long) scb->cmd, scb->hscb->tag);
-#endif;
+    DRIVER_UNLOCK
   }
   return (0);
 }
@@ -6996,53 +8107,54 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
   struct aic7xxx_scb   *scb;
   struct aic7xxx_hwscb *hscb;
   int result = -1;
-  char channel;
+  int channel;
   unsigned char saved_scbptr, lastphase;
-  unsigned char hscb_index, linked_next;
+  unsigned char hscb_index;
   int disconnected;
 
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   hscb = scb->hscb;
 
-  lastphase = inb(p->base + LASTPHASE);
-  if (aic7xxx_verbose > 1)
+  lastphase = aic_inb(p, LASTPHASE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus Device reset, scb flags 0x%x, ",
+    printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
          p->host_no, CTL_OF_SCB(scb), scb->flags);
     switch (lastphase)
     {
       case P_DATAOUT:
-        printk("Data-Out phase");
+        printk("Data-Out phase\n");
         break;
       case P_DATAIN:
-        printk("Data-In phase");
+        printk("Data-In phase\n");
         break;
       case P_COMMAND:
-        printk("Command phase");
+        printk("Command phase\n");
         break;
       case P_MESGOUT:
-        printk("Message-Out phase");
+        printk("Message-Out phase\n");
         break;
       case P_STATUS:
-        printk("Status phase");
+        printk("Status phase\n");
         break;
       case P_MESGIN:
-        printk("Message-In phase");
+        printk("Message-In phase\n");
         break;
       default:
       /*
        * We're not in a valid phase, so assume we're idle.
        */
-        printk("while idle, LASTPHASE = 0x%x", lastphase);
+        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
         break;
     }
-    printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
-         inb(p->base + SCSISIGI),
-         inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-         inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+         aic_inb(p, SCSISIGI),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
   }
 
-  channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
+  channel = cmd->channel;
 
     /*
      * Send a Device Reset Message:
@@ -7056,140 +8168,153 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
      * fails, we'll get another timeout a few seconds later which will
      * attempt a bus reset.
      */
-  saved_scbptr = inb(p->base + SCBPTR);
+  saved_scbptr = aic_inb(p, SCBPTR);
   disconnected = FALSE;
 
   if (lastphase != P_BUSFREE)
   {
-    if (inb(p->base + SCB_TAG) >= p->scb_data->numscbs)
+    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
     {
-        /*
-         * Perform a bus reset.
-         *
-         * XXX - We want to queue an abort for the timedout SCB
-         *       instead.
-         */
-      printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
-             "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
+      printk(WARN_LEAD "Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no,
+            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
       return(SCSI_RESET_ERROR);
     }
-    if (scb->hscb->tag == inb(p->base + SCB_TAG))
+    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
     { 
       if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
       {
         /* Send the abort message to the active SCB. */
-        outb(1, p->base + MSG_LEN);
-        outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
-        outb(lastphase | ATNO, p->base + SCSISIGO);
-       if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Device reset message in "
-               "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+        aic_outb(p, MSG_BUS_DEV_RESET, MSG_OUT);
+        aic_outb(p, lastphase | ATNO, SCSISIGO);
+        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+          printk(INFO_LEAD "Device reset message in "
+                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-       p->device_status[TARGET_INDEX(scb->cmd)].flags &= 
-               ~DEVICE_SUCCESS;
-       p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
-               BUS_DEVICE_RESET_PENDING;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
         return(SCSI_RESET_PENDING);
       }
       else
       {
-       /* We want to send out the message, but it could screw an already */
-       /* in place and being used message.  Instead, we return an error  */
-       /* to try and start the bus reset phase since this command is     */
+        /* We want to send out the message, but it could screw an already */
+        /* in place and being used message.  Instead, we return an error  */
+        /* to try and start the bus reset phase since this command is     */
         /* probably hung (aborts failed, and now reset is failing).  We   */
         /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
         /* any more on this device, but instead will escalate to a bus or */
         /* host reset (additionally, we won't try to abort any more).     */
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Device reset, Message buffer "
-               "in use\n", p->host_no, CTL_OF_SCB(scb));
-       scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        printk(WARN_LEAD "Device reset, Message buffer "
+                "in use\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-       p->device_status[TARGET_INDEX(scb->cmd)].flags &= 
-               ~DEVICE_SUCCESS;
-       p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
-               BUS_DEVICE_RESET_PENDING;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
+                ~DEVICE_SUCCESS;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
         return(SCSI_RESET_ERROR);
       }
     }
-  }
+  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
   hscb_index = aic7xxx_find_scb(p, scb);
   if (hscb_index == SCB_LIST_NULL)
   {
-    disconnected = TRUE;
-    linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
   }
   else
   {
-    outb(hscb_index, p->base + SCBPTR);
-    if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+    aic_outb(p, hscb_index, SCBPTR);
+    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
     {
       disconnected = TRUE;
     }
-    linked_next = inb(p->base + SCB_LINKED_NEXT);
   }
   if (disconnected)
   {
         /*
-         * Simply set the ABORT_SCB control bit and preserve the
-         * linked next pointer.
+         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+         * the rest on a reconnect.
          */
-    scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
-    scb->hscb->data_count &= ~0xFF000000;
-    scb->hscb->data_count |= linked_next << 24;
-    if ((p->flags & PAGE_ENABLED) == 0)
-    {
-      scb->hscb->control &= ~DISCONNECTED;
-    }
-    scb->flags |= SCB_RESET | SCB_DEVICE_RESET | SCB_QUEUED_ABORT;
-    p->device_status[TARGET_INDEX(scb->cmd)].flags &= ~DEVICE_SUCCESS;
-    p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
-       BUS_DEVICE_RESET_PENDING;
+    scb->hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+        BUS_DEVICE_RESET_PENDING;
     if (hscb_index != SCB_LIST_NULL)
     {
       unsigned char scb_control;
 
-      scb_control = inb(p->base + SCB_CONTROL);
-      outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+      aic_outb(p, hscb_index, SCBPTR);
+      scb_control = aic_inb(p, SCB_CONTROL);
+      aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
     }
         /*
          * Actually requeue this SCB in case we can select the
          * device before it reconnects.  If the transaction we
-         * want to abort is not tagged, unbusy it first so that
-         * we don't get held back from sending the command.
+         * want to abort is not tagged, then this will be the only
+         * outstanding command and we can simply shove it on the
+         * qoutfifo and be done.  If it is tagged, then it goes right
+         * in with all the others, no problem :)  We need to add it
+         * to the qinfifo and let the sequencer know it is there.
+         * Now, the only problem left to deal with is, *IF* this
+         * command completes, in spite of the MK_MESSAGE bit in the
+         * control byte, then we need to pick that up in the interrupt
+         * routine and clean things up.  This *shouldn't* ever happen.
          */
-    if ((scb->hscb->control & TAG_ENB) == 0)
-    {
-      aic7xxx_search_qinfifo(p, cmd->target, channel, cmd->lun, 
-            SCB_LIST_NULL, 0, TRUE, &p->waiting_scbs);
-    }
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queueing device reset command.\n",
-           p->host_no, CTL_OF_SCB(scb));
-    if ( !(scb->flags & SCB_WAITINGQ) ) /* Make sure we don't already have   */
-    {                                  /* an abort scb queued, or else we   */
-                                       /* corrupt the waiting queue and     */
-                                       /* active_cmds counter by queueing   */
-                                       /* again.                            */
-      scbq_insert_head(&p->waiting_scbs, scb);
-      scb->flags |= SCB_WAITINGQ;
-      p->device_status[TARGET_INDEX(scb->cmd)].active_cmds--;
-    }
-    else
-    {
-      scb->flags &= ~SCB_ABORT;
-    }
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Queueing device reset "
+           "command.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    scb->flags |= SCB_QUEUED_ABORT;
     result = SCSI_RESET_PENDING;
   }
   else if (result == -1)
   {
     result = SCSI_RESET_ERROR;
   }
-  outb(saved_scbptr, p->base + SCBPTR);
+  aic_outb(p, saved_scbptr, SCBPTR);
   return (result);
 }
 
 
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p)
+{
+  int i;
+
+  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if(p->dev_flags[i] & DEVICE_PRESENT)
+    {
+      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%s, SDTR:%s, q_depth=%d:%d\n",
+        p->host_no, 0, i, 0, p->dev_flags[i],
+        (p->needwdtr_copy & (1 << i)) ? "Yes" : "No",
+        (p->needsdtr_copy & (1 << i)) ? "Yes" : "No",
+        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+    }
+  }
+  printk("SIMODE0=0x%x, SIMODE1=0x%x, SSTAT0=0x%x, SSTAT1=0x%x, INTSTAT=0x%x\n",
+    aic_inb(p, SIMODE0), aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+    aic_inb(p, SSTAT1), aic_inb(p, INTSTAT) );
+  printk("p->flags=0x%x, p->type=0x%x, sequencer %s paused\n",
+     p->flags, p->type,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  panic("Stopping to debug\n");
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_abort
@@ -7204,15 +8329,26 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   struct aic7xxx_host *p;
   int    result, found=0;
   unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
-  unsigned long processor_flags;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
   Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
 
-  save_flags(processor_flags);
-  pause_sequencer(p);
-  cli();
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
+  DRIVER_LOCK
 
 /*
  *  Run the isr to grab any command in the QOUTFIFO and any other misc.
@@ -7222,19 +8358,22 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
  *  code.
  */
 
-  while ( (inb(p->base + INTSTAT) & INT_PEND) && !(p->flags & IN_ISR) )
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL);
+    aic7xxx_isr(p->irq, p, (void *)NULL);
     pause_sequencer(p);
   }
 
-  if (scb == NULL)    /*  Totally bogus cmd since it points beyond our  */
-  {                   /*  valid SCB range.  The suspect scb hasn't been */
-                      /*  allocated yet.                                */
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called with bogus Scsi_Cmnd->"
-       "SCB mapping.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+                      /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range or doesn't even match it's own*/
+                      /*  timeout serial number.                        */
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_NOT_RUNNING);
   }
   if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
@@ -7254,25 +8393,27 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
     {
       if (cmd_next == cmd) 
       {
-       if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called for command "
-         "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
-       if ( cmd_prev == NULL )
-         p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-       else
-         cmd_prev->host_scribble = cmd_next->host_scribble;
-       cmd_next->done(cmd_next);
-        unpause_sequencer(p, TRUE);
-       restore_flags(processor_flags);
-       return(SCSI_ABORT_SUCCESS);
-      }                                  
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "Abort called for command "
+          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        if ( cmd_prev == NULL )
+          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+        else
+          cmd_prev->host_scribble = cmd_next->host_scribble;
+        cmd_next->done(cmd_next);
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+                                         * completion */
+      }                                  
       cmd_prev = cmd_next;
       cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
     }
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called for already completed"
-       " command.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called for already completed"
+        " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_NOT_RUNNING);
   }
     
@@ -7298,29 +8439,29 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
 
   if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB aborted once already, "
-       "escalating.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB aborted once already, "
+        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_SNOOZE);
   }
-  if ( (p->flags & (RESET_PENDING | ABORT_PENDING)) || 
-          (p->device_status[TARGET_INDEX(scb->cmd)].flags & 
+  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
+          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
            BUS_DEVICE_RESET_PENDING) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset/Abort pending for this "
-       "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, TRUE);
-    restore_flags(processor_flags);
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "Reset/Abort pending for this "
+        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_ABORT_PENDING);
   }
 
   found = 0;
-  p->flags |= IN_ABORT;
-  if (aic7xxx_verbose)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+  p->flags |= AHC_IN_ABORT;
+  if (aic7xxx_verbose & VERBOSE_ABORT)
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
          p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
 
 /*
@@ -7331,13 +8472,13 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
  *    level code to reset the timeout.
  */
 
-  if ( scb->hscb->tag == inb(p->base + SCB_TAG) )
+  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
   {
    /*
     *  Check to see if the sequencer is just sitting on this command, or
     *   if it's actively being run.
     */
-    result = inb(p->base + LASTPHASE);
+    result = aic_inb(p, LASTPHASE);
     switch (result)
     {
       case P_DATAOUT:    /*    For any of these cases, we can assume we are */
@@ -7346,15 +8487,15 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
       case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
       case P_MESGOUT:    /*    chances to finish and then escalate to a     */
       case P_MESGIN:     /*    reset call                                   */
-       if (aic7xxx_verbose > 1)
-         printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB is currently active.  "
-               "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
-        unpause_sequencer(p, TRUE);
-       p->flags &= ~IN_ABORT;
-       scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
-       p->flags |= ABORT_PENDING;      /*  here so we will know not to    */
-        restore_flags(processor_flags); /*  muck with other SCBs if this   */
-        return(SCSI_ABORT_PENDING);      /*  one doesn't complete and clear */
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB is currently active.  "
+                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, FALSE);
+        p->flags &= ~AHC_IN_ABORT;
+        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
+        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
+        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
         break;                          /*  out.                           */
       default:
         break;
@@ -7365,12 +8506,13 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   {
       int tindex = TARGET_INDEX(cmd);
      
-      if (aic7xxx_verbose > 1
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found on waiting list and "
-           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS
+        printk(INFO_LEAD "SCB found on waiting list and "
+            "aborted.\n", p->host_no, CTL_OF_SCB(scb));
       scbq_remove(&p->waiting_scbs, scb);
-      scbq_remove(&p->device_status[tindex].delayed_scbs, scb);
-      p->device_status[tindex].active_cmds++;
+      scbq_remove(&p->delayed_scbs[tindex], scb);
+      p->dev_active_cmds[tindex]++;
+      p->activescbs++;
       scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
       scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
       found = 1;
@@ -7382,10 +8524,11 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   if ( found == 0 )
   {
     if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
-                     INT_TO_CHAN(cmd->channel),
-                    cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
-                    FALSE, NULL)) != 0) && (aic7xxx_verbose > 1))
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found in QINFIFO and "
+                     cmd->channel,
+                     cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                     FALSE, NULL)) != 0) &&
+                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "SCB found in QINFIFO and "
         "aborted.\n", p->host_no, CTL_OF_SCB(scb));
   }
 
@@ -7397,35 +8540,41 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   {
     unsigned char scb_next_ptr;
     prev_hscbptr = SCB_LIST_NULL;
-    saved_hscbptr = inb(p->base + SCBPTR);
-    next_hscbptr = inb(p->base + WAITING_SCBH);
+    saved_hscbptr = aic_inb(p, SCBPTR);
+    next_hscbptr = aic_inb(p, WAITING_SCBH);
     while ( next_hscbptr != SCB_LIST_NULL )
     {
-      outb( next_hscbptr, p->base + SCBPTR );
-      if ( scb->hscb->tag == inb(p->base + SCB_TAG) )
+      aic_outb(p,  next_hscbptr, SCBPTR );
+      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
       {
         found = 1;
-       if (aic7xxx_verbose > 1)
-          printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found on hardware waiting"
-           " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
-       if ( prev_hscbptr == SCB_LIST_NULL )
-           outb(inb(p->base + SCB_NEXT), p->base + WAITING_SCBH);
-       else
-       {
-           scb_next_ptr = inb(p->base + SCB_NEXT);
-           outb(prev_hscbptr, p->base + SCBPTR);
-           outb(scb_next_ptr, p->base + SCB_NEXT);
-           outb(next_hscbptr, p->base + SCBPTR);
-       }
-       outb(SCB_LIST_NULL, p->base + SCB_TAG);
-       aic7xxx_add_curscb_to_free_list(p);
-       scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB found on hardware waiting"
+            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+        if ( prev_hscbptr == SCB_LIST_NULL )
+        {
+            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
+            aic_outb(p, 0, SCSISEQ);    /* stop the selection since we just
+                                         * grabbed the scb out from under the
+                                         * card */
+        }
+        else
+        {
+            scb_next_ptr = aic_inb(p, SCB_NEXT);
+            aic_outb(p, prev_hscbptr, SCBPTR);
+            aic_outb(p, scb_next_ptr, SCB_NEXT);
+            aic_outb(p, next_hscbptr, SCBPTR);
+        }
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        aic7xxx_add_curscb_to_free_list(p);
+        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
         break;
       }
       prev_hscbptr = next_hscbptr;
-      next_hscbptr = inb(p->base + SCB_NEXT);
+      next_hscbptr = aic_inb(p, SCB_NEXT);
     }
-    outb( saved_hscbptr, p->base + SCBPTR );
+    aic_outb(p,  saved_hscbptr, SCBPTR );
   }
         
 /*
@@ -7440,42 +8589,32 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
 
   if ( found == 0 )
   {
-    p->flags |= ABORT_PENDING;
+    p->flags |= AHC_ABORT_PENDING;
     scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-    scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+    scb->hscb->control |= MK_MESSAGE;
     result=aic7xxx_find_scb(p, scb);
     if ( result != SCB_LIST_NULL ) 
     {
-      saved_hscbptr = inb(p->base + SCBPTR);
-      outb(result, p->base + SCBPTR);
-      tmp_char = inb(p->base + SCB_CONTROL);
-      outb( tmp_char | MK_MESSAGE | ABORT_SCB, p->base + SCB_CONTROL);
-      outb(saved_hscbptr, p->base + SCBPTR);
+      saved_hscbptr = aic_inb(p, SCBPTR);
+      aic_outb(p, result, SCBPTR);
+      tmp_char = aic_inb(p, SCB_CONTROL);
+      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
+      aic_outb(p, saved_hscbptr, SCBPTR);
     }
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB disconnected.  Queueing Abort"
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
         " SCB.\n", p->host_no, CTL_OF_SCB(scb));
-    if ( (scb->hscb->control & TAG_ENB) == 0 )
-    {
-      aic7xxx_search_qinfifo(p, cmd->target, INT_TO_CHAN(cmd->channel),
-       cmd->lun, SCB_LIST_NULL, 0, TRUE, &p->waiting_scbs);
-    }
-    if ( !(scb->flags & SCB_WAITINGQ) )
-    {
-      scbq_insert_head(&p->waiting_scbs, scb);
-      scb->flags |= SCB_WAITINGQ;
-      p->device_status[TARGET_INDEX(scb->cmd)].active_cmds--;
-    }
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
   }
-  else
-  { 
-    scb->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+  if (found)
+  {
+    aic7xxx_run_done_queue(p, TRUE);
+    aic7xxx_run_waiting_queues(p);
   }
-  aic7xxx_run_done_queue(p, TRUE);
-  aic7xxx_run_waiting_queues(p);
-  p->flags &= ~IN_ABORT;
-  restore_flags(processor_flags);
+  p->flags &= ~AHC_IN_ABORT;
+  unpause_sequencer(p, FALSE);
+  DRIVER_UNLOCK
 
 /*
  *  On the return value.  If we found the command and aborted it, then we know
@@ -7511,44 +8650,54 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   struct aic7xxx_host *p;
   int    tindex;
   int    result = -1;
-  char   channel = 'A';
-  unsigned long processor_flags;
-#define        DEVICE_RESET 0x01
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+#define DEVICE_RESET 0x01
 #define BUS_RESET    0x02
 #define HOST_RESET   0x04
 #define FAIL         0x08
-#define        RESET_DELAY  0x10
-  int  action;
+#define RESET_DELAY  0x10
+  int        action;
   Scsi_Cmnd *cmd_prev, *cmd_next;
 
 
   if ( cmd == NULL )
   {
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(aic7xxx) Reset called with NULL Scsi_Cmnd "
-       "pointer, failing.\n");
+    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
+      "pointer, failing.\n");
     return(SCSI_RESET_SNOOZE);
   }
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  channel = INT_TO_CHAN(cmd->channel);
   tindex = TARGET_INDEX(cmd);
 
-  save_flags(processor_flags);
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
+  DRIVER_LOCK
+
   pause_sequencer(p);
-  cli();
-  while ( (inb(p->base + INTSTAT) & INT_PEND) && !(p->flags & IN_ISR) )
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
-    aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL );
+    aic7xxx_isr(p->irq, p, (void *)NULL );
     pause_sequencer(p);
   }
 
   if (scb == NULL)
   {
-    if (aic7xxx_verbose)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called with bogus Scsi_Cmnd"
-          "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -7560,43 +8709,38 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   }
   else if (scb->cmd != cmd) 
   {
-    if (aic7xxx_verbose > 1)
-    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called with recycled SCB "
-       "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+    printk(INFO_LEAD "Reset called with recycled SCB "
+        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
     cmd_prev = NULL;
     cmd_next = p->completeq.head;
     while ( cmd_next != NULL )
     {
       if (cmd_next == cmd)
       {
-       if (aic7xxx_verbose > 1)
-         printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset, found cmd on completeq"
-         ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
-       if ( cmd_prev == NULL )
-         p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-       else
-         cmd_prev->host_scribble = cmd_next->host_scribble;
-       cmd_next->done(cmd_next);
-       unpause_sequencer(p, TRUE);
-       restore_flags(processor_flags);
-       return(SCSI_RESET_SUCCESS);
+        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+          printk(INFO_LEAD "Reset, found cmd on completeq"
+          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_RESET_NOT_RUNNING);
       }
       cmd_prev = cmd_next;
       cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
     }
     if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
     {
-      if (aic7xxx_verbose)
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset, cmd not found,"
-         " failing.\n", p->host_no, CTL_OF_CMD(cmd));
-      unpause_sequencer(p, TRUE);
-      restore_flags(processor_flags);
+      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "Reset, cmd not found,"
+          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(SCSI_RESET_NOT_RUNNING);
     }
     else
     {
-      if (aic7xxx_verbose)
-        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called, no scb, "
+      if (aic7xxx_verbose & VERBOSE_RESET_MID)
+        printk(INFO_LEAD "Reset called, no scb, "
           "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
       scb = NULL;
       action = HOST_RESET;
@@ -7604,9 +8748,18 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   }
   else
   {
-    if (aic7xxx_verbose)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called, scb %d, flags "
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called, scb %d, flags "
         "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
+    {
+      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+          CTL_OF_SCB(scb));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
+    }
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -7620,58 +8773,65 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       action = DEVICE_RESET;
     }
   }
-  if ( ((jiffies - p->last_reset) < (HZ * AIC7XXX_RESET_DELAY)) &&
-    (action & (HOST_RESET | BUS_RESET | DEVICE_RESET)) )
+  if ( (action & DEVICE_RESET) && 
+        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
   {
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called too soon after "
-       "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = RESET_DELAY;
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Bus device reset already sent to "
+        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
   }
-  if ( ((jiffies - p->device_status[tindex].last_reset) < 
-       (HZ * AIC7XXX_RESET_DELAY)) && !(action & (HOST_RESET | BUS_RESET)))
+  if ( (action & DEVICE_RESET) &&
+       (scb->flags & SCB_QUEUED_ABORT) )
   {
-    if (aic7xxx_verbose > 1)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called too soon after last "
-       "reset without requesting\n"
-       "(scsi%d:%d:%d:%d) bus or host reset, escalating.\n", p->host_no,
-       CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Have already attempted to reach "
+        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "message, will escalate to bus "
+        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
+    }
     action = BUS_RESET;
   }
   if ( (action & DEVICE_RESET) && 
-       (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING) )
+       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset already sent to "
-       "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+     printk(INFO_LEAD "Bus device reset stupid when "
+        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
     action = BUS_RESET;
   }
-  if ( (action & DEVICE_RESET) &&
-       (scb->flags & SCB_QUEUED_ABORT) )
+  if ( (action & BUS_RESET) && !(p->type & AHC_TWIN) )
   {
-    if (aic7xxx_verbose > 2)
-      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Have already attempted to reach "
-       "device with queued\n(scsi%d:%d:%d:%d) message, will escalate to bus "
-       "reset.\n", p->host_no, CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd));
-    action = BUS_RESET;
+    action = HOST_RESET;
   }
-  if ( (action & DEVICE_RESET) && (p->flags & (RESET_PENDING | ABORT_PENDING)) )
+  if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+       !(action & (HOST_RESET | BUS_RESET)))
   {
-    if (aic7xxx_verbose > 2)
-     printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset stupid when "
-       "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Reset called too soon after last "
+        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
+        CTL_OF_CMD(cmd));
+    }
     action = BUS_RESET;
   }
-  if ( (action & BUS_RESET) && (p->bus_type != AIC_TWIN) )
+  if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
+        (action & (HOST_RESET | BUS_RESET)) )
   {
-    action = HOST_RESET;
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Reset called too soon after "
+        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = RESET_DELAY;
   }
-  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & RESET_PENDING)
-       && ((jiffies - p->reset_start) > (2 * HZ * AIC7XXX_RESET_DELAY)) )
+  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
+        && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
   {
     printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!!  Card must have left to go "
-       "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
-    restore_flags(processor_flags);
+        "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
     return(SCSI_RESET_SNOOZE);
   }
 /*
@@ -7681,37 +8841,41 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   switch (action)
   {
     case RESET_DELAY:
-      restore_flags(processor_flags);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(SCSI_RESET_PENDING);
       break;
     case FAIL:
-      restore_flags(processor_flags);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(SCSI_RESET_ERROR);
       break;
     case DEVICE_RESET:
-      p->flags |= RESET_PENDING;
+      p->flags |= AHC_IN_RESET;
       result = aic7xxx_bus_device_reset(p, cmd);
       aic7xxx_run_done_queue(p, TRUE);
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
       aic7xxx_run_waiting_queues(p);
-      p->flags &= ~RESET_PENDING;
-      restore_flags(processor_flags);
+      unpause_sequencer(p, FALSE);
+      p->flags &= ~AHC_IN_RESET;
+      DRIVER_UNLOCK
       return(result);
       break;
     case BUS_RESET:
     case HOST_RESET:
     default:
       p->reset_start = jiffies;
-      p->flags |= RESET_PENDING;
-      aic7xxx_reset_channel(p, channel, TRUE);
-      if ( (p->bus_type == AIC_TWIN) && (action & HOST_RESET) )
+      p->flags |= AHC_IN_RESET;
+      aic7xxx_reset_channel(p, cmd->channel, TRUE);
+      if ( (p->type & AHC_TWIN) && (action & HOST_RESET) )
       {
-        aic7xxx_reset_channel(p, (channel == 'A') ? 'B' : 'A', TRUE);
+        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
         restart_sequencer(p);
-       pause_sequencer(p);
       }
       if (scb == NULL)
       {
-       cmd->result = DID_RESET << 16;
+        cmd->result = DID_RESET << 16;
         cmd->done(cmd);
       }
       p->last_reset = jiffies;
@@ -7720,13 +8884,20 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       else
       {
         result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-        while (inb(p->base + QOUTCNT)) inb(p->base + QOUTFIFO);
-        if (p->flags & PAGE_ENABLED) outb(0, p->base + CMDOUTCNT);
+        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
+          SIMODE1);
         aic7xxx_clear_intstat(p);
+        p->flags &= ~AHC_HANDLING_REQINITS;
+        p->msg_type = MSG_TYPE_NONE;
+        p->msg_index = 0;
+        p->msg_len = 0;
       }
-      p->flags &= ~RESET_PENDING;
+      p->flags &= ~AHC_IN_RESET;
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
       aic7xxx_run_waiting_queues(p);
-      restore_flags(processor_flags);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
       return(result);
       break;
   }
@@ -7756,7 +8927,7 @@ aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);
 
-  if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024))
+  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
   {
     heads = 255;
     sectors = 63;
index 074f4d2bc1a626cb2ee72cf376d9eb5f8e547865..8da5edba0a22d642521ed3a3299e14a82208f8c5 100644 (file)
 #ifndef _aic7xxx_h
 #define _aic7xxx_h
 
-#define AIC7XXX_H_VERSION  "$Revision: 3.2.1 $"
+#define AIC7XXX_H_VERSION  "3.2.4"
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if defined(__i386__)
+#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+#else
+#  define AIC7XXX_BIOSPARAM NULL
+#endif
 
 /*
  * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
  * to do with card config are filled in after the card is detected.
  */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+#define AIC7XXX        {                                               \
+       next: NULL,                                             \
+       module: NULL,                                           \
+       proc_dir: NULL,                                         \
+       proc_info: aic7xxx_proc_info,                           \
+       name: NULL,                                             \
+       detect: aic7xxx_detect,                                 \
+       release: NULL,                                          \
+       info: aic7xxx_info,                                     \
+       command: NULL,                                          \
+       queuecommand: aic7xxx_queue,                            \
+       eh_strategy_handler: NULL,                              \
+       eh_abort_handler: NULL,                                 \
+       eh_device_reset_handler: NULL,                          \
+       eh_bus_reset_handler: NULL,                             \
+       eh_host_reset_handler: NULL,                            \
+       abort: aic7xxx_abort,                                   \
+       reset: aic7xxx_reset,                                   \
+       slave_attach: NULL,                                     \
+       bios_param: AIC7XXX_BIOSPARAM,                          \
+       can_queue: 255,         /* max simultaneous cmds      */\
+       this_id: -1,            /* scsi id of host adapter    */\
+       sg_tablesize: 0,        /* max scatter-gather cmds    */\
+       cmd_per_lun: 3,         /* cmds per lun (linked cmds) */\
+       present: 0,             /* number of 7xxx's present   */\
+       unchecked_isa_dma: 0,   /* no memory DMA restrictions */\
+       use_clustering: ENABLE_CLUSTERING,                      \
+       use_new_eh_code: 0                                      \
+}
+#else
 #define AIC7XXX        {                                               \
-       NULL,                                                   \
-       NULL,                                                   \
-       NULL,                                                   \
-       aic7xxx_proc_info,                                      \
-       NULL,                                                   \
-       aic7xxx_detect,                                         \
-       NULL,                                                   \
-       aic7xxx_info,                                           \
-       NULL,                                                   \
-       aic7xxx_queue,                                          \
-       aic7xxx_abort,                                          \
-       aic7xxx_reset,                                          \
-       NULL,                                                   \
-       aic7xxx_biosparam,                                      \
-       -1,                     /* max simultaneous cmds      */\
-       -1,                     /* scsi id of host adapter    */\
-       0,                      /* max scatter-gather cmds    */\
-       2,                      /* cmds per lun (linked cmds) */\
-       0,                      /* number of 7xxx's present   */\
-       0,                      /* no memory DMA restrictions */\
-       ENABLE_CLUSTERING                                       \
+       next: NULL,                                             \
+       usage_count: NULL,                                      \
+       proc_dir: NULL,                                         \
+       proc_info: aic7xxx_proc_info,                           \
+       name: NULL,                                             \
+       detect: aic7xxx_detect,                                 \
+       release: NULL,                                          \
+       info: aic7xxx_info,                                     \
+       command: NULL,                                          \
+       queuecommand: aic7xxx_queue,                            \
+       abort: aic7xxx_abort,                                   \
+       reset: aic7xxx_reset,                                   \
+       slave_attach: NULL,                                     \
+       bios_param: AIC7XXX_BIOSPARAM,                          \
+       can_queue: 255,         /* max simultaneous cmds      */\
+       this_id: -1,            /* scsi id of host adapter    */\
+       sg_tablesize: 0,        /* max scatter-gather cmds    */\
+       cmd_per_lun: 3,         /* cmds per lun (linked cmds) */\
+       present: 0,             /* number of 7xxx's present   */\
+       unchecked_isa_dma: 0,   /* no memory DMA restrictions */\
+       use_clustering: ENABLE_CLUSTERING                       \
 }
+#endif
 
 extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
index 58254a2754ec8040a62baf2e18f2bb07c8f17e69..6dffebc8bf1cf20ede945c18ce04d7847ed633d6 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -392,6 +389,27 @@ register SELID {
        bit     ONEBIT          0x08
 }
 
+/*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+       address                 0x01b
+       access_mode RW
+       bit     SOFT1           0x80
+       bit     SOFT0           0x40
+       bit     SOFTCMDEN       0x20    
+       bit     HAS_BRDCTL      0x10    /* External Board control */
+       bit     SEEPROM         0x08    /* External serial eeprom logic */
+       bit     EEPROM          0x04    /* Writable external BIOS ROM */
+       bit     ROM             0x02    /* Logic for accessing external ROM */
+       bit     SSPIOCPS        0x01    /* Termination and cable detection */
+}
+
 /*
  * SCSI Block Control (p. 3-32)
  * Controls Bus type and channel selection.  In a twin channel configuration
@@ -622,26 +640,19 @@ register INTSTAT {
        mask    NO_IDENT        0x20|SEQINT     /* no IDENTIFY after reconnect*/
        mask    NO_MATCH        0x30|SEQINT     /* no cmd match for reconnect */
        mask    EXTENDED_MSG    0x40|SEQINT     /* Extended message received */
-       mask    NO_MATCH_BUSY   0x50|SEQINT     /* Couldn't find BUSY SCB */
+       mask    ABORT_REQUESTED 0x50|SEQINT     /* Reconect of aborted SCB */
        mask    REJECT_MSG      0x60|SEQINT     /* Reject message received */
        mask    BAD_STATUS      0x70|SEQINT     /* Bad status from target */
        mask    RESIDUAL        0x80|SEQINT     /* Residual byte count != 0 */
-       mask    ABORT_CMDCMPLT  0x91            /*
-                                                * Command tagged for abort
-                                                * completed successfully.
-                                                */
        mask    AWAITING_MSG    0xa0|SEQINT     /*
                                                 * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-       mask    MSG_BUFFER_BUSY 0xc0|SEQINT     /*
-                                                * Sequencer wants to use the
-                                                * message buffer, but it
-                                                * already contains a message
+                                                * a message to this target
+                                                * (command was null), so tell
+                                                * it that it can fill the
+                                                * message buffer.
                                                 */
+       mask    TRACEPOINT      0xb0|SEQINT
+       mask    TRACEPOINT2     0xc0|SEQINT
        mask    MSGIN_PHASEMIS  0xd0|SEQINT     /*
                                                 * Target changed phase on us
                                                 * when we were expecting
@@ -665,7 +676,10 @@ register INTSTAT {
 register ERROR {
        address                 0x092
        access_mode RO
-       bit     PARERR          0x08
+       bit     PCIERRSTAT      0x40    /* PCI only */
+       bit     MPARERR         0x20    /* PCI only */
+       bit     DPARERR         0x10    /* PCI only */
+       bit     SQPARERR        0x08
        bit     ILLOPCODE       0x04
        bit     ILLSADDR        0x02
        bit     ILLHADDR        0x01
@@ -677,6 +691,7 @@ register ERROR {
 register CLRINT {
        address                 0x092
        access_mode WO
+       bit     CLRPARERR       0x10    /* PCI only */
        bit     CLRBRKADRINT    0x08
        bit     CLRSCSIINT      0x04
        bit     CLRCMDINT       0x02
@@ -771,8 +786,6 @@ scb {
                bit     MK_MESSAGE      0x80
                bit     DISCENB         0x40
                bit     TAG_ENB         0x20
-               bit     MUST_DMAUP_SCB  0x10
-               bit     ABORT_SCB       0x08
                bit     DISCONNECTED    0x04
                mask    SCB_TAG_TYPE    0x03
        }
@@ -801,10 +814,11 @@ scb {
                size    4
        }
        SCB_DATACNT {
-               size    3
-       }
-       SCB_LINKED_NEXT {
-               size    1
+               /*
+                * Really only 3 bytes, but padded to make
+                * the kernel's job easier.
+                */
+               size    4
        }
        SCB_CMDPTR {
                size    4
@@ -924,6 +938,9 @@ scratch_ram {
        TARG_SCRATCH {
                size            16
        }
+       /*
+        * Bit vector of targets that have ULTRA enabled.
+        */
        ULTRA_ENB {
                size            2
        }
@@ -934,14 +951,11 @@ scratch_ram {
                size            2
        }
        /*
-        * Length of pending message
+        * Single byte buffer used to designate the type or message
+        * to send to a target.
         */
-       MSG_LEN {
-               size            1
-       }
-       /* We reserve 8bytes to store outgoing messages */
        MSG_OUT {
-               size            8
+               size            1
        }
        /* Parameters for DMA Logic */
        DMAPARAMS {
@@ -956,35 +970,12 @@ scratch_ram {
                bit     FIFOFLUSH       0x02
                bit     FIFORESET       0x01
        }
-       /*
-        * Number of SCBs supported by
-        * this card.
-        */
-       SCBCOUNT {
-               size            1
-       }
-       /*
-        * Two's complement of SCBCOUNT
-        */
-       COMP_SCBCOUNT {
-               size            1
-       }
-       /*
-        * Mask of bits to test against
-        * when looking at the Queue Count
-        * registers.  Works around a bug
-        * on aic7850 chips. 
-        */
-       QCNTMASK {
-               size            1
-       }
        SEQ_FLAGS {
                size            1
-               bit     RESELECTED      0x80
-               bit     IDENTIFY_SEEN   0x40
-               bit     TAGGED_SCB      0x20
+               bit     IDENTIFY_SEEN   0x80
+               bit     SCBPTR_VALID    0x20
                bit     DPHASE          0x10
-               bit     PAGESCBS        0x04
+               bit     AMTARGET        0x08
                bit     WIDE_BUS        0x02
                bit     TWIN_BUS        0x01
        }
@@ -996,33 +987,14 @@ scratch_ram {
        SAVED_TCL {
                size            1
        }
+       /* Working value of the number of SG segments left */
        SG_COUNT {
                size            1
        }
-       /* working value of SG pointer */
+       /* Working value of SG pointer */
        SG_NEXT {
                size            4
        }
-       /*
-        * head of list of SCBs awaiting
-        * selection
-        */
-       WAITING_SCBH {
-               size            1
-       }
-       SAVED_LINKPTR {
-               size            1
-       }
-       SAVED_SCBPTR {
-               size            1
-       }
-       /*
-        * The sequencer will stick the frist byte of any rejected message here
-        * so we can see what is getting thrown away.
-        */
-       REJBYTE {
-               size            1
-       }
        /*
         * The last bus phase as seen by the sequencer. 
         */
@@ -1040,23 +1012,12 @@ scratch_ram {
                mask    P_MESGIN        CDI|IOI|MSGI
                mask    P_BUSFREE       0x01
        }
-       MSGIN_EXT_LEN {
-               size            1
-       }
-       MSGIN_EXT_OPCODE {
-               size            1
-       }
        /*
-        * location 3, stores the last
-        * byte of an extended message if
-        * it passes the two bytes of space
-        * we allow now.  This byte isn't
-        * used for anything, it just makes
-        * the code shorter for tossing
-        * extra bytes.
+        * head of list of SCBs awaiting
+        * selection
         */
-       MSGIN_EXT_BYTES {
-               size            3
+       WAITING_SCBH {
+               size            1
        }
        /*
         * head of list of SCBs that are
@@ -1073,10 +1034,40 @@ scratch_ram {
        FREE_SCBH {
                size            1
        }
+       /*
+        * Address of the hardware scb array in the host.
+        */
        HSCB_ADDR {
                size            4
        }
-       CUR_SCBID {
+       /*
+        * Address of the 256 byte array storing the SCBID of outstanding
+        * untagged SCBs indexed by TCL.
+        */
+       SCBID_ADDR {
+               size            4
+       }
+       /*
+        * Address of the array of command descriptors used to store
+        * information about incoming selections.
+        */
+       TMODE_CMDADDR {
+               size            4
+       }
+       KERNEL_QINPOS {
+               size            1
+       }
+       QINPOS {
+               size            1
+       }
+       QOUTPOS {
+               size            1
+       }
+       /*
+        * Offset into the command descriptor array for the next
+        * available desciptor to use.
+        */
+       TMODE_CMDADDR_NEXT {
                size            1
        }
        ARG_1 {
@@ -1084,30 +1075,13 @@ scratch_ram {
                mask    SEND_MSG        0x80
                mask    SEND_SENSE      0x40
                mask    SEND_REJ        0x20
+               mask    MSGOUT_PHASEMIS 0x10
                alias   RETURN_1
        }
        /*
-        * Running count of commands placed in
-        * the QOUTFIFO.  This is cleared by the
-        * kernel driver every FIFODEPTH commands.
-        *
-        * NOTE: These scratch RAM registers are overlaying SCSICONF
-        *       and SCSICONF2 and are only used on cards that are
-        *       capable of SCB paging.   Currently, only the PCI
-        *       controllers can do this, which is good because the
-        *       AIC-7770 based controllers use the SCSICONF register
-        *       to control termination.  In other words, do not
-        *       destroy the contents of SCSICONF and SCSICONF2 for
-        *       AIC-7770 based controllers.
+        * Snapshot of MSG_OUT taken after each message is sent.
         */
-       CMDOUTCNT {
-               size            1
-       }
-       /*
-        * Maximum number of entries allowed in
-        * the QOUT/INFIFO.
-        */
-       FIFODEPTH {
+       LAST_MSG {
                size            1
        }
        /*
@@ -1118,12 +1092,10 @@ scratch_ram {
        SCSICONF {
                address         0x05a
                size            1
+               bit     TERM_ENB        0x80
                bit     RESET_SCSI      0x40
-       }
-        SCSICONF2 {
-               address         0x05b
-               size            1
-               bit     RESET_SCSI      0x40
+               mask    HSCSIID         0x07    /* our SCSI ID */
+               mask    HWSCSIID        0x0f    /* our SCSI ID if Wide Bus */
        }
        HOSTCONF {
                address         0x05d
@@ -1140,6 +1112,10 @@ scratch_ram {
 
 const SCB_LIST_NULL    0xff
 
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET       0
+const QOUTFIFO_OFFSET          1
+const QINFIFO_OFFSET           2
 
 /* WDTR Message values */
 const BUS_8_BIT                0x00
@@ -1147,3 +1123,24 @@ const BUS_16_BIT         0x01
 const BUS_32_BIT               0x02
 const MAX_OFFSET_8BIT          0x0f
 const MAX_OFFSET_16BIT 0x08
+const HOST_MSG         0xFF
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT     0x05
+const CMD_GROUP0_BYTE_DELTA    -4
+const CMD_GROUP2_BYTE_DELTA    -6
+const CMD_GROUP4_BYTE_DELTA    4
+const CMD_GROUP5_BYTE_DELTA    11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+/*
+ * Mask of bits to test against when looking at the Queue Count
+ * registers.  Works around a bug on aic7850 chips. 
+ */
+const QCNTMASK         download
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS    download
index 9966646e83326e6ac549c95d6f6649d90bda8306..b4613387f2a913c6650bca1124cc5c92475be518 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
@@ -38,8 +35,8 @@
  *     $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
  */
 
-#include <aic7xxx.reg>
-#include <scsi_message.h>
+#include "aic7xxx.reg"
+#include "scsi_message.h"
 
 /*
  * A few words on the waiting SCB list:
  * automatically consume the entries.
  */
 
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
 reset:
        clr     SCSISIGO;               /* De-assert BSY */
        /* Always allow reselection */
+.if ( TARGET_MODE )
+       mvi     SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+.else
        mvi     SCSISEQ, ENRSELI|ENAUTOATNP;
+.endif
        call    clear_target_state;
+       and     SXFRCTL0, ~SPIOEN;
 poll_for_work:
-       test    SSTAT0,SELDO    jnz select;
-       test    SSTAT0,SELDI    jnz reselect;
+       mov     A, QINPOS;
+poll_for_work_loop:
+       and     SEQCTL, ~PAUSEDIS;
+       test    SSTAT0, SELDO|SELDI     jnz selection;
        test    SCSISEQ, ENSELO jnz poll_for_work;
 .if ( TWIN_CHANNEL )
        /*
@@ -80,16 +80,17 @@ poll_for_work:
         * either a selection or reselection occurs.
         */
        xor     SBLKCTL,SELBUSB;        /* Toggle to the other bus */
-       test    SSTAT0,SELDO    jnz select;
-       test    SSTAT0,SELDI    jnz reselect;
+       test    SSTAT0, SELDO|SELDI     jnz selection;
        test    SCSISEQ, ENSELO jnz poll_for_work;
        xor     SBLKCTL,SELBUSB;        /* Toggle back */
 .endif
        cmp     WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
 test_queue:
        /* Has the driver posted any work for us? */
-       mov     A, QCNTMASK;
-       test    QINCNT,A        jz poll_for_work;
+       or      SEQCTL, PAUSEDIS;
+       cmp     KERNEL_QINPOS, A je poll_for_work_loop;
+       inc     QINPOS;
+       and     SEQCTL, ~PAUSEDIS;
 
 /*
  * We have at least one queued SCB now and we don't have any 
@@ -99,76 +100,24 @@ test_queue:
  */
 .if ( SCB_PAGING )
        mov     ALLZEROS        call    get_free_or_disc_scb;
-       cmp     SINDEX, SCB_LIST_NULL   je poll_for_work;
 .endif
 dequeue_scb:
-       mov     CUR_SCBID,QINFIFO;
+       add     A, -1, QINPOS;
+       mvi     QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+       call    dma_finish;
+       mov     SINDEX, DFDAT;
 .if !( SCB_PAGING )
        /* In the non-paging case, the SCBID == hardware SCB index */
-       mov     SCBPTR, CUR_SCBID;
+       mov     SCBPTR, SINDEX;
 .endif
 dma_queued_scb:
 /*
  * DMA the SCB from host ram into the current SCB location.
  */
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     CUR_SCBID       call dma_scb;
-
-/*
- * See if there is not already an active SCB for this target.  This code
- * locks out on a per target basis instead of target/lun.  Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands.  We also don't have enough spare SCB space for us to store the
- * SCBID of the currently busy transaction for each target/lun making it
- * impossible to link up the SCBs.
- */
-test_busy:
-       test    SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
-       mvi     SEQCTL, PAUSEDIS|FASTMODE;
-       mov     SAVED_SCBPTR, SCBPTR;
-       mov     SCB_TCL         call    index_untagged_scb;
-       mov     ARG_1, SINDIR;                  /*
-                                                * ARG_1 should
-                                                * now have the SCB ID of
-                                                * any active, non-tagged,
-                                                * command for this target.
-                                                */
-       cmp     ARG_1, SCB_LIST_NULL je make_busy;
-.if ( SCB_PAGING )
-       /*
-        * Put this SCB back onto the free list.  It
-        * may be necessary to satisfy the search for
-        * the active SCB.
-        */
-       mov     SCBPTR, SAVED_SCBPTR;
-       call    add_scb_to_free_list;
-       /* Find the active SCB */
-       mov     ALLZEROS        call findSCB;
-       /*
-        * If we couldn't find it, tell the kernel.  This should
-        * never happen.
-        */
-       cmp     SINDEX, SCB_LIST_NULL   jne paged_busy_link;
-       mvi     INTSTAT, NO_MATCH_BUSY;
-paged_busy_link:
-       /* Link us in */
-       mov     SCB_LINKED_NEXT, CUR_SCBID;
-       /* Put it back on the disconnected list */
-       call    add_scb_to_disc_list;
-       mvi     SEQCTL, FASTMODE;
-       jmp     poll_for_work;
-.else
-simple_busy_link:
-       mov     SCBPTR, ARG_1;
-       mov     SCB_LINKED_NEXT, CUR_SCBID;
-       mvi     SEQCTL, FASTMODE;
-       jmp     poll_for_work;
-.endif
-make_busy:
-       mov     DINDIR, CUR_SCBID;
-       mov     SCBPTR, SAVED_SCBPTR;
-       mvi     SEQCTL, FASTMODE;
+       call    dma_scb;
 
 start_scb:
        /*
@@ -179,9 +128,7 @@ start_scb:
        mov     WAITING_SCBH, SCBPTR;
 start_waiting:
        /*
-        * Pull the first entry off of the waiting SCB list
-        * We don't have to "test_busy" because only transactions that
-        * have passed that test can be in the WAITING_SCB list.
+        * Pull the first entry off of the waiting SCB list.
         */
        mov     SCBPTR, WAITING_SCBH;
        call    start_selection;
@@ -199,17 +146,170 @@ initialize_scsiid:
        and     SCSIID, OID;            /* Clear old target */
        or      SCSIID, A;
        mvi     SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+       or      A, CLRSTCNT|CLRCHN, SINDEX;
+       or      SXFRCTL0, A;
+.if ( ULTRA )
+ultra:
+       mvi     SINDEX, ULTRA_ENB+1;
+       test    SAVED_TCL, 0x80         jnz ultra_2;    /* Target ID > 7 */
+       dec     SINDEX;
+ultra_2:
+       mov     FUNCTION1,SAVED_TCL;
+       mov     A,FUNCTION1;
+       test    SINDIR, A       jz ndx_dtr;
+       or      SXFRCTL0, FAST20;
+.endif
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCRATCH.
+ */
+ndx_dtr:
+       shr     A,4,SAVED_TCL;
+       test    SBLKCTL,SELBUSB jz ndx_dtr_2;
+       or      SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+       or      A,0x08;                 /* Channel B entries add 8 */
+ndx_dtr_2:
+       add     SINDEX,TARG_SCRATCH,A;
+       mov     SCSIRATE,SINDIR ret;
+
+
+selection:
+       test    SSTAT0,SELDO    jnz select_out;
+select_in:
+.if ( TARGET_MODE )
+       test    SSTAT0, TARGET  jz initiator_reselect;
+       /*
+        * We've just been selected.  Assert BSY and
+        * setup the phase for receiving the messages
+        * from the target.
+        */
+       mvi     SCSISIGO, P_MESGOUT|BSYO;
+       mvi     CLRSINT0, CLRSELDO;
+
+       /*
+        * If ATN isn't asserted, go directly to bus free.
+        */
+       test    SCSISIGI, ATNI  jz      target_busfree;
+
+       /*
+        * Setup the DMA for sending the identify and
+        * command information.
+        */
+       mov     A, TMODE_CMDADDR_NEXT;
+       mvi     TMODE_CMDADDR call set_32byte_haddr_and_clrcnt;
+       mvi     DFCNTRL, FIFORESET;
+
+       clr     SINDEX;
+       /* Watch ATN closely now */
+message_loop:
+       or      SXFRCTL0, SPIOEN;
+       test    SSTAT0, SPIORDY jz .;
+       and     SXFRCTL0, ~SPIOEN;
+       mov     DINDEX, SCSIDATL;
+       mov     DFDAT, DINDEX;
+       inc     SINDEX;
+
+       /* Message Testing... */
+       test    DINDEX, MSG_IDENTIFYFLAG jz . + 2;
+       mov     ARG_1, DINDEX;
+
+       test    SCSISIGI, ATNI  jnz     message_loop;
+       add     A, -4, SINDEX;
+       jc      target_cmdphase;
+       mvi     DFDAT, SCB_LIST_NULL;   /* Terminate the message list */
+
+target_cmdphase:
+       add     HCNT[0], 1, A;
+       mvi     SCSISIGO, P_COMMAND|BSYO;
+       or      SXFRCTL0, SPIOEN;
+       test    SSTAT0, SPIORDY jz .;
+       mov     A, SCSIDATL;
+       mov     DFDAT, A;       /* Store for host */
+
+       /*
+        * Determine the number of bytes to read
+        * based on the command group code.  Count is
+        * one less than the total since we've already
+        * fetched the first byte.
+        */
+       clr     SINDEX;
+       shr     A, CMD_GROUP_CODE_SHIFT;
+       add     SEQADDR0, A;
+
+       add     SINDEX, CMD_GROUP0_BYTE_DELTA;
+       nop;    /* Group 1 and 2 are the same */
+       add     SINDEX, CMD_GROUP2_BYTE_DELTA;
+       nop;    /* Group 3 is reserved */
+       add     SINDEX, CMD_GROUP4_BYTE_DELTA;
+       add     SINDEX, CMD_GROUP5_BYTE_DELTA;
+               /* Group 6 and 7 are not handled yet */
+
+       mov     A, SINDEX;
+       add     HCNT[0], A;
+
+command_loop:
+       test    SSTAT0, SPIORDY jz .;
+       cmp     SINDEX, 1 jne . + 2;
+       and     SXFRCTL0, ~SPIOEN;      /* Last Byte */
+       mov     DFDAT, SCSIDATL;
+       dec     SINDEX;
+       test    SINDEX, 0xFF jnz command_loop;
+
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+       
+       call    dma_finish;
+
+       test    ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+
+       mvi     SCSISIGO, P_MESGIN|BSYO;
+
+       or      SXFRCTL0, SPIOEN;
+
+       mvi     MSG_DISCONNECT call target_outb;
+       
+selectin_post:
+       inc     TMODE_CMDADDR_NEXT;
+       cmp     TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+       clr     TMODE_CMDADDR_NEXT;
+       mvi     QOUTFIFO, SCB_LIST_NULL;
+       mvi     INTSTAT,CMDCMPLT;
+
+       test    ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
+
+       /* Busy loop on something then go to data or status phase */
+
+target_busfree:
+       clr     SCSISIGO;
+       jmp     poll_for_work;
+
+.endif /* TARGET_MODE */
 /*
  * Reselection has been initiated by a target. Make a note that we've been
  * reselected, but haven't seen an IDENTIFY message from the target yet.
  */
-reselect:
-       clr     MSG_LEN;        /* Don't have anything in the mesg buffer */
+initiator_reselect:
        mvi     CLRSINT0, CLRSELDI;
        /* XXX test for and handle ONE BIT condition */
        and     SAVED_TCL, SELID_MASK, SELID;
-       or      SEQ_FLAGS,RESELECTED;
-       jmp     select2;
+       mvi     CLRSINT1,CLRBUSFREE;
+       or      SIMODE1, ENBUSFREE;             /*
+                                                * We aren't expecting a
+                                                * bus free, so interrupt
+                                                * the kernel driver if it
+                                                * happens.
+                                                */
+       mvi     SPIOEN call     initialize_channel;
+       mvi     MSG_OUT, MSG_NOOP;              /* No message to send */
+       jmp     ITloop;
 
 /*
  * After the selection, remove this SCB from the "waiting SCB"
@@ -217,7 +317,7 @@ reselect:
  * WAITING_SCBH.  Our next pointer will be set to null the next time this
  * SCB is used, so don't bother with it now.
  */
-select:
+select_out:
        /* Turn off the selection hardware */
        mvi     SCSISEQ, ENRSELI|ENAUTOATNP;    /*
                                                 * ATN on parity errors
@@ -227,41 +327,6 @@ select:
        mov     SCBPTR, WAITING_SCBH;
        mov     WAITING_SCBH,SCB_NEXT;
        mov     SAVED_TCL, SCB_TCL;
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted.  Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
-
-mk_identify:
-       and     MSG_OUT,0x7,SCB_TCL;    /* lun */
-       and     A,DISCENB,SCB_CONTROL;  /* mask off disconnect privledge */
-       or      MSG_OUT,A;              /* or in disconnect privledge */
-       or      MSG_OUT,MSG_IDENTIFYFLAG;
-       mvi     MSG_LEN, 1;
-
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-mk_tag:
-       test    SCB_CONTROL,TAG_ENB jz  mk_message;
-       and     MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
-       mov     MSG_OUT[2],SCB_TAG;
-       add     MSG_LEN,2;      /* update message length */
-
-/*
- * Interrupt the driver, and allow it to tweak the message buffer
- * if it asks.
- */
-mk_message:
-       test    SCB_CONTROL,MK_MESSAGE  jz select2;
-       mvi     INTSTAT,AWAITING_MSG;
-
-select2:
        mvi     CLRSINT1,CLRBUSFREE;
        or      SIMODE1, ENBUSFREE;             /*
                                                 * We aren't expecting a
@@ -269,54 +334,24 @@ select2:
                                                 * the kernel driver if it
                                                 * happens.
                                                 */
+       mvi     SPIOEN call     initialize_channel;
 /*
- * Initialize Ultra mode setting and clear the SCSI channel.
- */
-       or      SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
-.if ( ULTRA )
-ultra:
-       mvi     SINDEX, ULTRA_ENB+1;
-       test    SAVED_TCL, 0x80         jnz ultra_2;    /* Target ID > 7 */
-       dec     SINDEX;
-ultra_2:
-       mov     FUNCTION1,SAVED_TCL;
-       mov     A,FUNCTION1;
-       test    SINDIR, A       jz ndx_dtr;
-       or      SXFRCTL0, FAST20;
-.endif
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
  */
-ndx_dtr:
-       shr     A,4,SAVED_TCL;
-       test    SBLKCTL,SELBUSB jz ndx_dtr_2;
-       or      SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
-       or      A,0x08;                 /* Channel B entries add 8 */
-ndx_dtr_2:
-       add     SINDEX,TARG_SCRATCH,A;
-       mov     SCSIRATE,SINDIR;
-
+       mvi     MSG_OUT, MSG_IDENTIFYFLAG;
+       or      SEQ_FLAGS, IDENTIFY_SEEN;
 
 /*
- * Main loop for information transfer phases.  If BSY is false, then
- * we have a bus free condition, expected or not.  Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
+ * Main loop for information transfer phases.  Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
  */
 ITloop:
-       test    SSTAT1,REQINIT          jz ITloop;
-       test    SSTAT1, SCSIPERR        jnz ITloop;
+       call    phase_lock;
 
-       and     A,PHASE_MASK,SCSISIGI;
-       mov     LASTPHASE,A;
-       mov     SCSISIGO,A;
+       mov     A, LASTPHASE;
 
-       cmp     ALLZEROS,A      je p_dataout;
-       cmp     A,P_DATAIN      je p_datain;
+       test    A, ~P_DATAIN    jz p_data;
        cmp     A,P_COMMAND     je p_command;
        cmp     A,P_MESGOUT     je p_mesgout;
        cmp     A,P_STATUS      je p_status;
@@ -329,25 +364,27 @@ await_busfree:
        and     SIMODE1, ~ENBUSFREE;
        call    clear_target_state;
        mov     NONE, SCSIDATL;         /* Ack the last byte */
+       and     SXFRCTL0, ~SPIOEN;
        test    SSTAT1,REQINIT|BUSFREE  jz .;
        test    SSTAT1, BUSFREE jnz poll_for_work;
        mvi     INTSTAT, BAD_PHASE;
        
 clear_target_state:
-       clr     DFCNTRL;
+       clr     DFCNTRL;                /*
+                                        * We assume that the kernel driver
+                                        * may reset us at any time, even
+                                        * in the middle of a DMA, so clear
+                                        * DFCNTRL too.
+                                        */
        clr     SCSIRATE;               /*
                                         * We don't know the target we will
                                         * connect to, so default to narrow
                                         * transfers to avoid parity problems.
                                         */
-       and     SXFRCTL0, ~FAST20;      
+       and     SXFRCTL0, ~(FAST20);
        mvi     LASTPHASE, P_BUSFREE;
        /* clear target specific flags */
-       and     SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
-
-p_dataout:
-       mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
-       jmp     data_phase_init;
+       and     SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
 
 /*
  * If we re-enter the data phase after going through another phase, the
@@ -358,9 +395,10 @@ data_phase_reinit:
        mvi     SCB_RESID_DCNT  call bcopy_3;
        jmp     data_phase_loop;
 
-p_datain:
+p_data:
        mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-data_phase_init:
+       test    LASTPHASE, IOI jnz . + 2;
+       or      DMAPARAMS, DIRECTION;
        call    assert;                 /*
                                         * Ensure entering a data
                                         * phase is okay - seen identify, etc.
@@ -398,6 +436,7 @@ data_phase_loop:
        mvi     HCNT[1], 0xff;
        mvi     HCNT[2], 0xff;
        call    set_stcnt_from_hcnt;
+       and     DMAPARAMS, ~(HDMAEN|SDMAEN);
 
 data_phase_inbounds:
 /* If we are the last SG block, ensure wideodd is off. */
@@ -512,54 +551,85 @@ p_status:
        jmp     ITloop;
 
 /*
- * Message out phase.  If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
+ * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
  */
 p_mesgout:
-       test    MSG_LEN, 0xff   jnz  p_mesgout_start;
-       mvi     MSG_NOOP        call mk_mesg;   /* build NOP message */
-p_mesgout_start:
+       mov     SINDEX, MSG_OUT;
+       cmp     SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+.if ( WIDE )
+       and     SINDEX,0xf,SCB_TCL;     /* lun */
+.else
+       and     SINDEX,0x7,SCB_TCL;     /* lun */
+.endif
+       and     A,DISCENB,SCB_CONTROL;  /* mask off disconnect privledge */
+       or      SINDEX,A;               /* or in disconnect privledge */
+       or      SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+       test    SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
+       mov     SCSIDATL, SINDEX;       /* Send the last byte */
+       jmp     p_mesgout_from_host + 1;/* Skip HOST_MSG test */
 /*
- * Set up automatic PIO transfer from MSG_OUT.  Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
  */
-       mvi     SINDEX,MSG_OUT;
-       mov     DINDEX,MSG_LEN;
-
+p_mesgout_tag:
+       test    SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+       mov     SCSIDATL, SINDEX;       /* Send the identify message */
+       call    phase_lock;
+       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
+       and     SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+       call    phase_lock;
+       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
+       mov     SCB_TAG jmp p_mesgout_onebyte;
 /*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message.  Otherwise, keep going until the message is exhausted.
- * ATN must be dropped *at least* 90ns before we ack the last byte, so
- * the code is aranged to execute two instructions before the byte is
- * transferred to give a good margin of safety
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
  */
-p_mesgout_loop:
-       test    SSTAT1, REQINIT         jz p_mesgout_loop;
-       test    SSTAT1, SCSIPERR        jnz p_mesgout_loop;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
-       cmp     LASTPHASE, P_MESGOUT jne p_mesgout_done;
-p_mesgout_testretry:
-       test    DINDEX,0xff     jnz p_mesgout_dropatn;
-       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
-       jmp     p_mesgout_start;
+p_mesgout_from_host:
+       cmp     SINDEX, HOST_MSG        jne p_mesgout_onebyte;
+       mvi     INTSTAT,AWAITING_MSG;
+       /*
+        * Did the host detect a phase change?
+        */
+       cmp     RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+       mvi     CLRSINT1, CLRATNO;
+       mov     SCSIDATL, SINDEX;
+
 /*
  * If the next bus phase after ATN drops is a message out, it means
  * that the target is requesting that the last message(s) be resent.
  */
-p_mesgout_dropatn:
-       cmp     DINDEX,1        jne p_mesgout_outb;     /* last byte? */
-       mvi     CLRSINT1,CLRATNO;                       /* drop ATN */
-p_mesgout_outb:
-       dec     DINDEX;
-       mov     SCSIDATL,SINDIR;
-       jmp     p_mesgout_loop;
+       call    phase_lock;
+       cmp     LASTPHASE, P_MESGOUT    jne p_mesgout_done;
+       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+       jmp     p_mesgout;
 
 p_mesgout_done:
        mvi     CLRSINT1,CLRATNO;       /* Be sure to turn ATNO off */
-       clr     MSG_LEN;                /* no active msg */
+       mov     LAST_MSG, MSG_OUT;
+       cmp     MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+       and     SCB_CONTROL, ~MK_MESSAGE;
+       mvi     MSG_OUT, MSG_NOOP;      /* No message left */
        jmp     ITloop;
 
 /*
@@ -567,7 +637,6 @@ p_mesgout_done:
  */
 p_mesgin:
        mvi     ACCUM           call inb_first; /* read the 1st message byte */
-       mov     REJBYTE,A;                      /* save it for the driver */
 
        test    A,MSG_IDENTIFYFLAG      jnz mesgin_identify;
        cmp     A,MSG_DISCONNECT        je mesgin_disconnect;
@@ -597,8 +666,8 @@ mesgin_complete:
 /*
  * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
  * and trigger a completion interrupt.  Before doing so, check to see if there
- * is a residual or the status byte is something other than NO_ERROR (0).  In
- * either of these conditions, we upload the SCB back to the host so it can
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
  * process this information.  In the case of a non zero status byte, we 
  * additionally interrupt the kernel driver synchronously, allowing it to
  * decide if sense should be retrieved.  If the kernel driver wishes to request
@@ -616,60 +685,17 @@ mesgin_complete:
  * First check for residuals
  */
        test    SCB_RESID_SGCNT,0xff    jnz upload_scb;
-       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* Good Status? */
+       test    SCB_TARGET_STATUS,0xff  jz complete;    /* Good Status? */
 upload_scb:
        mvi     DMAPARAMS, FIFORESET;
        mov     SCB_TAG         call dma_scb;
 check_status:
-       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* Just a residual? */
+       test    SCB_TARGET_STATUS,0xff  jz complete;    /* Just a residual? */
        mvi     INTSTAT,BAD_STATUS;                     /* let driver know */
-       cmp     RETURN_1, SEND_SENSE    jne status_ok;
+       cmp     RETURN_1, SEND_SENSE    jne complete;
        /* This SCB becomes the next to execute as it will retrieve sense */
-       mov     SCB_LINKED_NEXT, SCB_TAG;
-       jmp     dma_next_scb;
-
-status_ok:
-/* First, mark this target as free. */
-       test    SCB_CONTROL,TAG_ENB jnz complete;       /*
-                                                        * Tagged commands
-                                                        * don't busy the
-                                                        * target.
-                                                        */
-       mov     SAVED_SCBPTR, SCBPTR;
-       mov     SAVED_LINKPTR, SCB_LINKED_NEXT;
-       mov     SCB_TCL call index_untagged_scb;
-       mov     DINDIR, SAVED_LINKPTR;
-       mov     SCBPTR, SAVED_SCBPTR;
-
-complete:
-       /* Post the SCB and issue an interrupt */
-.if ( SCB_PAGING )
-       /*
-        * Spin loop until there is space
-        * in the QOUTFIFO.
-        */
-       mov     A, FIFODEPTH;
-       cmp     CMDOUTCNT, A    je .;
-       inc     CMDOUTCNT;
-.endif
-       mov     QOUTFIFO,SCB_TAG;
-       mvi     INTSTAT,CMDCMPLT;
-       test    SCB_CONTROL, ABORT_SCB jz dma_next_scb;
-       mvi     INTSTAT, ABORT_CMDCMPLT;
-
-dma_next_scb:
-       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL  je add_to_free_list;
-.if !( SCB_PAGING )
-       /* Only DMA on top of ourselves if we are the SCB to download */
-       mov     A, SCB_LINKED_NEXT;
-       cmp     SCB_TAG, A      je dma_next_scb2;
-       call    add_scb_to_free_list;
-       mov     SCBPTR, A;
-       jmp     add_to_waiting_list;
-.endif
-dma_next_scb2:
        mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     SCB_LINKED_NEXT         call dma_scb;
+       mov     SCB_TAG         call dma_scb;
 add_to_waiting_list:
        mov     SCB_NEXT,WAITING_SCBH;
        mov     WAITING_SCBH, SCBPTR;
@@ -679,6 +705,28 @@ add_to_waiting_list:
         */
        call    start_selection;
        jmp     await_busfree;
+
+complete:
+       /* If we are untagged, clear our address up in host ram */
+       test    SCB_CONTROL, TAG_ENB jnz complete_post;
+       mov     A, SAVED_TCL;
+       mvi     UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, FIFORESET;
+       mvi     DFDAT, SCB_LIST_NULL;
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+       call    dma_finish;
+
+complete_post:
+       /* Post the SCB and issue an interrupt */
+       mov     A, QOUTPOS;
+       mvi     QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, FIFORESET;
+       mov     DFDAT, SCB_TAG;
+       or      DFCNTRL, HDMAEN|FIFOFLUSH;
+       call    dma_finish;
+       inc     QOUTPOS;
+       mvi     INTSTAT,CMDCMPLT;
+
 add_to_free_list:
        call    add_scb_to_free_list;
        jmp     await_busfree;
@@ -690,22 +738,8 @@ add_to_free_list:
  * or simply to do nothing.
  */
 mesgin_extended:
-       mvi     MSGIN_EXT_LEN    call inb_next;
-       mov     A, MSGIN_EXT_LEN;
-mesgin_extended_loop:
-       mov     DINDEX  call    inb_next;
-       dec     A;
-       cmp     DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
-       dec     DINDEX;         /* dump by repeatedly filling the last byte */
-mesgin_extended_loop_test:
-       test    A, 0xFF         jnz mesgin_extended_loop;
-mesgin_extended_intr:
        mvi     INTSTAT,EXTENDED_MSG;           /* let driver know */
-       cmp     RETURN_1,SEND_REJ je rej_mesgin;
-       cmp     RETURN_1,SEND_MSG jne mesgin_done;
-/* The kernel has setup a message to be sent */
-       or      SCSISIGO,ATNO,LASTPHASE;        /* turn on ATNO */
-       jmp     mesgin_done;
+       jmp     ITloop;
 
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -713,9 +747,7 @@ mesgin_extended_intr:
  */
 mesgin_disconnect:
        or      SCB_CONTROL,DISCONNECTED;
-.if ( SCB_PAGING )
        call    add_scb_to_disc_list;
-.endif
        jmp     await_busfree;
 
 /*
@@ -764,24 +796,30 @@ mesgin_rdptrs:
  * clearing the "disconnected" bit so we don't "find" it by accident later.
  */
 mesgin_identify:
-       test    A,0x78  jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
+.if ( WIDE )
+       and     A,0x0f;                 /* lun in lower four bits */
+.else
        and     A,0x07;                 /* lun in lower three bits */
+.endif
        or      SAVED_TCL,A;            /* SAVED_TCL should be complete now */
-       mov     SAVED_TCL call index_untagged_scb;
-       mov     ARG_1, SINDIR;
+
+       call    get_untagged_SCBID;
+       cmp     ARG_1, SCB_LIST_NULL    je snoop_tag;
 .if ( SCB_PAGING )
-       cmp     ARG_1,SCB_LIST_NULL     jne use_findSCB;
-.else
-       cmp     ARG_1,SCB_LIST_NULL     je snoop_tag;
-       /* Directly index the SCB */
-       mov     SCBPTR,ARG_1;
-       test    SCB_CONTROL,DISCONNECTED jz not_found;
-       jmp     setup_SCB;
+       test    SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
 .endif
+       /*
+        * If the SCB was found in the disconnected list (as is
+        * always the case in non-paging scenarios), SCBPTR is already
+        * set to the correct SCB.  So, simply setup the SCB and get
+        * on with things.
+        */
+       mov     SCBPTR  call rem_scb_from_disc_list;
+       jmp     setup_SCB;
 /*
  * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
  * If we get one, we use the tag returned to find the proper
- * SCB.  With SCB paging, this requires using findSCB for both tagged
+ * SCB.  With SCB paging, this requires using search for both tagged
  * and non-tagged transactions since the SCB may exist in any slot.
  * If we're not using SCB paging, we can use the tag as the direct
  * index to the SCB.
@@ -789,44 +827,42 @@ mesgin_identify:
 snoop_tag:
        mov     NONE,SCSIDATL;          /* ACK Identify MSG */
 snoop_tag_loop:
-       test    SSTAT1,REQINIT          jz snoop_tag_loop;
-       test    SSTAT1, SCSIPERR        jnz snoop_tag_loop;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
+       call    phase_lock;
        cmp     LASTPHASE, P_MESGIN     jne not_found;
        cmp     SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
 get_tag:
-       or      SEQ_FLAGS, TAGGED_SCB;
        mvi     ARG_1   call inb_next;  /* tag value */
-/*
- * See if the tag is in range.  The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incomming tag and there is
- * no carry.
- */
-       mov     A,COMP_SCBCOUNT;
-       add     SINDEX,A,ARG_1;
-       jc      not_found;
 
 .if ! ( SCB_PAGING )
 index_by_tag:
        mov     SCBPTR,ARG_1;
-       mov     A, SAVED_TCL;
-       cmp     SCB_TCL,A               jne not_found;
        test    SCB_CONTROL,TAG_ENB     jz  not_found;
-       test    SCB_CONTROL,DISCONNECTED jz not_found;
+       mov     SCBPTR  call rem_scb_from_disc_list;
 .else
 /*
  * Ensure that the SCB the tag points to is for an SCB transaction
  * to the reconnecting target.
  */
-use_findSCB:
-       mov     ALLZEROS        call findSCB;     /* Have to search */
-       cmp     SINDEX, SCB_LIST_NULL   je not_found;
+use_retrieveSCB:
+       call    retrieveSCB;
 .endif
 setup_SCB:
+       mov     A, SAVED_TCL;
+       cmp     SCB_TCL, A      jne not_found_cleanup_scb;
+       test    SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
        and     SCB_CONTROL,~DISCONNECTED;
        or      SEQ_FLAGS,IDENTIFY_SEEN;          /* make note of IDENTIFY */
+       /* See if the host wants to send a message upon reconnection */
+       test    SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+       and     SCB_CONTROL, ~MK_MESSAGE;
+       mvi     HOST_MSG        call mk_mesg;
        jmp     mesgin_done;
 
+not_found_cleanup_scb:
+       test    SCB_CONTROL, DISCONNECTED jz . + 3;
+       call    add_scb_to_disc_list;
+       jmp     not_found;
+       call    add_scb_to_free_list;
 not_found:
        mvi     INTSTAT, NO_MATCH;
        mvi     MSG_BUS_DEV_RESET       call mk_mesg;
@@ -851,23 +887,8 @@ mesgin_reject:
  * if there is no active message already.  SINDEX is returned intact.
  */
 mk_mesg:
-       mvi     SEQCTL, PAUSEDIS|FASTMODE;
-       test    MSG_LEN,0xff    jz mk_mesg1;    /* Should always succeed */
-       
-       /*
-        * Hmmm.  For some reason the mesg buffer is in use.
-        * Tell the driver.  It should look at SINDEX to find
-        * out what we wanted to use the buffer for and resolve
-        * the conflict.
-        */
-       mvi     SEQCTL,FASTMODE;
-       mvi     INTSTAT,MSG_BUFFER_BUSY;
-
-mk_mesg1:
        or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
-       mvi     MSG_LEN,1;              /* length = 1 */
-       mov     MSG_OUT,SINDEX;         /* 1-byte message */
-       mvi     SEQCTL,FASTMODE ret;
+       mov     MSG_OUT,SINDEX ret;
 
 /*
  * Functions to read data in Automatic PIO mode.
@@ -903,6 +924,17 @@ inb_first:
 inb_last:
        mov     NONE,SCSIDATL ret;              /*dummy read from latch to ACK*/
 
+.if ( TARGET_MODE )
+/*
+ * Send a byte to an initiator in Automatic PIO mode.
+ * SPIOEN must be on prior to calling this routine.
+ */
+target_outb:
+       mov     SCSIDATL, SINDEX;
+       test    SSTAT0, SPIORDY jz .;
+       ret;
+.endif
+       
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -957,60 +989,114 @@ return:
  * message.
  */
 assert:
-       test    SEQ_FLAGS,RESELECTED    jz return;      /* reselected? */
        test    SEQ_FLAGS,IDENTIFY_SEEN jnz return;     /* seen IDENTIFY? */
 
        mvi     INTSTAT,NO_IDENT        ret;    /* no - tell the kernel */
 
-.if ( SCB_PAGING )
 /*
  * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
- * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
- * otherwise, SCBPTR is set to the proper SCB.
+ * or by the SCBID ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list.  If
+ * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
+ * is set to the proper SCB.
  */
 findSCB:
-       mov     SCBPTR,SINDEX;                  /* switch to next SCB */
+       mov     SCBPTR,SINDEX;                  /* Initialize SCBPTR */
+       cmp     ARG_1, SCB_LIST_NULL    jne findSCB_by_SCBID;
+       mov     A, SAVED_TCL;
+       mvi     SCB_TCL jmp findSCB_loop;       /* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
        mov     A, ARG_1;                       /* Tag passed in ARG_1 */
-       cmp     SCB_TAG,A       jne findSCB_loop;
-       test    SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
+       mvi     SCB_TAG jmp findSCB_loop;       /* &SCB_TAG -> SINDEX */
+findSCB_next:
+       cmp     SCB_NEXT, SCB_LIST_NULL je notFound;
+       mov     SCBPTR,SCB_NEXT;
+       dec     SINDEX;         /* Last comparison moved us too far */
 findSCB_loop:
-       inc     SINDEX;
-       mov     A,SCBCOUNT;
-       cmp     SINDEX,A        jne findSCB;
+       cmp     SINDIR, A       jne findSCB_next;
+       mov     SINDEX, SCBPTR  ret;
+notFound:
+       mvi     SINDEX, SCB_LIST_NULL   ret;
+
 /*
- * We didn't find it.  If we're paging, pull an SCB and DMA down the
- * one we want.  If we aren't paging or the SCB we dma down has the
- * abort flag set, return not found.
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host.  This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+       test    SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host;
+       mov     SCBPTR  call findSCB;   /* Continue the search */
+       cmp     SINDEX, SCB_LIST_NULL   je retrieve_from_host;
+
+/*
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed and SCBPTR to be pointing to that SCB.
  */
-       mov     ALLZEROS        call    get_free_or_disc_scb;
-       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     ARG_1   call dma_scb;
-       test    SCB_RESID_SGCNT, 0xff jz . + 2;
-       or      SCB_CONTROL, MUST_DMAUP_SCB;
-       test    SCB_CONTROL, ABORT_SCB jz return;
-find_error:
-       mvi     SINDEX, SCB_LIST_NULL ret;
-foundSCB:
-       test    SCB_CONTROL, ABORT_SCB jnz find_error;
 rem_scb_from_disc_list:
 /* Remove this SCB from the disconnection list */
        cmp     SCB_NEXT,SCB_LIST_NULL je unlink_prev;
-       mov     SAVED_LINKPTR, SCB_PREV;
+       mov     DINDEX, SCB_PREV;
        mov     SCBPTR, SCB_NEXT;
-       mov     SCB_PREV, SAVED_LINKPTR;
+       mov     SCB_PREV, DINDEX;
        mov     SCBPTR, SINDEX;
 unlink_prev:
        cmp     SCB_PREV,SCB_LIST_NULL  je rHead;/* At the head of the list */
-       mov     SAVED_LINKPTR, SCB_NEXT;
+       mov     DINDEX, SCB_NEXT;
        mov     SCBPTR, SCB_PREV;
-       mov     SCB_NEXT, SAVED_LINKPTR;
+       mov     SCB_NEXT, DINDEX;
        mov     SCBPTR, SINDEX ret;
 rHead:
        mov     DISCONNECTED_SCBH,SCB_NEXT ret;
-.else
-       ret;
-.endif
+
+retrieve_from_host:
+/*
+ * We didn't find it.  Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+       mov     ALLZEROS        call    get_free_or_disc_scb;
+       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+       /* Jump instead of call as we want to return anyway */
+       mov     ARG_1   jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL.  The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+       cmp     DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+       mvi     ARG_1, SCB_LIST_NULL;
+       mov     DISCONNECTED_SCBH call findSCB;
+       cmp     SINDEX, SCB_LIST_NULL   je get_SCBID_from_host;
+       or      SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+       test    SCB_CONTROL, TAG_ENB    jnz . + 2;
+       mov     ARG_1, SCB_TAG  ret;
+       mvi     ARG_1, SCB_LIST_NULL ret;
+
+set_SCBID_host_addr_and_cnt:
+       mov     DINDEX, SINDEX;
+       mvi     SCBID_ADDR call set_1byte_haddr_and_clrcnt;
+       mvi     HCNT[0], 1 ret;
+
+get_SCBID_from_host:
+       mov     A, SAVED_TCL;
+       mvi     UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
+       mvi     DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+       call    dma_finish;
+       mov     ARG_1, DFDAT ret;
+
+phase_lock:     
+       test    SSTAT1, REQINIT jz phase_lock;
+       test    SSTAT1, SCSIPERR jnz phase_lock;
+       and     LASTPHASE, PHASE_MASK, SCSISIGI;
+       mov     SCSISIGO, LASTPHASE ret;
 
 set_stcnt_from_hcnt:
        mov     STCNT[0], HCNT[0];
@@ -1029,23 +1115,32 @@ bcopy_3:
        mov     DINDIR, SINDIR;
        mov     DINDIR, SINDIR ret;
 
+/*
+ * Setup haddr and count assuming that A is an
+ * index into an array of 32byte objects.
+ */
+set_32byte_haddr_and_clrcnt:
+       shr     DINDEX, 3, A;
+       shl     A, 5;
+set_1byte_haddr_and_clrcnt:    /* DINDEX must be 0 upon call */
+       add     HADDR[0], A, SINDIR;
+       mov     A, DINDEX;
+       adc     HADDR[1], A, SINDIR;
+       clr     A;
+       adc     HADDR[2], A, SINDIR;
+       adc     HADDR[3], A, SINDIR;
+       /* Clear Count */
+       clr     HCNT[1];
+       clr     HCNT[2] ret;
+
 dma_scb:
        /*
         * SCB index is in SINDEX.  Determine the physical address in
         * the host where this SCB is located and load HADDR with it.
         */
-       shr     DINDEX, 3, SINDEX;
-       shl     A, 5, SINDEX;
-       add     HADDR[0], A, HSCB_ADDR[0];
-       mov     A, DINDEX;
-       adc     HADDR[1], A, HSCB_ADDR[1];
-       clr     A;
-       adc     HADDR[2], A, HSCB_ADDR[2];
-       adc     HADDR[3], A, HSCB_ADDR[3];
-       /* Setup Count */
+       mov     A, SINDEX;
+       mvi     HSCB_ADDR call set_32byte_haddr_and_clrcnt;
        mvi     HCNT[0], 28;
-       clr     HCNT[1];
-       clr     HCNT[2];
        mov     DFCNTRL, DMAPARAMS;
        test    DMAPARAMS, DIRECTION    jnz dma_scb_fromhost;
        /* Fill it with the SCB data */
@@ -1092,25 +1187,12 @@ dma_finish:
        test    DFCNTRL, HDMAEN jnz .;
        ret;
 
-index_untagged_scb:
-       mov     DINDEX, SINDEX;
-       shr     DINDEX, 4;
-       and     DINDEX, 0x03;                   /* Bottom two bits of tid */
-       add     DINDEX, SCB_BUSYTARGETS;
-       shr     A, 6, SINDEX;                   /* Target ID divided by 4 */
-       test    SINDEX, SELBUSB jz index_untagged_scb2;
-       add     A, 2;                           /* Add 2 positions */
-index_untagged_scb2:
-       mov     SCBPTR, A;                      /*
-                                                * Select the SCB with this 
-                                                * target's information.
-                                                */
-       mov     SINDEX, DINDEX  ret;
-
 add_scb_to_free_list:
+.if ( SCB_PAGING )
        mov     SCB_NEXT, FREE_SCBH;
-       mvi     SCB_TAG, SCB_LIST_NULL;
-       mov     FREE_SCBH, SCBPTR ret;
+       mov     FREE_SCBH, SCBPTR;
+.endif
+       mvi     SCB_TAG, SCB_LIST_NULL ret;
 
 .if ( SCB_PAGING )
 get_free_or_disc_scb:
@@ -1120,11 +1202,6 @@ return_error:
        mvi     SINDEX, SCB_LIST_NULL   ret;
 dequeue_disc_scb:
        mov     SCBPTR, DISCONNECTED_SCBH;
-/*
- * Whenever we are going to dequeue a disconnected SCB and wipe it out
- * with a new SCB, we always send the SCB back to the kernel to make sure
- * any residual info and any save/restore pointers are saved for later use..
- */
 dma_up_scb:
        mvi     DMAPARAMS, FIFORESET;
        mov     SCB_TAG         call dma_scb;
@@ -1134,6 +1211,7 @@ unlink_disc_scb:
 dequeue_free_scb:
        mov     SCBPTR, FREE_SCBH;
        mov     FREE_SCBH, SCB_NEXT ret;
+.endif
 
 add_scb_to_disc_list:
 /*
@@ -1148,4 +1226,3 @@ add_scb_to_disc_list:
        mov     SCBPTR,SCB_NEXT;
        mov     SCB_PREV,DISCONNECTED_SCBH;
        mov     SCBPTR,DISCONNECTED_SCBH ret;
-.endif
index 267a01591636d83aa7d3c00552561643603c73cc..16c40138893204060a9e32e784639357f70e80af 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * SCSI messages definitions.
- */
-
 /* Messages (1 byte) */                     /* I/T (M)andatory or (O)ptional */
 #define MSG_CMDCOMPLETE                0x00 /* M/M */
 #define MSG_EXTENDED           0x01 /* O/O */
@@ -30,6 +26,7 @@
 
 /* Identify message */              /* M/M */  
 #define MSG_IDENTIFYFLAG       0x80 
+#define MSG_IDENTIFY_DISCFLAG  0x40 
 #define MSG_IDENTIFY(lun, disc)        (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
 #define MSG_ISIDENTIFY(m)      ((m) & MSG_IDENTIFYFLAG)
 
@@ -39,3 +36,6 @@
 
 #define MSG_EXT_WDTR           0x03
 #define MSG_EXT_WDTR_LEN       0x02
+#define MSG_EXT_WDTR_BUS_8_BIT 0x00
+#define MSG_EXT_WDTR_BUS_16_BIT        0x01
+#define MSG_EXT_WDTR_BUS_32_BIT        0x02 
index 7112c2e3310fe5bc6145e9aa5479753e0aebacfd..875283fc8dbcbfdad99120378d5f4a24039b4175 100644 (file)
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions, and the following disclaimer,
  *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
+ * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *      $Id: sequencer.h,v 1.2 1997/06/27 19:38:52 gibbs Exp $
+ *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
  */
 
-#if defined(__KERNEL__)
-typedef unsigned char u_int8_t;
-#endif
-
 struct ins_format1 {
-       u_int8_t immediate;
-       u_int8_t source;
-       u_int8_t destination;
-       u_int8_t opcode_ret;
+       unsigned char immediate;
+       unsigned char source;
+       unsigned char destination;
+       unsigned char opcode_ret;
+#define DOWNLOAD_CONST_IMMEDIATE 0x80
 };
 
 struct ins_format2 {
-       u_int8_t shift_control;
-       u_int8_t source;
-       u_int8_t destination;
-       u_int8_t opcode_ret;
+       unsigned char shift_control;
+       unsigned char source;
+       unsigned char destination;
+       unsigned char opcode_ret;
 #define RETURN_BIT 0x01
 };
 
 struct ins_format3 {
-       u_int8_t immediate;
-       u_int8_t source;
-       u_int8_t address;
-       u_int8_t opcode_addr;
+       unsigned char immediate;
+       unsigned char source;
+       unsigned char address;
+       unsigned char opcode_addr;
 #define ADDR_HIGH_BIT 0x01
 };
 
+#ifndef __KERNEL__
 struct instruction {
        union {
                struct ins_format1 format1;
                struct ins_format2 format2;
                struct ins_format3 format3;
-               u_int8_t           bytes[4];
+               unsigned char      bytes[4];
        } format;
        u_int   srcline;
        struct symbol *patch_label;
-       struct {
-               struct instruction *stqe_next; /* next element */
-       } links;
+       STAILQ_ENTRY(instruction) links;
 };
+#endif
 
 #define        AIC_OP_OR       0x0
 #define        AIC_OP_AND      0x1
index 8ad2cfb030f8c61f3e3bdb0a20c40969df1ddbf8..c923cecec2fb942171b988267496de420cf406e1 100644 (file)
@@ -53,9 +53,6 @@ proc_debug(const char *fmt, ...)
 
 static int aic7xxx_buffer_size = 0;
 static char *aic7xxx_buffer = NULL;
-static const char *bus_names[] = { "Single", "Twin", "Wide" };
-static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
-   "AIC-787x", "AIC-788x" };
 
 
 /*+F*************************************************************************
@@ -86,7 +83,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
 {
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
-  int    found = FALSE;
   int    size = 0;
   unsigned char i;
 #ifdef AIC7XXX_PROC_STATS
@@ -95,36 +91,11 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
 #endif
 
   HBAptr = NULL;
-  for (i=0; i < NUMBER(aic7xxx_boards); i++)
-  {
-    if ((HBAptr = aic7xxx_boards[i]) != NULL)
-    {
-      if (HBAptr->host_no == hostno)
-      {
-        break;
-      }
 
-      while ((HBAptr->hostdata != NULL) && !found &&
-          ((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
-      {
-        if (HBAptr->host_no == hostno)
-        {
-          found = TRUE;
-        }
-      }
-
-      if (!found)
-      {
-        HBAptr = NULL;
-      }
-      else
-      {
-        break;
-      }
-    }
-  }
+  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+    ;
 
-  if (HBAptr == NULL)
+  if (!p)
   {
     size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
     if (size > length)
@@ -137,6 +108,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
     }
   }
 
+  HBAptr = p->host;
+
   if (inout == TRUE) /* Has data been written to the file? */ 
   {
     return (aic7xxx_set_info(buffer, length, HBAptr));
@@ -150,16 +123,20 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
    * if proc_stats is defined, then we sweep the stats structure to see
    * how many drives we will be printing out for and add 384 bytes per
    * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
    */
 
-  size = 1536;
+  size = 4096;
 #ifdef AIC7XXX_PROC_STATS
   for (target = 0; target < MAX_TARGETS; target++)
   {
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
       if (p->stats[target][lun].xfers != 0)
-        size += 384;
+        size += 512;
     }
   }
 #endif
@@ -182,29 +159,20 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
 
   size = 0;
   size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
-  size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
-  size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
-#if 0
-  size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
-#endif
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
 #ifdef AIC7XXX_RESET_DELAY
   size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
 #endif
-#ifdef AIC7XXX_CMDS_PER_LUN
-  size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
-#endif
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Disabled\n");
-#endif
-#ifdef AIC7XXX_PAGE_ENABLE
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Disabled\n");
-#endif
+  size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
+  size += sprintf(BLS, "                             Check below to see "
+                       "which\n"
+                       "                             devices use tagged "
+                       "queueing\n");
+  size += sprintf(BLS, "  AIC7XXX_PAGE_ENABLE    : Enabled (This is no longer "
+                       "an option)\n");
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
 #else
@@ -213,17 +181,54 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
-      board_names[p->chip_type]);
-  size += sprintf(BLS, "                         (%s chipset)\n",
-      chip_names[p->chip_class]);
-  size += sprintf(BLS, "               Host Bus: %s\n", bus_names[p->bus_type]);
-  size += sprintf(BLS, "                Base IO: %#.4x\n", p->base);
-  size += sprintf(BLS, "         Base IO Memory: 0x%x\n", p->mbase);
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel\n");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->type & AHC_WIDE)
+      wide = "Wide ";
+    if (p->type & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s\n",
+      ultra, wide, channel);
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( !(p->type & AHC_AIC78x0) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+    size += sprintf(BLS, "                         %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
+  else
+  {
+    size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+            (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  }
   size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
-  size += sprintf(BLS, "                   SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  size += sprintf(BLS, "             Interrupts: %d", p->isr_count);
-  if (p->chip_class == AIC_777x)
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->type & AHC_AIC7770)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
@@ -232,16 +237,39 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   {
     size += sprintf(BLS, "\n");
   }
-  size += sprintf(BLS, "          Serial EEPROM: %s\n",
-      (p->flags & HAVE_SEEPROM) ? "True" : "False");
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
   size += sprintf(BLS, "   Extended Translation: %sabled\n",
-      (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis");
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
   size += sprintf(BLS, "         SCSI Bus Reset: %sabled\n",
       aic7xxx_no_reset ? "Dis" : "En");
-  size += sprintf(BLS, "             Ultra SCSI: %sabled\n",
-      (p->flags & ULTRA_ENABLED) ? "En" : "Dis");
-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable);
-  
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->type & AHC_ULTRA)
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+#ifdef AIC7XXX_CMDS_PER_LUN
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
+#else
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
+#endif
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
 #ifdef AIC7XXX_PROC_STATS
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Statistics:\n");
@@ -254,15 +282,15 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
       {
         continue;
       }
-      if (p->bus_type == AIC_TWIN)
+      if (p->type & AHC_TWIN)
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A' + (target >> 3), (target & 0x7), lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, (target >> 3), (target & 0x7), lun);
       }
       else
       {
-        size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
-            'A', target, lun);
+        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+            p->host_no, 0, target, lun);
       }
       size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
           sp->xfers, sp->r_total, sp->w_total);
index 92b5afa54e9019eab515cfac99de4f08e8513b86..a0682fd3ee6e7bb82a9efffbfdf262d6db1fadc1 100644 (file)
 #define                SELID_MASK              0xf0
 #define                ONEBIT                  0x08
 
+#define        SPIOCAP                         0x1b
+#define                SOFT1                   0x80
+#define                SOFT0                   0x40
+#define                SOFTCMDEN               0x20
+#define                HAS_BRDCTL              0x10
+#define                SEEPROM                 0x08
+#define                EEPROM                  0x04
+#define                ROM                     0x02
+#define                SSPIOCPS                0x01
+
 #define        BRDCTL                          0x1d
 #define                BRDDAT7                 0x80
 #define                BRDDAT6                 0x40
 
 #define        DISC_DSB                        0x32
 
-#define        MSG_LEN                         0x34
-
-#define        MSG_OUT                         0x35
+#define        MSG_OUT                         0x34
 
-#define        DMAPARAMS                       0x3d
+#define        DMAPARAMS                       0x35
 #define                WIDEODD                 0x40
 #define                SCSIEN                  0x20
 #define                SDMAENACK               0x10
 #define                FIFOFLUSH               0x02
 #define                FIFORESET               0x01
 
-#define        SCBCOUNT                        0x3e
-
-#define        COMP_SCBCOUNT                   0x3f
-
-#define        QCNTMASK                        0x40
-
-#define        SEQ_FLAGS                       0x41
-#define                RESELECTED              0x80
-#define                IDENTIFY_SEEN           0x40
-#define                TAGGED_SCB              0x20
+#define        SEQ_FLAGS                       0x36
+#define                IDENTIFY_SEEN           0x80
+#define                SCBPTR_VALID            0x20
 #define                DPHASE                  0x10
-#define                PAGESCBS                0x04
+#define                AMTARGET                0x08
 #define                WIDE_BUS                0x02
 #define                TWIN_BUS                0x01
 
-#define        SAVED_TCL                       0x42
+#define        SAVED_TCL                       0x37
 
-#define        SG_COUNT                        0x43
+#define        SG_COUNT                        0x38
 
-#define        SG_NEXT                         0x44
+#define        SG_NEXT                         0x39
 
-#define        WAITING_SCBH                    0x48
-
-#define        SAVED_LINKPTR                   0x49
-
-#define        SAVED_SCBPTR                    0x4a
-
-#define        REJBYTE                         0x4b
-
-#define        LASTPHASE                       0x4c
+#define        LASTPHASE                       0x3d
 #define                P_MESGIN                0xe0
 #define                PHASE_MASK              0xe0
 #define                P_STATUS                0xc0
 #define                P_BUSFREE               0x01
 #define                P_DATAOUT               0x00
 
-#define        MSGIN_EXT_LEN                   0x4d
+#define        WAITING_SCBH                    0x3e
+
+#define        DISCONNECTED_SCBH               0x3f
 
-#define        MSGIN_EXT_OPCODE                0x4e
+#define        FREE_SCBH                       0x40
 
-#define        MSGIN_EXT_BYTES                 0x4f
+#define        HSCB_ADDR                       0x41
 
-#define        DISCONNECTED_SCBH               0x52
+#define        SCBID_ADDR                      0x45
 
-#define        FREE_SCBH                       0x53
+#define        TMODE_CMDADDR                   0x49
 
-#define        HSCB_ADDR                       0x54
+#define        KERNEL_QINPOS                   0x4d
 
-#define        CUR_SCBID                       0x58
+#define        QINPOS                          0x4e
 
-#define        ARG_1                           0x59
-#define        RETURN_1                        0x59
+#define        QOUTPOS                         0x4f
+
+#define        TMODE_CMDADDR_NEXT              0x50
+
+#define        ARG_1                           0x51
+#define        RETURN_1                        0x51
 #define                SEND_MSG                0x80
 #define                SEND_SENSE              0x40
 #define                SEND_REJ                0x20
+#define                MSGOUT_PHASEMIS         0x10
 
-#define        SCSICONF                        0x5a
-
-#define        CMDOUTCNT                       0x5a
-
-#define        FIFODEPTH                       0x5b
+#define        LAST_MSG                        0x52
 
-#define        SCSICONF2                       0x5b
+#define        SCSICONF                        0x5a
+#define                TERM_ENB                0x80
 #define                RESET_SCSI              0x40
+#define                HWSCSIID                0x0f
+#define                HSCSIID                 0x07
 
 #define        HOSTCONF                        0x5d
 
 #define                SEQINT_MASK             0xf1
 #define                DATA_OVERRUN            0xe1
 #define                MSGIN_PHASEMIS          0xd1
-#define                MSG_BUFFER_BUSY         0xc1
+#define                TRACEPOINT2             0xc1
+#define                TRACEPOINT              0xb1
 #define                AWAITING_MSG            0xa1
-#define                ABORT_CMDCMPLT          0x91
 #define                RESIDUAL                0x81
 #define                BAD_STATUS              0x71
 #define                REJECT_MSG              0x61
-#define                NO_MATCH_BUSY           0x51
+#define                ABORT_REQUESTED         0x51
 #define                EXTENDED_MSG            0x41
 #define                NO_MATCH                0x31
 #define                NO_IDENT                0x21
 #define                SEQINT                  0x01
 
 #define        CLRINT                          0x92
+#define                CLRPARERR               0x10
 #define                CLRBRKADRINT            0x08
 #define                CLRSCSIINT              0x04
 #define                CLRCMDINT               0x02
 #define                CLRSEQINT               0x01
 
 #define        ERROR                           0x92
-#define                PARERR                  0x08
+#define                PCIERRSTAT              0x40
+#define                MPARERR                 0x20
+#define                DPARERR                 0x10
+#define                SQPARERR                0x08
 #define                ILLOPCODE               0x04
 #define                ILLSADDR                0x02
 #define                ILLHADDR                0x01
 #define                MK_MESSAGE              0x80
 #define                DISCENB                 0x40
 #define                TAG_ENB                 0x20
-#define                MUST_DMAUP_SCB          0x10
-#define                ABORT_SCB               0x08
 #define                DISCONNECTED            0x04
 #define                SCB_TAG_TYPE            0x03
 
 
 #define        SCB_DATACNT                     0xb0
 
-#define        SCB_LINKED_NEXT                 0xb3
-
 #define        SCB_CMDPTR                      0xb4
 
 #define        SCB_CMDLEN                      0xb8
 #define                DI_2840                 0x01
 
 
+#define        CMD_GROUP_CODE_SHIFT    0x05
 #define        BUS_8_BIT       0x00
+#define        QOUTFIFO_OFFSET 0x01
+#define        CMD_GROUP2_BYTE_DELTA   0xfa
 #define        MAX_OFFSET_8BIT 0x0f
 #define        BUS_16_BIT      0x01
+#define        QINFIFO_OFFSET  0x02
+#define        CMD_GROUP5_BYTE_DELTA   0x0b
 #define        MAX_OFFSET_16BIT        0x08
+#define        UNTAGGEDSCB_OFFSET      0x00
 #define        SCB_LIST_NULL   0xff
 #define        SG_SIZEOF       0x08
+#define        CMD_GROUP4_BYTE_DELTA   0x04
+#define        CMD_GROUP0_BYTE_DELTA   0xfc
+#define        HOST_MSG        0xff
 #define        BUS_32_BIT      0x02
+
+
+/* Downloaded Constant Definitions */
+#define        TMODE_NUMCMDS   0x01
+#define        QCNTMASK        0x00
index dc07e2a98ff3d9b9871b82733760bf5f25117983..2721f6bcde906f442eec7f3968c84288fddceaac 100644 (file)
@@ -1,54 +1,39 @@
 /*
   * DO NOT EDIT - This file is automatically generated.
   */
-static u_int8_t seqprog[] = {
+static unsigned char seqprog[] = {
        0xff, 0x6a, 0x03, 0x02,
+       0x32, 0x6a, 0x00, 0x00,
        0x12, 0x6a, 0x00, 0x00,
-       0x00, 0x65, 0x6f, 0x16,
-       0x40, 0x0b, 0x3c, 0x1a,
-       0x20, 0x0b, 0x37, 0x1a,
-       0x40, 0x00, 0x03, 0x1a,
+       0x00, 0x65, 0x92, 0x16,
+       0xf7, 0x01, 0x01, 0x02,
+       0xff, 0x4e, 0x64, 0x02,
+       0xbf, 0x60, 0x60, 0x02,
+       0x60, 0x0b, 0x37, 0x1a,
+       0x40, 0x00, 0x05, 0x1a,
        0x08, 0x1f, 0x1f, 0x04,
-       0x40, 0x0b, 0x3c, 0x1a,
-       0x20, 0x0b, 0x37, 0x1a,
-       0x40, 0x00, 0x03, 0x1a,
+       0x60, 0x0b, 0x37, 0x1a,
+       0x40, 0x00, 0x05, 0x1a,
        0x08, 0x1f, 0x1f, 0x04,
-       0xff, 0x48, 0x2c, 0x18,
-       0xff, 0x40, 0x64, 0x02,
-       0x00, 0x9c, 0x03, 0x1e,
-       0x00, 0x6a, 0xad, 0x17,
-       0xff, 0x65, 0x03, 0x1c,
-       0xff, 0x9b, 0x58, 0x02,
-       0xff, 0x58, 0x90, 0x02,
-       0x0d, 0x6a, 0x3d, 0x00,
-       0x00, 0x58, 0x77, 0x17,
-       0x28, 0xa0, 0x2a, 0x1a,
-       0x50, 0x6a, 0x60, 0x00,
-       0xff, 0x90, 0x4a, 0x02,
-       0x00, 0xa1, 0xa1, 0x17,
-       0xff, 0x6c, 0x59, 0x02,
-       0xff, 0x59, 0x27, 0x1c,
-       0xff, 0x4a, 0x90, 0x02,
-       0x00, 0x65, 0xaa, 0x17,
-       0x00, 0x6a, 0x52, 0x17,
-       0xff, 0x65, 0x1f, 0x18,
-       0x51, 0x6a, 0x91, 0x00,
-       0xff, 0x58, 0xb3, 0x02,
-       0x00, 0x65, 0xb6, 0x17,
-       0x10, 0x6a, 0x60, 0x00,
-       0x00, 0x65, 0x03, 0x10,
-       0xff, 0x59, 0x90, 0x02,
-       0xff, 0x58, 0xb3, 0x02,
-       0x10, 0x6a, 0x60, 0x00,
-       0x00, 0x65, 0x03, 0x10,
-       0xff, 0x58, 0x6d, 0x02,
-       0xff, 0x4a, 0x90, 0x02,
-       0x10, 0x6a, 0x60, 0x00,
-       0xff, 0x48, 0xba, 0x02,
-       0xff, 0x90, 0x48, 0x02,
-       0xff, 0x48, 0x90, 0x02,
-       0x00, 0x65, 0x2f, 0x16,
-       0x00, 0x65, 0x03, 0x10,
+       0xff, 0x3e, 0x1d, 0x18,
+       0x40, 0x60, 0x60, 0x00,
+       0x00, 0x4d, 0x06, 0x1c,
+       0x01, 0x4e, 0x4e, 0x06,
+       0xbf, 0x60, 0x60, 0x02,
+       0x00, 0x6a, 0xd8, 0x17,
+       0xff, 0x4e, 0x64, 0x06,
+       0x02, 0x6a, 0x93, 0x17,
+       0x0d, 0x6a, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0xff, 0x99, 0x65, 0x02,
+       0xff, 0x65, 0x90, 0x02,
+       0x0d, 0x6a, 0x35, 0x00,
+       0x00, 0x65, 0xb3, 0x17,
+       0xff, 0x3e, 0xba, 0x02,
+       0xff, 0x90, 0x3e, 0x02,
+       0xff, 0x3e, 0x90, 0x02,
+       0x00, 0x65, 0x20, 0x16,
+       0x00, 0x65, 0x05, 0x10,
        0xf7, 0x1f, 0x65, 0x02,
        0x08, 0xa1, 0x64, 0x02,
        0x00, 0x65, 0x65, 0x00,
@@ -57,316 +42,381 @@ static u_int8_t seqprog[] = {
        0x0f, 0x05, 0x05, 0x02,
        0x00, 0x05, 0x05, 0x00,
        0x5a, 0x6a, 0x00, 0x01,
-       0xff, 0x6a, 0x34, 0x02,
-       0x20, 0x6a, 0x0b, 0x00,
-       0xf0, 0x19, 0x42, 0x02,
-       0x80, 0x41, 0x41, 0x00,
-       0x00, 0x65, 0x4c, 0x10,
-       0x12, 0x6a, 0x00, 0x00,
-       0x40, 0x6a, 0x0b, 0x00,
-       0xff, 0x48, 0x90, 0x02,
-       0xff, 0xba, 0x48, 0x02,
-       0xff, 0xa1, 0x42, 0x02,
-       0x07, 0xa1, 0x35, 0x02,
-       0x40, 0xa0, 0x64, 0x02,
-       0x00, 0x35, 0x35, 0x00,
-       0x80, 0x35, 0x35, 0x00,
-       0x01, 0x6a, 0x34, 0x00,
-       0x20, 0xa0, 0x4a, 0x1e,
-       0x23, 0xa0, 0x36, 0x02,
-       0xff, 0xb9, 0x37, 0x02,
-       0x02, 0x34, 0x34, 0x06,
-       0x80, 0xa0, 0x4c, 0x1e,
-       0xa1, 0x6a, 0x91, 0x00,
-       0x08, 0x6a, 0x0c, 0x00,
-       0x08, 0x11, 0x11, 0x00,
-       0x1a, 0x01, 0x01, 0x00,
+       0x12, 0x65, 0x64, 0x00,
+       0x00, 0x01, 0x01, 0x00,
        0x31, 0x6a, 0x65, 0x00,
-       0x80, 0x42, 0x52, 0x1a,
+       0x80, 0x37, 0x2d, 0x1a,
        0xff, 0x65, 0x65, 0x06,
-       0xff, 0x42, 0x6e, 0x02,
+       0xff, 0x37, 0x6e, 0x02,
        0xff, 0x6e, 0x64, 0x02,
-       0x00, 0x6c, 0x56, 0x1e,
+       0x00, 0x6c, 0x31, 0x1e,
        0x20, 0x01, 0x01, 0x00,
-       0x4c, 0x42, 0x64, 0x0a,
-       0x08, 0x1f, 0x5a, 0x1e,
-       0x08, 0x42, 0x42, 0x00,
+       0x4c, 0x37, 0x64, 0x0a,
+       0x08, 0x1f, 0x35, 0x1e,
+       0x08, 0x37, 0x37, 0x00,
        0x08, 0x64, 0x64, 0x00,
        0x20, 0x64, 0x65, 0x06,
-       0xff, 0x6c, 0x04, 0x02,
-       0x01, 0x0c, 0x5c, 0x1e,
-       0x04, 0x0c, 0x5c, 0x1a,
-       0xe0, 0x03, 0x64, 0x02,
-       0xff, 0x64, 0x4c, 0x02,
-       0xff, 0x64, 0x03, 0x02,
-       0x00, 0x6a, 0x74, 0x1c,
-       0x40, 0x64, 0x79, 0x1c,
-       0x80, 0x64, 0xa5, 0x1c,
-       0xa0, 0x64, 0xb0, 0x1c,
-       0xc0, 0x64, 0xad, 0x1c,
-       0xe0, 0x64, 0xc3, 0x1c,
+       0xff, 0x6c, 0x04, 0x03,
+       0x40, 0x0b, 0x78, 0x1a,
+       0x80, 0x0b, 0x71, 0x1e,
+       0xa4, 0x6a, 0x03, 0x00,
+       0x40, 0x6a, 0x0b, 0x00,
+       0x10, 0x03, 0x6f, 0x1e,
+       0xff, 0x50, 0x64, 0x02,
+       0x49, 0x6a, 0xa9, 0x17,
+       0x01, 0x6a, 0x93, 0x00,
+       0xff, 0x6a, 0x65, 0x02,
+       0x08, 0x01, 0x01, 0x00,
+       0x02, 0x0b, 0x41, 0x1e,
+       0xf7, 0x01, 0x01, 0x02,
+       0xff, 0x06, 0x66, 0x02,
+       0xff, 0x66, 0x99, 0x02,
+       0x01, 0x65, 0x65, 0x06,
+       0x80, 0x66, 0x48, 0x1e,
+       0xff, 0x66, 0x51, 0x02,
+       0x10, 0x03, 0x40, 0x1a,
+       0xfc, 0x65, 0x64, 0x06,
+       0x00, 0x65, 0x4c, 0x12,
+       0xff, 0x6a, 0x99, 0x00,
+       0x01, 0x64, 0x8c, 0x06,
+       0x84, 0x6a, 0x03, 0x00,
+       0x08, 0x01, 0x01, 0x00,
+       0x02, 0x0b, 0x4f, 0x1e,
+       0xff, 0x06, 0x64, 0x02,
+       0xff, 0x64, 0x99, 0x02,
+       0xff, 0x6a, 0x65, 0x02,
+       0x5b, 0x64, 0x64, 0x0a,
+       0x00, 0x62, 0x62, 0x06,
+       0xfc, 0x65, 0x65, 0x06,
+       0xff, 0x6a, 0x6a, 0x02,
+       0xfa, 0x65, 0x65, 0x06,
+       0xff, 0x6a, 0x6a, 0x02,
+       0x04, 0x65, 0x65, 0x06,
+       0x0b, 0x65, 0x65, 0x06,
+       0xff, 0x65, 0x64, 0x02,
+       0x00, 0x8c, 0x8c, 0x06,
+       0x02, 0x0b, 0x5d, 0x1e,
+       0x01, 0x65, 0x60, 0x18,
+       0xf7, 0x01, 0x01, 0x02,
+       0xff, 0x06, 0x99, 0x02,
+       0xff, 0x65, 0x65, 0x06,
+       0xff, 0x65, 0x5d, 0x1a,
+       0x0a, 0x93, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0x40, 0x51, 0x69, 0x1e,
+       0xe4, 0x6a, 0x03, 0x00,
+       0x08, 0x01, 0x01, 0x00,
+       0x04, 0x6a, 0x5c, 0x17,
+       0x01, 0x50, 0x50, 0x06,
+       0x01, 0x50, 0x6c, 0x98,
+       0xff, 0x6a, 0x50, 0x02,
+       0xff, 0x6a, 0x9d, 0x00,
+       0x02, 0x6a, 0x91, 0x00,
+       0x40, 0x51, 0x6f, 0x1a,
+       0xff, 0x6a, 0x03, 0x02,
+       0x00, 0x65, 0x05, 0x10,
+       0x20, 0x6a, 0x0b, 0x00,
+       0xf0, 0x19, 0x37, 0x02,
+       0x08, 0x6a, 0x0c, 0x00,
+       0x08, 0x11, 0x11, 0x00,
+       0x08, 0x6a, 0x28, 0x16,
+       0x08, 0x6a, 0x34, 0x00,
+       0x00, 0x65, 0x82, 0x10,
+       0x12, 0x6a, 0x00, 0x00,
+       0x40, 0x6a, 0x0b, 0x00,
+       0xff, 0x3e, 0x90, 0x02,
+       0xff, 0xba, 0x3e, 0x02,
+       0xff, 0xa1, 0x37, 0x02,
+       0x08, 0x6a, 0x0c, 0x00,
+       0x08, 0x11, 0x11, 0x00,
+       0x08, 0x6a, 0x28, 0x16,
+       0x80, 0x6a, 0x34, 0x00,
+       0x80, 0x36, 0x36, 0x00,
+       0x00, 0x65, 0x9b, 0x17,
+       0xff, 0x3d, 0x64, 0x02,
+       0xbf, 0x64, 0x9a, 0x1e,
+       0x80, 0x64, 0xc9, 0x1c,
+       0xa0, 0x64, 0xd4, 0x1c,
+       0xc0, 0x64, 0xd1, 0x1c,
+       0xe0, 0x64, 0xf5, 0x1c,
        0x01, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
+       0x00, 0x65, 0x82, 0x10,
        0xf7, 0x11, 0x11, 0x02,
-       0x00, 0x65, 0x6f, 0x16,
+       0x00, 0x65, 0x92, 0x16,
        0xff, 0x06, 0x6a, 0x02,
-       0x09, 0x0c, 0x6c, 0x1e,
-       0x08, 0x0c, 0x03, 0x1a,
+       0xf7, 0x01, 0x01, 0x02,
+       0x09, 0x0c, 0x8f, 0x1e,
+       0x08, 0x0c, 0x05, 0x1a,
        0x01, 0x6a, 0x91, 0x00,
        0xff, 0x6a, 0x93, 0x02,
        0xff, 0x6a, 0x04, 0x02,
        0xdf, 0x01, 0x01, 0x02,
-       0x01, 0x6a, 0x4c, 0x00,
-       0x0f, 0x41, 0x41, 0x03,
-       0x7d, 0x6a, 0x3d, 0x00,
-       0x00, 0x65, 0x7a, 0x10,
+       0x01, 0x6a, 0x3d, 0x00,
+       0x03, 0x36, 0x36, 0x03,
        0x08, 0x6a, 0x66, 0x00,
-       0xa9, 0x6a, 0x74, 0x17,
-       0x00, 0x65, 0x82, 0x10,
-       0x79, 0x6a, 0x3d, 0x00,
-       0x00, 0x65, 0x4f, 0x17,
-       0x10, 0x41, 0x76, 0x1a,
+       0xa9, 0x6a, 0xa6, 0x17,
+       0x00, 0x65, 0xa5, 0x10,
+       0x79, 0x6a, 0x35, 0x00,
+       0x40, 0x3d, 0x9d, 0x1a,
+       0x04, 0x35, 0x35, 0x00,
+       0x00, 0x65, 0x6c, 0x17,
+       0x10, 0x36, 0x97, 0x1a,
        0x88, 0x6a, 0x66, 0x00,
-       0xac, 0x6a, 0x70, 0x17,
-       0x00, 0x65, 0x6d, 0x17,
-       0xff, 0xa3, 0x43, 0x02,
-       0x44, 0x6a, 0x66, 0x00,
-       0xa4, 0x6a, 0x73, 0x17,
-       0xff, 0x43, 0x88, 0x1a,
+       0xac, 0x6a, 0xa2, 0x17,
+       0x00, 0x65, 0x9f, 0x17,
+       0xff, 0xa3, 0x38, 0x02,
+       0x39, 0x6a, 0x66, 0x00,
+       0xa4, 0x6a, 0xa5, 0x17,
+       0xff, 0x38, 0xac, 0x1a,
        0x80, 0x02, 0x02, 0x00,
        0xff, 0x6a, 0x8c, 0x00,
        0xff, 0x6a, 0x8d, 0x00,
        0xff, 0x6a, 0x8e, 0x00,
-       0x00, 0x65, 0x6d, 0x17,
-       0x01, 0x43, 0x8a, 0x18,
-       0xbf, 0x3d, 0x3d, 0x02,
-       0x00, 0x3d, 0x44, 0x17,
-       0x80, 0x02, 0xa2, 0x1a,
-       0xff, 0x65, 0x9c, 0x1e,
-       0xff, 0x43, 0x43, 0x06,
-       0xff, 0x43, 0x9c, 0x1e,
+       0x00, 0x65, 0x9f, 0x17,
+       0xe7, 0x35, 0x35, 0x02,
+       0x01, 0x38, 0xae, 0x18,
+       0xbf, 0x35, 0x35, 0x02,
+       0x00, 0x35, 0x61, 0x17,
+       0x80, 0x02, 0xc6, 0x1a,
+       0xff, 0x65, 0xc0, 0x1e,
+       0xff, 0x38, 0x38, 0x06,
+       0xff, 0x38, 0xc0, 0x1e,
        0xff, 0x6a, 0x64, 0x02,
-       0x08, 0x44, 0x44, 0x06,
-       0x00, 0x45, 0x45, 0x08,
+       0x08, 0x39, 0x39, 0x06,
+       0x00, 0x3a, 0x3a, 0x08,
        0x88, 0x6a, 0x66, 0x00,
-       0x44, 0x6a, 0x73, 0x17,
+       0x39, 0x6a, 0xa5, 0x17,
        0x08, 0x6a, 0x8c, 0x00,
        0xff, 0x6a, 0x8d, 0x02,
        0xff, 0x6a, 0x8e, 0x02,
        0x0d, 0x93, 0x93, 0x00,
-       0x00, 0x65, 0x9d, 0x17,
-       0x88, 0x6a, 0x95, 0x17,
-       0x00, 0x65, 0x6d, 0x17,
-       0x10, 0x0c, 0x82, 0x1e,
+       0x00, 0x65, 0xd1, 0x17,
+       0x88, 0x6a, 0xc9, 0x17,
+       0x00, 0x65, 0x9f, 0x17,
+       0x10, 0x0c, 0xa5, 0x1e,
        0xff, 0x08, 0xa9, 0x02,
        0xff, 0x09, 0xaa, 0x02,
        0xff, 0x0a, 0xab, 0x02,
-       0xff, 0x43, 0xa8, 0x02,
-       0x10, 0x41, 0x41, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
+       0xff, 0x38, 0xa8, 0x02,
+       0x10, 0x36, 0x36, 0x00,
+       0x00, 0x65, 0x82, 0x10,
        0x7f, 0x02, 0x02, 0x02,
        0xe1, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
-       0x00, 0x65, 0x4f, 0x17,
+       0x00, 0x65, 0x82, 0x10,
+       0x00, 0x65, 0x6c, 0x17,
        0x88, 0x6a, 0x66, 0x00,
-       0xb4, 0x6a, 0x72, 0x17,
+       0xb4, 0x6a, 0xa4, 0x17,
        0xff, 0x6a, 0x8d, 0x02,
        0xff, 0x6a, 0x8e, 0x02,
-       0x00, 0x65, 0x6d, 0x17,
-       0x3d, 0x6a, 0x44, 0x17,
-       0x00, 0x65, 0x5c, 0x10,
-       0x00, 0x65, 0x4f, 0x17,
+       0x00, 0x65, 0x9f, 0x17,
+       0x3d, 0x6a, 0x61, 0x17,
+       0x00, 0x65, 0x82, 0x10,
+       0x00, 0x65, 0x6c, 0x17,
        0xff, 0x06, 0xa2, 0x02,
-       0x00, 0x65, 0x5c, 0x10,
-       0xff, 0x34, 0xb2, 0x1a,
-       0x08, 0x6a, 0x32, 0x17,
-       0x35, 0x6a, 0x65, 0x00,
-       0xff, 0x34, 0x66, 0x02,
-       0x01, 0x0c, 0xb4, 0x1e,
-       0x04, 0x0c, 0xb4, 0x1a,
-       0xe0, 0x03, 0x4c, 0x02,
-       0xa0, 0x4c, 0xc0, 0x18,
-       0xff, 0x66, 0xbb, 0x1a,
-       0x10, 0x4c, 0x03, 0x00,
-       0x00, 0x65, 0xb2, 0x10,
-       0x01, 0x66, 0xbd, 0x18,
+       0x00, 0x65, 0x82, 0x10,
+       0xff, 0x34, 0x65, 0x02,
+       0x80, 0x65, 0xe6, 0x18,
+       0x0f, 0xa1, 0x65, 0x02,
+       0x07, 0xa1, 0x65, 0x02,
+       0x40, 0xa0, 0x64, 0x02,
+       0x00, 0x65, 0x65, 0x00,
+       0x80, 0x65, 0x65, 0x00,
+       0x80, 0xa0, 0xde, 0x1e,
+       0xff, 0x65, 0x06, 0x02,
+       0x00, 0x65, 0xe7, 0x10,
+       0x20, 0xa0, 0xe9, 0x1e,
+       0xff, 0x65, 0x06, 0x02,
+       0x00, 0x65, 0x9b, 0x17,
+       0xa0, 0x3d, 0xef, 0x18,
+       0x23, 0xa0, 0x06, 0x02,
+       0x00, 0x65, 0x9b, 0x17,
+       0xa0, 0x3d, 0xef, 0x18,
+       0x00, 0xb9, 0xe9, 0x10,
+       0xff, 0x65, 0xe9, 0x18,
+       0xa1, 0x6a, 0x91, 0x00,
+       0x10, 0x51, 0xef, 0x1c,
        0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x66, 0x66, 0x06,
-       0xff, 0x6c, 0x06, 0x02,
-       0x00, 0x65, 0xb4, 0x10,
+       0xff, 0x65, 0x06, 0x02,
+       0x00, 0x65, 0x9b, 0x17,
+       0xa0, 0x3d, 0xef, 0x18,
+       0x10, 0x3d, 0x03, 0x00,
+       0x00, 0x65, 0xd4, 0x10,
        0x40, 0x6a, 0x0c, 0x00,
-       0xff, 0x6a, 0x34, 0x02,
-       0x00, 0x65, 0x5c, 0x10,
-       0x64, 0x6a, 0x3f, 0x17,
-       0xff, 0x64, 0x4b, 0x02,
-       0x80, 0x64, 0x0e, 0x1b,
-       0x04, 0x64, 0x01, 0x1d,
-       0x02, 0x64, 0x04, 0x1d,
-       0x00, 0x6a, 0xd1, 0x1c,
-       0x03, 0x64, 0x0c, 0x1d,
-       0x01, 0x64, 0xf5, 0x1c,
-       0x07, 0x64, 0x30, 0x1d,
-       0x08, 0x64, 0xcf, 0x1c,
+       0xff, 0x34, 0x52, 0x02,
+       0x80, 0x34, 0xf3, 0x18,
+       0x7f, 0xa0, 0xa0, 0x02,
+       0x08, 0x6a, 0x34, 0x00,
+       0x00, 0x65, 0x82, 0x10,
+       0x64, 0x6a, 0x59, 0x17,
+       0x80, 0x64, 0x2f, 0x1b,
+       0x04, 0x64, 0x22, 0x1d,
+       0x02, 0x64, 0x25, 0x1d,
+       0x00, 0x6a, 0x02, 0x1d,
+       0x03, 0x64, 0x2d, 0x1d,
+       0x01, 0x64, 0x20, 0x1d,
+       0x07, 0x64, 0x50, 0x1d,
+       0x08, 0x64, 0x00, 0x1d,
        0x11, 0x6a, 0x91, 0x00,
-       0x07, 0x6a, 0x32, 0x17,
+       0x07, 0x6a, 0x52, 0x17,
        0xff, 0x06, 0x6a, 0x02,
-       0x00, 0x65, 0x5c, 0x10,
-       0xff, 0xa8, 0xd3, 0x1a,
-       0xff, 0xa2, 0xda, 0x1e,
-       0x01, 0x6a, 0x3d, 0x00,
-       0x00, 0xb9, 0x77, 0x17,
-       0xff, 0xa2, 0xda, 0x1e,
+       0x00, 0x65, 0x82, 0x10,
+       0xff, 0xa8, 0x04, 0x1b,
+       0xff, 0xa2, 0x0f, 0x1f,
+       0x01, 0x6a, 0x35, 0x00,
+       0x00, 0xb9, 0xb3, 0x17,
+       0xff, 0xa2, 0x0f, 0x1f,
        0x71, 0x6a, 0x91, 0x00,
-       0x40, 0x59, 0xda, 0x18,
-       0xff, 0xb9, 0xb3, 0x02,
-       0x00, 0x65, 0xe7, 0x10,
-       0x20, 0xa0, 0xe0, 0x1a,
-       0xff, 0x90, 0x4a, 0x02,
-       0xff, 0xb3, 0x49, 0x02,
-       0x00, 0xa1, 0xa1, 0x17,
-       0xff, 0x49, 0x6d, 0x02,
-       0xff, 0x4a, 0x90, 0x02,
-       0xff, 0x5b, 0x64, 0x02,
-       0x00, 0x5a, 0xe1, 0x1c,
-       0x01, 0x5a, 0x5a, 0x06,
-       0xff, 0xb9, 0x9d, 0x02,
+       0x40, 0x51, 0x0f, 0x19,
+       0x0d, 0x6a, 0x35, 0x00,
+       0x00, 0xb9, 0xb3, 0x17,
+       0xff, 0x3e, 0xba, 0x02,
+       0xff, 0x90, 0x3e, 0x02,
+       0x00, 0x65, 0x20, 0x16,
+       0x00, 0x65, 0x8b, 0x10,
+       0x20, 0xa0, 0x16, 0x1b,
+       0xff, 0x37, 0x64, 0x02,
+       0x00, 0x6a, 0x93, 0x17,
+       0x01, 0x6a, 0x93, 0x00,
+       0xff, 0x6a, 0x99, 0x00,
+       0x0a, 0x93, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0xff, 0x4f, 0x64, 0x02,
+       0x01, 0x6a, 0x93, 0x17,
+       0x01, 0x6a, 0x93, 0x00,
+       0xff, 0xb9, 0x99, 0x02,
+       0x0a, 0x93, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0x01, 0x4f, 0x4f, 0x06,
        0x02, 0x6a, 0x91, 0x00,
-       0x08, 0xa0, 0xe7, 0x1e,
-       0x91, 0x6a, 0x91, 0x00,
-       0xff, 0xb3, 0xf3, 0x1c,
-       0xff, 0xb3, 0x64, 0x02,
-       0x00, 0xb9, 0xed, 0x1c,
-       0x00, 0x65, 0xaa, 0x17,
-       0xff, 0x64, 0x90, 0x02,
-       0x00, 0x65, 0xef, 0x10,
-       0x0d, 0x6a, 0x3d, 0x00,
-       0x00, 0xb3, 0x77, 0x17,
-       0xff, 0x48, 0xba, 0x02,
-       0xff, 0x90, 0x48, 0x02,
-       0x00, 0x65, 0x2f, 0x16,
-       0x00, 0x65, 0x69, 0x10,
-       0x00, 0x65, 0xaa, 0x17,
-       0x00, 0x65, 0x69, 0x10,
-       0x4d, 0x6a, 0x3a, 0x17,
-       0xff, 0x4d, 0x64, 0x02,
-       0x00, 0x66, 0x3a, 0x17,
-       0xff, 0x64, 0x64, 0x06,
-       0x52, 0x66, 0xfb, 0x18,
-       0xff, 0x66, 0x66, 0x06,
-       0xff, 0x64, 0xf7, 0x1a,
+       0x00, 0x65, 0xd5, 0x17,
+       0x00, 0x65, 0x8b, 0x10,
        0x41, 0x6a, 0x91, 0x00,
-       0x20, 0x59, 0xcd, 0x1c,
-       0x80, 0x59, 0xcf, 0x18,
-       0x10, 0x4c, 0x03, 0x00,
-       0x00, 0x65, 0xcf, 0x10,
+       0x00, 0x65, 0x82, 0x10,
        0x04, 0xa0, 0xa0, 0x00,
-       0x00, 0x65, 0xb6, 0x17,
-       0x00, 0x65, 0x69, 0x10,
-       0x10, 0x41, 0xcf, 0x1e,
-       0xff, 0x43, 0xa3, 0x02,
+       0x00, 0x65, 0xe1, 0x17,
+       0x00, 0x65, 0x8b, 0x10,
+       0x10, 0x36, 0x00, 0x1f,
+       0xff, 0x38, 0xa3, 0x02,
        0xa4, 0x6a, 0x66, 0x00,
-       0x44, 0x6a, 0x73, 0x17,
+       0x39, 0x6a, 0xa5, 0x17,
        0xac, 0x6a, 0x66, 0x00,
-       0x14, 0x6a, 0x73, 0x17,
-       0xa9, 0x6a, 0x74, 0x17,
-       0x00, 0x65, 0xcf, 0x10,
-       0xef, 0x41, 0x41, 0x02,
-       0x00, 0x65, 0xcf, 0x10,
-       0x78, 0x64, 0xcd, 0x1a,
+       0x14, 0x6a, 0xa5, 0x17,
+       0xa9, 0x6a, 0xa6, 0x17,
+       0x00, 0x65, 0x00, 0x11,
+       0xef, 0x36, 0x36, 0x02,
+       0x00, 0x65, 0x00, 0x11,
+       0x0f, 0x64, 0x64, 0x02,
        0x07, 0x64, 0x64, 0x02,
-       0x00, 0x42, 0x42, 0x00,
-       0x00, 0x42, 0xa1, 0x17,
-       0xff, 0x6c, 0x59, 0x02,
-       0xff, 0x59, 0x28, 0x19,
-       0xff, 0x59, 0x18, 0x1d,
-       0xff, 0x59, 0x90, 0x02,
-       0x04, 0xa0, 0x2d, 0x1f,
-       0x00, 0x65, 0x2a, 0x11,
+       0x00, 0x37, 0x37, 0x00,
+       0x00, 0x65, 0x8b, 0x17,
+       0xff, 0x51, 0x37, 0x1d,
+       0x20, 0x36, 0x3f, 0x1f,
+       0x00, 0x90, 0x7d, 0x17,
+       0x00, 0x65, 0x40, 0x11,
        0xff, 0x06, 0x6a, 0x02,
-       0x01, 0x0c, 0x19, 0x1f,
-       0x04, 0x0c, 0x19, 0x1b,
-       0xe0, 0x03, 0x4c, 0x02,
-       0xe0, 0x4c, 0x2d, 0x19,
-       0x20, 0x12, 0x2d, 0x19,
-       0x20, 0x41, 0x41, 0x00,
-       0x59, 0x6a, 0x3a, 0x17,
-       0xff, 0x3f, 0x64, 0x02,
-       0x00, 0x59, 0x65, 0x06,
-       0x00, 0x65, 0x2d, 0x13,
-       0xff, 0x59, 0x90, 0x02,
-       0xff, 0x42, 0x64, 0x02,
-       0x00, 0xa1, 0x2d, 0x19,
-       0x20, 0xa0, 0x2d, 0x1f,
-       0x04, 0xa0, 0x2d, 0x1f,
-       0x00, 0x6a, 0x52, 0x17,
-       0xff, 0x65, 0x2d, 0x1d,
+       0x00, 0x65, 0x9b, 0x17,
+       0xe0, 0x3d, 0x4d, 0x19,
+       0x20, 0x12, 0x4d, 0x19,
+       0x51, 0x6a, 0x54, 0x17,
+       0xff, 0x51, 0x90, 0x02,
+       0x20, 0xa0, 0x4d, 0x1f,
+       0x00, 0x90, 0x7d, 0x17,
+       0x00, 0x65, 0x7a, 0x17,
+       0xff, 0x37, 0x64, 0x02,
+       0x00, 0xa1, 0x49, 0x19,
+       0x04, 0xa0, 0x49, 0x1f,
        0xfb, 0xa0, 0xa0, 0x02,
-       0x40, 0x41, 0x41, 0x00,
-       0x00, 0x65, 0xcf, 0x10,
+       0x80, 0x36, 0x36, 0x00,
+       0x80, 0xa0, 0x00, 0x1f,
+       0x7f, 0xa0, 0xa0, 0x02,
+       0xff, 0x6a, 0x52, 0x17,
+       0x00, 0x65, 0x00, 0x11,
+       0x04, 0xa0, 0x4c, 0x1f,
+       0x00, 0x65, 0xe1, 0x17,
+       0x00, 0x65, 0x4d, 0x11,
+       0x00, 0x65, 0xd5, 0x17,
        0x31, 0x6a, 0x91, 0x00,
-       0x0c, 0x6a, 0x32, 0x17,
-       0x00, 0x65, 0xcf, 0x10,
+       0x0c, 0x6a, 0x52, 0x17,
+       0x00, 0x65, 0x00, 0x11,
        0x61, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0xcf, 0x10,
-       0x50, 0x6a, 0x60, 0x00,
-       0xff, 0x34, 0x36, 0x1f,
-       0x10, 0x6a, 0x60, 0x00,
-       0xc1, 0x6a, 0x91, 0x00,
-       0x10, 0x4c, 0x03, 0x00,
-       0x01, 0x6a, 0x34, 0x00,
-       0xff, 0x65, 0x35, 0x02,
-       0x10, 0x6a, 0x60, 0x01,
+       0x00, 0x65, 0x00, 0x11,
+       0x10, 0x3d, 0x03, 0x00,
+       0xff, 0x65, 0x34, 0x03,
        0xff, 0x06, 0x6a, 0x02,
-       0x01, 0x0c, 0x3b, 0x1f,
-       0x04, 0x0c, 0x3b, 0x1b,
-       0xe0, 0x03, 0x4c, 0x02,
-       0xe0, 0x4c, 0x42, 0x19,
+       0x01, 0x0c, 0x55, 0x1f,
+       0x04, 0x0c, 0x55, 0x1b,
+       0xe0, 0x03, 0x3d, 0x02,
+       0xe0, 0x3d, 0x5f, 0x19,
        0xff, 0x65, 0x66, 0x02,
        0xff, 0x12, 0x6d, 0x03,
        0xff, 0x06, 0x6a, 0x03,
+       0xff, 0x65, 0x06, 0x02,
+       0x02, 0x0b, 0x5d, 0x1f,
+       0xff, 0x6a, 0x6a, 0x03,
        0xd1, 0x6a, 0x91, 0x00,
-       0x00, 0x65, 0x5c, 0x10,
+       0x00, 0x65, 0x82, 0x10,
        0xff, 0x65, 0x93, 0x02,
-       0x01, 0x0b, 0x4c, 0x1b,
-       0x10, 0x0c, 0x45, 0x1f,
-       0x04, 0x0b, 0x49, 0x1b,
+       0x01, 0x0b, 0x69, 0x1b,
+       0x10, 0x0c, 0x62, 0x1f,
+       0x04, 0x0b, 0x66, 0x1b,
        0xff, 0x6a, 0x65, 0x02,
-       0x04, 0x93, 0x4b, 0x1b,
-       0x01, 0x94, 0x4a, 0x1f,
-       0x10, 0x94, 0x4b, 0x1b,
+       0x04, 0x93, 0x68, 0x1b,
+       0x01, 0x94, 0x67, 0x1f,
+       0x10, 0x94, 0x68, 0x1b,
        0xc7, 0x93, 0x93, 0x02,
-       0x38, 0x93, 0x4d, 0x1b,
+       0x38, 0x93, 0x6a, 0x1b,
        0xff, 0x6a, 0x6a, 0x03,
-       0x80, 0x41, 0x4e, 0x1f,
-       0x40, 0x41, 0x4e, 0x1b,
+       0x80, 0x36, 0x6b, 0x1b,
        0x21, 0x6a, 0x91, 0x01,
        0xff, 0x65, 0x90, 0x02,
-       0xff, 0x59, 0x64, 0x02,
-       0x00, 0xb9, 0x56, 0x19,
-       0x04, 0xa0, 0x60, 0x1b,
-       0x01, 0x65, 0x65, 0x06,
-       0xff, 0x3e, 0x64, 0x02,
-       0x00, 0x65, 0x52, 0x19,
-       0x00, 0x6a, 0xad, 0x17,
-       0x0d, 0x6a, 0x3d, 0x00,
-       0x00, 0x59, 0x77, 0x17,
-       0xff, 0xa8, 0x5e, 0x1f,
-       0x10, 0xa0, 0xa0, 0x00,
-       0x08, 0xa0, 0x4e, 0x1f,
+       0xff, 0x51, 0x72, 0x19,
+       0xff, 0x37, 0x64, 0x02,
+       0xa1, 0x6a, 0x77, 0x11,
+       0xff, 0x51, 0x64, 0x02,
+       0xb9, 0x6a, 0x77, 0x11,
+       0xff, 0xba, 0x79, 0x1d,
+       0xff, 0xba, 0x90, 0x02,
+       0xff, 0x65, 0x65, 0x06,
+       0x00, 0x6c, 0x74, 0x19,
+       0xff, 0x90, 0x65, 0x03,
        0xff, 0x6a, 0x65, 0x01,
-       0x08, 0xa0, 0x5f, 0x1b,
-       0xff, 0xba, 0x66, 0x1d,
-       0xff, 0xbb, 0x49, 0x02,
+       0x20, 0x36, 0x88, 0x1f,
+       0x00, 0x90, 0x6e, 0x17,
+       0xff, 0x65, 0x88, 0x1d,
+       0xff, 0xba, 0x82, 0x1d,
+       0xff, 0xbb, 0x66, 0x02,
        0xff, 0xba, 0x90, 0x02,
-       0xff, 0x49, 0xbb, 0x02,
+       0xff, 0x66, 0xbb, 0x02,
        0xff, 0x65, 0x90, 0x02,
-       0xff, 0xbb, 0x6b, 0x1d,
-       0xff, 0xba, 0x49, 0x02,
+       0xff, 0xbb, 0x87, 0x1d,
+       0xff, 0xba, 0x66, 0x02,
        0xff, 0xbb, 0x90, 0x02,
-       0xff, 0x49, 0xba, 0x02,
+       0xff, 0x66, 0xba, 0x02,
        0xff, 0x65, 0x90, 0x03,
-       0xff, 0xba, 0x52, 0x03,
-       0xff, 0x6a, 0x6a, 0x03,
+       0xff, 0xba, 0x3f, 0x03,
+       0x00, 0x6a, 0xd8, 0x17,
+       0x0d, 0x6a, 0x35, 0x00,
+       0x00, 0x51, 0xb3, 0x11,
+       0xff, 0x3f, 0x96, 0x1d,
+       0xff, 0x6a, 0x51, 0x00,
+       0x00, 0x3f, 0x6e, 0x17,
+       0xff, 0x65, 0x96, 0x1d,
+       0x20, 0x36, 0x36, 0x00,
+       0x20, 0xa0, 0x92, 0x1b,
+       0xff, 0xb9, 0x51, 0x03,
+       0xff, 0x6a, 0x51, 0x01,
+       0xff, 0x65, 0x66, 0x02,
+       0x45, 0x6a, 0xab, 0x17,
+       0x01, 0x6a, 0x8c, 0x01,
+       0xff, 0x37, 0x64, 0x02,
+       0x00, 0x6a, 0x93, 0x17,
+       0x0d, 0x6a, 0x93, 0x00,
+       0x00, 0x65, 0xd1, 0x17,
+       0xff, 0x99, 0x51, 0x03,
+       0x01, 0x0c, 0x9b, 0x1f,
+       0x04, 0x0c, 0x9b, 0x1b,
+       0xe0, 0x03, 0x3d, 0x02,
+       0xff, 0x3d, 0x03, 0x03,
        0xff, 0x8c, 0x08, 0x02,
        0xff, 0x8d, 0x09, 0x02,
        0xff, 0x8e, 0x0a, 0x03,
@@ -377,19 +427,21 @@ static u_int8_t seqprog[] = {
        0xff, 0x6c, 0x6d, 0x02,
        0xff, 0x6c, 0x6d, 0x02,
        0xff, 0x6c, 0x6d, 0x03,
-       0x3d, 0x65, 0x66, 0x0a,
-       0x55, 0x65, 0x64, 0x0a,
-       0x00, 0x54, 0x88, 0x06,
+       0x3d, 0x64, 0x66, 0x0a,
+       0x55, 0x64, 0x64, 0x0a,
+       0x00, 0x6c, 0x88, 0x06,
        0xff, 0x66, 0x64, 0x02,
-       0x00, 0x55, 0x89, 0x08,
+       0x00, 0x6c, 0x89, 0x08,
        0xff, 0x6a, 0x64, 0x02,
-       0x00, 0x56, 0x8a, 0x08,
-       0x00, 0x57, 0x8b, 0x08,
-       0x1c, 0x6a, 0x8c, 0x00,
+       0x00, 0x6c, 0x8a, 0x08,
+       0x00, 0x6c, 0x8b, 0x08,
        0xff, 0x6a, 0x8d, 0x02,
-       0xff, 0x6a, 0x8e, 0x02,
-       0xff, 0x3d, 0x93, 0x02,
-       0x04, 0x3d, 0x8f, 0x1b,
+       0xff, 0x6a, 0x8e, 0x03,
+       0xff, 0x65, 0x64, 0x02,
+       0x41, 0x6a, 0xa9, 0x17,
+       0x1c, 0x6a, 0x8c, 0x00,
+       0xff, 0x35, 0x93, 0x02,
+       0x04, 0x35, 0xc3, 0x1b,
        0xa0, 0x6a, 0x65, 0x00,
        0x1c, 0x65, 0x64, 0x06,
        0xff, 0x6c, 0x99, 0x02,
@@ -399,14 +451,14 @@ static u_int8_t seqprog[] = {
        0xff, 0x6c, 0x99, 0x02,
        0xff, 0x6c, 0x99, 0x02,
        0xff, 0x6c, 0x99, 0x02,
-       0x00, 0x65, 0x86, 0x19,
+       0x00, 0x65, 0xba, 0x19,
        0x0a, 0x93, 0x93, 0x00,
-       0x00, 0x65, 0x9d, 0x17,
-       0x04, 0x3d, 0x4e, 0x1f,
-       0xa0, 0x6a, 0x95, 0x17,
-       0x00, 0x65, 0x96, 0x17,
-       0x00, 0x65, 0x96, 0x17,
-       0x00, 0x65, 0x96, 0x11,
+       0x00, 0x65, 0xd1, 0x17,
+       0x04, 0x35, 0x6b, 0x1f,
+       0xa0, 0x6a, 0xc9, 0x17,
+       0x00, 0x65, 0xca, 0x17,
+       0x00, 0x65, 0xca, 0x17,
+       0x00, 0x65, 0xca, 0x11,
        0xff, 0x65, 0x66, 0x02,
        0xff, 0x99, 0x6d, 0x02,
        0xff, 0x99, 0x6d, 0x02,
@@ -415,64 +467,58 @@ static u_int8_t seqprog[] = {
        0xff, 0x99, 0x6d, 0x02,
        0xff, 0x99, 0x6d, 0x02,
        0xff, 0x99, 0x6d, 0x03,
-       0x08, 0x94, 0x9d, 0x1f,
+       0x08, 0x94, 0xd1, 0x1f,
        0xf7, 0x93, 0x93, 0x02,
-       0x08, 0x93, 0x9f, 0x1b,
+       0x08, 0x93, 0xd3, 0x1b,
        0xff, 0x6a, 0x6a, 0x03,
-       0xff, 0x65, 0x66, 0x02,
-       0x4c, 0x66, 0x66, 0x0a,
-       0x03, 0x66, 0x66, 0x02,
-       0xbc, 0x66, 0x66, 0x06,
-       0x6a, 0x65, 0x64, 0x0a,
-       0x08, 0x65, 0xa8, 0x1f,
-       0x02, 0x64, 0x64, 0x06,
-       0xff, 0x64, 0x90, 0x02,
-       0xff, 0x66, 0x65, 0x03,
-       0xff, 0x53, 0xba, 0x02,
-       0xff, 0x6a, 0xb9, 0x00,
-       0xff, 0x90, 0x53, 0x03,
-       0xff, 0x53, 0xb4, 0x19,
-       0xff, 0x52, 0xb0, 0x19,
+       0xff, 0x40, 0xba, 0x02,
+       0xff, 0x90, 0x40, 0x02,
+       0xff, 0x6a, 0xb9, 0x01,
+       0xff, 0x40, 0xdf, 0x19,
+       0xff, 0x3f, 0xdb, 0x19,
        0xff, 0x6a, 0x65, 0x01,
-       0xff, 0x52, 0x90, 0x02,
-       0x01, 0x6a, 0x3d, 0x00,
-       0x00, 0xb9, 0x77, 0x17,
-       0x00, 0x90, 0x61, 0x11,
-       0xff, 0x53, 0x90, 0x02,
-       0xff, 0xba, 0x53, 0x03,
+       0xff, 0x3f, 0x90, 0x02,
+       0x01, 0x6a, 0x35, 0x00,
+       0x00, 0xb9, 0xb3, 0x17,
+       0x00, 0x90, 0x7d, 0x11,
+       0xff, 0x40, 0x90, 0x02,
+       0xff, 0xba, 0x40, 0x03,
        0xff, 0x6a, 0xbb, 0x00,
-       0xff, 0x52, 0xba, 0x02,
-       0xff, 0x90, 0x52, 0x02,
-       0xff, 0xba, 0x4e, 0x1d,
+       0xff, 0x3f, 0xba, 0x02,
+       0xff, 0x90, 0x3f, 0x02,
+       0xff, 0xba, 0x6b, 0x1d,
        0xff, 0xba, 0x90, 0x02,
-       0xff, 0x52, 0xbb, 0x02,
-       0xff, 0x52, 0x90, 0x03,
+       0xff, 0x3f, 0xbb, 0x02,
+       0xff, 0x3f, 0x90, 0x03,
 };
-#define        ULTRA                   0x8
-#define        SCB_PAGING              0x4
-#define        TWIN_CHANNEL            0x2
+#define        WIDE                    0x20
+#define        ULTRA                   0x10
+#define        SCB_PAGING              0x8
+#define        TWIN_CHANNEL            0x4
+#define        TARGET_MODE             0x2
 struct patch {
        int     options;
        int     negative;
        int     begin;
        int     end;
 } patches[] = {
-       { 0x00000002, 0, 0x006, 0x00b },
-       { 0x00000004, 0, 0x00e, 0x010 },
-       { 0x00000004, 1, 0x011, 0x012 },
-       { 0x00000004, 0, 0x01a, 0x023 },
-       { 0x00000004, 1, 0x023, 0x027 },
-       { 0x00000002, 0, 0x02f, 0x033 },
-       { 0x00000008, 0, 0x04f, 0x056 },
-       { 0x00000004, 0, 0x0e0, 0x0e3 },
-       { 0x00000004, 1, 0x0e8, 0x0ed },
-       { 0x00000004, 0, 0x102, 0x103 },
-       { 0x00000004, 0, 0x113, 0x114 },
-       { 0x00000004, 1, 0x114, 0x118 },
-       { 0x00000004, 1, 0x123, 0x128 },
-       { 0x00000004, 0, 0x128, 0x12a },
-       { 0x00000004, 0, 0x152, 0x16c },
-       { 0x00000004, 1, 0x16c, 0x16d },
-       { 0x00000004, 0, 0x1ad, 0x1bd },
+       { 0x00000002, 0, 0x001, 0x002 },
+       { 0x00000002, 1, 0x002, 0x003 },
+       { 0x00000004, 0, 0x009, 0x00d },
+       { 0x00000008, 0, 0x012, 0x013 },
+       { 0x00000008, 1, 0x018, 0x019 },
+       { 0x00000004, 0, 0x020, 0x024 },
+       { 0x00000010, 0, 0x02a, 0x031 },
+       { 0x00000002, 0, 0x038, 0x071 },
+       { 0x00000020, 0, 0x0d6, 0x0d7 },
+       { 0x00000020, 1, 0x0d7, 0x0d8 },
+       { 0x00000020, 0, 0x12f, 0x130 },
+       { 0x00000020, 1, 0x130, 0x131 },
+       { 0x00000008, 0, 0x134, 0x135 },
+       { 0x00000008, 1, 0x13c, 0x13f },
+       { 0x00000008, 0, 0x13f, 0x140 },
+       { 0x00000002, 0, 0x15c, 0x15f },
+       { 0x00000008, 0, 0x1d5, 0x1d7 },
+       { 0x00000008, 0, 0x1d8, 0x1e1 },
        { 0x00000000, 0, 0x000, 0x000 }
 };
index e0a649462209da96f12474ed1a69238c5c11f78a..03bd0d7a041468a1ba6763e5683df52c4d1a55b3 100644 (file)
@@ -368,7 +368,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
     case SCSI_IOCTL_PROBE_HOST:
        return ioctl_probe(dev->host, arg);
     case SCSI_IOCTL_SEND_COMMAND:
-       if(!suser())  return -EACCES;
+       if(!suser() || securelevel > 0)  return -EACCES;
        return ioctl_command((Scsi_Device *) dev, arg);
     case SCSI_IOCTL_DOORLOCK:
        if (!dev->removable || !dev->lockable) return 0;
index 94e5cad61a81b2b1a45037aa4da12d0763f476f7..4d3d0d158877c4524fc33614714323924dbd06c0 100644 (file)
@@ -227,6 +227,10 @@ int check_disk_change(kdev_t dev)
 int blkdev_open(struct inode * inode, struct file * filp)
 {
        int ret = -ENODEV;
+
+       if (securelevel > 0 && (filp->f_mode & FMODE_WRITE))
+               return -EACCES; /* cevans */
+
        filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
        if (filp->f_op != NULL){
                ret = 0;
index 8e6b047e08e200c07ed4d3caff703d827cf36907..2645deea4edb45b7706d6f9c4c91cbed76a33c13 100644 (file)
@@ -78,7 +78,8 @@
 #define ID_ERR         0x10    /* ID field not found */
 #define MC_ERR         0x20    /* media changed */
 #define ECC_ERR                0x40    /* Uncorrectable ECC error */
-#define        BBD_ERR         0x80    /* block marked bad */
+#define        BBD_ERR         0x80    /* pre-EIDE meaning:  block marked bad */
+#define        ICRC_ERR        0x80    /* new meaning:  CRC error during transfer */
 
 struct hd_geometry {
       unsigned char heads;
@@ -151,11 +152,28 @@ struct hd_driveid {
        unsigned short  eide_dma_time;  /* recommended mword dma cycle time (ns) */
        unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
        unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
-       unsigned short  reserved69;     /* reserved (word 69) */
-       unsigned short  reserved70;     /* reserved (word 70) */
-       /* unsigned short reservedxx[57];*/     /* reserved (words 71-127) */
-       /* unsigned short vendor7  [32];*/      /* vendor unique (words 128-159) */
-       /* unsigned short reservedyy[96];*/     /* reserved (words 160-255) */
+       unsigned short  word69;
+       unsigned short  word70;
+       /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+       unsigned short  word71;
+       unsigned short  word72;
+       unsigned short  word73;
+       unsigned short  word74;
+       unsigned short  word75;
+       unsigned short  word76;
+       unsigned short  word77;
+       unsigned short  word78;
+       unsigned short  word79;
+       unsigned short  word80;
+       unsigned short  word81;
+       unsigned short  word82;
+       unsigned short  word83;
+       unsigned short  word84;
+       unsigned short  word85;
+       unsigned short  word86;
+       unsigned short  word87;
+       unsigned short  dma_ultra;
+       unsigned short  reserved[167];
 };
 
 #ifdef __KERNEL__
index 6dcbed8156bd378b762d8b1873e68eee28c9312d..8f76e7e985a8edea2cf880dd8c3de4eb7effda26 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef _FRAD_H_
 #define _FRAD_H_
 
+#include <linux/config.h>
 #include <linux/if.h>
 
 /* Structures and constants associated with the DLCI device driver */
diff --git a/include/linux/modversions.h b/include/linux/modversions.h
new file mode 100644 (file)
index 0000000..1103f93
--- /dev/null
@@ -0,0 +1,30 @@
+#ifdef MODVERSIONS
+#undef  CONFIG_MODVERSIONS
+#define CONFIG_MODVERSIONS
+#ifndef _set_ver
+#define _set_ver(sym,vers) sym ## _R ## vers
+#endif
+#include <linux/modules/b1capi.ver>
+#include <linux/modules/b1pci.ver>
+#include <linux/modules/capidrv.ver>
+#include <linux/modules/capiutil.ver>
+#include <linux/modules/fatfs_syms.ver>
+#include <linux/modules/firewall.ver>
+#include <linux/modules/isdn_syms.ver>
+#include <linux/modules/ksyms.ver>
+#include <linux/modules/md.ver>
+#include <linux/modules/misc.ver>
+#include <linux/modules/msdosfs_syms.ver>
+#include <linux/modules/netsyms.ver>
+#include <linux/modules/nls.ver>
+#include <linux/modules/p8022.ver>
+#include <linux/modules/p8022tr.ver>
+#include <linux/modules/ppp.ver>
+#include <linux/modules/procfs_syms.ver>
+#include <linux/modules/psnap.ver>
+#include <linux/modules/scsi_syms.ver>
+#include <linux/modules/serial.ver>
+#include <linux/modules/slhc.ver>
+#include <linux/modules/vfatfs_syms.ver>
+#undef  CONFIG_MODVERSIONS
+#endif
index dc55e2e84de19e7460c15c474f6bfead5f98d283..1770811be121014e27718f1daf34a260bdd39299 100644 (file)
 #define PCI_DEVICE_ID_KTI_ET32P2       0x3000
 
 #define PCI_VENDOR_ID_ADAPTEC          0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810     0x1078
 #define PCI_DEVICE_ID_ADAPTEC_7850     0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855     0x5578
 #define PCI_DEVICE_ID_ADAPTEC_7860     0x6078
 #define PCI_DEVICE_ID_ADAPTEC_7872     0x7278
 #define PCI_DEVICE_ID_ADAPTEC_7873     0x7378
 #define PCI_DEVICE_ID_ADAPTEC_7874     0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895     0x7895
 #define PCI_DEVICE_ID_ADAPTEC_7880     0x8078
 #define PCI_DEVICE_ID_ADAPTEC_7881     0x8178
 #define PCI_DEVICE_ID_ADAPTEC_7882     0x8278
index b3b55d6409846ea295a15b139875976d37ca6aaa..1116e915fe7e92a67e4fb19c61d4319fb1f77076 100644 (file)
@@ -163,6 +163,7 @@ struct symbol_table symbol_table = {
        X(__brelse),
        X(__bforget),
        X(ll_rw_block),
+       X(brw_page),
        X(__wait_on_buffer),
        X(mark_buffer_uptodate),
        X(unlock_buffer),
index c050a0d56dbe19ecd290b85f408cecd45e54c3fe..d4d2628076d2862f1c8e868cc1ab8c83baac6243 100644 (file)
@@ -1283,6 +1283,9 @@ static __u16 ipx_set_checksum(ipx_packet *packet,int length)
         */
 
        __u32 i=length>>1;
+       char    hops = packet->ipx_tctrl;
+
+       packet->ipx_tctrl = 0;     /* hop count excluded from checksum calc */
 
        /*
         *      Loop through all complete words except the checksum field 
@@ -1298,6 +1301,7 @@ static __u16 ipx_set_checksum(ipx_packet *packet,int length)
        if(packet->ipx_pktsize&htons(1))
                sum+=ntohs(0xff00)&*p;
 
+       packet->ipx_tctrl = hops;
        /*
         *      Do final fixup 
         */
index da4731c602ea3f057db370f1bebf88ce4f33f1f0..76404b0d0b98eee9999aafcda7b8f9c7f9b04039 100644 (file)
 #
 # Please send comments / questions / bug fixes to roadcapw@titus.org
 #
+# 070498 Stepan Kasal <kasal@math.cas.cz> - one change borrowed
+# from 2.1.x version:
+#     131197 Michael Chastain (mec@shout.net) - output all lines for a
+#     choice list, not just the selected one.  This makes the output
+#     the same as Configure output, which is important for smart config
+#     dependencies.
+# It also fixes the bug when menuconfig sets CONFIG_M386=y every time
+# it is ran.
 #----------------------------------------------------------------------------
 
 #
@@ -972,11 +980,19 @@ save_configuration () {
                : ${current:=$default}
 
                #
-               # Then extract the actual option from the list of choices.
+               # Output all choices (to be compatible with other configs).
                #
-               current=${choices#*$current} ; set $current
-
-               define_bool "$1" "y"
+               set -- $choices
+               while [ -n "$2" ]
+               do
+                       if eval [ "$1" = "$current" ]
+                       then
+                           define_bool "$2" "y"
+                       else
+                           define_bool "$2" "n"
+                       fi
+                       shift ; shift
+               done
        }
 
        function mainmenu_name () {